Mercurial > mplayer.hg
annotate libao2/ao_esd.c @ 12022:293141b57c01
Use MultiplyElement to control volume.
Works with multiple videos at the same time and even
when NAS does not control the mixer or it is unavailable.
Show buffer underrun hint only once and add missing linebreaks.
author | ranma |
---|---|
date | Sat, 13 Mar 2004 21:54:35 +0000 |
parents | 179138947307 |
children | 99798c3cdb93 |
rev | line source |
---|---|
8572 | 1 /* |
2 * ao_esd - EsounD audio output driver for MPlayer | |
3 * | |
4 * Juergen Keil <jk@tools.de> | |
5 * | |
6 * This driver is distributed under the terms of the GPL | |
7 * | |
8 * TODO / known problems: | |
9 * - does not work well when the esd daemon has autostandby disabled | |
10 * (workaround: run esd with option "-as 2" - fortunatelly this is | |
11 * the default) | |
12 * - plays noise on a linux 2.4.4 kernel with a SB16PCI card, when using | |
13 * a local tcp connection to the esd daemon; there is no noise when using | |
14 * a unix domain socket connection. | |
15 * (there are EIO errors reported by the sound card driver, so this is | |
16 * most likely a linux sound card driver problem) | |
17 */ | |
18 | |
19 #include "../config.h" | |
20 | |
21 #include <sys/types.h> | |
22 #include <sys/time.h> | |
23 #include <sys/socket.h> | |
24 #include <stdio.h> | |
25 #include <string.h> | |
26 #include <unistd.h> | |
27 #include <errno.h> | |
28 #include <fcntl.h> | |
8623
440301fef3fe
Added/reordered #includes to silence warnings about "implicit declaration".
rathann
parents:
8572
diff
changeset
|
29 #include <time.h> |
8572 | 30 #ifdef __svr4__ |
31 #include <stropts.h> | |
32 #endif | |
33 #include <esd.h> | |
34 | |
35 #include "audio_out.h" | |
36 #include "audio_out_internal.h" | |
37 #include "afmt.h" | |
38 #include "../config.h" | |
39 #include "../mp_msg.h" | |
40 | |
41 | |
42 #undef ESD_DEBUG | |
43 | |
44 #if ESD_DEBUG | |
45 #define dprintf(...) printf(__VA_ARGS__) | |
46 #else | |
47 #define dprintf(...) /**/ | |
48 #endif | |
49 | |
50 | |
51 #define ESD_CLIENT_NAME "MPlayer" | |
52 #define ESD_MAX_DELAY (1.0f) /* max amount of data buffered in esd (#sec) */ | |
53 | |
54 static ao_info_t info = | |
55 { | |
56 "EsounD audio output", | |
57 "esd", | |
58 "Juergen Keil <jk@tools.de>", | |
59 "" | |
60 }; | |
61 | |
62 LIBAO_EXTERN(esd) | |
63 | |
64 static int esd_fd = -1; | |
65 static int esd_play_fd = -1; | |
66 static esd_server_info_t *esd_svinfo; | |
67 static int esd_latency; | |
68 static int esd_bytes_per_sample; | |
69 static unsigned long esd_samples_written; | |
70 static struct timeval esd_play_start; | |
10213
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
71 extern float audio_delay; |
8572 | 72 |
73 /* | |
74 * to set/get/query special features/parameters | |
75 */ | |
9633
12b1790038b0
64bit libao2 fix by Jens Axboe <mplayer-dev@kernel.dk>
alex
parents:
8623
diff
changeset
|
76 static int control(int cmd, void *arg) |
8572 | 77 { |
78 esd_player_info_t *esd_pi; | |
79 esd_info_t *esd_i; | |
80 time_t now; | |
81 static time_t vol_cache_time; | |
82 static ao_control_vol_t vol_cache; | |
83 | |
84 switch (cmd) { | |
85 case AOCONTROL_GET_VOLUME: | |
86 time(&now); | |
87 if (now == vol_cache_time) { | |
88 *(ao_control_vol_t *)arg = vol_cache; | |
89 return CONTROL_OK; | |
90 } | |
91 | |
92 dprintf("esd: get vol\n"); | |
93 if ((esd_i = esd_get_all_info(esd_fd)) == NULL) | |
94 return CONTROL_ERROR; | |
95 | |
96 for (esd_pi = esd_i->player_list; esd_pi != NULL; esd_pi = esd_pi->next) | |
97 if (strcmp(esd_pi->name, ESD_CLIENT_NAME) == 0) | |
98 break; | |
99 | |
100 if (esd_pi != NULL) { | |
101 ao_control_vol_t *vol = (ao_control_vol_t *)arg; | |
102 vol->left = esd_pi->left_vol_scale * 100 / ESD_VOLUME_BASE; | |
103 vol->right = esd_pi->right_vol_scale * 100 / ESD_VOLUME_BASE; | |
104 | |
105 vol_cache = *vol; | |
106 vol_cache_time = now; | |
107 } | |
108 esd_free_all_info(esd_i); | |
109 | |
110 return CONTROL_OK; | |
111 | |
112 case AOCONTROL_SET_VOLUME: | |
113 dprintf("esd: set vol\n"); | |
114 if ((esd_i = esd_get_all_info(esd_fd)) == NULL) | |
115 return CONTROL_ERROR; | |
116 | |
117 for (esd_pi = esd_i->player_list; esd_pi != NULL; esd_pi = esd_pi->next) | |
118 if (strcmp(esd_pi->name, ESD_CLIENT_NAME) == 0) | |
119 break; | |
120 | |
121 if (esd_pi != NULL) { | |
122 ao_control_vol_t *vol = (ao_control_vol_t *)arg; | |
123 esd_set_stream_pan(esd_fd, esd_pi->source_id, | |
124 vol->left * ESD_VOLUME_BASE / 100, | |
125 vol->right * ESD_VOLUME_BASE / 100); | |
126 | |
127 vol_cache = *vol; | |
128 time(&vol_cache_time); | |
129 } | |
130 esd_free_all_info(esd_i); | |
131 return CONTROL_OK; | |
132 | |
133 default: | |
134 return CONTROL_UNKNOWN; | |
135 } | |
136 } | |
137 | |
138 | |
139 /* | |
140 * open & setup audio device | |
141 * return: 1=success 0=fail | |
142 */ | |
143 static int init(int rate_hz, int channels, int format, int flags) | |
144 { | |
145 esd_format_t esd_fmt; | |
146 int bytes_per_sample; | |
147 int fl; | |
10213
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
148 char *server = ao_subdevice; /* NULL for localhost */ |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
149 float lag_seconds, lag_net, lag_serv; |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
150 struct timeval proto_start, proto_end; |
8572 | 151 |
152 if (esd_fd < 0) { | |
10213
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
153 esd_fd = esd_open_sound(server); |
8572 | 154 if (esd_fd < 0) { |
10213
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
155 mp_msg(MSGT_AO, MSGL_ERR, |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
156 "AO: [esd] esd_open_sound failed: %s\n", |
8572 | 157 strerror(errno)); |
158 return 0; | |
159 } | |
160 | |
10213
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
161 /* get server info, and measure network latency */ |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
162 gettimeofday(&proto_start, NULL); |
8572 | 163 esd_svinfo = esd_get_server_info(esd_fd); |
10213
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
164 if(server) { |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
165 gettimeofday(&proto_end, NULL); |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
166 lag_net = (proto_end.tv_sec - proto_start.tv_sec) + |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
167 (proto_end.tv_usec - proto_start.tv_usec) / 1000000.0; |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
168 lag_net /= 2.0; /* round trip -> one way */ |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
169 } else |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
170 lag_net = 0.0; /* no network lag */ |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
171 |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
172 /* |
8572 | 173 if (esd_svinfo) { |
174 mp_msg(MSGT_AO, MSGL_INFO, "AO: [esd] server info:\n"); | |
175 esd_print_server_info(esd_svinfo); | |
176 } | |
10213
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
177 */ |
8572 | 178 } |
179 | |
180 esd_fmt = ESD_STREAM | ESD_PLAY; | |
181 | |
182 #if ESD_RESAMPLES | |
183 /* let the esd daemon convert sample rate */ | |
184 #else | |
185 /* let mplayer's audio filter convert the sample rate */ | |
186 if (esd_svinfo != NULL) | |
187 rate_hz = esd_svinfo->rate; | |
188 #endif | |
189 ao_data.samplerate = rate_hz; | |
190 | |
191 /* EsounD can play mono or stereo */ | |
192 switch (channels) { | |
193 case 1: | |
194 esd_fmt |= ESD_MONO; | |
195 ao_data.channels = bytes_per_sample = 1; | |
196 break; | |
197 default: | |
198 esd_fmt |= ESD_STEREO; | |
199 ao_data.channels = bytes_per_sample = 2; | |
200 break; | |
201 } | |
202 | |
203 /* EsounD can play 8bit unsigned and 16bit signed native */ | |
204 switch (format) { | |
205 case AFMT_S8: | |
206 case AFMT_U8: | |
207 esd_fmt |= ESD_BITS8; | |
208 ao_data.format = AFMT_U8; | |
209 break; | |
210 default: | |
211 esd_fmt |= ESD_BITS16; | |
212 ao_data.format = AFMT_S16_NE; | |
213 bytes_per_sample *= 2; | |
214 break; | |
215 } | |
216 | |
10213
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
217 /* modify audio_delay depending on esd_latency |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
218 * latency is number of samples @ 44.1khz stereo 16 bit |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
219 * adjust according to rate_hz & bytes_per_sample |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
220 */ |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
221 #ifdef HAVE_ESD_LATENCY |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
222 esd_latency = esd_get_latency(esd_fd); |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
223 #else |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
224 esd_latency = ((channels == 1 ? 2 : 1) * ESD_DEFAULT_RATE * |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
225 (ESD_BUF_SIZE + 64 * (4.0f / bytes_per_sample)) |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
226 ) / rate_hz; |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
227 esd_latency += ESD_BUF_SIZE * 2; |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
228 #endif |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
229 if(esd_latency > 0) { |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
230 lag_serv = (esd_latency * 4.0f) / (bytes_per_sample * rate_hz); |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
231 lag_seconds = lag_net + lag_serv; |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
232 audio_delay += lag_seconds; |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
233 mp_msg(MSGT_AO, MSGL_INFO, |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
234 "AO: [esd] latency: [server: %0.2fs, net: %0.2fs] " |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
235 "(adjust %0.2fs)\n", lag_serv, lag_net, lag_seconds); |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
236 } |
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
237 |
8572 | 238 esd_play_fd = esd_play_stream_fallback(esd_fmt, rate_hz, |
10213
5e15ff3261ff
esd:server and esd latency support by Andrew Williams <andrew.s.williams@adelaide.edu.au>
alex
parents:
9633
diff
changeset
|
239 server, ESD_CLIENT_NAME); |
8572 | 240 if (esd_play_fd < 0) { |
241 mp_msg(MSGT_AO, MSGL_ERR, | |
242 "AO: [esd] failed to open esd playback stream: %s\n", | |
243 strerror(errno)); | |
244 return 0; | |
245 } | |
246 | |
247 /* enable non-blocking i/o on the socket connection to the esd server */ | |
248 if ((fl = fcntl(esd_play_fd, F_GETFL)) >= 0) | |
249 fcntl(esd_play_fd, F_SETFL, O_NDELAY|fl); | |
250 | |
251 #if ESD_DEBUG | |
252 { | |
253 int sbuf, rbuf, len; | |
254 len = sizeof(sbuf); | |
255 getsockopt(esd_play_fd, SOL_SOCKET, SO_SNDBUF, &sbuf, &len); | |
256 len = sizeof(rbuf); | |
257 getsockopt(esd_play_fd, SOL_SOCKET, SO_RCVBUF, &rbuf, &len); | |
258 dprintf("esd: send/receive socket buffer space %d/%d bytes\n", | |
259 sbuf, rbuf); | |
260 } | |
261 #endif | |
262 | |
263 ao_data.bps = bytes_per_sample * rate_hz; | |
264 ao_data.outburst = ao_data.bps > 100000 ? 4*ESD_BUF_SIZE : 2*ESD_BUF_SIZE; | |
265 | |
266 esd_play_start.tv_sec = 0; | |
267 esd_samples_written = 0; | |
268 esd_bytes_per_sample = bytes_per_sample; | |
269 | |
270 return 1; | |
271 } | |
272 | |
273 | |
274 /* | |
275 * close audio device | |
276 */ | |
277 static void uninit() | |
278 { | |
279 if (esd_play_fd >= 0) { | |
280 esd_close(esd_play_fd); | |
281 esd_play_fd = -1; | |
282 } | |
283 | |
284 if (esd_svinfo) { | |
285 esd_free_server_info(esd_svinfo); | |
286 esd_svinfo = NULL; | |
287 } | |
288 | |
289 if (esd_fd >= 0) { | |
290 esd_close(esd_fd); | |
291 esd_fd = -1; | |
292 } | |
293 } | |
294 | |
295 | |
296 /* | |
297 * plays 'len' bytes of 'data' | |
298 * it should round it down to outburst*n | |
299 * return: number of bytes played | |
300 */ | |
301 static int play(void* data, int len, int flags) | |
302 { | |
303 int offs; | |
304 int nwritten; | |
305 int nsamples; | |
306 int remainder, n; | |
307 int saved_fl; | |
308 | |
309 /* round down buffersize to a multiple of ESD_BUF_SIZE bytes */ | |
310 len = len / ESD_BUF_SIZE * ESD_BUF_SIZE; | |
311 if (len <= 0) | |
312 return 0; | |
313 | |
314 #define SINGLE_WRITE 0 | |
315 #if SINGLE_WRITE | |
316 nwritten = write(esd_play_fd, data, len); | |
317 #else | |
11619
179138947307
This patch contains bugfixes for the esd audio output driver that I
attila
parents:
10213
diff
changeset
|
318 for (offs = 0, nwritten=0; offs + ESD_BUF_SIZE <= len; offs += ESD_BUF_SIZE) { |
8572 | 319 /* |
320 * note: we're writing to a non-blocking socket here. | |
321 * A partial write means, that the socket buffer is full. | |
322 */ | |
11619
179138947307
This patch contains bugfixes for the esd audio output driver that I
attila
parents:
10213
diff
changeset
|
323 n = write(esd_play_fd, (char*)data + offs, ESD_BUF_SIZE); |
179138947307
This patch contains bugfixes for the esd audio output driver that I
attila
parents:
10213
diff
changeset
|
324 if ( n < 0 ) { |
179138947307
This patch contains bugfixes for the esd audio output driver that I
attila
parents:
10213
diff
changeset
|
325 if ( errno != EAGAIN ) |
8572 | 326 dprintf("esd play: write failed: %s\n", strerror(errno)); |
327 break; | |
11619
179138947307
This patch contains bugfixes for the esd audio output driver that I
attila
parents:
10213
diff
changeset
|
328 } else if ( n != ESD_BUF_SIZE ) { |
179138947307
This patch contains bugfixes for the esd audio output driver that I
attila
parents:
10213
diff
changeset
|
329 nwritten += n; |
179138947307
This patch contains bugfixes for the esd audio output driver that I
attila
parents:
10213
diff
changeset
|
330 break; |
8572 | 331 } else |
332 nwritten += n; | |
333 } | |
11619
179138947307
This patch contains bugfixes for the esd audio output driver that I
attila
parents:
10213
diff
changeset
|
334 #endif |
179138947307
This patch contains bugfixes for the esd audio output driver that I
attila
parents:
10213
diff
changeset
|
335 |
8572 | 336 if (nwritten > 0) { |
337 if (!esd_play_start.tv_sec) | |
338 gettimeofday(&esd_play_start, NULL); | |
339 nsamples = nwritten / esd_bytes_per_sample; | |
340 esd_samples_written += nsamples; | |
341 | |
342 dprintf("esd play: %d %lu\n", nsamples, esd_samples_written); | |
343 } else { | |
344 dprintf("esd play: blocked / %lu\n", esd_samples_written); | |
345 } | |
346 | |
347 return nwritten; | |
348 } | |
349 | |
350 | |
351 /* | |
352 * stop playing, keep buffers (for pause) | |
353 */ | |
354 static void audio_pause() | |
355 { | |
356 /* | |
357 * not possible with esd. the esd daemom will continue playing | |
358 * buffered data (not more than ESD_MAX_DELAY seconds of samples) | |
359 */ | |
360 } | |
361 | |
362 | |
363 /* | |
364 * resume playing, after audio_pause() | |
365 */ | |
366 static void audio_resume() | |
367 { | |
368 /* | |
369 * not possible with esd. | |
370 * | |
371 * Let's hope the pause was long enough that the esd ran out of | |
372 * buffered data; we restart our time based delay computation | |
373 * for an audio resume. | |
374 */ | |
375 esd_play_start.tv_sec = 0; | |
376 esd_samples_written = 0; | |
377 } | |
378 | |
379 | |
380 /* | |
381 * stop playing and empty buffers (for seeking/pause) | |
382 */ | |
383 static void reset() | |
384 { | |
385 #ifdef __svr4__ | |
386 /* throw away data buffered in the esd connection */ | |
387 if (ioctl(esd_play_fd, I_FLUSH, FLUSHW)) | |
388 perror("I_FLUSH"); | |
389 #endif | |
390 } | |
391 | |
392 | |
393 /* | |
394 * return: how many bytes can be played without blocking | |
395 */ | |
396 static int get_space() | |
397 { | |
398 struct timeval tmout; | |
399 fd_set wfds; | |
400 float current_delay; | |
401 int space; | |
402 | |
403 /* | |
404 * Don't buffer too much data in the esd daemon. | |
405 * | |
406 * If we send too much, esd will block in write()s to the sound | |
407 * device, and the consequence is a huge slow down for things like | |
408 * esd_get_all_info(). | |
409 */ | |
410 if ((current_delay = get_delay()) >= ESD_MAX_DELAY) { | |
411 dprintf("esd get_space: too much data buffered\n"); | |
412 return 0; | |
413 } | |
414 | |
415 FD_ZERO(&wfds); | |
416 FD_SET(esd_play_fd, &wfds); | |
417 tmout.tv_sec = 0; | |
418 tmout.tv_usec = 0; | |
419 | |
420 if (select(esd_play_fd + 1, NULL, &wfds, NULL, &tmout) != 1) | |
421 return 0; | |
422 | |
423 if (!FD_ISSET(esd_play_fd, &wfds)) | |
424 return 0; | |
425 | |
426 /* try to fill 50% of the remaining "free" buffer space */ | |
427 space = (ESD_MAX_DELAY - current_delay) * ao_data.bps * 0.5f; | |
428 | |
429 /* round up to next multiple of ESD_BUF_SIZE */ | |
430 space = (space + ESD_BUF_SIZE-1) / ESD_BUF_SIZE * ESD_BUF_SIZE; | |
431 | |
432 dprintf("esd get_space: %d\n", space); | |
433 return space; | |
434 } | |
435 | |
436 | |
437 /* | |
438 * return: delay in seconds between first and last sample in buffer | |
439 */ | |
440 static float get_delay() | |
441 { | |
442 struct timeval now; | |
443 double buffered_samples_time; | |
444 double play_time; | |
445 | |
446 if (!esd_play_start.tv_sec) | |
447 return 0; | |
448 | |
449 buffered_samples_time = (float)esd_samples_written / ao_data.samplerate; | |
450 gettimeofday(&now, NULL); | |
451 play_time = now.tv_sec - esd_play_start.tv_sec; | |
452 play_time += (now.tv_usec - esd_play_start.tv_usec) / 1000000.; | |
453 | |
454 /* dprintf("esd delay: %f %f\n", play_time, buffered_samples_time); */ | |
455 | |
456 if (play_time > buffered_samples_time) { | |
457 dprintf("esd: underflow\n"); | |
458 esd_play_start.tv_sec = 0; | |
459 esd_samples_written = 0; | |
460 return 0; | |
461 } | |
462 | |
463 dprintf("esd: get_delay %f\n", buffered_samples_time - play_time); | |
464 return buffered_samples_time - play_time; | |
465 } |