Changes: https://www.mozilla.org/thunderbird/38.0.1/releasenotes/ Changes: https://www.mozilla.org/thunderbird/38.1.0/releasenotes/ PR: 201769 Submitted by: Christoph Moench-Tegeder <cmt@burggraben.net> (based on) MFH: 2015Q3 X-MFH-With: r392273 Security: https://vuxml.freebsd.org/freebsd/44d9daee-940c-4179-86bb-6e3ffd617869.html
179 lines
6.2 KiB
Text
179 lines
6.2 KiB
Text
commit eab3e3a
|
|
Author: Mikhail Teterin <mi@aldan.algebra.com>
|
|
Date: Tue Dec 16 19:34:02 2014 -0800
|
|
|
|
Bug 1130155 - Avoid assert failures when consuming only part of buffer.
|
|
---
|
|
media/libcubeb/src/cubeb_alsa.c | 112 ++++++++++++++++++++++++++++++----------
|
|
1 file changed, 85 insertions(+), 27 deletions(-)
|
|
|
|
diff --git media/libcubeb/src/cubeb_alsa.c media/libcubeb/src/cubeb_alsa.c
|
|
index 9bbc129..e72944a 100644
|
|
--- mozilla/media/libcubeb/src/cubeb_alsa.c
|
|
+++ mozilla/media/libcubeb/src/cubeb_alsa.c
|
|
@@ -14,6 +14,8 @@
|
|
#include <limits.h>
|
|
#include <dlfcn.h>
|
|
#include <poll.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <alsa/asoundlib.h>
|
|
#include "cubeb/cubeb.h"
|
|
@@ -45,6 +47,7 @@ MAKE_TYPEDEF(snd_pcm_avail_update);
|
|
MAKE_TYPEDEF(snd_pcm_close);
|
|
MAKE_TYPEDEF(snd_pcm_delay);
|
|
MAKE_TYPEDEF(snd_pcm_drain);
|
|
+MAKE_TYPEDEF(snd_pcm_forward);
|
|
MAKE_TYPEDEF(snd_pcm_frames_to_bytes);
|
|
MAKE_TYPEDEF(snd_pcm_get_params);
|
|
/* snd_pcm_hw_params_alloca is actually a macro */
|
|
@@ -305,32 +308,35 @@ alsa_refill_stream(cubeb_stream * stm)
|
|
long got;
|
|
void * p;
|
|
int draining;
|
|
+ unsigned pipefailures, againfailures;
|
|
|
|
draining = 0;
|
|
|
|
pthread_mutex_lock(&stm->mutex);
|
|
|
|
- r = WRAP(snd_pcm_poll_descriptors_revents)(stm->pcm, stm->fds, stm->nfds, &revents);
|
|
- if (r < 0 || revents != POLLOUT) {
|
|
- /* This should be a stream error; it makes no sense for poll(2) to wake
|
|
- for this stream and then have the stream report that it's not ready.
|
|
- Unfortunately, this does happen, so just bail out and try again. */
|
|
- pthread_mutex_unlock(&stm->mutex);
|
|
- return RUNNING;
|
|
- }
|
|
+ for (pipefailures = 0;;) {
|
|
+ r = WRAP(snd_pcm_poll_descriptors_revents)(stm->pcm, stm->fds, stm->nfds, &revents);
|
|
+ if (r < 0 || revents != POLLOUT ||
|
|
+ (avail = WRAP(snd_pcm_avail_update)(stm->pcm)) == 0) {
|
|
+ /* This should be a stream error; it makes no sense for poll(2) to wake
|
|
+ for this stream and then have the stream report that it's not ready.
|
|
+ Unfortunately, this does happen, so just bail out and try again. */
|
|
+ pthread_mutex_unlock(&stm->mutex);
|
|
+ return RUNNING;
|
|
+ }
|
|
|
|
- avail = WRAP(snd_pcm_avail_update)(stm->pcm);
|
|
- if (avail == -EPIPE) {
|
|
+ if (avail > 0)
|
|
+ break;
|
|
+ if (pipefailures++ > 11) {
|
|
+ fprintf(stderr, "%s: repeated failures from snd_pcm_avail_update, "
|
|
+ "giving up\n", __func__);
|
|
+ pthread_mutex_unlock(&stm->mutex);
|
|
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
|
|
+ return ERROR;
|
|
+ }
|
|
WRAP(snd_pcm_recover)(stm->pcm, avail, 1);
|
|
- avail = WRAP(snd_pcm_avail_update)(stm->pcm);
|
|
- }
|
|
-
|
|
- /* Failed to recover from an xrun, this stream must be broken. */
|
|
- if (avail < 0) {
|
|
- pthread_mutex_unlock(&stm->mutex);
|
|
- stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
|
|
- return ERROR;
|
|
}
|
|
+ pipefailures = againfailures = 0;
|
|
|
|
/* This should never happen. */
|
|
if ((unsigned int) avail > stm->buffer_size) {
|
|
@@ -359,10 +365,11 @@ alsa_refill_stream(cubeb_stream * stm)
|
|
if (got < 0) {
|
|
pthread_mutex_unlock(&stm->mutex);
|
|
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
|
|
+ free(p);
|
|
return ERROR;
|
|
}
|
|
if (got > 0) {
|
|
- snd_pcm_sframes_t wrote;
|
|
+ snd_pcm_sframes_t wrote, towrite = got;
|
|
|
|
if (stm->params.format == CUBEB_SAMPLE_FLOAT32NE) {
|
|
float * b = (float *) p;
|
|
@@ -375,14 +382,62 @@ alsa_refill_stream(cubeb_stream * stm)
|
|
b[i] *= stm->volume;
|
|
}
|
|
}
|
|
- wrote = WRAP(snd_pcm_writei)(stm->pcm, p, got);
|
|
- if (wrote == -EPIPE) {
|
|
- WRAP(snd_pcm_recover)(stm->pcm, wrote, 1);
|
|
- wrote = WRAP(snd_pcm_writei)(stm->pcm, p, got);
|
|
+ for (;;) {
|
|
+ wrote = WRAP(snd_pcm_writei)(stm->pcm, p,
|
|
+ towrite > avail ? avail : towrite);
|
|
+ switch(wrote) {
|
|
+ case -EPIPE:
|
|
+ if (pipefailures++ > 3) {
|
|
+ fprintf(stderr, "%s: Too many underflows, giving up\n", __func__);
|
|
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
|
|
+ pthread_mutex_unlock(&stm->mutex);
|
|
+ free(p);
|
|
+ return ERROR;
|
|
+ }
|
|
+ WRAP(snd_pcm_recover)(stm->pcm, wrote, 1);
|
|
+ continue;
|
|
+ case -EAGAIN:
|
|
+ if (againfailures++ > 3) {
|
|
+ fprintf(stderr, "%s: Too many -EAGAIN errors from snd_pcm_writei, "
|
|
+ "giving up\n", __func__);
|
|
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
|
|
+ pthread_mutex_unlock(&stm->mutex);
|
|
+ free(p);
|
|
+ return ERROR;
|
|
+ }
|
|
+ continue;
|
|
+ case -EBADFD:
|
|
+ fprintf(stderr, "%s: snc_pcm_writei returned -%s, giving up\n",
|
|
+ __func__, "EBADFD");
|
|
+ free(p);
|
|
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
|
|
+ pthread_mutex_unlock(&stm->mutex);
|
|
+ return ERROR;
|
|
+ }
|
|
+ if (wrote < 0) {
|
|
+ fprintf(stderr, "%s: snc_pcm_writei returned unexpected error %lld, "
|
|
+ "giving up\n", __func__, (long long)wrote);
|
|
+ free(p);
|
|
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
|
|
+ pthread_mutex_unlock(&stm->mutex);
|
|
+ return ERROR;
|
|
+ }
|
|
+ pipefailures = againfailures = 0;
|
|
+ stm->write_position += wrote;
|
|
+ gettimeofday(&stm->last_activity, NULL);
|
|
+ if (wrote > towrite) {
|
|
+ fprintf(stderr, "%s: snc_pcm_writei wrote %lld frames, which was more "
|
|
+ "than we requested (%lld). This should not happen, giving up\n",
|
|
+ __func__, (long long)wrote, (long long)towrite);
|
|
+ free(p);
|
|
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
|
|
+ pthread_mutex_unlock(&stm->mutex);
|
|
+ return ERROR;
|
|
+ }
|
|
+ if (towrite == wrote)
|
|
+ break;
|
|
+ towrite -= wrote;
|
|
}
|
|
- assert(wrote >= 0 && wrote == got);
|
|
- stm->write_position += wrote;
|
|
- gettimeofday(&stm->last_activity, NULL);
|
|
}
|
|
if (got != avail) {
|
|
long buffer_fill = stm->buffer_size - (avail - got);
|
|
@@ -1177,7 +1232,10 @@ alsa_stream_get_position(cubeb_stream * stm, uint64_t * position)
|
|
return CUBEB_OK;
|
|
}
|
|
|
|
- assert(delay >= 0);
|
|
+ if (delay < 0) {
|
|
+ WRAP(snd_pcm_forward)(stm->pcm, -delay);
|
|
+ delay = 0;
|
|
+ }
|
|
|
|
*position = 0;
|
|
if (stm->write_position >= (snd_pcm_uframes_t) delay) {
|