void decoder_mixramp(struct decoder *decoder, char *mixramp_start, char *mixramp_end) { assert(decoder != NULL); struct decoder_control *dc = decoder->dc; assert(dc != NULL); dc_mixramp_start(dc, mixramp_start); dc_mixramp_end(dc, mixramp_end); }
void decoder_mixramp(struct decoder *decoder, float replay_gain_db, char *mixramp_start, char *mixramp_end) { assert(decoder != NULL); struct decoder_control *dc = decoder->dc; assert(dc != NULL); dc->replay_gain_db = replay_gain_db; dc_mixramp_start(dc, mixramp_start); dc_mixramp_end(dc, mixramp_end); }
static gpointer decoder_task(gpointer arg) { struct decoder_control *dc = arg; decoder_lock(dc); do { assert(dc->state == DECODE_STATE_STOP || dc->state == DECODE_STATE_ERROR); switch (dc->command) { case DECODE_COMMAND_START: g_debug("clearing mixramp tags"); dc_mixramp_start(dc, NULL); dc_mixramp_prev_end(dc, dc->mixramp_end); dc->mixramp_end = NULL; /* Don't free, it's copied above. */ dc->replay_gain_prev_db = dc->replay_gain_db; dc->replay_gain_db = 0; /* fall through */ case DECODE_COMMAND_SEEK: decoder_run(dc); break; case DECODE_COMMAND_STOP: decoder_command_finished_locked(dc); break; case DECODE_COMMAND_NONE: decoder_wait(dc); break; } } while (dc->command != DECODE_COMMAND_NONE || !dc->quit); decoder_unlock(dc); return NULL; }
static void decoder_run_song(struct decoder_control *dc, const struct song *song, const char *uri) { struct decoder decoder = { .dc = dc, .initial_seek_pending = dc->start_ms > 0, .initial_seek_running = false, }; int ret; decoder.timestamp = 0.0; decoder.seeking = false; decoder.song_tag = song->tag != NULL && song_is_file(song) ? tag_dup(song->tag) : NULL; decoder.stream_tag = NULL; decoder.decoder_tag = NULL; decoder.chunk = NULL; dc->state = DECODE_STATE_START; decoder_command_finished_locked(dc); pcm_convert_init(&decoder.conv_state); ret = song_is_file(song) ? decoder_run_file(&decoder, uri) : decoder_run_stream(&decoder, uri); decoder_unlock(dc); pcm_convert_deinit(&decoder.conv_state); /* flush the last chunk */ if (decoder.chunk != NULL) decoder_flush_chunk(&decoder); if (decoder.song_tag != NULL) tag_free(decoder.song_tag); if (decoder.stream_tag != NULL) tag_free(decoder.stream_tag); if (decoder.decoder_tag != NULL) tag_free(decoder.decoder_tag); decoder_lock(dc); dc->state = ret ? DECODE_STATE_STOP : DECODE_STATE_ERROR; } static void decoder_run(struct decoder_control *dc) { const struct song *song = dc->song; char *uri; assert(song != NULL); if (song_is_file(song)) uri = map_song_fs(song); else uri = song_get_uri(song); if (uri == NULL) { dc->state = DECODE_STATE_ERROR; decoder_command_finished_locked(dc); return; } decoder_run_song(dc, song, uri); g_free(uri); } static gpointer decoder_task(gpointer arg) { struct decoder_control *dc = arg; decoder_lock(dc); do { assert(dc->state == DECODE_STATE_STOP || dc->state == DECODE_STATE_ERROR); switch (dc->command) { case DECODE_COMMAND_START: dc_mixramp_start(dc, NULL); dc_mixramp_prev_end(dc, dc->mixramp_end); dc->mixramp_end = NULL; /* Don't free, it's copied above. */ dc->replay_gain_prev_db = dc->replay_gain_db; dc->replay_gain_db = 0; /* fall through */ case DECODE_COMMAND_SEEK: decoder_run(dc); break; case DECODE_COMMAND_STOP: decoder_command_finished_locked(dc); break; case DECODE_COMMAND_NONE: decoder_wait(dc); break; } } while (dc->command != DECODE_COMMAND_NONE || !dc->quit); decoder_unlock(dc); return NULL; } void decoder_thread_start(struct decoder_control *dc) { GError *e = NULL; assert(dc->thread == NULL); dc->quit = false; dc->thread = g_thread_create(decoder_task, dc, true, &e); if (dc->thread == NULL) MPD_ERROR("Failed to spawn decoder task: %s", e->message); }