From 51de8fd10a98e6ed9a2ac10a796236c5b3fe2bf8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 24 Nov 2013 20:20:57 +0100 Subject: Volume, Output: use new class PeriodClock instead of GTimer --- Makefile.am | 1 + src/Main.cxx | 1 - src/OutputAll.cxx | 5 +- src/OutputControl.cxx | 22 +++---- src/OutputFinish.cxx | 4 +- src/OutputInit.cxx | 1 - src/OutputInternal.hxx | 6 +- src/OutputThread.cxx | 25 +++----- src/Volume.cxx | 15 +---- src/Volume.hxx | 2 - src/system/PeriodClock.hxx | 149 +++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 173 insertions(+), 58 deletions(-) create mode 100644 src/system/PeriodClock.hxx diff --git a/Makefile.am b/Makefile.am index f7ce9e377..9c789ced2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -299,6 +299,7 @@ libsystem_a_SOURCES = \ src/system/EventFD.cxx src/system/EventFD.hxx \ src/system/SignalFD.cxx src/system/SignalFD.hxx \ src/system/EPollFD.cxx src/system/EPollFD.hxx \ + src/system/PeriodClock.hxx \ src/system/Clock.cxx src/system/Clock.hxx # Event loop library diff --git a/src/Main.cxx b/src/Main.cxx index 6023e8bed..3b89e9ffa 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -544,7 +544,6 @@ int mpd_main(int argc, char *argv[]) playlist_list_global_finish(); input_stream_global_finish(); audio_output_all_finish(); - volume_finish(); mapper_finish(); delete instance->partition; command_finish(); diff --git a/src/OutputAll.cxx b/src/OutputAll.cxx index 36d41184a..d167a80cd 100644 --- a/src/OutputAll.cxx +++ b/src/OutputAll.cxx @@ -225,10 +225,7 @@ audio_output_reset_reopen(struct audio_output *ao) { const ScopeLock protect(ao->mutex); - if (!ao->open && ao->fail_timer != nullptr) { - g_timer_destroy(ao->fail_timer); - ao->fail_timer = nullptr; - } + ao->fail_timer.Reset(); } /** diff --git a/src/OutputControl.cxx b/src/OutputControl.cxx index 553507a2a..b2e9b284f 100644 --- a/src/OutputControl.cxx +++ b/src/OutputControl.cxx @@ -32,8 +32,6 @@ #include "util/Error.hxx" #include "Log.hxx" -#include - #include #include @@ -152,10 +150,7 @@ audio_output_open(struct audio_output *ao, assert(ao->allow_play); assert(audio_format.IsValid()); - if (ao->fail_timer != nullptr) { - g_timer_destroy(ao->fail_timer); - ao->fail_timer = nullptr; - } + ao->fail_timer.Reset(); if (ao->open && audio_format == ao->in_audio_format) { assert(ao->pipe == &mp || @@ -213,14 +208,12 @@ audio_output_close_locked(struct audio_output *ao) if (ao->mixer != nullptr) mixer_auto_close(ao->mixer); - assert(!ao->open || ao->fail_timer == nullptr); + assert(!ao->open || !ao->fail_timer.IsDefined()); if (ao->open) ao_command(ao, AO_COMMAND_CLOSE); - else if (ao->fail_timer != nullptr) { - g_timer_destroy(ao->fail_timer); - ao->fail_timer = nullptr; - } + else + ao->fail_timer.Reset(); } bool @@ -231,8 +224,7 @@ audio_output_update(struct audio_output *ao, const ScopeLock protect(ao->mutex); if (ao->enabled && ao->really_enabled) { - if (ao->fail_timer == nullptr || - g_timer_elapsed(ao->fail_timer, nullptr) > REOPEN_AFTER) { + if (ao->fail_timer.Check(REOPEN_AFTER * 1000)) { return audio_output_open(ao, audio_format, mp); } } else if (audio_output_is_open(ao)) @@ -312,7 +304,7 @@ audio_output_release(struct audio_output *ao) void audio_output_close(struct audio_output *ao) { assert(ao != nullptr); - assert(!ao->open || ao->fail_timer == nullptr); + assert(!ao->open || !ao->fail_timer.IsDefined()); const ScopeLock protect(ao->mutex); audio_output_close_locked(ao); @@ -322,7 +314,7 @@ void audio_output_finish(struct audio_output *ao) { audio_output_close(ao); - assert(ao->fail_timer == nullptr); + assert(!ao->fail_timer.IsDefined()); if (ao->thread.IsDefined()) { assert(ao->allow_play); diff --git a/src/OutputFinish.cxx b/src/OutputFinish.cxx index db6599b53..b19f4c402 100644 --- a/src/OutputFinish.cxx +++ b/src/OutputFinish.cxx @@ -29,7 +29,7 @@ void ao_base_finish(struct audio_output *ao) { assert(!ao->open); - assert(ao->fail_timer == nullptr); + assert(!ao->fail_timer.IsDefined()); assert(!ao->thread.IsDefined()); if (ao->mixer != nullptr) @@ -44,7 +44,7 @@ void audio_output_free(struct audio_output *ao) { assert(!ao->open); - assert(ao->fail_timer == nullptr); + assert(!ao->fail_timer.IsDefined()); assert(!ao->thread.IsDefined()); ao_plugin_finish(ao); diff --git a/src/OutputInit.cxx b/src/OutputInit.cxx index 28eba1ab2..4a7978908 100644 --- a/src/OutputInit.cxx +++ b/src/OutputInit.cxx @@ -173,7 +173,6 @@ ao_base_init(struct audio_output *ao, ao->allow_play = true; ao->in_playback_loop = false; ao->woken_for_play = false; - ao->fail_timer = nullptr; /* set up the filter chain */ diff --git a/src/OutputInternal.hxx b/src/OutputInternal.hxx index c07cdf856..f05073bd7 100644 --- a/src/OutputInternal.hxx +++ b/src/OutputInternal.hxx @@ -25,15 +25,13 @@ #include "thread/Mutex.hxx" #include "thread/Cond.hxx" #include "thread/Thread.hxx" - -#include +#include "system/PeriodClock.hxx" class Error; class Filter; class MusicPipe; struct config_param; struct PlayerControl; -typedef struct _GTimer GTimer; enum audio_output_command { AO_COMMAND_NONE = 0, @@ -147,7 +145,7 @@ struct audio_output { * to estimate how long it should stay disabled (unless * explicitly reopened with "play"). */ - GTimer *fail_timer; + PeriodClock fail_timer; /** * The configured audio format. diff --git a/src/OutputThread.cxx b/src/OutputThread.cxx index dc81643f3..c65309503 100644 --- a/src/OutputThread.cxx +++ b/src/OutputThread.cxx @@ -35,8 +35,6 @@ #include "Log.hxx" #include "Compiler.h" -#include - #include #include @@ -137,14 +135,7 @@ ao_open(struct audio_output *ao) assert(ao->chunk == nullptr); assert(ao->in_audio_format.IsValid()); - if (ao->fail_timer != nullptr) { - /* this can only happen when this - output thread fails while - audio_output_open() is run in the - player thread */ - g_timer_destroy(ao->fail_timer); - ao->fail_timer = nullptr; - } + ao->fail_timer.Reset(); /* enable the device (just in case the last enable has failed) */ @@ -160,7 +151,7 @@ ao_open(struct audio_output *ao) FormatError(error, "Failed to open filter for \"%s\" [%s]", ao->name, ao->plugin->name); - ao->fail_timer = g_timer_new(); + ao->fail_timer.Update(); return; } @@ -180,7 +171,7 @@ ao_open(struct audio_output *ao) ao->name, ao->plugin->name); ao_filter_close(ao); - ao->fail_timer = g_timer_new(); + ao->fail_timer.Update(); return; } @@ -190,7 +181,7 @@ ao_open(struct audio_output *ao) ao->name, ao->plugin->name); ao_filter_close(ao); - ao->fail_timer = g_timer_new(); + ao->fail_timer.Update(); return; } @@ -256,7 +247,7 @@ ao_reopen_filter(struct audio_output *ao) ao->chunk = nullptr; ao->open = false; - ao->fail_timer = g_timer_new(); + ao->fail_timer.Update(); ao->mutex.unlock(); ao_plugin_close(ao); @@ -445,7 +436,7 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) /* don't automatically reopen this device for 10 seconds */ - ao->fail_timer = g_timer_new(); + ao->fail_timer.Update(); return false; } @@ -469,8 +460,8 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) /* don't automatically reopen this device for 10 seconds */ - assert(ao->fail_timer == nullptr); - ao->fail_timer = g_timer_new(); + assert(!ao->fail_timer.IsDefined()); + ao->fail_timer.Update(); return false; } diff --git a/src/Volume.cxx b/src/Volume.cxx index 6c5f8dc4d..3f7210f6c 100644 --- a/src/Volume.cxx +++ b/src/Volume.cxx @@ -23,6 +23,7 @@ #include "Idle.hxx" #include "GlobalEvents.hxx" #include "util/Domain.hxx" +#include "system/PeriodClock.hxx" #include "Log.hxx" #include @@ -39,7 +40,7 @@ static unsigned volume_software_set = 100; /** the cached hardware mixer value; invalid if negative */ static int last_hardware_volume = -1; /** the age of #last_hardware_volume */ -static GTimer *hardware_volume_timer; +static PeriodClock hardware_volume_clock; /** * Handler for #GlobalEvents::MIXER. @@ -54,29 +55,19 @@ mixer_event_callback(void) idle_add(IDLE_MIXER); } -void volume_finish(void) -{ - g_timer_destroy(hardware_volume_timer); -} - void volume_init(void) { - hardware_volume_timer = g_timer_new(); - GlobalEvents::Register(GlobalEvents::MIXER, mixer_event_callback); } int volume_level_get(void) { - assert(hardware_volume_timer != nullptr); - if (last_hardware_volume >= 0 && - g_timer_elapsed(hardware_volume_timer, nullptr) < 1.0) + !hardware_volume_clock.CheckUpdate(1000)) /* throttle access to hardware mixers */ return last_hardware_volume; last_hardware_volume = mixer_all_get_volume(); - g_timer_start(hardware_volume_timer); return last_hardware_volume; } diff --git a/src/Volume.hxx b/src/Volume.hxx index 6b937aca3..d448cc4e4 100644 --- a/src/Volume.hxx +++ b/src/Volume.hxx @@ -26,8 +26,6 @@ void volume_init(void); -void volume_finish(void); - gcc_pure int volume_level_get(void); diff --git a/src/system/PeriodClock.hxx b/src/system/PeriodClock.hxx new file mode 100644 index 000000000..61f52933f --- /dev/null +++ b/src/system/PeriodClock.hxx @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_PERIOD_CLOCK_HXX +#define MPD_PERIOD_CLOCK_HXX + +#include "Clock.hxx" + +/** + * This is a stopwatch which saves the timestamp of an event, and can + * check whether a specified time span has passed since then. + */ +class PeriodClock { +protected: + typedef unsigned Stamp; + +private: + Stamp last; + +public: + /** + * Initializes the object, setting the last time stamp to "0", + * i.e. a Check() will always succeed. If you do not want this + * default behaviour, call Update() immediately after creating the + * object. + */ + constexpr + PeriodClock():last(0) {} + +protected: + static Stamp GetNow() { + return MonotonicClockMS(); + } + + constexpr int Elapsed(Stamp now) const { + return last == 0 + ? -1 + : now - last; + } + + constexpr bool Check(Stamp now, unsigned duration) const { + return now >= last + duration; + } + + void Update(Stamp now) { + last = now; + } + +public: + bool IsDefined() const { + return last != 0; + } + + /** + * Resets the clock. + */ + void Reset() { + last = 0; + } + + /** + * Returns the number of milliseconds elapsed since the last + * update(). Returns -1 if update() was never called. + */ + int Elapsed() const { + return Elapsed(GetNow()); + } + + /** + * Combines a call to Elapsed() and Update(). + */ + int ElapsedUpdate() { + const auto now = GetNow(); + int result = Elapsed(now); + Update(now); + return result; + } + + /** + * Checks whether the specified duration has passed since the last + * update. + * + * @param duration the duration in milliseconds + */ + bool Check(unsigned duration) const { + return Check(GetNow(), duration); + } + + /** + * Updates the time stamp, setting it to the current clock. + */ + void Update() { + Update(GetNow()); + } + + /** + * Updates the time stamp, setting it to the current clock plus the + * specified offset. + */ + void UpdateWithOffset(int offset) { + Update(GetNow() + offset); + } + + /** + * Checks whether the specified duration has passed since the last + * update. If yes, it updates the time stamp. + * + * @param duration the duration in milliseconds + */ + bool CheckUpdate(unsigned duration) { + Stamp now = GetNow(); + if (Check(now, duration)) { + Update(now); + return true; + } else + return false; + } + + /** + * Checks whether the specified duration has passed since the last + * update. After that, it updates the time stamp. + * + * @param duration the duration in milliseconds + */ + bool CheckAlwaysUpdate(unsigned duration) { + Stamp now = GetNow(); + bool ret = Check(now, duration); + Update(now); + return ret; + } +}; + +#endif -- cgit v1.2.3