Lines 120-138
Link Here
|
120 |
}; |
120 |
}; |
121 |
int i; |
121 |
int i; |
122 |
|
122 |
|
123 |
diff --git media/libcubeb/src/cubeb_alsa.c media/libcubeb/src/cubeb_alsa.c |
123 |
--- media/libcubeb/src/cubeb_alsa.c 2014-11-26 07:30:16.000000000 -0500 |
124 |
index a962553..1f780f4 100644 |
124 |
+++ media/libcubeb/src/cubeb_alsa.c 2014-12-16 22:03:04.000000000 -0500 |
125 |
--- media/libcubeb/src/cubeb_alsa.c |
125 |
@@ -11,7 +11,10 @@ |
126 |
+++ media/libcubeb/src/cubeb_alsa.c |
|
|
127 |
@@ -11,6 +11,7 @@ |
128 |
#include <sys/time.h> |
126 |
#include <sys/time.h> |
129 |
#include <assert.h> |
127 |
#include <assert.h> |
130 |
#include <limits.h> |
128 |
#include <limits.h> |
131 |
+#include <dlfcn.h> |
129 |
+#include <dlfcn.h> |
132 |
#include <poll.h> |
130 |
#include <poll.h> |
|
|
131 |
+#include <stdlib.h> |
132 |
+#include <stdio.h> |
133 |
#include <unistd.h> |
133 |
#include <unistd.h> |
134 |
#include <alsa/asoundlib.h> |
134 |
#include <alsa/asoundlib.h> |
135 |
@@ -24,6 +25,50 @@ |
135 |
#include "cubeb/cubeb.h" |
|
|
136 |
@@ -24,6 +27,51 @@ |
136 |
|
137 |
|
137 |
#define ALSA_PA_PLUGIN "ALSA <-> PulseAudio PCM I/O Plugin" |
138 |
#define ALSA_PA_PLUGIN "ALSA <-> PulseAudio PCM I/O Plugin" |
138 |
|
139 |
|
Lines 155-160
Link Here
|
155 |
+MAKE_TYPEDEF(snd_pcm_close); |
156 |
+MAKE_TYPEDEF(snd_pcm_close); |
156 |
+MAKE_TYPEDEF(snd_pcm_delay); |
157 |
+MAKE_TYPEDEF(snd_pcm_delay); |
157 |
+MAKE_TYPEDEF(snd_pcm_drain); |
158 |
+MAKE_TYPEDEF(snd_pcm_drain); |
|
|
159 |
+MAKE_TYPEDEF(snd_pcm_forward); |
158 |
+MAKE_TYPEDEF(snd_pcm_frames_to_bytes); |
160 |
+MAKE_TYPEDEF(snd_pcm_frames_to_bytes); |
159 |
+MAKE_TYPEDEF(snd_pcm_get_params); |
161 |
+MAKE_TYPEDEF(snd_pcm_get_params); |
160 |
+/* snd_pcm_hw_params_alloca is actually a macro */ |
162 |
+/* snd_pcm_hw_params_alloca is actually a macro */ |
Lines 183-189
Link Here
|
183 |
/* ALSA is not thread-safe. snd_pcm_t instances are individually protected |
185 |
/* ALSA is not thread-safe. snd_pcm_t instances are individually protected |
184 |
by the owning cubeb_stream's mutex. snd_pcm_t creation and destruction |
186 |
by the owning cubeb_stream's mutex. snd_pcm_t creation and destruction |
185 |
is not thread-safe until ALSA 1.0.24 (see alsa-lib.git commit 91c9c8f1), |
187 |
is not thread-safe until ALSA 1.0.24 (see alsa-lib.git commit 91c9c8f1), |
186 |
@@ -64,6 +109,8 @@ struct cubeb { |
188 |
@@ -64,6 +112,8 @@ |
187 |
workaround is not required. */ |
189 |
workaround is not required. */ |
188 |
snd_config_t * local_config; |
190 |
snd_config_t * local_config; |
189 |
int is_pa; |
191 |
int is_pa; |
Lines 192-221
Link Here
|
192 |
}; |
194 |
}; |
193 |
|
195 |
|
194 |
enum stream_state { |
196 |
enum stream_state { |
195 |
@@ -262,7 +309,7 @@ alsa_refill_stream(cubeb_stream * stm) |
197 |
@@ -257,32 +307,35 @@ |
|
|
198 |
long got; |
199 |
void * p; |
200 |
int draining; |
201 |
+ unsigned pipefailures, againfailures; |
196 |
|
202 |
|
|
|
203 |
draining = 0; |
204 |
|
197 |
pthread_mutex_lock(&stm->mutex); |
205 |
pthread_mutex_lock(&stm->mutex); |
198 |
|
206 |
|
199 |
- r = snd_pcm_poll_descriptors_revents(stm->pcm, stm->fds, stm->nfds, &revents); |
207 |
- r = snd_pcm_poll_descriptors_revents(stm->pcm, stm->fds, stm->nfds, &revents); |
200 |
+ r = WRAP(snd_pcm_poll_descriptors_revents)(stm->pcm, stm->fds, stm->nfds, &revents); |
208 |
- if (r < 0 || revents != POLLOUT) { |
201 |
if (r < 0 || revents != POLLOUT) { |
209 |
- /* This should be a stream error; it makes no sense for poll(2) to wake |
202 |
/* This should be a stream error; it makes no sense for poll(2) to wake |
210 |
- for this stream and then have the stream report that it's not ready. |
203 |
for this stream and then have the stream report that it's not ready. |
211 |
- Unfortunately, this does happen, so just bail out and try again. */ |
204 |
@@ -271,10 +318,10 @@ alsa_refill_stream(cubeb_stream * stm) |
212 |
- pthread_mutex_unlock(&stm->mutex); |
205 |
return RUNNING; |
213 |
- return RUNNING; |
206 |
} |
214 |
- } |
207 |
|
215 |
- |
208 |
- avail = snd_pcm_avail_update(stm->pcm); |
216 |
- avail = snd_pcm_avail_update(stm->pcm); |
209 |
+ avail = WRAP(snd_pcm_avail_update)(stm->pcm); |
217 |
- if (avail == -EPIPE) { |
210 |
if (avail == -EPIPE) { |
|
|
211 |
- snd_pcm_recover(stm->pcm, avail, 1); |
218 |
- snd_pcm_recover(stm->pcm, avail, 1); |
212 |
- avail = snd_pcm_avail_update(stm->pcm); |
219 |
- avail = snd_pcm_avail_update(stm->pcm); |
|
|
220 |
- } |
221 |
+ for (pipefailures = 0;;) { |
222 |
+ r = WRAP(snd_pcm_poll_descriptors_revents)(stm->pcm, stm->fds, stm->nfds, &revents); |
223 |
+ if (r < 0 || revents != POLLOUT || |
224 |
+ (avail = WRAP(snd_pcm_avail_update)(stm->pcm)) == 0) { |
225 |
+ /* This should be a stream error; it makes no sense for poll(2) to wake |
226 |
+ for this stream and then have the stream report that it's not ready. |
227 |
+ Unfortunately, this does happen, so just bail out and try again. */ |
228 |
+ pthread_mutex_unlock(&stm->mutex); |
229 |
+ return RUNNING; |
230 |
+ } |
231 |
|
232 |
- /* Failed to recover from an xrun, this stream must be broken. */ |
233 |
- if (avail < 0) { |
234 |
- pthread_mutex_unlock(&stm->mutex); |
235 |
- stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
236 |
- return ERROR; |
237 |
+ if (avail > 0) |
238 |
+ break; |
239 |
+ if (pipefailures++ > 11) { |
240 |
+ fprintf(stderr, "%s: repeated failures from snd_pcm_avail_update, " |
241 |
+ "giving up\n", __func__); |
242 |
+ pthread_mutex_unlock(&stm->mutex); |
243 |
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
244 |
+ return ERROR; |
245 |
+ } |
213 |
+ WRAP(snd_pcm_recover)(stm->pcm, avail, 1); |
246 |
+ WRAP(snd_pcm_recover)(stm->pcm, avail, 1); |
214 |
+ avail = WRAP(snd_pcm_avail_update)(stm->pcm); |
|
|
215 |
} |
247 |
} |
|
|
248 |
+ pipefailures = againfailures = 0; |
216 |
|
249 |
|
217 |
/* Failed to recover from an xrun, this stream must be broken. */ |
250 |
/* This should never happen. */ |
218 |
@@ -293,8 +340,8 @@ alsa_refill_stream(cubeb_stream * stm) |
251 |
if ((unsigned int) avail > stm->buffer_size) { |
|
|
252 |
@@ -293,8 +346,8 @@ |
219 |
available to write. If avail is still zero here, the stream must be in |
253 |
available to write. If avail is still zero here, the stream must be in |
220 |
a funky state, so recover and try again. */ |
254 |
a funky state, so recover and try again. */ |
221 |
if (avail == 0) { |
255 |
if (avail == 0) { |
Lines 226-232
Link Here
|
226 |
if (avail <= 0) { |
260 |
if (avail <= 0) { |
227 |
pthread_mutex_unlock(&stm->mutex); |
261 |
pthread_mutex_unlock(&stm->mutex); |
228 |
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
262 |
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
229 |
@@ -302,7 +349,7 @@ alsa_refill_stream(cubeb_stream * stm) |
263 |
@@ -302,7 +355,7 @@ |
230 |
} |
264 |
} |
231 |
} |
265 |
} |
232 |
|
266 |
|
Lines 235-255
Link Here
|
235 |
assert(p); |
269 |
assert(p); |
236 |
|
270 |
|
237 |
pthread_mutex_unlock(&stm->mutex); |
271 |
pthread_mutex_unlock(&stm->mutex); |
238 |
@@ -327,10 +374,10 @@ alsa_refill_stream(cubeb_stream * stm) |
272 |
@@ -311,10 +364,11 @@ |
|
|
273 |
if (got < 0) { |
274 |
pthread_mutex_unlock(&stm->mutex); |
275 |
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
276 |
+ free(p); |
277 |
return ERROR; |
278 |
} |
279 |
if (got > 0) { |
280 |
- snd_pcm_sframes_t wrote; |
281 |
+ snd_pcm_sframes_t wrote, towrite = got; |
282 |
|
283 |
if (stm->params.format == CUBEB_SAMPLE_FLOAT32NE) { |
284 |
float * b = (float *) p; |
285 |
@@ -327,14 +381,62 @@ |
239 |
b[i] *= stm->volume; |
286 |
b[i] *= stm->volume; |
240 |
} |
287 |
} |
241 |
} |
288 |
} |
242 |
- wrote = snd_pcm_writei(stm->pcm, p, got); |
289 |
- wrote = snd_pcm_writei(stm->pcm, p, got); |
243 |
+ wrote = WRAP(snd_pcm_writei)(stm->pcm, p, got); |
290 |
- if (wrote == -EPIPE) { |
244 |
if (wrote == -EPIPE) { |
|
|
245 |
- snd_pcm_recover(stm->pcm, wrote, 1); |
291 |
- snd_pcm_recover(stm->pcm, wrote, 1); |
246 |
- wrote = snd_pcm_writei(stm->pcm, p, got); |
292 |
- wrote = snd_pcm_writei(stm->pcm, p, got); |
247 |
+ WRAP(snd_pcm_recover)(stm->pcm, wrote, 1); |
293 |
- } |
248 |
+ wrote = WRAP(snd_pcm_writei)(stm->pcm, p, got); |
294 |
- assert(wrote >= 0 && wrote == got); |
249 |
} |
295 |
- stm->write_position += wrote; |
250 |
assert(wrote >= 0 && wrote == got); |
296 |
- gettimeofday(&stm->last_activity, NULL); |
251 |
stm->write_position += wrote; |
297 |
+ for (;;) { |
252 |
@@ -342,7 +389,7 @@ alsa_refill_stream(cubeb_stream * stm) |
298 |
+ wrote = WRAP(snd_pcm_writei)(stm->pcm, p, |
|
|
299 |
+ towrite > avail ? avail : towrite); |
300 |
+ switch(wrote) { |
301 |
+ case -EPIPE: |
302 |
+ if (pipefailures++ > 3) { |
303 |
+ fprintf(stderr, "%s: Too many underflows, giving up\n", __func__); |
304 |
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
305 |
+ pthread_mutex_unlock(&stm->mutex); |
306 |
+ free(p); |
307 |
+ return ERROR; |
308 |
+ } |
309 |
+ WRAP(snd_pcm_recover)(stm->pcm, wrote, 1); |
310 |
+ continue; |
311 |
+ case -EAGAIN: |
312 |
+ if (againfailures++ > 3) { |
313 |
+ fprintf(stderr, "%s: Too many -EAGAIN errors from snd_pcm_writei, " |
314 |
+ "giving up\n", __func__); |
315 |
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
316 |
+ pthread_mutex_unlock(&stm->mutex); |
317 |
+ free(p); |
318 |
+ return ERROR; |
319 |
+ } |
320 |
+ continue; |
321 |
+ case -EBADFD: |
322 |
+ fprintf(stderr, "%s: snc_pcm_writei returned -%s, giving up\n", |
323 |
+ __func__, "EBADFD"); |
324 |
+ free(p); |
325 |
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
326 |
+ pthread_mutex_unlock(&stm->mutex); |
327 |
+ return ERROR; |
328 |
+ } |
329 |
+ if (wrote < 0) { |
330 |
+ fprintf(stderr, "%s: snc_pcm_writei returned unexpected error %lld, " |
331 |
+ "giving up\n", __func__, (long long)wrote); |
332 |
+ free(p); |
333 |
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
334 |
+ pthread_mutex_unlock(&stm->mutex); |
335 |
+ return ERROR; |
336 |
+ } |
337 |
+ pipefailures = againfailures = 0; |
338 |
+ stm->write_position += wrote; |
339 |
+ gettimeofday(&stm->last_activity, NULL); |
340 |
+ if (wrote > towrite) { |
341 |
+ fprintf(stderr, "%s: snc_pcm_writei wrote %lld frames, which was more " |
342 |
+ "than we requested (%lld). This should not happen, giving up\n", |
343 |
+ __func__, (long long)wrote, (long long)towrite); |
344 |
+ free(p); |
345 |
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); |
346 |
+ pthread_mutex_unlock(&stm->mutex); |
347 |
+ return ERROR; |
348 |
+ } |
349 |
+ if (towrite == wrote) |
350 |
+ break; |
351 |
+ towrite -= wrote; |
352 |
+ } |
353 |
} |
354 |
if (got != avail) { |
355 |
long buffer_fill = stm->buffer_size - (avail - got); |
356 |
@@ -342,7 +444,7 @@ |
253 |
|
357 |
|
254 |
/* Fill the remaining buffer with silence to guarantee one full period |
358 |
/* Fill the remaining buffer with silence to guarantee one full period |
255 |
has been written. */ |
359 |
has been written. */ |
Lines 258-264
Link Here
|
258 |
|
362 |
|
259 |
set_timeout(&stm->drain_timeout, buffer_time * 1000); |
363 |
set_timeout(&stm->drain_timeout, buffer_time * 1000); |
260 |
|
364 |
|
261 |
@@ -453,26 +500,26 @@ get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm) |
365 |
@@ -453,26 +555,26 @@ |
262 |
|
366 |
|
263 |
slave_def = NULL; |
367 |
slave_def = NULL; |
264 |
|
368 |
|
Lines 290-296
Link Here
|
290 |
if (r < 0) { |
394 |
if (r < 0) { |
291 |
break; |
395 |
break; |
292 |
} |
396 |
} |
293 |
@@ -481,7 +528,7 @@ get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm) |
397 |
@@ -481,7 +583,7 @@ |
294 |
if (r < 0 || r > (int) sizeof(node_name)) { |
398 |
if (r < 0 || r > (int) sizeof(node_name)) { |
295 |
break; |
399 |
break; |
296 |
} |
400 |
} |
Lines 299-305
Link Here
|
299 |
if (r < 0) { |
403 |
if (r < 0) { |
300 |
break; |
404 |
break; |
301 |
} |
405 |
} |
302 |
@@ -490,7 +537,7 @@ get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm) |
406 |
@@ -490,7 +592,7 @@ |
303 |
} while (0); |
407 |
} while (0); |
304 |
|
408 |
|
305 |
if (slave_def) { |
409 |
if (slave_def) { |
Lines 308-314
Link Here
|
308 |
} |
412 |
} |
309 |
|
413 |
|
310 |
return NULL; |
414 |
return NULL; |
311 |
@@ -513,22 +560,22 @@ init_local_config_with_workaround(char const * pcm_name) |
415 |
@@ -513,22 +615,22 @@ |
312 |
|
416 |
|
313 |
lconf = NULL; |
417 |
lconf = NULL; |
314 |
|
418 |
|
Lines 335-341
Link Here
|
335 |
if (r < 0) { |
439 |
if (r < 0) { |
336 |
break; |
440 |
break; |
337 |
} |
441 |
} |
338 |
@@ -537,7 +584,7 @@ init_local_config_with_workaround(char const * pcm_name) |
442 |
@@ -537,7 +639,7 @@ |
339 |
if (r < 0 || r > (int) sizeof(node_name)) { |
443 |
if (r < 0 || r > (int) sizeof(node_name)) { |
340 |
break; |
444 |
break; |
341 |
} |
445 |
} |
Lines 344-350
Link Here
|
344 |
if (r < 0) { |
448 |
if (r < 0) { |
345 |
break; |
449 |
break; |
346 |
} |
450 |
} |
347 |
@@ -548,12 +595,12 @@ init_local_config_with_workaround(char const * pcm_name) |
451 |
@@ -548,12 +650,12 @@ |
348 |
} |
452 |
} |
349 |
|
453 |
|
350 |
/* Fetch the PCM node's type, and bail out if it's not the PulseAudio plugin. */ |
454 |
/* Fetch the PCM node's type, and bail out if it's not the PulseAudio plugin. */ |
Lines 359-365
Link Here
|
359 |
if (r < 0) { |
463 |
if (r < 0) { |
360 |
break; |
464 |
break; |
361 |
} |
465 |
} |
362 |
@@ -564,18 +611,18 @@ init_local_config_with_workaround(char const * pcm_name) |
466 |
@@ -564,18 +666,18 @@ |
363 |
|
467 |
|
364 |
/* Don't clobber an explicit existing handle_underrun value, set it only |
468 |
/* Don't clobber an explicit existing handle_underrun value, set it only |
365 |
if it doesn't already exist. */ |
469 |
if it doesn't already exist. */ |
Lines 381-387
Link Here
|
381 |
if (r < 0) { |
485 |
if (r < 0) { |
382 |
break; |
486 |
break; |
383 |
} |
487 |
} |
384 |
@@ -583,7 +630,7 @@ init_local_config_with_workaround(char const * pcm_name) |
488 |
@@ -583,7 +685,7 @@ |
385 |
return lconf; |
489 |
return lconf; |
386 |
} while (0); |
490 |
} while (0); |
387 |
|
491 |
|
Lines 390-396
Link Here
|
390 |
|
494 |
|
391 |
return NULL; |
495 |
return NULL; |
392 |
} |
496 |
} |
393 |
@@ -595,9 +642,9 @@ alsa_locked_pcm_open(snd_pcm_t ** pcm, snd_pcm_stream_t stream, snd_config_t * l |
497 |
@@ -595,9 +697,9 @@ |
394 |
|
498 |
|
395 |
pthread_mutex_lock(&cubeb_alsa_mutex); |
499 |
pthread_mutex_lock(&cubeb_alsa_mutex); |
396 |
if (local_config) { |
500 |
if (local_config) { |
Lines 402-408
Link Here
|
402 |
} |
506 |
} |
403 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
507 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
404 |
|
508 |
|
405 |
@@ -610,7 +657,7 @@ alsa_locked_pcm_close(snd_pcm_t * pcm) |
509 |
@@ -610,7 +712,7 @@ |
406 |
int r; |
510 |
int r; |
407 |
|
511 |
|
408 |
pthread_mutex_lock(&cubeb_alsa_mutex); |
512 |
pthread_mutex_lock(&cubeb_alsa_mutex); |
Lines 411-417
Link Here
|
411 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
515 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
412 |
|
516 |
|
413 |
return r; |
517 |
return r; |
414 |
@@ -667,12 +714,65 @@ alsa_init(cubeb ** context, char const * context_name) |
518 |
@@ -667,12 +769,65 @@ |
415 |
pthread_attr_t attr; |
519 |
pthread_attr_t attr; |
416 |
snd_pcm_t * dummy; |
520 |
snd_pcm_t * dummy; |
417 |
|
521 |
|
Lines 478-484
Link Here
|
478 |
cubeb_alsa_error_handler_set = 1; |
582 |
cubeb_alsa_error_handler_set = 1; |
479 |
} |
583 |
} |
480 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
584 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
481 |
@@ -680,6 +780,8 @@ alsa_init(cubeb ** context, char const * context_name) |
585 |
@@ -680,6 +835,8 @@ |
482 |
ctx = calloc(1, sizeof(*ctx)); |
586 |
ctx = calloc(1, sizeof(*ctx)); |
483 |
assert(ctx); |
587 |
assert(ctx); |
484 |
|
588 |
|
Lines 487-493
Link Here
|
487 |
ctx->ops = &alsa_ops; |
591 |
ctx->ops = &alsa_ops; |
488 |
|
592 |
|
489 |
r = pthread_mutex_init(&ctx->mutex, NULL); |
593 |
r = pthread_mutex_init(&ctx->mutex, NULL); |
490 |
@@ -729,7 +831,7 @@ alsa_init(cubeb ** context, char const * context_name) |
594 |
@@ -729,7 +886,7 @@ |
491 |
config fails with EINVAL, the PA PCM is too old for this workaround. */ |
595 |
config fails with EINVAL, the PA PCM is too old for this workaround. */ |
492 |
if (r == -EINVAL) { |
596 |
if (r == -EINVAL) { |
493 |
pthread_mutex_lock(&cubeb_alsa_mutex); |
597 |
pthread_mutex_lock(&cubeb_alsa_mutex); |
Lines 496-502
Link Here
|
496 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
600 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
497 |
ctx->local_config = NULL; |
601 |
ctx->local_config = NULL; |
498 |
} else if (r >= 0) { |
602 |
} else if (r >= 0) { |
499 |
@@ -768,9 +870,13 @@ alsa_destroy(cubeb * ctx) |
603 |
@@ -768,9 +925,13 @@ |
500 |
pthread_mutex_destroy(&ctx->mutex); |
604 |
pthread_mutex_destroy(&ctx->mutex); |
501 |
free(ctx->fds); |
605 |
free(ctx->fds); |
502 |
|
606 |
|
Lines 511-517
Link Here
|
511 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
615 |
pthread_mutex_unlock(&cubeb_alsa_mutex); |
512 |
} |
616 |
} |
513 |
|
617 |
|
514 |
@@ -838,7 +944,7 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name, |
618 |
@@ -838,7 +999,7 @@ |
515 |
return CUBEB_ERROR; |
619 |
return CUBEB_ERROR; |
516 |
} |
620 |
} |
517 |
|
621 |
|
Lines 520-526
Link Here
|
520 |
assert(r == 0); |
624 |
assert(r == 0); |
521 |
|
625 |
|
522 |
/* Ugly hack: the PA ALSA plugin allows buffer configurations that can't |
626 |
/* Ugly hack: the PA ALSA plugin allows buffer configurations that can't |
523 |
@@ -848,23 +954,23 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name, |
627 |
@@ -848,23 +1009,23 @@ |
524 |
latency = latency < 500 ? 500 : latency; |
628 |
latency = latency < 500 ? 500 : latency; |
525 |
} |
629 |
} |
526 |
|
630 |
|
Lines 550-556
Link Here
|
550 |
assert((nfds_t) r == stm->nfds); |
654 |
assert((nfds_t) r == stm->nfds); |
551 |
|
655 |
|
552 |
r = pthread_cond_init(&stm->cond, NULL); |
656 |
r = pthread_cond_init(&stm->cond, NULL); |
553 |
@@ -895,7 +1001,7 @@ alsa_stream_destroy(cubeb_stream * stm) |
657 |
@@ -895,7 +1056,7 @@ |
554 |
pthread_mutex_lock(&stm->mutex); |
658 |
pthread_mutex_lock(&stm->mutex); |
555 |
if (stm->pcm) { |
659 |
if (stm->pcm) { |
556 |
if (stm->state == DRAINING) { |
660 |
if (stm->state == DRAINING) { |
Lines 559-565
Link Here
|
559 |
} |
663 |
} |
560 |
alsa_locked_pcm_close(stm->pcm); |
664 |
alsa_locked_pcm_close(stm->pcm); |
561 |
stm->pcm = NULL; |
665 |
stm->pcm = NULL; |
562 |
@@ -937,12 +1043,12 @@ alsa_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) |
666 |
@@ -937,12 +1098,12 @@ |
563 |
return CUBEB_ERROR; |
667 |
return CUBEB_ERROR; |
564 |
} |
668 |
} |
565 |
|
669 |
|
Lines 574-580
Link Here
|
574 |
if (rv < 0) { |
678 |
if (rv < 0) { |
575 |
return CUBEB_ERROR; |
679 |
return CUBEB_ERROR; |
576 |
} |
680 |
} |
577 |
@@ -962,34 +1068,34 @@ alsa_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) { |
681 |
@@ -962,34 +1123,34 @@ |
578 |
|
682 |
|
579 |
/* get a pcm, disabling resampling, so we get a rate the |
683 |
/* get a pcm, disabling resampling, so we get a rate the |
580 |
* hardware/dmix/pulse/etc. supports. */ |
684 |
* hardware/dmix/pulse/etc. supports. */ |
Lines 617-623
Link Here
|
617 |
|
721 |
|
618 |
return CUBEB_OK; |
722 |
return CUBEB_OK; |
619 |
} |
723 |
} |
620 |
@@ -1013,7 +1119,7 @@ alsa_stream_start(cubeb_stream * stm) |
724 |
@@ -1013,7 +1174,7 @@ |
621 |
ctx = stm->context; |
725 |
ctx = stm->context; |
622 |
|
726 |
|
623 |
pthread_mutex_lock(&stm->mutex); |
727 |
pthread_mutex_lock(&stm->mutex); |
Lines 626-632
Link Here
|
626 |
gettimeofday(&stm->last_activity, NULL); |
730 |
gettimeofday(&stm->last_activity, NULL); |
627 |
pthread_mutex_unlock(&stm->mutex); |
731 |
pthread_mutex_unlock(&stm->mutex); |
628 |
|
732 |
|
629 |
@@ -1047,7 +1153,7 @@ alsa_stream_stop(cubeb_stream * stm) |
733 |
@@ -1047,7 +1208,7 @@ |
630 |
pthread_mutex_unlock(&ctx->mutex); |
734 |
pthread_mutex_unlock(&ctx->mutex); |
631 |
|
735 |
|
632 |
pthread_mutex_lock(&stm->mutex); |
736 |
pthread_mutex_lock(&stm->mutex); |
Lines 635-641
Link Here
|
635 |
pthread_mutex_unlock(&stm->mutex); |
739 |
pthread_mutex_unlock(&stm->mutex); |
636 |
|
740 |
|
637 |
return CUBEB_OK; |
741 |
return CUBEB_OK; |
638 |
@@ -1063,8 +1169,8 @@ alsa_stream_get_position(cubeb_stream * stm, uint64_t * position) |
742 |
@@ -1063,14 +1224,17 @@ |
639 |
pthread_mutex_lock(&stm->mutex); |
743 |
pthread_mutex_lock(&stm->mutex); |
640 |
|
744 |
|
641 |
delay = -1; |
745 |
delay = -1; |
Lines 646-652
Link Here
|
646 |
*position = stm->last_position; |
750 |
*position = stm->last_position; |
647 |
pthread_mutex_unlock(&stm->mutex); |
751 |
pthread_mutex_unlock(&stm->mutex); |
648 |
return CUBEB_OK; |
752 |
return CUBEB_OK; |
649 |
@@ -1089,7 +1195,7 @@ alsa_stream_get_latency(cubeb_stream * stm, uint32_t * latency) |
753 |
} |
|
|
754 |
|
755 |
- assert(delay >= 0); |
756 |
+ if (delay < 0) { |
757 |
+ WRAP(snd_pcm_forward)(stm->pcm, -delay); |
758 |
+ delay = 0; |
759 |
+ } |
760 |
|
761 |
*position = 0; |
762 |
if (stm->write_position >= (snd_pcm_uframes_t) delay) { |
763 |
@@ -1089,7 +1253,7 @@ |
650 |
snd_pcm_sframes_t delay; |
764 |
snd_pcm_sframes_t delay; |
651 |
/* This function returns the delay in frames until a frame written using |
765 |
/* This function returns the delay in frames until a frame written using |
652 |
snd_pcm_writei is sent to the DAC. The DAC delay should be < 1ms anyways. */ |
766 |
snd_pcm_writei is sent to the DAC. The DAC delay should be < 1ms anyways. */ |