-/*
- * open and prepare the PCM handle for writing
- *
- * Install PCM software and hardware configuration. Exit on errors.
- */
-static int alsa_open(struct writer_node *w)
-{
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_sw_params_t *swparams;
- snd_pcm_uframes_t buffer_size, xfer_align, start_threshold,
- stop_threshold;
- unsigned buffer_time = 0;
- int err;
- snd_pcm_info_t *info;
- snd_output_t *log;
- snd_pcm_uframes_t period_size;
- struct private_alsa_data *pad = para_malloc(sizeof(struct private_alsa_data));
- w->private_data = pad;
-
- snd_pcm_info_alloca(&info);
- if (snd_output_stdio_attach(&log, stderr, 0) < 0)
- return -E_ALSA_LOG;
- err = snd_pcm_open(&pad->handle, conf.device_arg,
- SND_PCM_STREAM_PLAYBACK, 0);
- if (err < 0)
- return -E_PCM_OPEN;
- if ((err = snd_pcm_info(pad->handle, info)) < 0)
- return -E_SND_PCM_INFO;
-
- snd_pcm_hw_params_alloca(&hwparams);
- snd_pcm_sw_params_alloca(&swparams);
- if (snd_pcm_hw_params_any(pad->handle, hwparams) < 0)
- return -E_BROKEN_CONF;
- if (snd_pcm_hw_params_set_access(pad->handle, hwparams,
- SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
- return -E_ACCESS_TYPE;
- 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)
- return -E_CHANNEL_COUNT;
- if (snd_pcm_hw_params_set_rate_near(pad->handle, hwparams,
- (unsigned int*) &conf.sample_rate_arg, 0) < 0)
- return -E_SET_RATE;
- err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0);
- if (err < 0 || !buffer_time)
- return -E_GET_BUFFER_TIME;
- PARA_DEBUG_LOG("buffer time: %d\n", buffer_time);
- if (snd_pcm_hw_params_set_buffer_time_near(pad->handle, hwparams,
- &buffer_time, 0) < 0)
- return -E_SET_BUFFER_TIME;
- if (snd_pcm_hw_params(pad->handle, hwparams) < 0)
- return -E_HW_PARAMS;
- snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0);
- snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
- PARA_DEBUG_LOG("buffer size: %lu, period_size: %lu\n", buffer_size,
- period_size);
- if (period_size == buffer_size)
- return -E_BAD_PERIOD;
- snd_pcm_sw_params_current(pad->handle, swparams);
- err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
- if (err < 0 || !xfer_align)
- return -E_GET_XFER;
- snd_pcm_sw_params_set_avail_min(pad->handle, swparams, period_size);
- /* round to closest transfer boundary */
- start_threshold = (buffer_size / xfer_align) * xfer_align;
- if (start_threshold < 1)
- start_threshold = 1;
- if (snd_pcm_sw_params_set_start_threshold(pad->handle, swparams,
- start_threshold) < 0)
- return -E_START_THRESHOLD;
- stop_threshold = buffer_size;
- if (snd_pcm_sw_params_set_stop_threshold(pad->handle, swparams,
- stop_threshold) < 0)
- return -E_STOP_THRESHOLD;
- if (snd_pcm_sw_params_set_xfer_align(pad->handle, swparams,
- xfer_align) < 0)
- return -E_SET_XFER;
- 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;
- return period_size * pad->bytes_per_frame;
+static int load_file(struct play_task *pt)
+{
+ const char *af;
+ char *tmp;
+ int ret;
+ struct filter *decoder;
+
+ btr_remove_node(&pt->rn.btrn);
+ if (!pt->rn.receiver || pt->next_file != pt->current_file) {
+ ret = open_new_file(pt);
+ if (ret < 0)
+ return ret;
+ } else {
+ char buf[20];
+ pt->rn.btrn = new_recv_btrn(&pt->rn);
+ sprintf(buf, "repos %lu", pt->start_chunk);
+ ret = btr_exec_up(pt->rn.btrn, buf, &tmp);
+ if (ret < 0)
+ PARA_CRIT_LOG("repos failed: %s\n", para_strerror(-ret));
+ freep(&tmp);
+ }
+ if (!pt->playing)
+ return 0;
+ /* set up decoding filter */
+ af = audio_format_name(pt->audio_format_num);
+ tmp = make_message("%sdec", af);
+ ret = check_filter_arg(tmp, &pt->fn.conf);
+ freep(&tmp);
+ if (ret < 0)
+ goto fail;
+ pt->fn.filter_num = ret;
+ decoder = filters + ret;
+ pt->fn.task.pre_select = decoder->pre_select;
+ if (decoder->new_post_select) {
+ pt->fn.task.new_post_select = decoder->new_post_select;
+ pt->fn.task.post_select = NULL;
+ } else {
+ pt->fn.task.new_post_select = NULL;
+ pt->fn.task.post_select = decoder->post_select;
+ }
+ sprintf(pt->fn.task.status, "%s decoder", af);
+ pt->fn.btrn = btr_new_node(&(struct btr_node_description)
+ EMBRACE(.name = decoder->name, .parent = pt->rn.btrn,
+ .handler = decoder->execute, .context = &pt->fn));
+ decoder->open(&pt->fn);
+
+ /* setup default writer */
+ pt->wn.conf = check_writer_arg_or_die(NULL, &pt->wn.writer_num);
+ pt->wn.task.error = 0;
+
+ /* success, register tasks */
+ register_task(&sched, &pt->rn.task);
+ register_task(&sched, &pt->fn.task);
+ register_writer_node(&pt->wn, pt->fn.btrn, &sched);
+ return 1;
+fail:
+ wipe_receiver_node(pt);
+ return ret;