void audio_output_finish(struct audio_output *ao) { audio_output_close(ao); assert(ao->fail_timer == NULL); if (ao->thread != NULL) { g_mutex_lock(ao->mutex); ao_command(ao, AO_COMMAND_KILL); g_mutex_unlock(ao->mutex); g_thread_join(ao->thread); } if (ao->mixer != NULL) mixer_free(ao->mixer); ao_plugin_finish(ao->plugin, ao->data); g_cond_free(ao->cond); g_mutex_free(ao->mutex); if (ao->replay_gain_filter != NULL) filter_free(ao->replay_gain_filter); if (ao->other_replay_gain_filter != NULL) filter_free(ao->other_replay_gain_filter); filter_free(ao->filter); pcm_buffer_deinit(&ao->cross_fade_buffer); }
/** * Lock the #audio_output object and execute the command * synchronously. */ static void ao_lock_command(struct audio_output *ao, enum audio_output_command cmd) { g_mutex_lock(ao->mutex); ao_command(ao, cmd); g_mutex_unlock(ao->mutex); }
/** * Same as audio_output_close(), but expects the lock to be held by * the caller. */ static void audio_output_close_locked(struct audio_output *ao) { if (ao->mixer != NULL) mixer_auto_close(ao->mixer); assert(!ao->open || ao->fail_timer == NULL); if (ao->open) ao_command(ao, AO_COMMAND_CLOSE); else if (ao->fail_timer != NULL) { g_timer_destroy(ao->fail_timer); ao->fail_timer = NULL; } }
static int aoplug_seek_sample (DB_fileinfo_t *_info, int sample) { aoplug_info_t *info = (aoplug_info_t *)_info; if (sample > info->currentsample) { info->skipsamples = sample-info->currentsample; } else { // restart song ao_command (info->type, info->decoder, COMMAND_RESTART, 0); info->skipsamples = sample; } info->currentsample = sample; _info->readpos = (float)sample / _info->fmt.samplerate; return 0; }
void audio_output_disable(struct audio_output *ao) { if (ao->thread == NULL) { if (ao->plugin->disable == NULL) ao->really_enabled = false; else /* if there's no thread yet, the device cannot be enabled */ assert(!ao->really_enabled); return; } g_mutex_lock(ao->mutex); ao_command(ao, AO_COMMAND_DISABLE); g_mutex_unlock(ao->mutex); }
void audio_output_enable(struct audio_output *ao) { if (ao->thread == NULL) { if (ao->plugin->enable == NULL) { /* don't bother to start the thread now if the device doesn't even have a enable() method; just assign the variable and we're done */ ao->really_enabled = true; return; } audio_output_thread_start(ao); } g_mutex_lock(ao->mutex); ao_command(ao, AO_COMMAND_ENABLE); g_mutex_unlock(ao->mutex); }
static bool audio_output_open(struct audio_output *ao, const struct audio_format *audio_format, const struct music_pipe *mp) { bool open; assert(mp != NULL); if (ao->fail_timer != NULL) { g_timer_destroy(ao->fail_timer); ao->fail_timer = NULL; } if (ao->open && audio_format_equals(audio_format, &ao->in_audio_format)) { assert(ao->pipe == mp || (ao->always_on && ao->pause)); if (ao->pause) { ao->chunk = NULL; ao->pipe = mp; /* unpause with the CANCEL command; this is a hack, but suits well for forcing the thread to leave the ao_pause() thread, and we need to flush the device buffer anyway */ /* we're not using audio_output_cancel() here, because that function is asynchronous */ ao_command(ao, AO_COMMAND_CANCEL); /* the audio output is now waiting for a signal; wake it up immediately */ g_cond_signal(ao->cond); } return true; } ao->in_audio_format = *audio_format; ao->chunk = NULL; ao->pipe = mp; if (ao->thread == NULL) audio_output_thread_start(ao); ao_command(ao, ao->open ? AO_COMMAND_REOPEN : AO_COMMAND_OPEN); open = ao->open; if (open && ao->mixer != NULL) { GError *error = NULL; if (!mixer_open(ao->mixer, &error)) { g_warning("Failed to open mixer for '%s': %s", ao->name, error->message); g_error_free(error); } } return open; }