From a95093cd8b62d411b9448aa77768774e1bdd81e5 Mon Sep 17 00:00:00 2001 From: Andre Date: Tue, 30 May 2006 01:05:54 +0200 Subject: [PATCH] audio: fix handling of sample_rate and channels count. This was utterly broken for both para_write and para_audiod as the writer didn't have a chance to see the computed value from the filter/wav header. Fix it by introducing two new pointers in struct writer_node_group which point to the corresponding variables in struct filter/check_wav_task. Tested with 22KHz mono files. --- alsa_write.ggo | 2 +- alsa_writer.c | 71 ++++++++++++++++++++++++++------------------------ audiod.c | 30 ++++++++++++++++----- error.h | 1 + filter_chain.c | 6 ++--- sched.c | 6 ++++- write.c | 10 ++++--- write.h | 2 ++ 8 files changed, 78 insertions(+), 50 deletions(-) diff --git a/alsa_write.ggo b/alsa_write.ggo index 4863a53a..8de4958d 100644 --- a/alsa_write.ggo +++ b/alsa_write.ggo @@ -17,7 +17,7 @@ audio)" default="2" optional -option "sample_rate" s +option "samplerate" s #~~~~~~~~~~~~~~~~~~~~~ "force given sample rate (only neccessary for diff --git a/alsa_writer.c b/alsa_writer.c index 7c6e8ca7..355da05e 100644 --- a/alsa_writer.c +++ b/alsa_writer.c @@ -49,6 +49,8 @@ struct private_alsa_data { struct timeval next_chunk; /** the return value of snd_pcm_hw_params_get_buffer_time_max() */ unsigned buffer_time; + unsigned samplerate; + unsigned channels; }; /* @@ -67,7 +69,17 @@ static int alsa_open(struct writer_node *w) snd_pcm_uframes_t period_size; struct private_alsa_data *pad = para_calloc(sizeof(struct private_alsa_data)); struct alsa_write_args_info *conf = w->conf; - + struct writer_node_group *wng = w->wng; + + if (!conf->samplerate_given && wng->samplerate) + pad->samplerate = *wng->samplerate; + else + pad->samplerate = conf->samplerate_arg; + if (!conf->channels_given && wng->channels) + pad->channels = *wng->channels; + else + pad->channels = conf->channels_arg; + PARA_INFO_LOG("%d channel(s), %dHz\n", pad->channels, pad->samplerate); w->private_data = pad; snd_pcm_info_alloca(&info); err = snd_pcm_open(&pad->handle, conf->device_arg, @@ -87,10 +99,10 @@ static int alsa_open(struct writer_node *w) if (snd_pcm_hw_params_set_format(pad->handle, hwparams, FORMAT) < 0) return -E_SAMPLE_FORMAT; if (snd_pcm_hw_params_set_channels(pad->handle, hwparams, - conf->channels_arg) < 0) + pad->channels) < 0) return -E_CHANNEL_COUNT; if (snd_pcm_hw_params_set_rate_near(pad->handle, hwparams, - (unsigned int*) &conf->sample_rate_arg, 0) < 0) + &pad->samplerate, 0) < 0) return -E_SET_RATE; err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &pad->buffer_time, 0); if (err < 0 || !pad->buffer_time) @@ -129,7 +141,7 @@ static int alsa_open(struct writer_node *w) if (snd_pcm_sw_params(pad->handle, swparams) < 0) return -E_SW_PARAMS; pad->bytes_per_frame = snd_pcm_format_physical_width(FORMAT) - * conf->channels_arg / 8; + * pad->channels / 8; if (snd_pcm_nonblock(pad->handle, 1)) PARA_ERROR_LOG("%s\n", "failed to set nonblock mode"); return period_size * pad->bytes_per_frame; @@ -141,19 +153,17 @@ static void alsa_write_pre_select(struct sched *s, struct task *t) struct writer_node_group *wng = wn->wng; struct timeval diff; - t->ret = 0; - if (*wng->input_eof && *wng->loaded < pad->bytes_per_frame) - return; t->ret = 1; - if (*wng->loaded < pad->bytes_per_frame) + if (*wng->input_eof && *wng->loaded < pad->bytes_per_frame) return; if (tv_diff(&s->now, &pad->next_chunk, &diff) < 0) { if (tv_diff(&s->timeout, &diff, NULL) > 0) s->timeout = diff; } else { s->timeout.tv_sec = 0; - s->timeout.tv_usec = 0; + s->timeout.tv_usec = 1000; } +// PARA_INFO_LOG("timeout: %lu\n", tv2ms(&s->timeout)); } static void alsa_write_post_select(struct sched *s, struct task *t) @@ -162,10 +172,12 @@ static void alsa_write_post_select(struct sched *s, struct task *t) struct private_alsa_data *pad = wn->private_data; struct writer_node_group *wng = wn->wng; size_t frames = *wng->loaded / pad->bytes_per_frame; - snd_pcm_sframes_t ret, result = 0; + snd_pcm_sframes_t ret; unsigned char *data = (unsigned char*)wng->buf; + struct timeval tv; t->ret = 0; +// PARA_INFO_LOG("%zd frames\n", frames); if (!frames) { if (*wng->input_eof) t->ret = *wng->loaded; @@ -173,30 +185,21 @@ static void alsa_write_post_select(struct sched *s, struct task *t) } if (tv_diff(&s->now, &pad->next_chunk, NULL) < 0) return; -// PARA_INFO_LOG("%zd frames\n", frames); -// while (frames > 0) { - ret = snd_pcm_writei(pad->handle, data, frames); - if (ret == -EAGAIN || (ret >= 0 && ret < frames)) { - struct timeval tv; - ms2tv(pad->buffer_time / 2000, &tv); - PARA_DEBUG_LOG("EAGAIN. frames: %d, ret: %lu\n", frames, ret); - tv_add(&s->now, &tv, &pad->next_chunk); - } else if (ret == -EPIPE) { - PARA_WARNING_LOG("%s", "EPIPE\n"); - snd_pcm_prepare(pad->handle); - } else if (ret < 0) { - t->ret = -E_ALSA_WRITE; - return; - } - if (ret >= 0) { - result += ret; - frames -= ret; - data += ret * pad->bytes_per_frame; - } -// if (ret == -EAGAIN) -// break; -// } - t->ret = result * pad->bytes_per_frame; + ret = snd_pcm_writei(pad->handle, data, frames); + if (ret == -EPIPE) { + PARA_WARNING_LOG("%s", "EPIPE\n"); + snd_pcm_prepare(pad->handle); + return; + } + if (ret < 0) { + PARA_WARNING_LOG("%s", "ALSA ERROR\n"); + t->ret = -E_ALSA_WRITE; + return; + } +// ms2tv(pad->buffer_time / 4000, &tv); + ms2tv(1, &tv); + tv_add(&s->now, &tv, &pad->next_chunk); + t->ret = ret * pad->bytes_per_frame; // PARA_INFO_LOG("ret: %d, frames: %zd\n", t->ret, frames); } diff --git a/audiod.c b/audiod.c index d635fbfc..56014cad 100644 --- a/audiod.c +++ b/audiod.c @@ -680,7 +680,10 @@ static void open_writers(int slot_num) s->wng->buf = s->fc->outbuf; s->wng->loaded = s->fc->out_loaded; s->wng->input_eof = &s->fc->eof; + s->wng->channels = &s->fc->channels; + s->wng->samplerate = &s->fc->samplerate; s->fc->output_eof = &s->wng->eof; + PARA_INFO_LOG("samplerate: %d\n", *s->wng->samplerate); } else { s->wng->buf = s->receiver_node->buf; s->wng->loaded = &s->receiver_node->loaded; @@ -692,7 +695,7 @@ static void open_writers(int slot_num) s->wng->writer_nodes[i].writer = a->writers[i]; sprintf(s->wng->writer_nodes[i].task.status, "writer_node"); } - ret = wng_open(s->wng); + ret = wng_open(s->wng); /* FIXME */ s->wstime = *now; current_decoder = slot_num; activate_inactive_grab_clients(slot_num, s->format, &s->fc->filters); @@ -892,22 +895,33 @@ static void audiod_pre_select(struct sched *s, __a_unused struct task *t) { int i; + t->ret = 1; now = &s->now; if (audiod_status != AUDIOD_ON) kill_all_decoders(); else if (playing) open_current_receiver(); FOR_EACH_SLOT(i) { - struct receiver_node *rn; + struct slot_info *s = &slot[i]; + struct audio_format_info *a; try_to_close_slot(i); - if (slot[i].format < 0) + if (s->format < 0) + continue; + a = &afi[s->format]; + if (!s->receiver_node) continue; - rn = slot[i].receiver_node; - if (rn && rn->loaded && !slot[i].wng) { + if (!a->num_filters) { + if (s->receiver_node->loaded && !s->wng) + open_writers(i); + continue; + } + if (s->receiver_node->loaded && !s->fc) { open_filters(i); - open_writers(i); + continue; } + if (s->fc && *s->fc->out_loaded && !s->wng) + open_writers(i); } } @@ -915,6 +929,7 @@ static void audiod_post_select(struct sched *s, __a_unused struct task *t) { /* only save away the current time for other users */ now = &s->now; + t->ret = 1; } static void init_audiod_task(struct task *t) @@ -1483,6 +1498,7 @@ void signal_setup_default(struct signal_task *st) static void command_pre_select(struct sched *s, struct task *t) { struct command_task *ct = t->private_data; + t->ret = 1; para_fd_set(ct->fd, &s->rfds, &s->max_fileno); } @@ -1492,9 +1508,9 @@ static void command_post_select(struct sched *s, struct task *t) int ret; struct command_task *ct = t->private_data; + t->ret = 1; /* always successful */ if (audiod_status != AUDIOD_OFF) audiod_status_dump(); - t->ret = 1; /* always successful */ if (!FD_ISSET(ct->fd, &s->rfds)) return; ret = handle_connect(ct->fd); diff --git a/error.h b/error.h index 8458ae2b..b08a31ec 100644 --- a/error.h +++ b/error.h @@ -226,6 +226,7 @@ extern const char **para_errlist[]; PARA_ERROR(AAC_READ, "aac read error"), \ PARA_ERROR(STSZ, "did not find stcz atom"), \ PARA_ERROR(MP4ASC, "audio spec config error"), \ + PARA_ERROR(AAC_OVERRUN, "aac output buffer overrun"), \ #define AAC_COMMON_ERRORS \ diff --git a/filter_chain.c b/filter_chain.c index 17f67058..4797b256 100644 --- a/filter_chain.c +++ b/filter_chain.c @@ -122,7 +122,7 @@ void filter_pre_select(__a_unused struct sched *s, struct task *t) int conv, conv_total = 0; t->ret = -E_FC_EOF; - if (*fc->output_eof) + if (fc->output_eof && *fc->output_eof) goto err_out; again: ib = fc->inbuf; @@ -150,8 +150,8 @@ again: loaded = &fn->loaded; } conv_total += conv; - PARA_INFO_LOG("eof (in/out/fc): %d/%d/%d out_loaded: %d, conv: %d, conv_total: %d\n", *fc->input_eof, - *fc->output_eof, fc->eof, *fc->out_loaded, conv, conv_total); +// PARA_INFO_LOG("eof (in/out/fc): %d/%d/%d out_loaded: %d, conv: %d, conv_total: %d\n", *fc->input_eof, +// *fc->output_eof, fc->eof, *fc->out_loaded, conv, conv_total); if (conv) goto again; t->ret = 1; diff --git a/sched.c b/sched.c index 9db7c092..ea79a3e8 100644 --- a/sched.c +++ b/sched.c @@ -16,7 +16,10 @@ static void sched_preselect(struct sched *s) again: list_for_each_entry_safe(t, tmp, &pre_select_list, pre_select_node) { t->pre_select(s, t); - if (t->ret > 0 || !t->event_handler) +// PARA_INFO_LOG("%s \n", t->status); + if (t->ret > 0) + continue; + if (!t->event_handler) continue; t->event_handler(t); goto again; @@ -29,6 +32,7 @@ static void sched_post_select(struct sched *s) list_for_each_entry_safe(t, tmp, &post_select_list, post_select_node) { t->post_select(s, t); +// PARA_INFO_LOG("%s \n", t->status); if (t->ret > 0 || !t->event_handler) continue; t->event_handler(t); diff --git a/write.c b/write.c index e4206203..e82e0be0 100644 --- a/write.c +++ b/write.c @@ -34,7 +34,7 @@ struct check_wav_task { size_t *loaded; int *eof; unsigned channels; - unsigned sample_rate; + unsigned samplerate; struct task task; }; @@ -67,17 +67,17 @@ static void check_wav_pre_select(__a_unused struct sched *s, struct task *t) return; } cwt->channels = 2; - cwt->sample_rate = 44100; + cwt->samplerate = 44100; a = (unsigned char*)cwt->buf; t->ret = -E_NO_WAV_HEADER; if (a[0] != 'R' || a[1] != 'I' || a[2] != 'F' || a[3] != 'F') return; cwt->channels = (unsigned) a[22]; - cwt->sample_rate = a[24] + (a[25] << 8) + (a[26] << 16) + (a[27] << 24); + cwt->samplerate = a[24] + (a[25] << 8) + (a[26] << 16) + (a[27] << 24); *cwt->loaded -= WAV_HEADER_LEN; memmove(cwt->buf, cwt->buf + WAV_HEADER_LEN, *cwt->loaded); t->ret = -E_WAV_HEADER_SUCCESS; - PARA_INFO_LOG("channels: %d, sample_rate: %d\n", cwt->channels, cwt->sample_rate); + PARA_INFO_LOG("channels: %d, sample rate: %d\n", cwt->channels, cwt->samplerate); } static void initial_delay_pre_select(struct sched *s, struct task *t) @@ -182,6 +182,8 @@ static void idt_event_handler(struct task *t) wng->loaded = &sit.loaded; wng->input_eof = &sit.eof; wng->task.event_handler = wng_event_handler; + wng->channels = &cwt.channels; + wng->samplerate = &cwt.samplerate; ret = wng_open(wng); if (ret < 0) { PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret)); diff --git a/write.h b/write.h index f4c54ca3..cc24d359 100644 --- a/write.h +++ b/write.h @@ -111,6 +111,8 @@ struct writer_node_group { int *input_eof; int eof; char *buf; + unsigned int *channels; + unsigned int *samplerate; size_t *loaded; struct task task; }; -- 2.39.5