Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / os-support / solaris / sun_bell.c
CommitLineData
a09e091a
JB
1/* Copyright (c) 2004-2005, Oracle and/or its affiliates. All rights reserved.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice (including the next
11 * paragraph) shall be included in all copies or substantial portions of the
12 * Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#ifdef HAVE_XORG_CONFIG_H
24#include <xorg-config.h>
25#endif
26
27#include <sys/audio.h>
28#include <sys/uio.h>
29#include <limits.h>
30#include <math.h>
31#include <poll.h>
32
33#include "xf86.h"
34#include "xf86Priv.h"
35#include "xf86_OSlib.h"
36
37#define BELL_RATE 48000 /* Samples per second */
38#define BELL_HZ 50 /* Fraction of a second i.e. 1/x */
39#define BELL_MS (1000/BELL_HZ) /* MS */
40#define BELL_SAMPLES (BELL_RATE / BELL_HZ)
41#define BELL_MIN 3 /* Min # of repeats */
42
43#define AUDIO_DEVICE "/dev/audio"
44
45void
46xf86OSRingBell(int loudness, int pitch, int duration)
47{
48 static short samples[BELL_SAMPLES];
49 static short silence[BELL_SAMPLES]; /* "The Sound of Silence" */
50 static int lastFreq;
51 int cnt;
52 int i;
53 int written;
54 int repeats;
55 int freq;
56 audio_info_t audioInfo;
57 struct iovec iov[IOV_MAX];
58 int iovcnt;
59 double ampl, cyclen, phase;
60 int audioFD;
61
62 if ((loudness <= 0) || (pitch <= 0) || (duration <= 0)) {
63 return;
64 }
65
66 lastFreq = 0;
67 memset(silence, 0, sizeof(silence));
68
69 audioFD = open(AUDIO_DEVICE, O_WRONLY | O_NONBLOCK);
70 if (audioFD == -1) {
71 xf86Msg(X_ERROR, "Bell: cannot open audio device \"%s\": %s\n",
72 AUDIO_DEVICE, strerror(errno));
73 return;
74 }
75
76 freq = pitch;
77 freq = min(freq, (BELL_RATE / 2) - 1);
78 freq = max(freq, 2 * BELL_HZ);
79
80 /*
81 * Ensure full waves per buffer
82 */
83 freq -= freq % BELL_HZ;
84
85 if (freq != lastFreq) {
86 lastFreq = freq;
87 ampl = 16384.0;
88
89 cyclen = (double) freq / (double) BELL_RATE;
90 phase = 0.0;
91
92 for (i = 0; i < BELL_SAMPLES; i++) {
93 samples[i] = (short) (ampl * sin(2.0 * M_PI * phase));
94 phase += cyclen;
95 if (phase >= 1.0)
96 phase -= 1.0;
97 }
98 }
99
100 repeats = (duration + (BELL_MS / 2)) / BELL_MS;
101 repeats = max(repeats, BELL_MIN);
102
103 loudness = max(0, loudness);
104 loudness = min(loudness, 100);
105
106#ifdef DEBUG
107 ErrorF("BELL : freq %d volume %d duration %d repeats %d\n",
108 freq, loudness, duration, repeats);
109#endif
110
111 AUDIO_INITINFO(&audioInfo);
112 audioInfo.play.encoding = AUDIO_ENCODING_LINEAR;
113 audioInfo.play.sample_rate = BELL_RATE;
114 audioInfo.play.channels = 2;
115 audioInfo.play.precision = 16;
116 audioInfo.play.gain = min(AUDIO_MAX_GAIN, AUDIO_MAX_GAIN * loudness / 100);
117
118 if (ioctl(audioFD, AUDIO_SETINFO, &audioInfo) < 0) {
119 xf86Msg(X_ERROR,
120 "Bell: AUDIO_SETINFO failed on audio device \"%s\": %s\n",
121 AUDIO_DEVICE, strerror(errno));
122 close(audioFD);
123 return;
124 }
125
126 iovcnt = 0;
127
128 for (cnt = 0; cnt <= repeats; cnt++) {
129 if (cnt == repeats) {
130 /* Insert a bit of silence so that multiple beeps are distinct and
131 * not compressed into a single tone.
132 */
133 iov[iovcnt].iov_base = (char *) silence;
134 iov[iovcnt++].iov_len = sizeof(silence);
135 }
136 else {
137 iov[iovcnt].iov_base = (char *) samples;
138 iov[iovcnt++].iov_len = sizeof(samples);
139 }
140 if ((iovcnt >= IOV_MAX) || (cnt == repeats)) {
141 written = writev(audioFD, iov, iovcnt);
142
143 if ((written < ((int) (sizeof(samples) * iovcnt)))) {
144 /* audio buffer was full! */
145
146 int naptime;
147
148 if (written == -1) {
149 if (errno != EAGAIN) {
150 xf86Msg(X_ERROR,
151 "Bell: writev failed on audio device \"%s\": %s\n",
152 AUDIO_DEVICE, strerror(errno));
153 close(audioFD);
154 return;
155 }
156 i = iovcnt;
157 }
158 else {
159 i = ((sizeof(samples) * iovcnt) - written)
160 / sizeof(samples);
161 }
162 cnt -= i;
163
164 /* sleep a little to allow audio buffer to drain */
165 naptime = BELL_MS * i;
166 poll(NULL, 0, naptime);
167
168 i = ((sizeof(samples) * iovcnt) - written) % sizeof(samples);
169 iovcnt = 0;
170 if ((written != -1) && (i > 0)) {
171 iov[iovcnt].iov_base = ((char *) samples) + i;
172 iov[iovcnt++].iov_len = sizeof(samples) - i;
173 }
174 }
175 else {
176 iovcnt = 0;
177 }
178 }
179 }
180
181 close(audioFD);
182 return;
183}