summaryrefslogtreecommitdiff
path: root/src/xine-engine/audio_out.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xine-engine/audio_out.c')
-rw-r--r--src/xine-engine/audio_out.c64
1 files changed, 48 insertions, 16 deletions
diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c
index 7fe92d9fe..a6f83dc9d 100644
--- a/src/xine-engine/audio_out.c
+++ b/src/xine-engine/audio_out.c
@@ -215,6 +215,7 @@ typedef struct {
int num_driver_actions; /* number of threads, that wish to call
* functions needing driver_lock */
pthread_mutex_t driver_action_lock; /* protects num_driver_actions */
+ pthread_cond_t driver_action_cond; /* informs about num_driver_actions-- */
metronom_clock_t *clock;
xine_t *xine;
@@ -243,6 +244,7 @@ typedef struct {
audio_fifo_t *free_fifo;
audio_fifo_t *out_fifo;
int64_t last_audio_vpts;
+ pthread_mutex_t current_speed_lock;
uint32_t current_speed; /* the current playback speed */
/* FIXME: replace all this->clock->speed with this->current_speed. we should make
* sure nobody will change speed without going through xine.c:set_speed_internal */
@@ -287,13 +289,14 @@ struct audio_fifo_s {
int num_buffers;
};
+static int ao_get_property (xine_audio_port_t *this_gen, int property);
static int ao_set_property (xine_audio_port_t *this_gen, int property, int value);
-static audio_fifo_t *fifo_new (xine_t *xine) {
+static audio_fifo_t *XINE_MALLOC fifo_new (xine_t *xine) {
audio_fifo_t *fifo;
- fifo = (audio_fifo_t *) xine_xmalloc (sizeof (audio_fifo_t));
+ fifo = (audio_fifo_t *) calloc(1, sizeof(audio_fifo_t));
if (!fifo)
return NULL;
@@ -1039,6 +1042,7 @@ static void *ao_loop (void *this_gen) {
* we must process/free buffers otherwise the entire engine will stop.
*/
+ pthread_mutex_lock(&this->current_speed_lock);
if ( this->audio_loop_running &&
(this->clock->speed == XINE_SPEED_PAUSE ||
(this->clock->speed != XINE_FINE_SPEED_NORMAL &&
@@ -1054,6 +1058,7 @@ static void *ao_loop (void *this_gen) {
_x_refcounter_dec(in_buf->stream->refcounter);
fifo_append (this->free_fifo, in_buf);
in_buf = NULL;
+ pthread_mutex_unlock(&this->current_speed_lock);
continue;
}
@@ -1064,6 +1069,7 @@ static void *ao_loop (void *this_gen) {
}
lprintf ("loop:pause: I feel sleepy (%d buffers).\n", this->out_fifo->num_buffers);
+ pthread_mutex_unlock(&this->current_speed_lock);
xine_usec_sleep (10000);
lprintf ("loop:pause: I wake up.\n");
continue;
@@ -1273,12 +1279,20 @@ static void *ao_loop (void *this_gen) {
fifo_append (this->free_fifo, in_buf);
in_buf = NULL;
}
+ pthread_mutex_unlock(&this->current_speed_lock);
/* Give other threads a chance to use functions which require this->driver_lock to
* be available. This is needed when using NPTL on Linux (and probably PThreads
* on Solaris as well). */
- if (this->num_driver_actions > 0)
- sched_yield();
+ if (this->num_driver_actions > 0) {
+ /* calling sched_yield() is not sufficient on multicore systems */
+ /* sched_yield(); */
+ /* instead wait for the other thread to acquire this->driver_lock */
+ pthread_mutex_lock(&this->driver_action_lock);
+ if (this->num_driver_actions > 0)
+ pthread_cond_wait(&this->driver_action_cond, &this->driver_action_lock);
+ pthread_mutex_unlock(&this->driver_action_lock);
+ }
}
if (in_buf) {
@@ -1469,6 +1483,8 @@ static inline void dec_num_driver_actions(aos_t *this) {
pthread_mutex_lock(&this->driver_action_lock);
this->num_driver_actions--;
+ /* indicate the change to ao_loop() */
+ pthread_cond_broadcast(&this->driver_action_cond);
pthread_mutex_unlock(&this->driver_action_lock);
}
@@ -1608,17 +1624,21 @@ static void ao_close(xine_audio_port_t *this_gen, xine_stream_t *stream) {
pthread_mutex_unlock(&this->streams_lock);
/* close driver if no streams left */
- if (!ite && !this->grab_only && !stream->gapless_switch) {
+ if (!ite && !this->grab_only && !stream->keep_ao_driver_open) {
xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_out: no streams left, closing driver\n");
if (this->audio_loop_running) {
+ /* make sure there are no more buffers on queue */
if (this->clock->speed == XINE_SPEED_PAUSE ||
(this->clock->speed != XINE_FINE_SPEED_NORMAL && !this->slow_fast_audio)) {
- /* discard buffers, otherwise we'll wait forever */
+ int discard = ao_get_property(this_gen, AO_PROP_DISCARD_BUFFERS);
+ /* discard buffers while waiting, otherwise we'll wait forever */
ao_set_property(this_gen, AO_PROP_DISCARD_BUFFERS, 1);
+ fifo_wait_empty(this->out_fifo);
+ ao_set_property(this_gen, AO_PROP_DISCARD_BUFFERS, discard);
}
- /* make sure there are no more buffers on queue */
- fifo_wait_empty(this->out_fifo);
+ else
+ fifo_wait_empty(this->out_fifo);
}
pthread_mutex_lock( &this->driver_lock );
@@ -1667,6 +1687,7 @@ static void ao_exit(xine_audio_port_t *this_gen) {
}
pthread_mutex_destroy(&this->driver_lock);
+ pthread_cond_destroy(&this->driver_action_cond);
pthread_mutex_destroy(&this->driver_action_lock);
pthread_mutex_destroy(&this->streams_lock);
xine_list_delete(this->streams);
@@ -1679,6 +1700,7 @@ static void ao_exit(xine_audio_port_t *this_gen) {
free (this->frame_buf[1]);
free (this->zero_space);
+ pthread_mutex_destroy(&this->current_speed_lock);
pthread_mutex_destroy(&this->flush_audio_driver_lock);
pthread_cond_destroy(&this->flush_audio_driver_reached);
@@ -1905,8 +1927,15 @@ static int ao_set_property (xine_audio_port_t *this_gen, int property, int value
if (value != XINE_FINE_SPEED_NORMAL && value != XINE_SPEED_PAUSE && !this->slow_fast_audio )
this->ao.control(&this->ao, AO_CTRL_FLUSH_BUFFERS, NULL);
- this->ao.control(&this->ao,
- (value == XINE_SPEED_PAUSE) ? AO_CTRL_PLAY_PAUSE : AO_CTRL_PLAY_RESUME, NULL);
+ if( value == XINE_SPEED_PAUSE ) {
+ /* current_speed_lock is here to make sure the ao_loop will pause in a safe place.
+ * that is, we cannot pause writing to device, filling gaps etc. */
+ pthread_mutex_lock(&this->current_speed_lock);
+ this->ao.control(&this->ao, AO_CTRL_PLAY_PAUSE, NULL);
+ pthread_mutex_unlock(&this->current_speed_lock);
+ } else {
+ this->ao.control(&this->ao, AO_CTRL_PLAY_RESUME, NULL);
+ }
this->current_speed = value;
if( this->slow_fast_audio )
ao_update_resample_factor(this);
@@ -2046,11 +2075,12 @@ xine_audio_port_t *_x_ao_new_port (xine_t *xine, ao_driver_t *driver,
static const char* resample_modes[] = {"auto", "off", "on", NULL};
static const char* av_sync_methods[] = {"metronom feedback", "resample", NULL};
- this = xine_xmalloc (sizeof (aos_t)) ;
+ this = calloc(1, sizeof(aos_t)) ;
this->driver = driver;
this->xine = xine;
this->clock = xine->clock;
+ this->current_speed = xine->clock->speed;
this->streams = xine_list_new();
/* warning: driver_lock is a recursive mutex. it must NOT be
@@ -2062,6 +2092,7 @@ xine_audio_port_t *_x_ao_new_port (xine_t *xine, ao_driver_t *driver,
pthread_mutex_init( &this->streams_lock, NULL );
pthread_mutex_init( &this->driver_lock, &attr );
pthread_mutex_init( &this->driver_action_lock, NULL );
+ pthread_cond_init( &this->driver_action_cond, NULL );
this->ao.open = ao_open;
this->ao.get_buffer = ao_get_buffer;
@@ -2080,8 +2111,9 @@ xine_audio_port_t *_x_ao_new_port (xine_t *xine, ao_driver_t *driver,
this->grab_only = grab_only;
this->flush_audio_driver = 0;
this->discard_buffers = 0;
- this->zero_space = xine_xmalloc (ZERO_BUF_SIZE * 4 * 6); /* MAX as 32bit, 6 channels. */
+ this->zero_space = calloc (1, ZERO_BUF_SIZE * 4 * 6); /* MAX as 32bit, 6 channels. */
+ pthread_mutex_init( &this->current_speed_lock, NULL );
pthread_mutex_init( &this->flush_audio_driver_lock, NULL );
pthread_cond_init( &this->flush_audio_driver_reached, NULL );
@@ -2191,8 +2223,8 @@ xine_audio_port_t *_x_ao_new_port (xine_t *xine, ao_driver_t *driver,
audio_buffer_t *buf;
- buf = (audio_buffer_t *) xine_xmalloc (sizeof (audio_buffer_t));
- buf->mem = xine_xmalloc (AUDIO_BUF_SIZE);
+ buf = (audio_buffer_t *) calloc(1, sizeof(audio_buffer_t));
+ buf->mem = calloc (1, AUDIO_BUF_SIZE);
buf->mem_size = AUDIO_BUF_SIZE;
buf->extra_info = malloc(sizeof(extra_info_t));
@@ -2206,8 +2238,8 @@ xine_audio_port_t *_x_ao_new_port (xine_t *xine, ao_driver_t *driver,
audio_buffer_t *buf;
- buf = (audio_buffer_t *) xine_xmalloc (sizeof (audio_buffer_t));
- buf->mem = xine_xmalloc (4*AUDIO_BUF_SIZE);
+ buf = (audio_buffer_t *) calloc(1, sizeof(audio_buffer_t));
+ buf->mem = calloc(4, AUDIO_BUF_SIZE);
buf->mem_size = 4*AUDIO_BUF_SIZE;
buf->extra_info = malloc(sizeof(extra_info_t));