audio: fix handling of sample_rate and channels count.
authorAndre <maan@p133.(none)>
Mon, 29 May 2006 23:05:54 +0000 (01:05 +0200)
committerAndre <maan@p133.(none)>
Mon, 29 May 2006 23:05:54 +0000 (01:05 +0200)
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
alsa_writer.c
audiod.c
error.h
filter_chain.c
sched.c
write.c
write.h

index 4863a53..8de4958 100644 (file)
@@ -17,7 +17,7 @@ audio)"
        default="2"
        optional
 
-option "sample_rate" s
+option "samplerate" s
 #~~~~~~~~~~~~~~~~~~~~~
 
 "force given sample rate (only neccessary for
index 7c6e8ca..355da05 100644 (file)
@@ -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);
 }
 
index d635fbf..56014ca 100644 (file)
--- 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 8458ae2..b08a31e 100644 (file)
--- 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 \
index 17f6705..4797b25 100644 (file)
@@ -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 9db7c09..ea79a3e 100644 (file)
--- 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 e420620..e82e0be 100644 (file)
--- 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 f4c54ca..cc24d35 100644 (file)
--- 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;
 };