For very short streams it may happen that the receiver and decoder
unregister themselves from the buffer tree before the writer had a
chance to query the information from the decoder which it needs to
open the audio device. This leads to errors such as
Aug 25 14:24:51 schubert (5) get_btr_value: cmd sample_rate: Operation not supported
Aug 25 14:24:51 schubert (5) get_btr_value: cmd channels: Operation not supported
Aug 25 14:24:51 schubert (5) get_btr_value: cmd sample_format: Operation not supported
Aug 25 14:24:51 schubert (4) alsa_init: channels count not available: Invalid argument
This may happen with all receivers, audio formats and writers,
although it is most common with ogg streams.
This commit changes get_btr_sample_rate() and friends to return a
standard error code rather than assuming success. The alsa, ao and
oss writers are patched to check the return value and fail gracefully
if one of these functions fails.
if (bytes == 0) /* no data available */
return 0;
pad = wn->private_data = para_calloc(sizeof(*pad));
if (bytes == 0) /* no data available */
return 0;
pad = wn->private_data = para_calloc(sizeof(*pad));
- get_btr_sample_rate(btrn, &val);
+ ret = get_btr_sample_rate(btrn, &val);
+ if (ret < 0)
+ goto err;
- get_btr_channels(btrn, &val);
+ ret = get_btr_channels(btrn, &val);
+ if (ret < 0)
+ goto err;
- get_btr_sample_format(btrn, &val);
+ ret = get_btr_sample_format(btrn, &val);
+ if (ret < 0)
+ goto err;
pad->sample_format = get_alsa_pcm_format(val);
pad->sample_format = get_alsa_pcm_format(val);
PARA_INFO_LOG("%u channel(s), %uHz\n", pad->channels,
pad->sample_rate);
ret = alsa_init(wn);
PARA_INFO_LOG("%u channel(s), %uHz\n", pad->channels,
pad->sample_rate);
ret = alsa_init(wn);
goto remove_btrn;
if (ret == 0)
return 0;
goto remove_btrn;
if (ret == 0)
return 0;
- get_btr_sample_rate(wn->btrn, &rate);
- get_btr_channels(wn->btrn, &ch);
- get_btr_sample_format(wn->btrn, &format);
+ ret = get_btr_sample_rate(wn->btrn, &rate);
+ if (ret < 0)
+ goto remove_btrn;
+ ret = get_btr_channels(wn->btrn, &ch);
+ if (ret < 0)
+ goto remove_btrn;
+ ret = get_btr_sample_format(wn->btrn, &format);
+ if (ret < 0)
+ goto remove_btrn;
ret = aow_init(wn, rate, ch, format);
if (ret < 0)
goto remove_btrn;
ret = aow_init(wn, rate, ch, format);
if (ret < 0)
goto remove_btrn;
if (sound_device_is_busy())
return 0;
if (sound_device_is_busy())
return 0;
- get_btr_sample_rate(btrn, &rate);
- get_btr_channels(btrn, &ch);
- get_btr_sample_format(btrn, &format);
+ ret = get_btr_sample_rate(btrn, &rate);
+ if (ret < 0)
+ goto out;
+ ret = get_btr_channels(btrn, &ch);
+ if (ret < 0)
+ goto out;
+ ret = get_btr_sample_format(btrn, &format);
+ if (ret < 0)
+ goto out;
ret = oss_init(wn, rate, ch, format);
if (ret < 0)
goto out;
ret = oss_init(wn, rate, ch, format);
if (ret < 0)
goto out;
const char *writer_name(int wid);
void register_writer_node(struct writer_node *wn, struct btr_node *parent,
struct sched *s);
const char *writer_name(int wid);
void register_writer_node(struct writer_node *wn, struct btr_node *parent,
struct sched *s);
-void get_btr_sample_rate(struct btr_node *btrn, int32_t *result);
-void get_btr_channels(struct btr_node *btrn, int32_t *result);
-void get_btr_sample_format(struct btr_node *btrn, int32_t *result);
+int get_btr_sample_rate(struct btr_node *btrn, int32_t *result);
+int get_btr_channels(struct btr_node *btrn, int32_t *result);
+int get_btr_sample_format(struct btr_node *btrn, int32_t *result);
void print_writer_helps(bool detailed);
void print_writer_helps(bool detailed);
-static void get_btr_value(struct btr_node *btrn, const char *cmd,
+static int get_btr_value(struct btr_node *btrn, const char *cmd,
int32_t *result)
{
char *buf = NULL;
int ret = btr_exec_up(btrn, cmd, &buf);
int32_t *result)
{
char *buf = NULL;
int ret = btr_exec_up(btrn, cmd, &buf);
- if (ret < 0) {
- /*
- * This really should not happen. It means one of our parent
- * nodes died unexpectedly. Proceed with fingers crossed.
- */
- PARA_CRIT_LOG("cmd %s: %s\n", cmd, para_strerror(-ret));
- *result = 0;
- return;
- }
+ *result = 0;
+ /*
+ * Errors may happen when the decoder returns EOF before the writer had
+ * a chance to query the buffer tree for the channel count, sample rate
+ * etc.
+ */
+ if (ret < 0)
+ return ret;
ret = para_atoi32(buf, result);
assert(ret >= 0);
free(buf);
ret = para_atoi32(buf, result);
assert(ret >= 0);
free(buf);
* \param btrn Where to start the search.
* \param result Filled in by this function.
*
* \param btrn Where to start the search.
* \param result Filled in by this function.
*
- * This function is assumed to succeed and terminates on errors.
-void get_btr_sample_rate(struct btr_node *btrn, int32_t *result)
+int get_btr_sample_rate(struct btr_node *btrn, int32_t *result)
- get_btr_value(btrn, "sample_rate", result);
+ return get_btr_value(btrn, "sample_rate", result);
*
* \param btrn See \ref get_btr_sample_rate.
* \param result See \ref get_btr_sample_rate.
*
* \param btrn See \ref get_btr_sample_rate.
* \param result See \ref get_btr_sample_rate.
+ *
+ * \return Standard.
-void get_btr_channels(struct btr_node *btrn, int32_t *result)
+int get_btr_channels(struct btr_node *btrn, int32_t *result)
- get_btr_value(btrn, "channels", result);
+ return get_btr_value(btrn, "channels", result);
*
* \param btrn See \ref get_btr_sample_rate.
* \param result Contains the sample format as an enum sample_format type.
*
* \param btrn See \ref get_btr_sample_rate.
* \param result Contains the sample format as an enum sample_format type.
+ *
+ * \return Standard.
-void get_btr_sample_format(struct btr_node *btrn, int32_t *result)
+int get_btr_sample_format(struct btr_node *btrn, int32_t *result)
- get_btr_value(btrn, "sample_format", result);
+ return get_btr_value(btrn, "sample_format", result);