bool audio_format_parse(struct audio_format *dest, const char *src, bool mask, GError **error_r) { uint32_t rate; enum sample_format sample_format; uint8_t channels; audio_format_clear(dest); /* parse sample rate */ #if GCC_CHECK_VERSION(4,7) /* workaround -Wmaybe-uninitialized false positive */ rate = 0; #endif if (!parse_sample_rate(src, mask, &rate, &src, error_r)) return false; if (*src++ != ':') { g_set_error(error_r, audio_parser_quark(), 0, "Sample format missing"); return false; } /* parse sample format */ #if GCC_CHECK_VERSION(4,7) /* workaround -Wmaybe-uninitialized false positive */ sample_format = SAMPLE_FORMAT_UNDEFINED; #endif if (!parse_sample_format(src, mask, &sample_format, &src, error_r)) return false; if (*src++ != ':') { g_set_error(error_r, audio_parser_quark(), 0, "Channel count missing"); return false; } /* parse channel count */ if (!parse_channel_count(src, mask, &channels, &src, error_r)) return false; if (*src != 0) { g_set_error(error_r, audio_parser_quark(), 0, "Extra data after channel count: %s", src); return false; } audio_format_init(dest, rate, sample_format, channels); assert(mask ? audio_format_mask_valid(dest) : audio_format_valid(dest)); return true; }
/** * After the decoder has been started asynchronously, wait for the * "START" command to finish. The decoder may not be initialized yet, * i.e. there is no audio_format information yet. * * The player lock is not held. */ static bool player_wait_for_decoder(struct player *player) { struct player_control *pc = player->pc; struct decoder_control *dc = player->dc; assert(player->queued || pc->command == PLAYER_COMMAND_SEEK); assert(pc->next_song != NULL); player->queued = false; GError *error = dc_lock_get_error(dc); if (error != NULL) { player_lock(pc); pc_set_error(pc, PLAYER_ERROR_DECODER, error); song_free(pc->next_song); pc->next_song = NULL; player_unlock(pc); return false; } if (player->song != NULL) song_free(player->song); player->song = pc->next_song; player->elapsed_time = 0.0; /* set the "starting" flag, which will be cleared by player_check_decoder_startup() */ player->decoder_starting = true; player_lock(pc); /* update player_control's song information */ pc->total_time = song_get_duration(pc->next_song); pc->bit_rate = 0; audio_format_clear(&pc->audio_format); /* clear the queued song */ pc->next_song = NULL; player_unlock(pc); /* call syncPlaylistWithQueue() in the main thread */ event_pipe_emit(PIPE_EVENT_PLAYLIST); return true; }
bool audio_format_parse(struct audio_format *dest, const char *src, bool mask, GError **error_r) { uint32_t rate; enum sample_format sample_format; uint8_t channels; audio_format_clear(dest); /* parse sample rate */ if (!parse_sample_rate(src, mask, &rate, &src, error_r)) return false; if (*src++ != ':') { g_set_error(error_r, audio_parser_quark(), 0, "Sample format missing"); return false; } /* parse sample format */ if (!parse_sample_format(src, mask, &sample_format, &src, error_r)) return false; if (*src++ != ':') { g_set_error(error_r, audio_parser_quark(), 0, "Channel count missing"); return false; } /* parse channel count */ if (!parse_channel_count(src, mask, &channels, &src, error_r)) return false; if (*src != 0) { g_set_error(error_r, audio_parser_quark(), 0, "Extra data after channel count: %s", src); return false; } audio_format_init(dest, rate, sample_format, channels); assert(mask ? audio_format_mask_valid(dest) : audio_format_valid(dest)); return true; }
/** * After the decoder has been started asynchronously, wait for the * "START" command to finish. The decoder may not be initialized yet, * i.e. there is no audio_format information yet. * * The player lock is not held. */ static bool player_wait_for_decoder(struct player *player) { struct decoder_control *dc = player->dc; assert(player->queued || pc.command == PLAYER_COMMAND_SEEK); assert(pc.next_song != NULL); player->queued = false; if (decoder_lock_has_failed(dc)) { player_lock(); pc.errored_song = dc->song; pc.error = PLAYER_ERROR_FILE; pc.next_song = NULL; player_unlock(); return false; } player->song = pc.next_song; player->elapsed_time = 0.0; /* set the "starting" flag, which will be cleared by player_check_decoder_startup() */ player->decoder_starting = true; player_lock(); /* update player_control's song information */ pc.total_time = song_get_duration(pc.next_song); pc.bit_rate = 0; audio_format_clear(&pc.audio_format); /* clear the queued song */ pc.next_song = NULL; player_unlock(); /* call syncPlaylistWithQueue() in the main thread */ event_pipe_emit(PIPE_EVENT_PLAYLIST); return true; }
bool audio_output_init(struct audio_output *ao, const struct config_param *param, GError **error_r) { const struct audio_output_plugin *plugin = NULL; GError *error = NULL; if (param) { const char *p; p = config_get_block_string(param, AUDIO_OUTPUT_TYPE, NULL); if (p == NULL) { g_set_error(error_r, audio_output_quark(), 0, "Missing \"type\" configuration"); return false; } plugin = audio_output_plugin_get(p); if (plugin == NULL) { g_set_error(error_r, audio_output_quark(), 0, "No such audio output plugin: %s", p); return false; } ao->name = config_get_block_string(param, AUDIO_OUTPUT_NAME, NULL); if (ao->name == NULL) { g_set_error(error_r, audio_output_quark(), 0, "Missing \"name\" configuration"); return false; } p = config_get_block_string(param, AUDIO_OUTPUT_FORMAT, NULL); if (p != NULL) { bool success = audio_format_parse(&ao->config_audio_format, p, true, error_r); if (!success) return false; } else audio_format_clear(&ao->config_audio_format); } else { g_warning("No \"%s\" defined in config file\n", CONF_AUDIO_OUTPUT); plugin = audio_output_detect(error_r); if (plugin == NULL) return false; g_message("Successfully detected a %s audio device", plugin->name); ao->name = "default detected output"; audio_format_clear(&ao->config_audio_format); } ao->plugin = plugin; ao->always_on = config_get_block_bool(param, "always_on", false); ao->enabled = config_get_block_bool(param, "enabled", true); ao->really_enabled = false; ao->open = false; ao->pause = false; ao->fail_timer = NULL; pcm_buffer_init(&ao->cross_fade_buffer); /* set up the filter chain */ ao->filter = filter_chain_new(); assert(ao->filter != NULL); /* create the replay_gain filter */ const char *replay_gain_handler = config_get_block_string(param, "replay_gain_handler", "software"); if (strcmp(replay_gain_handler, "none") != 0) { ao->replay_gain_filter = filter_new(&replay_gain_filter_plugin, param, NULL); assert(ao->replay_gain_filter != NULL); ao->replay_gain_serial = 0; ao->other_replay_gain_filter = filter_new(&replay_gain_filter_plugin, param, NULL); assert(ao->other_replay_gain_filter != NULL); ao->other_replay_gain_serial = 0; } else { ao->replay_gain_filter = NULL; ao->other_replay_gain_filter = NULL; } /* create the normalization filter (if configured) */ if (config_get_bool(CONF_VOLUME_NORMALIZATION, false)) { struct filter *normalize_filter = filter_new(&normalize_filter_plugin, NULL, NULL); assert(normalize_filter != NULL); filter_chain_append(ao->filter, autoconvert_filter_new(normalize_filter)); } filter_chain_parse(ao->filter, config_get_block_string(param, AUDIO_FILTERS, ""), &error ); // It's not really fatal - Part of the filter chain has been set up already // and even an empty one will work (if only with unexpected behaviour) if (error != NULL) { g_warning("Failed to initialize filter chain for '%s': %s", ao->name, error->message); g_error_free(error); } ao->thread = NULL; ao->command = AO_COMMAND_NONE; ao->mutex = g_mutex_new(); ao->cond = g_cond_new(); ao->data = ao_plugin_init(plugin, &ao->config_audio_format, param, error_r); if (ao->data == NULL) return false; ao->mixer = audio_output_load_mixer(ao->data, param, plugin->mixer_plugin, ao->filter, &error); if (ao->mixer == NULL && error != NULL) { g_warning("Failed to initialize hardware mixer for '%s': %s", ao->name, error->message); g_error_free(error); } /* use the hardware mixer for replay gain? */ if (strcmp(replay_gain_handler, "mixer") == 0) { if (ao->mixer != NULL) replay_gain_filter_set_mixer(ao->replay_gain_filter, ao->mixer, 100); else g_warning("No such mixer for output '%s'", ao->name); } else if (strcmp(replay_gain_handler, "software") != 0 && ao->replay_gain_filter != NULL) { g_set_error(error_r, audio_output_quark(), 0, "Invalid \"replay_gain_handler\" value"); return false; } /* the "convert" filter must be the last one in the chain */ ao->convert_filter = filter_new(&convert_filter_plugin, NULL, NULL); assert(ao->convert_filter != NULL); filter_chain_append(ao->filter, ao->convert_filter); /* done */ return true; }