diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/audio_out/audio_alsa_out.c | 193 |
1 files changed, 83 insertions, 110 deletions
diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c index 23632c96d..e76a0f730 100644 --- a/src/audio_out/audio_alsa_out.c +++ b/src/audio_out/audio_alsa_out.c @@ -24,7 +24,7 @@ * (c) 2001 James Courtier-Dutton <James@superbug.demon.co.uk> * * - * $Id: audio_alsa_out.c,v 1.12 2001/07/18 21:38:16 f1rmb Exp $ + * $Id: audio_alsa_out.c,v 1.13 2001/08/01 18:17:40 joachim_koenig Exp $ */ #ifdef HAVE_CONFIG_H @@ -98,15 +98,14 @@ typedef struct alsa_functions_s { * For this plugin, we will use frames instead of bytes for everything. * The term sample is also equil to frames */ - snd_pcm_sframes_t frames_in_buffer; /* number of frames writen to audio hardware */ - uint32_t last_vpts; /* vpts at which last written package ends */ + uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */ - uint32_t sync_vpts; /* this syncpoint is used as a starting point */ - snd_pcm_sframes_t sync_frames_in_buffer; /* for vpts <-> samplecount assoc */ int audio_step; /* pts per 32 768 frames (frame = #bytes/2(16 bits)/channels) */ /* frames = pts * rate / pts_per_second */ /* pts = frame * pts_per_second / rate */ + int32_t bytes_per_kpts; /* bytes per 1024/90000 sec */ + snd_pcm_sframes_t pts_per_second; /* pts per second */ @@ -120,6 +119,7 @@ typedef struct alsa_functions_s { } alsa_functions_t; void write_pause_burst(alsa_functions_t *,int ); +void write_burst(alsa_functions_t *,u_char *, size_t ); static snd_output_t *jcd_out; /* @@ -160,11 +160,8 @@ static int ao_open(ao_functions_t *this_gen, uint32_t bits, uint32_t rate, int m snd_pcm_close (this->audio_fd); } this->input_sample_rate = rate; - this->frames_in_buffer = 0; - this->last_vpts = 0; + this->bytes_in_buffer = 0; this->output_rate_correction = 0; - this->sync_vpts = 0; - this->sync_frames_in_buffer = 0; this->audio_started = 0; this->open_mode = mode; this->last_audio_vpts = 0; @@ -297,9 +294,10 @@ static int ao_open(ao_functions_t *this_gen, uint32_t bits, uint32_t rate, int m this->output_sample_rate = this->input_sample_rate; this->sample_rate_factor = (double) this->output_sample_rate / (double) this->input_sample_rate; - this->audio_step = (double) 90000 * (double) 32768 + this->audio_step = (uint32_t) 90000 * (uint32_t) 32768 / this->input_sample_rate; - this->pts_per_second = 90000; + this->bytes_per_kpts = this->output_sample_rate * this->num_channels * 2 * 1024 / 90000; + this->metronom->set_audio_rate(this->metronom, this->audio_step); /* * audio buffer size handling @@ -307,6 +305,8 @@ static int ao_open(ao_functions_t *this_gen, uint32_t bits, uint32_t rate, int m /* Copy current parameters into swparams */ snd_pcm_sw_params_current(this->audio_fd, swparams); tmp=snd_pcm_sw_params_set_xfer_align(this->audio_fd, swparams, 4); + tmp=snd_pcm_sw_params_set_avail_min(this->audio_fd, swparams, 1); + tmp=snd_pcm_sw_params_set_start_threshold(this->audio_fd, swparams, 1); /* Install swparams into current parameters */ snd_pcm_sw_params(this->audio_fd, swparams); @@ -315,7 +315,7 @@ static int ao_open(ao_functions_t *this_gen, uint32_t bits, uint32_t rate, int m snd_pcm_sw_params_dump(swparams, jcd_out); - write_pause_burst(this,0); + // write_pause_burst(this,0); return 1; @@ -325,13 +325,13 @@ __close: return -1; } -static uint32_t ao_get_current_vpts (alsa_functions_t *this) +static uint32_t ao_get_current_pos (alsa_functions_t *this) { snd_pcm_sframes_t pos ; snd_pcm_status_t *pcm_stat; snd_pcm_sframes_t delay; int err; - uint32_t vpts ; + snd_pcm_status_alloca(&pcm_stat); snd_pcm_status(this->audio_fd, pcm_stat); /* Dump ALSA info to stderr */ @@ -341,49 +341,51 @@ static uint32_t ao_get_current_vpts (alsa_functions_t *this) if(err < 0) { //Hide error report error("snd_pcm_delay() failed"); - return 0; + return this->bytes_in_buffer; } - /* Correction factor, bigger -, sound earlier - * bigger +, sound later - * current setting for SB Live - */ - pos = this->frames_in_buffer - delay + 1500; + pos = delay * 2 * this->num_channels; } else { - pos=0; + pos=this->bytes_in_buffer; } - vpts = ((double)pos * (double)this->pts_per_second / (double)this->input_sample_rate); - return vpts; + return pos; } -static void ao_fill_gap (alsa_functions_t *this, uint32_t pts_len) -{ - snd_pcm_sframes_t res; - int num_frames; +static void ao_fill_gap (alsa_functions_t *this, uint32_t pts_len) { + + int num_bytes ; if (pts_len > MAX_GAP) pts_len = MAX_GAP; + num_bytes = pts_len * this->bytes_per_kpts / 1024; + num_bytes = (num_bytes / (2*this->num_channels)) * (2*this->num_channels); - num_frames = (double)pts_len * (double)this->input_sample_rate / (double)this->pts_per_second; - num_frames = (num_frames / 4) * 4; - this->frames_in_buffer += num_frames; - while (num_frames>0) { - if (num_frames>2048) { - res=snd_pcm_writei(this->audio_fd, this->zero_space, 2048 ); - num_frames -= 2048; + if(this->open_mode == AO_CAP_MODE_AC3) { + write_pause_burst(this,0); +printf("audio_alsa_out: SPDIF write pause\n"); + return; + } + + printf ("audio_alsa_out: inserting %d 0-bytes to fill a gap of %d pts\n",num_bytes, pts_len); + + this->bytes_in_buffer += num_bytes; + + while (num_bytes>0) { + if (num_bytes>8192) { + write_burst(this, (unsigned char *)this->zero_space, 8192 / (2 * this->num_channels)); + num_bytes -= 8192; } else { - res=snd_pcm_writei(this->audio_fd, this->zero_space, num_frames ); - num_frames = 0; + write_burst(this, (unsigned char *)this->zero_space, num_bytes / (2 * this->num_channels)); + num_bytes = 0; } } - this->last_vpts += pts_len; } void xrun(alsa_functions_t *this) { - snd_pcm_status_t *status; - int res; + snd_pcm_status_t *status; + int res; snd_pcm_status_alloca(&status); if ((res = snd_pcm_status(this->audio_fd, status))<0) { @@ -395,10 +397,9 @@ void xrun(alsa_functions_t *this) gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); timersub(&now, &tstamp, &diff); - fprintf(stderr, "xrun!!! (at least %.3f ms long)\n", -diff.tv_sec * 1000 + diff.tv_usec / 1000.0); + fprintf(stderr, "xrun!!! (at least %.3f ms long)\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0); - if ((res = snd_pcm_prepare(this->audio_fd))<0) { + if ((res = snd_pcm_prepare(this->audio_fd))<0) { printf("xrun: prepare error: %s", snd_strerror(res)); return; } @@ -407,9 +408,10 @@ diff.tv_sec * 1000 + diff.tv_usec / 1000.0); } void write_burst(alsa_functions_t *this,u_char *data, size_t count) - { +{ ssize_t r; - while(count > 0) { + + while( count > 0) { r = snd_pcm_writei(this->audio_fd, data, count); if (r == -EAGAIN || (r >=0 && r < count)) { snd_pcm_wait(this->audio_fd, 1000); @@ -418,9 +420,10 @@ void write_burst(alsa_functions_t *this,u_char *data, size_t count) } if (r > 0) { count -= r; - data += r * 4; + data += r * 2 * this->num_channels; } } + } void write_pause_burst(alsa_functions_t *this,int error) @@ -458,9 +461,9 @@ static int ao_write_audio_data(ao_functions_t *this_gen, alsa_functions_t *this = (alsa_functions_t *) this_gen; uint32_t vpts, - audio_vpts, - master_vpts; - int32_t diff, gap; + pos, + buffer_vpts; + int32_t gap; int bDropPackage; uint16_t sample_buffer[8192]; int num_output_samples; @@ -468,10 +471,15 @@ static int ao_write_audio_data(ao_functions_t *this_gen, if (this->audio_fd == NULL) { error("Nothing open"); - return; + return 1; } - vpts = this->metronom->got_audio_samples (this->metronom, pts_, num_samples); + if(this->open_mode == AO_CAP_MODE_AC3) + num_samples = 1536; /* FIXME */ + + vpts = this->metronom->got_audio_samples (this->metronom, pts_, num_samples); + + if (vpts<this->last_audio_vpts) { /* reject this */ @@ -479,15 +487,24 @@ static int ao_write_audio_data(ao_functions_t *this_gen, return 1; } this->last_audio_vpts = vpts; + bDropPackage = 0; + + pos = ao_get_current_pos (this) ; + +// if (pos>this->bytes_in_buffer) /* buffer ran dry */ +// this->bytes_in_buffer = pos; + +//printf("samples %d pos %d bytes_in_buffer %d ",num_samples,pos,this->bytes_in_buffer); + buffer_vpts = this->metronom->get_current_time (this->metronom); +//printf("buffer_vpts %d vpts %d ",buffer_vpts,vpts); + buffer_vpts += (this->bytes_in_buffer - pos) * 1024 / this->bytes_per_kpts; + this->bytes_in_buffer -= (this->bytes_in_buffer - pos); + + gap = vpts - buffer_vpts; + +//printf("gap %d \n",gap); - /* - * check if these samples "fit" in the audio output buffer - * or do we have an audio "gap" here? - */ - gap = vpts - this->last_vpts ; - bDropPackage = 0; -#if 0 if (gap>GAP_TOLERANCE) { ao_fill_gap (this, gap); @@ -498,50 +515,21 @@ static int ao_write_audio_data(ao_functions_t *this_gen, } else if (gap<-GAP_TOLERANCE) { bDropPackage = 1; +//printf("audio_alsa_out: drop package\n"); } -#endif - /* - * sync on master clock - */ - audio_vpts = ao_get_current_vpts (this) ; - master_vpts = this->metronom->get_current_time (this->metronom); - diff = audio_vpts - master_vpts; - /* - * method 1 : resampling - */ - if (abs(diff)>5000) { - if (diff>5000) { - error("Fill Gap"); - if ((this->open_mode & AO_CAP_MODE_AC3) == 0) - ao_fill_gap (this,diff); - } else if (diff<-5000) { - error("Drop"); - bDropPackage = 1; - } - } else if (abs(diff)>1000) { - this->output_rate_correction = diff/10 ; - error("diff = %d => rate correction : %d", diff, this->output_rate_correction); - if ( this->output_rate_correction < -500) - this->output_rate_correction = -500; - else if ( this->output_rate_correction > 500) - this->output_rate_correction = 500; - } - /* - * method 2: adjust master clock - */ - if (abs(diff)>MAX_MASTER_CLOCK_DIV) { - error ("master clock adjust time %d -> %d (diff: %d)", master_vpts, audio_vpts, diff); - this->metronom->adjust_clock (this->metronom, audio_vpts); - } + /* * resample and output samples */ + + if(this->open_mode == AO_CAP_MODE_AC3) bDropPackage=0; + + if (!bDropPackage) { if ((this->open_mode & AO_CAP_MODE_AC3) == 0) { - /* Multiples of xfer_align eg:- 4 */ - num_output_samples = ((num_samples * (this->output_sample_rate + this->output_rate_correction) / this->input_sample_rate / 4) * 4)+4; + num_output_samples = num_samples * (this->output_sample_rate) / this->input_sample_rate; audio_out_resample_stereo (output_samples, num_samples, sample_buffer, num_output_samples); do { @@ -566,29 +554,14 @@ static int ao_write_audio_data(ao_functions_t *this_gen, * A Frame is one sample for all channels, so here a Stereo 16 bits frame is 4 bytes. */ -// res=snd_pcm_writei(this->audio_fd, sample_buffer, num_output_samples); - write_burst(this, sample_buffer, num_output_samples); - res = num_output_samples; - - if(res != num_output_samples) error("BUFFER MAYBE FULL!!!!!!!!!!!!"); - if (res < 0) - error("writei returned error: %s", snd_strerror(res)); - /* - * remember vpts - */ - this->sync_vpts = vpts; - this->sync_frames_in_buffer = this->frames_in_buffer; + write_burst(this, (unsigned char *)sample_buffer, num_output_samples); /* * step values */ - this->frames_in_buffer += num_samples ; + this->bytes_in_buffer += num_samples * 2 * this->num_channels ; this->audio_started = 1; - } else { - this->sync_vpts = vpts; } - this->last_vpts = vpts + num_samples * this->pts_per_second / this->input_sample_rate ; - return 1; } |