diff options
Diffstat (limited to 'src/xine-engine/audio_out.c')
-rw-r--r-- | src/xine-engine/audio_out.c | 253 |
1 files changed, 180 insertions, 73 deletions
diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index 47f440933..9767ba26b 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -17,7 +17,7 @@ * along with self program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.c,v 1.59 2002/06/22 13:40:38 mroi Exp $ + * $Id: audio_out.c,v 1.60 2002/07/01 13:51:27 miguelfreitas Exp $ * * 22-8-2001 James imported some useful AC3 sections from the previous alsa driver. * (c) 2001 Andy Lo A Foe <andy@alsaplayer.org> @@ -231,7 +231,7 @@ static void ao_fill_gap (ao_instance_t *this, int64_t pts_len) { printf ("audio_out: inserting %d 0-frames to fill a gap of %lld pts\n", num_frames, pts_len); - if ((this->mode == AO_CAP_MODE_A52) || (this->mode == AO_CAP_MODE_AC5)) { + if ((this->output.mode == AO_CAP_MODE_A52) || (this->output.mode == AO_CAP_MODE_AC5)) { write_pause_burst(this,num_frames); return; } @@ -247,19 +247,48 @@ static void ao_fill_gap (ao_instance_t *this, int64_t pts_len) { } } -static void ensure_buffer_size (ao_instance_t *this, int size) +static void ensure_buffer_size (audio_buffer_t *buf, int bytes_per_frame, + int frames) { - if (this->frame_buffer_size < size) { - this->frame_buffer = realloc( this->frame_buffer, size ); - this->frame_buffer_size = size; + int size = bytes_per_frame * frames; + + if (buf->mem_size < size) { + buf->mem = realloc( buf->mem, size ); + buf->mem_size = size; } + buf->num_frames = frames; +} + +static audio_buffer_t * swap_frame_buffers ( ao_instance_t *this ) { + audio_buffer_t *tmp; + + tmp = this->frame_buf[1]; + this->frame_buf[1] = this->frame_buf[0]; + this->frame_buf[0] = tmp; + return this->frame_buf[0]; } +static int mode_channels( int mode ) { + switch( mode ) { + case AO_CAP_MODE_MONO: + return 1; + case AO_CAP_MODE_STEREO: + return 2; + case AO_CAP_MODE_4CHANNEL: + return 4; + case AO_CAP_MODE_5CHANNEL: + return 5; + case AO_CAP_MODE_5_1CHANNEL: + return 6; + } + return 0; +} + static void *ao_loop (void *this_gen) { ao_instance_t *this = (ao_instance_t *) this_gen; int64_t hw_vpts; - audio_buffer_t *buf; + audio_buffer_t *buf, *in_buf; int64_t gap; int delay; int64_t cur_time; @@ -274,7 +303,7 @@ static void *ao_loop (void *this_gen) { while ((this->audio_loop_running) || (!this->audio_loop_running && this->out_fifo->first)) { - buf = fifo_remove (this->out_fifo); + in_buf = buf = fifo_remove (this->out_fifo); bufs_since_sync++; #ifdef LOG @@ -300,7 +329,7 @@ static void *ao_loop (void *this_gen) { #endif /* External A52 decoder delay correction */ - if ((this->mode==AO_CAP_MODE_A52) || (this->mode==AO_CAP_MODE_AC5)) + if ((this->output.mode==AO_CAP_MODE_A52) || (this->output.mode==AO_CAP_MODE_AC5)) delay+=10; hw_vpts += delay * 1024 / this->frames_per_kpts; @@ -387,53 +416,104 @@ static void *ao_loop (void *this_gen) { printf ("audio_out: outputting %d frames\n", num_output_frames); #endif - /* check if resample is needed */ - if (((!this->do_resample) || (buf->num_frames == num_output_frames)) - && (this->mode != AO_CAP_MODE_A52) - && (this->mode != AO_CAP_MODE_AC5)) { - - this->driver->write (this->driver, buf->mem, - buf->num_frames ); - } else switch (this->mode) { - case AO_CAP_MODE_MONO: - ensure_buffer_size(this, 2*num_output_frames); - audio_out_resample_mono (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_STEREO: - ensure_buffer_size(this, 4*num_output_frames); - audio_out_resample_stereo (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_4CHANNEL: - ensure_buffer_size(this, 8*num_output_frames); - audio_out_resample_4channel (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_5CHANNEL: - ensure_buffer_size(this, 10*num_output_frames); - audio_out_resample_5channel (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_5_1CHANNEL: - ensure_buffer_size(this, 12*num_output_frames); - audio_out_resample_6channel (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_A52: - case AO_CAP_MODE_AC5: - this->driver->write(this->driver, buf->mem, buf->num_frames); - break; + /* convert 8 bit samples as needed */ + if( this->input.bits == 8 && + (this->do_resample || this->output.bits != 8 || + this->input.mode != this->output.mode ) ) { + ensure_buffer_size(this->frame_buf[1], 2*mode_channels(this->input.mode), + buf->num_frames ); + audio_out_resample_8to16((int8_t *)buf->mem, this->frame_buf[1]->mem, + mode_channels(this->input.mode) * buf->num_frames ); + buf = swap_frame_buffers(this); + } + + /* check if resampling may be skipped */ + if ( this->do_resample && + buf->num_frames != num_output_frames ) { + switch (this->input.mode) { + case AO_CAP_MODE_MONO: + ensure_buffer_size(this->frame_buf[1], 2, num_output_frames); + audio_out_resample_mono (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_STEREO: + ensure_buffer_size(this->frame_buf[1], 4, num_output_frames); + audio_out_resample_stereo (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_4CHANNEL: + ensure_buffer_size(this->frame_buf[1], 8, num_output_frames); + audio_out_resample_4channel (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_5CHANNEL: + ensure_buffer_size(this->frame_buf[1], 10, num_output_frames); + audio_out_resample_5channel (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_5_1CHANNEL: + ensure_buffer_size(this->frame_buf[1], 12, num_output_frames); + audio_out_resample_6channel (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_A52: + case AO_CAP_MODE_AC5: + /* pass-through modes: no resampling */ + break; + } + } + + /* mode conversion */ + if ( this->input.mode != this->output.mode ) { + switch (this->input.mode) { + case AO_CAP_MODE_MONO: + if( this->output.mode == AO_CAP_MODE_STEREO ) { + ensure_buffer_size(this->frame_buf[1], 4, buf->num_frames ); + audio_out_resample_monotostereo(buf->mem, this->frame_buf[1]->mem, + buf->num_frames ); + buf = swap_frame_buffers(this); + } + break; + case AO_CAP_MODE_STEREO: + if( this->output.mode == AO_CAP_MODE_MONO ) { + ensure_buffer_size(this->frame_buf[1], 2, buf->num_frames ); + audio_out_resample_stereotomono(buf->mem, this->frame_buf[1]->mem, + buf->num_frames ); + buf = swap_frame_buffers(this); + } + break; + case AO_CAP_MODE_4CHANNEL: + break; + case AO_CAP_MODE_5CHANNEL: + break; + case AO_CAP_MODE_5_1CHANNEL: + break; + case AO_CAP_MODE_A52: + case AO_CAP_MODE_AC5: + break; + } } + + /* convert back to 8 bits after resampling */ + if( this->output.bits == 8 && (this->do_resample || + this->input.mode != this->output.mode) ) { + ensure_buffer_size(this->frame_buf[1], 1*mode_channels(this->output.mode), + buf->num_frames ); + audio_out_resample_16to8(buf->mem, (int8_t *)this->frame_buf[1]->mem, + mode_channels(this->output.mode) * buf->num_frames ); + buf = swap_frame_buffers(this); + } + + this->driver->write (this->driver, buf->mem, buf->num_frames ); } pthread_mutex_unlock( &this->driver_lock ); - fifo_append (this->free_fifo, buf); + fifo_append (this->free_fifo, in_buf); } @@ -455,6 +535,29 @@ static int ao_open(ao_instance_t *this, "audio_out: stream audio format is %d kHz sampling rate, %d bits. mode is %d.\n", rate, bits, mode); + this->input.mode = mode; + this->input.rate = rate; + this->input.bits = bits; + + /* not all drivers/cards support 8 bits */ + if( this->input.bits == 8 && + !(this->driver->get_capabilities(this->driver) & AO_CAP_8BITS) ) { + bits = 16; + printf("audio_out: 8 bits not supported by driver, converting to 16 bits.\n"); + } + + /* provide mono->stereo and stereo->mono conversions */ + if( this->input.mode == AO_CAP_MODE_MONO && + !(this->driver->get_capabilities(this->driver) & AO_CAP_MODE_MONO) ) { + mode = AO_CAP_MODE_STEREO; + printf("audio_out: mono not supported by driver, converting to stereo.\n"); + } + if( this->input.mode == AO_CAP_MODE_STEREO && + !(this->driver->get_capabilities(this->driver) & AO_CAP_MODE_STEREO) ) { + mode = AO_CAP_MODE_MONO; + printf("audio_out: stereo not supported by driver, converting to mono.\n"); + } + pthread_mutex_lock( &this->driver_lock ); output_sample_rate=this->driver->open(this->driver,bits,(this->force_rate ? this->force_rate : rate),mode); pthread_mutex_unlock( &this->driver_lock ); @@ -466,11 +569,10 @@ static int ao_open(ao_instance_t *this, printf("audio_out: output sample rate %d\n", output_sample_rate); - this->mode = mode; - this->input_frame_rate = rate; - this->bits = bits; this->last_audio_vpts = 0; - this->output_frame_rate = output_sample_rate; + this->output.mode = mode; + this->output.rate = output_sample_rate; + this->output.bits = bits; switch (this->resample_conf) { case 1: /* force off */ @@ -480,24 +582,16 @@ static int ao_open(ao_instance_t *this, this->do_resample = 1; break; default: /* AUTO */ - this->do_resample = this->output_frame_rate != this->input_frame_rate; + this->do_resample = this->output.rate != this->input.rate; } - /* HACK: we do not have resample functions for 8-bit audio */ - if (this->bits==8) - this->do_resample = 0; - if (this->do_resample) printf("audio_out: will resample audio from %d to %d\n", - this->input_frame_rate, this->output_frame_rate); - - pthread_mutex_lock( &this->driver_lock ); - this->num_channels = this->driver->num_channels(this->driver); - pthread_mutex_unlock( &this->driver_lock ); + this->input.rate, this->output.rate); - this->frame_rate_factor = (double) this->output_frame_rate / (double) this->input_frame_rate; - this->audio_step = (uint32_t) 90000 * (uint32_t) 32768 / this->input_frame_rate; - this->frames_per_kpts = this->output_frame_rate * 1024 / 90000; + this->frame_rate_factor = (double) this->output.rate / (double) this->input.rate; + this->audio_step = (uint32_t) 90000 * (uint32_t) 32768 / this->input.rate; + this->frames_per_kpts = this->output.rate * 1024 / 90000; #ifdef LOG printf ("audio_out : audio_step %d pts per 32768 frames\n", this->audio_step); #endif @@ -525,7 +619,7 @@ static int ao_open(ao_instance_t *this, } else printf ("audio_out: thread created\n"); - return this->output_frame_rate; + return this->output.rate; } static audio_buffer_t *ao_get_buffer (ao_instance_t *this) { @@ -616,7 +710,10 @@ static void ao_exit(ao_instance_t *this) { this->driver->exit(this->driver); pthread_mutex_unlock( &this->driver_lock ); - free (this->frame_buffer); + free (this->frame_buf[0]->mem); + free (this->frame_buf[0]); + free (this->frame_buf[1]->mem); + free (this->frame_buf[1]); free (this->zero_space); buf = this->free_fifo->first; @@ -719,8 +816,6 @@ ao_instance_t *ao_new_instance (ao_driver_t *driver, xine_t *xine) { this->control = ao_control; this->audio_loop_running = 0; this->audio_paused = 0; - this->frame_buffer = xine_xmalloc (4 * AUDIO_BUF_SIZE); - this->frame_buffer_size = 4 * AUDIO_BUF_SIZE; this->zero_space = xine_xmalloc (ZERO_BUF_SIZE * 2 * 6); this->gap_tolerance = driver->get_gap_tolerance (this->driver); @@ -749,6 +844,18 @@ ao_instance_t *ao_new_instance (ao_driver_t *driver, xine_t *xine) { fifo_append (this->free_fifo, buf); } + + /* buffers used for audio conversions */ + for (i=0; i<2; i++) { + + audio_buffer_t *buf; + + buf = (audio_buffer_t *) malloc (sizeof (audio_buffer_t)); + buf->mem = malloc (4*AUDIO_BUF_SIZE); + buf->mem_size = 4*AUDIO_BUF_SIZE; + + this->frame_buf[i] = buf; + } /* * Set audio volume to latest used one ? |