Merge branch 'v0.17.x'
This commit is contained in:
@@ -53,6 +53,31 @@ httpd_output_quark(void)
|
||||
return g_quark_from_static_string("httpd_output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there is at least one client.
|
||||
*
|
||||
* Caller must lock the mutex.
|
||||
*/
|
||||
G_GNUC_PURE
|
||||
static bool
|
||||
httpd_output_has_clients(const struct httpd_output *httpd)
|
||||
{
|
||||
return httpd->clients != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there is at least one client.
|
||||
*/
|
||||
G_GNUC_PURE
|
||||
static bool
|
||||
httpd_output_lock_has_clients(const struct httpd_output *httpd)
|
||||
{
|
||||
g_mutex_lock(httpd->mutex);
|
||||
bool result = httpd_output_has_clients(httpd);
|
||||
g_mutex_unlock(httpd->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
httpd_listen_in_event(int fd, const struct sockaddr *address,
|
||||
size_t address_length, int uid, void *ctx);
|
||||
@@ -397,6 +422,19 @@ httpd_output_delay(struct audio_output *ao)
|
||||
{
|
||||
struct httpd_output *httpd = (struct httpd_output *)ao;
|
||||
|
||||
if (!httpd_output_lock_has_clients(httpd) && httpd->base.pause) {
|
||||
/* if there's no client and this output is paused,
|
||||
then httpd_output_pause() will not do anything, it
|
||||
will not fill the buffer and it will not update the
|
||||
timer; therefore, we reset the timer here */
|
||||
timer_reset(httpd->timer);
|
||||
|
||||
/* some arbitrary delay that is long enough to avoid
|
||||
consuming too much CPU, and short enough to notice
|
||||
new clients quickly enough */
|
||||
return 1000;
|
||||
}
|
||||
|
||||
return httpd->timer->started
|
||||
? timer_delay(httpd->timer)
|
||||
: 0;
|
||||
@@ -475,13 +513,8 @@ httpd_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error)
|
||||
{
|
||||
struct httpd_output *httpd = (struct httpd_output *)ao;
|
||||
bool has_clients;
|
||||
|
||||
g_mutex_lock(httpd->mutex);
|
||||
has_clients = httpd->clients != NULL;
|
||||
g_mutex_unlock(httpd->mutex);
|
||||
|
||||
if (has_clients) {
|
||||
if (httpd_output_lock_has_clients(httpd)) {
|
||||
bool success;
|
||||
|
||||
success = httpd_output_encode_and_play(httpd, chunk, size,
|
||||
@@ -502,16 +535,11 @@ httpd_output_pause(struct audio_output *ao)
|
||||
{
|
||||
struct httpd_output *httpd = (struct httpd_output *)ao;
|
||||
|
||||
g_mutex_lock(httpd->mutex);
|
||||
bool has_clients = httpd->clients != NULL;
|
||||
g_mutex_unlock(httpd->mutex);
|
||||
|
||||
if (has_clients) {
|
||||
if (httpd_output_lock_has_clients(httpd)) {
|
||||
static const char silence[1020];
|
||||
return httpd_output_play(ao, silence, sizeof(silence),
|
||||
NULL) > 0;
|
||||
} else {
|
||||
g_usleep(100000);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,6 +608,16 @@ mpd_jack_close(G_GNUC_UNUSED struct audio_output *ao)
|
||||
mpd_jack_stop(jd);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
mpd_jack_delay(struct audio_output *ao)
|
||||
{
|
||||
struct jack_data *jd = (struct jack_data *)ao;
|
||||
|
||||
return jd->base.pause && jd->pause && !jd->shutdown
|
||||
? 1000
|
||||
: 0;
|
||||
}
|
||||
|
||||
static inline jack_default_audio_sample_t
|
||||
sample_16_to_jack(int16_t sample)
|
||||
{
|
||||
@@ -727,10 +737,6 @@ mpd_jack_pause(struct audio_output *ao)
|
||||
|
||||
jd->pause = true;
|
||||
|
||||
/* due to a MPD API limitation, we have to sleep a little bit
|
||||
here, to avoid hogging the CPU */
|
||||
g_usleep(50000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -742,6 +748,7 @@ const struct audio_output_plugin jack_output_plugin = {
|
||||
.enable = mpd_jack_enable,
|
||||
.disable = mpd_jack_disable,
|
||||
.open = mpd_jack_open,
|
||||
.delay = mpd_jack_delay,
|
||||
.play = mpd_jack_play,
|
||||
.pause = mpd_jack_pause,
|
||||
.close = mpd_jack_close,
|
||||
|
||||
@@ -681,35 +681,6 @@ pulse_output_close(struct audio_output *ao)
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the stream is (already) connected, and waits for a signal
|
||||
* if not. The mainloop must be locked before calling this function.
|
||||
*
|
||||
* @return the current stream state
|
||||
*/
|
||||
static pa_stream_state_t
|
||||
pulse_output_check_stream(struct pulse_output *po)
|
||||
{
|
||||
pa_stream_state_t state = pa_stream_get_state(po->stream);
|
||||
|
||||
assert(po->mainloop != NULL);
|
||||
|
||||
switch (state) {
|
||||
case PA_STREAM_READY:
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
case PA_STREAM_UNCONNECTED:
|
||||
break;
|
||||
|
||||
case PA_STREAM_CREATING:
|
||||
pa_threaded_mainloop_wait(po->mainloop);
|
||||
state = pa_stream_get_state(po->stream);
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the stream is (already) connected, and waits if not. The
|
||||
* mainloop must be locked before calling this function.
|
||||
@@ -719,35 +690,25 @@ pulse_output_check_stream(struct pulse_output *po)
|
||||
static bool
|
||||
pulse_output_wait_stream(struct pulse_output *po, GError **error_r)
|
||||
{
|
||||
pa_stream_state_t state = pa_stream_get_state(po->stream);
|
||||
while (true) {
|
||||
switch (pa_stream_get_state(po->stream)) {
|
||||
case PA_STREAM_READY:
|
||||
return true;
|
||||
|
||||
switch (state) {
|
||||
case PA_STREAM_READY:
|
||||
return true;
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
case PA_STREAM_UNCONNECTED:
|
||||
g_set_error(error_r, pulse_output_quark(),
|
||||
pa_context_errno(po->context),
|
||||
"failed to connect the stream: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
return false;
|
||||
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
case PA_STREAM_UNCONNECTED:
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"disconnected");
|
||||
return false;
|
||||
|
||||
case PA_STREAM_CREATING:
|
||||
break;
|
||||
case PA_STREAM_CREATING:
|
||||
pa_threaded_mainloop_wait(po->mainloop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
state = pulse_output_check_stream(po);
|
||||
} while (state == PA_STREAM_CREATING);
|
||||
|
||||
if (state != PA_STREAM_READY) {
|
||||
g_set_error(error_r, pulse_output_quark(), 0,
|
||||
"failed to connect the stream: %s",
|
||||
pa_strerror(pa_context_errno(po->context)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -801,6 +762,24 @@ pulse_output_stream_pause(struct pulse_output *po, bool pause,
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
pulse_output_delay(struct audio_output *ao)
|
||||
{
|
||||
struct pulse_output *po = (struct pulse_output *)ao;
|
||||
unsigned result = 0;
|
||||
|
||||
pa_threaded_mainloop_lock(po->mainloop);
|
||||
|
||||
if (po->base.pause && pulse_output_stream_is_paused(po) &&
|
||||
pa_stream_get_state(po->stream) == PA_STREAM_READY)
|
||||
/* idle while paused */
|
||||
result = 1000;
|
||||
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static size_t
|
||||
pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
GError **error_r)
|
||||
@@ -928,13 +907,8 @@ pulse_output_pause(struct audio_output *ao)
|
||||
|
||||
/* cork the stream */
|
||||
|
||||
if (pulse_output_stream_is_paused(po)) {
|
||||
/* already paused; due to a MPD API limitation, we
|
||||
have to sleep a little bit here, to avoid hogging
|
||||
the CPU */
|
||||
|
||||
g_usleep(50000);
|
||||
} else if (!pulse_output_stream_pause(po, true, &error)) {
|
||||
if (!pulse_output_stream_is_paused(po) &&
|
||||
!pulse_output_stream_pause(po, true, &error)) {
|
||||
pa_threaded_mainloop_unlock(po->mainloop);
|
||||
g_warning("%s", error->message);
|
||||
g_error_free(error);
|
||||
@@ -971,6 +945,7 @@ const struct audio_output_plugin pulse_output_plugin = {
|
||||
.enable = pulse_output_enable,
|
||||
.disable = pulse_output_disable,
|
||||
.open = pulse_output_open,
|
||||
.delay = pulse_output_delay,
|
||||
.play = pulse_output_play,
|
||||
.cancel = pulse_output_cancel,
|
||||
.pause = pulse_output_pause,
|
||||
|
||||
Reference in New Issue
Block a user