Merge branch 'v0.16.x'
Conflicts: configure.ac src/output_control.c
This commit is contained in:
@@ -1124,6 +1124,9 @@ input_curl_easy_init(struct input_curl *c, GError **error_r)
|
||||
curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5);
|
||||
curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true);
|
||||
curl_easy_setopt(c->easy, CURLOPT_ERRORBUFFER, c->error);
|
||||
curl_easy_setopt(c->easy, CURLOPT_NOPROGRESS, 1l);
|
||||
curl_easy_setopt(c->easy, CURLOPT_NOSIGNAL, 1l);
|
||||
curl_easy_setopt(c->easy, CURLOPT_CONNECTTIMEOUT, 10l);
|
||||
|
||||
if (proxy != NULL)
|
||||
curl_easy_setopt(c->easy, CURLOPT_PROXY, proxy);
|
||||
|
@@ -121,12 +121,6 @@ static void osx_output_close(void *data)
|
||||
{
|
||||
struct osx_output *od = data;
|
||||
|
||||
g_mutex_lock(od->mutex);
|
||||
while (od->len) {
|
||||
g_cond_wait(od->condition, od->mutex);
|
||||
}
|
||||
g_mutex_unlock(od->mutex);
|
||||
|
||||
AudioOutputUnitStop(od->au);
|
||||
AudioUnitUninitialize(od->au);
|
||||
CloseComponent(od->au);
|
||||
@@ -169,8 +163,8 @@ osx_render(void *vdata,
|
||||
if (od->pos >= od->buffer_size)
|
||||
od->pos = 0;
|
||||
|
||||
g_mutex_unlock(od->mutex);
|
||||
g_cond_signal(od->condition);
|
||||
g_mutex_unlock(od->mutex);
|
||||
|
||||
buffer->mDataByteSize = buffer_size;
|
||||
|
||||
|
@@ -224,6 +224,44 @@ pulse_output_connect(struct pulse_output *po, GError **error_r)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees and clears the stream.
|
||||
*/
|
||||
static void
|
||||
pulse_output_delete_stream(struct pulse_output *po)
|
||||
{
|
||||
assert(po != NULL);
|
||||
assert(po->stream != NULL);
|
||||
|
||||
#if PA_CHECK_VERSION(0,9,8)
|
||||
pa_stream_set_suspended_callback(po->stream, NULL, NULL);
|
||||
#endif
|
||||
|
||||
pa_stream_set_state_callback(po->stream, NULL, NULL);
|
||||
pa_stream_set_write_callback(po->stream, NULL, NULL);
|
||||
|
||||
pa_stream_disconnect(po->stream);
|
||||
pa_stream_unref(po->stream);
|
||||
po->stream = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees and clears the context.
|
||||
*/
|
||||
static void
|
||||
pulse_output_delete_context(struct pulse_output *po)
|
||||
{
|
||||
assert(po != NULL);
|
||||
assert(po->context != NULL);
|
||||
|
||||
pa_context_set_state_callback(po->context, NULL, NULL);
|
||||
pa_context_set_subscribe_callback(po->context, NULL, NULL);
|
||||
|
||||
pa_context_disconnect(po->context);
|
||||
pa_context_unref(po->context);
|
||||
po->context = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create, set up and connect a context.
|
||||
*
|
||||
@@ -249,28 +287,13 @@ pulse_output_setup_context(struct pulse_output *po, GError **error_r)
|
||||
pulse_output_subscribe_cb, po);
|
||||
|
||||
if (!pulse_output_connect(po, error_r)) {
|
||||
pa_context_unref(po->context);
|
||||
po->context = NULL;
|
||||
pulse_output_delete_context(po);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees and clears the context.
|
||||
*/
|
||||
static void
|
||||
pulse_output_delete_context(struct pulse_output *po)
|
||||
{
|
||||
assert(po != NULL);
|
||||
assert(po->context != NULL);
|
||||
|
||||
pa_context_disconnect(po->context);
|
||||
pa_context_unref(po->context);
|
||||
po->context = NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
pulse_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
|
||||
const struct config_param *param,
|
||||
@@ -540,8 +563,7 @@ pulse_output_open(void *data, struct audio_format *audio_format,
|
||||
error = pa_stream_connect_playback(po->stream, po->sink,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (error < 0) {
|
||||
pa_stream_unref(po->stream);
|
||||
po->stream = NULL;
|
||||
pulse_output_delete_stream(po);
|
||||
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"pa_stream_connect_playback() has failed: %s",
|
||||
@@ -579,9 +601,7 @@ pulse_output_close(void *data)
|
||||
pulse_wait_for_operation(po->mainloop, o);
|
||||
}
|
||||
|
||||
pa_stream_disconnect(po->stream);
|
||||
pa_stream_unref(po->stream);
|
||||
po->stream = NULL;
|
||||
pulse_output_delete_stream(po);
|
||||
|
||||
if (po->context != NULL &&
|
||||
pa_context_get_state(po->context) != PA_CONTEXT_READY)
|
||||
|
@@ -206,27 +206,14 @@ static void audio_output_wait_all(void)
|
||||
notify_wait(&audio_output_client_notify);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals the audio output if it is open. This function locks the
|
||||
* mutex.
|
||||
*/
|
||||
static void
|
||||
audio_output_lock_signal(struct audio_output *ao)
|
||||
{
|
||||
g_mutex_lock(ao->mutex);
|
||||
if (audio_output_is_open(ao))
|
||||
g_cond_signal(ao->cond);
|
||||
g_mutex_unlock(ao->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals all audio outputs which are open.
|
||||
*/
|
||||
static void
|
||||
audio_output_signal_all(void)
|
||||
audio_output_allow_play_all(void)
|
||||
{
|
||||
for (unsigned i = 0; i < num_audio_outputs; ++i)
|
||||
audio_output_lock_signal(&audio_outputs[i]);
|
||||
audio_output_allow_play(&audio_outputs[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -531,7 +518,7 @@ audio_output_all_cancel(void)
|
||||
/* the audio outputs are now waiting for a signal, to
|
||||
synchronize the cleared music pipe */
|
||||
|
||||
audio_output_signal_all();
|
||||
audio_output_allow_play_all();
|
||||
|
||||
/* invalidate elapsed_time */
|
||||
|
||||
|
@@ -139,6 +139,8 @@ audio_output_open(struct audio_output *ao,
|
||||
{
|
||||
bool open;
|
||||
|
||||
assert(ao != NULL);
|
||||
assert(ao->allow_play);
|
||||
assert(audio_format_valid(audio_format));
|
||||
assert(mp != NULL);
|
||||
|
||||
@@ -164,10 +166,6 @@ audio_output_open(struct audio_output *ao,
|
||||
/* 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;
|
||||
@@ -205,6 +203,7 @@ static void
|
||||
audio_output_close_locked(struct audio_output *ao)
|
||||
{
|
||||
assert(ao != NULL);
|
||||
assert(ao->allow_play);
|
||||
|
||||
if (ao->mixer != NULL)
|
||||
mixer_auto_close(ao->mixer);
|
||||
@@ -247,6 +246,8 @@ audio_output_play(struct audio_output *ao)
|
||||
{
|
||||
g_mutex_lock(ao->mutex);
|
||||
|
||||
assert(ao->allow_play);
|
||||
|
||||
if (audio_output_is_open(ao))
|
||||
g_cond_signal(ao->cond);
|
||||
|
||||
@@ -262,6 +263,7 @@ void audio_output_pause(struct audio_output *ao)
|
||||
mixer_auto_close(ao->mixer);
|
||||
|
||||
g_mutex_lock(ao->mutex);
|
||||
assert(ao->allow_play);
|
||||
if (audio_output_is_open(ao))
|
||||
ao_command_async(ao, AO_COMMAND_PAUSE);
|
||||
g_mutex_unlock(ao->mutex);
|
||||
@@ -271,6 +273,7 @@ void
|
||||
audio_output_drain_async(struct audio_output *ao)
|
||||
{
|
||||
g_mutex_lock(ao->mutex);
|
||||
assert(ao->allow_play);
|
||||
if (audio_output_is_open(ao))
|
||||
ao_command_async(ao, AO_COMMAND_DRAIN);
|
||||
g_mutex_unlock(ao->mutex);
|
||||
@@ -279,8 +282,24 @@ audio_output_drain_async(struct audio_output *ao)
|
||||
void audio_output_cancel(struct audio_output *ao)
|
||||
{
|
||||
g_mutex_lock(ao->mutex);
|
||||
if (audio_output_is_open(ao))
|
||||
|
||||
if (audio_output_is_open(ao)) {
|
||||
ao->allow_play = false;
|
||||
ao_command_async(ao, AO_COMMAND_CANCEL);
|
||||
}
|
||||
|
||||
g_mutex_unlock(ao->mutex);
|
||||
}
|
||||
|
||||
void
|
||||
audio_output_allow_play(struct audio_output *ao)
|
||||
{
|
||||
g_mutex_lock(ao->mutex);
|
||||
|
||||
ao->allow_play = true;
|
||||
if (audio_output_is_open(ao))
|
||||
g_cond_signal(ao->cond);
|
||||
|
||||
g_mutex_unlock(ao->mutex);
|
||||
}
|
||||
|
||||
@@ -310,6 +329,7 @@ void audio_output_finish(struct audio_output *ao)
|
||||
assert(ao->fail_timer == NULL);
|
||||
|
||||
if (ao->thread != NULL) {
|
||||
assert(ao->allow_play);
|
||||
ao_lock_command(ao, AO_COMMAND_KILL);
|
||||
g_thread_join(ao->thread);
|
||||
ao->thread = NULL;
|
||||
|
@@ -72,8 +72,19 @@ void audio_output_pause(struct audio_output *ao);
|
||||
void
|
||||
audio_output_drain_async(struct audio_output *ao);
|
||||
|
||||
/**
|
||||
* Clear the "allow_play" flag and send the "CANCEL" command
|
||||
* asynchronously. To finish the operation, the caller has to call
|
||||
* audio_output_allow_play().
|
||||
*/
|
||||
void audio_output_cancel(struct audio_output *ao);
|
||||
|
||||
/**
|
||||
* Set the "allow_play" and signal the thread.
|
||||
*/
|
||||
void
|
||||
audio_output_allow_play(struct audio_output *ao);
|
||||
|
||||
void audio_output_close(struct audio_output *ao);
|
||||
|
||||
/**
|
||||
|
@@ -193,6 +193,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
|
||||
ao->really_enabled = false;
|
||||
ao->open = false;
|
||||
ao->pause = false;
|
||||
ao->allow_play = true;
|
||||
ao->fail_timer = NULL;
|
||||
|
||||
pcm_buffer_init(&ao->cross_fade_buffer);
|
||||
|
@@ -109,6 +109,15 @@ struct audio_output {
|
||||
*/
|
||||
bool pause;
|
||||
|
||||
/**
|
||||
* When this flag is set, the output thread will not do any
|
||||
* playback. It will wait until the flag is cleared.
|
||||
*
|
||||
* This is used to synchronize the "clear" operation on the
|
||||
* shared music pipe during the CANCEL command.
|
||||
*/
|
||||
bool allow_play;
|
||||
|
||||
/**
|
||||
* If not NULL, the device has failed, and this timer is used
|
||||
* to estimate how long it should stay disabled (unless
|
||||
|
@@ -649,12 +649,6 @@ static gpointer audio_output_task(gpointer arg)
|
||||
}
|
||||
|
||||
ao_command_finished(ao);
|
||||
|
||||
/* the player thread will now clear our music
|
||||
pipe - wait for a notify, to give it some
|
||||
time */
|
||||
if (ao->command == AO_COMMAND_NONE)
|
||||
g_cond_wait(ao->cond, ao->mutex);
|
||||
continue;
|
||||
|
||||
case AO_COMMAND_KILL:
|
||||
@@ -664,7 +658,7 @@ static gpointer audio_output_task(gpointer arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ao->open && ao_play(ao))
|
||||
if (ao->open && ao->allow_play && ao_play(ao))
|
||||
/* don't wait for an event if there are more
|
||||
chunks in the pipe */
|
||||
continue;
|
||||
|
Reference in New Issue
Block a user