diff options
Diffstat (limited to 'src/output')
-rw-r--r-- | src/output/AlsaOutputPlugin.cxx | 11 | ||||
-rw-r--r-- | src/output/FifoOutputPlugin.cxx | 3 | ||||
-rw-r--r-- | src/output/HttpdClient.cxx | 71 | ||||
-rw-r--r-- | src/output/HttpdClient.hxx | 25 | ||||
-rw-r--r-- | src/output/HttpdInternal.hxx | 68 | ||||
-rw-r--r-- | src/output/HttpdOutputPlugin.cxx | 218 | ||||
-rw-r--r-- | src/output/JackOutputPlugin.cxx | 4 | ||||
-rw-r--r-- | src/output/NullOutputPlugin.cxx | 2 | ||||
-rw-r--r-- | src/output/OSXOutputPlugin.cxx | 49 | ||||
-rw-r--r-- | src/output/PulseOutputPlugin.hxx | 2 |
10 files changed, 281 insertions, 172 deletions
diff --git a/src/output/AlsaOutputPlugin.cxx b/src/output/AlsaOutputPlugin.cxx index 4877d3a46..b5ca511b2 100644 --- a/src/output/AlsaOutputPlugin.cxx +++ b/src/output/AlsaOutputPlugin.cxx @@ -27,7 +27,6 @@ #include "util/Domain.hxx" #include "Log.hxx" -#include <glib.h> #include <alsa/asoundlib.h> #include <string> @@ -118,7 +117,7 @@ struct AlsaOutput { * It contains silence samples, enough to fill one period (see * #period_frames). */ - void *silence; + uint8_t *silence; AlsaOutput():mode(0), writei(snd_pcm_writei) { } @@ -593,8 +592,8 @@ configure_hw: ad->period_frames = alsa_period_size; ad->period_position = 0; - ad->silence = g_malloc(snd_pcm_frames_to_bytes(ad->pcm, - alsa_period_size)); + ad->silence = new uint8_t[snd_pcm_frames_to_bytes(ad->pcm, + alsa_period_size)]; snd_pcm_format_set_silence(format, ad->silence, alsa_period_size * channels); @@ -641,7 +640,7 @@ alsa_setup_dsd(AlsaOutput *ad, const AudioFormat audio_format, error.Format(alsa_output_domain, "Failed to configure DSD-over-USB on ALSA device \"%s\"", alsa_device(ad)); - g_free(ad->silence); + delete[] ad->silence; return false; } @@ -811,7 +810,7 @@ alsa_close(struct audio_output *ao) AlsaOutput *ad = (AlsaOutput *)ao; snd_pcm_close(ad->pcm); - g_free(ad->silence); + delete[] ad->silence; } static size_t diff --git a/src/output/FifoOutputPlugin.cxx b/src/output/FifoOutputPlugin.cxx index aeb9a6a87..7963d8c82 100644 --- a/src/output/FifoOutputPlugin.cxx +++ b/src/output/FifoOutputPlugin.cxx @@ -22,7 +22,6 @@ #include "ConfigError.hxx" #include "OutputAPI.hxx" #include "Timer.hxx" -#include "system/fd_util.h" #include "fs/AllocatedPath.hxx" #include "fs/FileSystem.hxx" #include "util/Error.hxx" @@ -30,10 +29,8 @@ #include "Log.hxx" #include "open.h" -#include <sys/types.h> #include <sys/stat.h> #include <errno.h> -#include <string.h> #include <unistd.h> #define FIFO_BUFFER_SIZE 65536 /* pipe capacity on Linux >= 2.6.11 */ diff --git a/src/output/HttpdClient.cxx b/src/output/HttpdClient.cxx index 8e13fda38..102ce1ec3 100644 --- a/src/output/HttpdClient.cxx +++ b/src/output/HttpdClient.cxx @@ -37,24 +37,26 @@ HttpdClient::~HttpdClient() if (current_page != nullptr) current_page->Unref(); - for (auto page : pages) - page->Unref(); + ClearQueue(); } if (metadata) metadata->Unref(); + + if (IsDefined()) + BufferedSocket::Close(); } void HttpdClient::Close() { - httpd->RemoveClient(*this); + httpd.RemoveClient(*this); } void HttpdClient::LockClose() { - const ScopeLock protect(httpd->mutex); + const ScopeLock protect(httpd.mutex); Close(); } @@ -67,7 +69,7 @@ HttpdClient::BeginResponse() current_page = nullptr; if (!head_method) - httpd->SendHeader(*this); + httpd.SendHeader(*this); } /** @@ -155,13 +157,13 @@ HttpdClient::SendResponse() "realTimeInfo.dlna.org: DLNA.ORG_TLAG=*\r\n" "contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0\r\n" "\r\n", - httpd->content_type); + httpd.content_type); } else if (metadata_requested) { char *metadata_header = - icy_server_metadata_header(httpd->name, httpd->genre, - httpd->website, - httpd->content_type, + icy_server_metadata_header(httpd.name, httpd.genre, + httpd.website, + httpd.content_type, metaint); g_strlcpy(buffer, metadata_header, sizeof(buffer)); @@ -176,7 +178,7 @@ HttpdClient::SendResponse() "Pragma: no-cache\r\n" "Cache-Control: no-cache, no-store\r\n" "\r\n", - httpd->content_type); + httpd.content_type); } ssize_t nbytes = SocketMonitor::Write(buffer, strlen(buffer)); @@ -192,11 +194,12 @@ HttpdClient::SendResponse() return true; } -HttpdClient::HttpdClient(HttpdOutput *_httpd, int _fd, EventLoop &_loop, +HttpdClient::HttpdClient(HttpdOutput &_httpd, int _fd, EventLoop &_loop, bool _metadata_supported) :BufferedSocket(_fd, _loop), httpd(_httpd), state(REQUEST), + queue_size(0), head_method(false), dlna_streaming_requested(false), metadata_supported(_metadata_supported), @@ -207,16 +210,24 @@ HttpdClient::HttpdClient(HttpdOutput *_httpd, int _fd, EventLoop &_loop, { } -size_t -HttpdClient::GetQueueSize() const +void +HttpdClient::ClearQueue() { - if (state != RESPONSE) - return 0; + assert(state == RESPONSE); - size_t size = 0; - for (auto page : pages) - size += page->size; - return size; + while (!pages.empty()) { + Page *page = pages.front(); + pages.pop(); + +#ifndef NDEBUG + assert(queue_size >= page->size); + queue_size -= page->size; +#endif + + page->Unref(); + } + + assert(queue_size == 0); } void @@ -225,9 +236,7 @@ HttpdClient::CancelQueue() if (state != RESPONSE) return; - for (auto page : pages) - page->Unref(); - pages.clear(); + ClearQueue(); if (current_page == nullptr) CancelWrite(); @@ -262,7 +271,7 @@ HttpdClient::GetBytesTillMetaData() const inline bool HttpdClient::TryWrite() { - const ScopeLock protect(httpd->mutex); + const ScopeLock protect(httpd.mutex); assert(state == RESPONSE); @@ -270,14 +279,17 @@ HttpdClient::TryWrite() if (pages.empty()) { /* another thread has removed the event source while this thread was waiting for - httpd->mutex */ + httpd.mutex */ CancelWrite(); return true; } current_page = pages.front(); - pages.pop_front(); + pages.pop(); current_position = 0; + + assert(queue_size >= current_page->size); + queue_size -= current_page->size; } const ssize_t bytes_to_write = GetBytesTillMetaData(); @@ -378,8 +390,15 @@ HttpdClient::PushPage(Page *page) /* the client is still writing the HTTP request */ return; + if (queue_size > 256 * 1024) { + FormatDebug(httpd_output_domain, + "client is too slow, flushing its queue"); + ClearQueue(); + } + page->Ref(); - pages.push_back(page); + pages.push(page); + queue_size += page->size; ScheduleWrite(); } diff --git a/src/output/HttpdClient.hxx b/src/output/HttpdClient.hxx index 66a819232..94fe2ae62 100644 --- a/src/output/HttpdClient.hxx +++ b/src/output/HttpdClient.hxx @@ -23,18 +23,19 @@ #include "event/BufferedSocket.hxx" #include "Compiler.h" +#include <queue> #include <list> #include <stddef.h> -struct HttpdOutput; +class HttpdOutput; class Page; -class HttpdClient final : public BufferedSocket { +class HttpdClient final : BufferedSocket { /** * The httpd output object this client is connected to. */ - HttpdOutput *const httpd; + HttpdOutput &httpd; /** * The current state of the client. @@ -53,7 +54,12 @@ class HttpdClient final : public BufferedSocket { /** * A queue of #Page objects to be sent to the client. */ - std::list<Page *> pages; + std::queue<Page *, std::list<Page *>> pages; + + /** + * The sum of all page sizes in #pages. + */ + size_t queue_size; /** * The #page which is currently being sent to the client. @@ -120,7 +126,7 @@ public: * @param httpd the HTTP output device * @param fd the socket file descriptor */ - HttpdClient(HttpdOutput *httpd, int _fd, EventLoop &_loop, + HttpdClient(HttpdOutput &httpd, int _fd, EventLoop &_loop, bool _metadata_supported); /** @@ -137,12 +143,6 @@ public: void LockClose(); /** - * Returns the total size of this client's page queue. - */ - gcc_pure - size_t GetQueueSize() const; - - /** * Clears the page queue. */ void CancelQueue(); @@ -180,6 +180,9 @@ public: */ void PushMetaData(Page *page); +private: + void ClearQueue(); + protected: virtual bool OnSocketReady(unsigned flags) override; virtual InputResult OnSocketInput(void *data, size_t length) override; diff --git a/src/output/HttpdInternal.hxx b/src/output/HttpdInternal.hxx index b76493a44..8d35d35e9 100644 --- a/src/output/HttpdInternal.hxx +++ b/src/output/HttpdInternal.hxx @@ -29,6 +29,8 @@ #include "Timer.hxx" #include "thread/Mutex.hxx" #include "event/ServerSocket.hxx" +#include "event/DeferredMonitor.hxx" +#include "util/Cast.hxx" #ifdef _LIBCPP_VERSION /* can't use incomplete template arguments with libc++ */ @@ -36,6 +38,8 @@ #endif #include <forward_list> +#include <queue> +#include <list> struct config_param; class Error; @@ -46,7 +50,7 @@ class Page; struct Encoder; struct Tag; -struct HttpdOutput final : private ServerSocket { +class HttpdOutput final : ServerSocket, DeferredMonitor { struct audio_output base; /** @@ -68,6 +72,7 @@ struct HttpdOutput final : private ServerSocket { */ size_t unflushed_input; +public: /** * The MIME type produced by the #encoder. */ @@ -80,6 +85,13 @@ struct HttpdOutput final : private ServerSocket { mutable Mutex mutex; /** + * This condition gets signalled when an item is removed from + * #pages. + */ + Cond cond; + +private: + /** * A #Timer object to synchronize this output with the * wallclock. */ @@ -96,6 +108,15 @@ struct HttpdOutput final : private ServerSocket { Page *metadata; /** + * The page queue, i.e. pages from the encoder to be + * broadcasted to all clients. This container is necessary to + * pass pages from the OutputThread to the IOThread. It is + * protected by #mutex, and removing signals #cond. + */ + std::queue<Page *, std::list<Page *>> pages; + + public: + /** * The configured name. */ char const *name; @@ -108,6 +129,7 @@ struct HttpdOutput final : private ServerSocket { */ char const *website; +private: /** * A linked list containing all clients which are currently * connected. @@ -126,11 +148,46 @@ struct HttpdOutput final : private ServerSocket { */ unsigned clients_max, clients_cnt; +public: HttpdOutput(EventLoop &_loop); ~HttpdOutput(); +#if GCC_CHECK_VERSION(4,6) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif + + static constexpr HttpdOutput *Cast(audio_output *ao) { + return ContainerCast(ao, HttpdOutput, base); + } + +#if GCC_CHECK_VERSION(4,6) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + + using DeferredMonitor::GetEventLoop; + + bool Init(const config_param ¶m, Error &error); + + void Finish() { + ao_base_finish(&base); + } + bool Configure(const config_param ¶m, Error &error); + audio_output *InitAndConfigure(const config_param ¶m, + Error &error) { + if (!Init(param, error)) + return nullptr; + + if (!Configure(param, error)) { + Finish(); + return nullptr; + } + + return &base; + } + bool Bind(Error &error); void Unbind(); @@ -181,6 +238,9 @@ struct HttpdOutput final : private ServerSocket { */ void SendHeader(HttpdClient &client) const; + gcc_pure + unsigned Delay() const; + /** * Reads data from the encoder (as much as available) and * returns it as a new #page object. @@ -203,7 +263,13 @@ struct HttpdOutput final : private ServerSocket { void SendTag(const Tag *tag); + size_t Play(const void *chunk, size_t size, Error &error); + + void CancelAllClients(); + private: + virtual void RunDeferred() override; + virtual void OnAccept(int fd, const sockaddr &address, size_t address_length, int uid) override; }; diff --git a/src/output/HttpdOutputPlugin.cxx b/src/output/HttpdOutputPlugin.cxx index 369c06937..4cd2b4ae8 100644 --- a/src/output/HttpdOutputPlugin.cxx +++ b/src/output/HttpdOutputPlugin.cxx @@ -28,13 +28,12 @@ #include "Page.hxx" #include "IcyMetaDataServer.hxx" #include "system/fd_util.h" -#include "Main.hxx" +#include "IOThread.hxx" +#include "event/Call.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" #include "Log.hxx" -#include <glib.h> - #include <assert.h> #include <sys/types.h> @@ -51,7 +50,7 @@ const Domain httpd_output_domain("httpd_output"); inline HttpdOutput::HttpdOutput(EventLoop &_loop) - :ServerSocket(_loop), + :ServerSocket(_loop), DeferredMonitor(_loop), encoder(nullptr), unflushed_input(0), metadata(nullptr) { @@ -72,8 +71,11 @@ HttpdOutput::Bind(Error &error) { open = false; - const ScopeLock protect(mutex); - return ServerSocket::Open(error); + bool result = false; + BlockingCall(GetEventLoop(), [this, &error, &result](){ + result = ServerSocket::Open(error); + }); + return result; } inline void @@ -81,8 +83,9 @@ HttpdOutput::Unbind() { assert(!open); - const ScopeLock protect(mutex); - ServerSocket::Close(); + BlockingCall(GetEventLoop(), [this](){ + ServerSocket::Close(); + }); } inline bool @@ -130,47 +133,30 @@ HttpdOutput::Configure(const config_param ¶m, Error &error) return true; } +inline bool +HttpdOutput::Init(const config_param ¶m, Error &error) +{ + return ao_base_init(&base, &httpd_output_plugin, param, error); +} + static struct audio_output * httpd_output_init(const config_param ¶m, Error &error) { - HttpdOutput *httpd = new HttpdOutput(*main_loop); + HttpdOutput *httpd = new HttpdOutput(io_thread_get()); - if (!ao_base_init(&httpd->base, &httpd_output_plugin, param, - error)) { + audio_output *result = httpd->InitAndConfigure(param, error); + if (result == nullptr) delete httpd; - return nullptr; - } - if (!httpd->Configure(param, error)) { - ao_base_finish(&httpd->base); - delete httpd; - return nullptr; - } - - return &httpd->base; -} - -#if GCC_CHECK_VERSION(4,6) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Winvalid-offsetof" -#endif - -static inline constexpr HttpdOutput * -Cast(audio_output *ao) -{ - return (HttpdOutput *)((char *)ao - offsetof(HttpdOutput, base)); + return result; } -#if GCC_CHECK_VERSION(4,6) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - static void httpd_output_finish(struct audio_output *ao) { - HttpdOutput *httpd = Cast(ao); + HttpdOutput *httpd = HttpdOutput::Cast(ao); - ao_base_finish(&httpd->base); + httpd->Finish(); delete httpd; } @@ -181,7 +167,7 @@ httpd_output_finish(struct audio_output *ao) inline void HttpdOutput::AddClient(int fd) { - clients.emplace_front(this, fd, GetEventLoop(), + clients.emplace_front(*this, fd, GetEventLoop(), encoder->plugin.tag == nullptr); ++clients_cnt; @@ -191,6 +177,29 @@ HttpdOutput::AddClient(int fd) } void +HttpdOutput::RunDeferred() +{ + /* this method runs in the IOThread; it broadcasts pages from + our own queue to all clients */ + + const ScopeLock protect(mutex); + + while (!pages.empty()) { + Page *page = pages.front(); + pages.pop(); + + for (auto &client : clients) + client.PushPage(page); + + page->Unref(); + } + + /* wake up the client that may be waiting for the queue to be + flushed */ + cond.broadcast(); +} + +void HttpdOutput::OnAccept(int fd, const sockaddr &address, size_t address_length, gcc_unused int uid) { @@ -199,9 +208,10 @@ HttpdOutput::OnAccept(int fd, const sockaddr &address, #ifdef HAVE_LIBWRAP if (address.sa_family != AF_UNIX) { - char *hostaddr = sockaddr_to_string(&address, address_length, - IgnoreError()); - const char *progname = g_get_prgname(); + const auto hostaddr = sockaddr_to_string(&address, + address_length); + // TODO: shall we obtain the program name from argv[0]? + const char *progname = "mpd"; struct request_info req; request_init(&req, RQ_FILE, fd, RQ_DAEMON, progname, 0); @@ -212,13 +222,10 @@ HttpdOutput::OnAccept(int fd, const sockaddr &address, /* tcp wrappers says no */ FormatWarning(httpd_output_domain, "libwrap refused connection (libwrap=%s) from %s", - progname, hostaddr); - g_free(hostaddr); + progname, hostaddr.c_str()); close_socket(fd); return; } - - g_free(hostaddr); } #else (void)address; @@ -271,7 +278,7 @@ HttpdOutput::ReadPage() static bool httpd_output_enable(struct audio_output *ao, Error &error) { - HttpdOutput *httpd = Cast(ao); + HttpdOutput *httpd = HttpdOutput::Cast(ao); return httpd->Bind(error); } @@ -279,7 +286,7 @@ httpd_output_enable(struct audio_output *ao, Error &error) static void httpd_output_disable(struct audio_output *ao) { - HttpdOutput *httpd = Cast(ao); + HttpdOutput *httpd = HttpdOutput::Cast(ao); httpd->Unbind(); } @@ -325,9 +332,7 @@ static bool httpd_output_open(struct audio_output *ao, AudioFormat &audio_format, Error &error) { - HttpdOutput *httpd = Cast(ao); - - assert(httpd->clients.empty()); + HttpdOutput *httpd = HttpdOutput::Cast(ao); const ScopeLock protect(httpd->mutex); return httpd->Open(audio_format, error); @@ -342,7 +347,9 @@ HttpdOutput::Close() delete timer; - clients.clear(); + BlockingCall(GetEventLoop(), [this](){ + clients.clear(); + }); if (header != nullptr) header->Unref(); @@ -353,7 +360,7 @@ HttpdOutput::Close() static void httpd_output_close(struct audio_output *ao) { - HttpdOutput *httpd = Cast(ao); + HttpdOutput *httpd = HttpdOutput::Cast(ao); const ScopeLock protect(httpd->mutex); httpd->Close(); @@ -382,17 +389,15 @@ HttpdOutput::SendHeader(HttpdClient &client) const client.PushPage(header); } -static unsigned -httpd_output_delay(struct audio_output *ao) +inline unsigned +HttpdOutput::Delay() const { - HttpdOutput *httpd = Cast(ao); - - if (!httpd->LockHasClients() && httpd->base.pause) { + if (!LockHasClients() && 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 */ - httpd->timer->Reset(); + timer->Reset(); /* some arbitrary delay that is long enough to avoid consuming too much CPU, and short enough to notice @@ -400,39 +405,47 @@ httpd_output_delay(struct audio_output *ao) return 1000; } - return httpd->timer->IsStarted() - ? httpd->timer->GetDelay() + return timer->IsStarted() + ? timer->GetDelay() : 0; } +static unsigned +httpd_output_delay(struct audio_output *ao) +{ + HttpdOutput *httpd = HttpdOutput::Cast(ao); + + return httpd->Delay(); +} + void HttpdOutput::BroadcastPage(Page *page) { assert(page != nullptr); - const ScopeLock protect(mutex); - for (auto &client : clients) - client.PushPage(page); + mutex.lock(); + pages.push(page); + page->Ref(); + mutex.unlock(); + + DeferredMonitor::Schedule(); } void HttpdOutput::BroadcastFromEncoder() { + /* synchronize with the IOThread */ mutex.lock(); - for (auto &client : clients) { - if (client.GetQueueSize() > 256 * 1024) { - FormatDebug(httpd_output_domain, - "client is too slow, flushing its queue"); - client.CancelQueue(); - } - } - mutex.unlock(); + while (!pages.empty()) + cond.wait(mutex); Page *page; - while ((page = ReadPage()) != nullptr) { - BroadcastPage(page); - page->Unref(); - } + while ((page = ReadPage()) != nullptr) + pages.push(page); + + mutex.unlock(); + + DeferredMonitor::Schedule(); } inline bool @@ -447,28 +460,34 @@ HttpdOutput::EncodeAndPlay(const void *chunk, size_t size, Error &error) return true; } -static size_t -httpd_output_play(struct audio_output *ao, const void *chunk, size_t size, - Error &error) +inline size_t +HttpdOutput::Play(const void *chunk, size_t size, Error &error) { - HttpdOutput *httpd = Cast(ao); - - if (httpd->LockHasClients()) { - if (!httpd->EncodeAndPlay(chunk, size, error)) + if (LockHasClients()) { + if (!EncodeAndPlay(chunk, size, error)) return 0; } - if (!httpd->timer->IsStarted()) - httpd->timer->Start(); - httpd->timer->Add(size); + if (!timer->IsStarted()) + timer->Start(); + timer->Add(size); return size; } +static size_t +httpd_output_play(struct audio_output *ao, const void *chunk, size_t size, + Error &error) +{ + HttpdOutput *httpd = HttpdOutput::Cast(ao); + + return httpd->Play(chunk, size, error); +} + static bool httpd_output_pause(struct audio_output *ao) { - HttpdOutput *httpd = Cast(ao); + HttpdOutput *httpd = HttpdOutput::Cast(ao); if (httpd->LockHasClients()) { static const char silence[1020] = { 0 }; @@ -531,19 +550,36 @@ HttpdOutput::SendTag(const Tag *tag) static void httpd_output_tag(struct audio_output *ao, const Tag *tag) { - HttpdOutput *httpd = Cast(ao); + HttpdOutput *httpd = HttpdOutput::Cast(ao); httpd->SendTag(tag); } +inline void +HttpdOutput::CancelAllClients() +{ + const ScopeLock protect(mutex); + + while (!pages.empty()) { + Page *page = pages.front(); + pages.pop(); + page->Unref(); + } + + for (auto &client : clients) + client.CancelQueue(); + + cond.broadcast(); +} + static void httpd_output_cancel(struct audio_output *ao) { - HttpdOutput *httpd = Cast(ao); + HttpdOutput *httpd = HttpdOutput::Cast(ao); - const ScopeLock protect(httpd->mutex); - for (auto &client : httpd->clients) - client.CancelQueue(); + BlockingCall(io_thread_get(), [httpd](){ + httpd->CancelAllClients(); + }); } const struct audio_output_plugin httpd_output_plugin = { diff --git a/src/output/JackOutputPlugin.cxx b/src/output/JackOutputPlugin.cxx index 7ed672f95..ef06b5abf 100644 --- a/src/output/JackOutputPlugin.cxx +++ b/src/output/JackOutputPlugin.cxx @@ -34,10 +34,6 @@ #include <stdlib.h> #include <string.h> -#include <stdio.h> -#include <sys/types.h> -#include <unistd.h> -#include <errno.h> enum { MAX_PORTS = 16, diff --git a/src/output/NullOutputPlugin.cxx b/src/output/NullOutputPlugin.cxx index e2eec9dbc..a901b7d2a 100644 --- a/src/output/NullOutputPlugin.cxx +++ b/src/output/NullOutputPlugin.cxx @@ -22,8 +22,6 @@ #include "OutputAPI.hxx" #include "Timer.hxx" -#include <assert.h> - struct NullOutput { struct audio_output base; diff --git a/src/output/OSXOutputPlugin.cxx b/src/output/OSXOutputPlugin.cxx index 97ebae056..586210b21 100644 --- a/src/output/OSXOutputPlugin.cxx +++ b/src/output/OSXOutputPlugin.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "OSXOutputPlugin.hxx" #include "OutputAPI.hxx" -#include "util/fifo_buffer.h" +#include "util/DynamicFifoBuffer.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" #include "thread/Mutex.hxx" @@ -44,7 +44,7 @@ struct OSXOutput { Mutex mutex; Cond condition; - struct fifo_buffer *buffer; + DynamicFifoBuffer<uint8_t> *buffer; }; static constexpr Domain osx_output_domain("osx_output"); @@ -72,7 +72,7 @@ osx_output_configure(OSXOutput *oo, const config_param ¶m) } else { oo->component_subtype = kAudioUnitSubType_HALOutput; - /* XXX am I supposed to g_strdup() this? */ + /* XXX am I supposed to strdup() this? */ oo->device_name = device; } } @@ -207,22 +207,19 @@ osx_render(void *vdata, od->mutex.lock(); - size_t nbytes; - const void *src = fifo_buffer_read(od->buffer, &nbytes); + auto src = od->buffer->Read(); + if (!src.IsEmpty()) { + if (src.size > buffer_size) + src.size = buffer_size; - if (src != NULL) { - if (nbytes > buffer_size) - nbytes = buffer_size; - - memcpy(buffer->mData, src, nbytes); - fifo_buffer_consume(od->buffer, nbytes); - } else - nbytes = 0; + memcpy(buffer->mData, src.data, src.size); + od->buffer->Consume(src.size); + } od->condition.signal(); od->mutex.unlock(); - buffer->mDataByteSize = nbytes; + buffer->mDataByteSize = src.size; unsigned i; for (i = 1; i < buffer_list->mNumberBuffers; ++i) { @@ -298,7 +295,7 @@ osx_output_cancel(struct audio_output *ao) OSXOutput *od = (OSXOutput *)ao; const ScopeLock protect(od->mutex); - fifo_buffer_clear(od->buffer); + od->buffer->Clear(); } static void @@ -309,7 +306,7 @@ osx_output_close(struct audio_output *ao) AudioOutputUnitStop(od->au); AudioUnitUninitialize(od->au); - fifo_buffer_free(od->buffer); + delete od->buffer; } static bool @@ -370,8 +367,8 @@ osx_output_open(struct audio_output *ao, AudioFormat &audio_format, } /* create a buffer of 1s */ - od->buffer = fifo_buffer_new(audio_format.sample_rate * - audio_format.GetFrameSize()); + od->buffer = new DynamicFifoBuffer<uint8_t>(audio_format.sample_rate * + audio_format.GetFrameSize()); status = AudioOutputUnitStart(od->au); if (status != 0) { @@ -393,23 +390,21 @@ osx_output_play(struct audio_output *ao, const void *chunk, size_t size, const ScopeLock protect(od->mutex); - void *dest; - size_t max_length; - + DynamicFifoBuffer<uint8_t>::Range dest; while (true) { - dest = fifo_buffer_write(od->buffer, &max_length); - if (dest != NULL) + dest = od->buffer->Write(); + if (!dest.IsEmpty()) break; /* wait for some free space in the buffer */ od->condition.wait(od->mutex); } - if (size > max_length) - size = max_length; + if (size > dest.size) + size = dest.size; - memcpy(dest, chunk, size); - fifo_buffer_append(od->buffer, size); + memcpy(dest.data, chunk, size); + od->buffer->Append(size); return size; } diff --git a/src/output/PulseOutputPlugin.hxx b/src/output/PulseOutputPlugin.hxx index 0ed8404bc..69d6c5f99 100644 --- a/src/output/PulseOutputPlugin.hxx +++ b/src/output/PulseOutputPlugin.hxx @@ -41,6 +41,6 @@ pulse_output_clear_mixer(PulseOutput *po, PulseMixer *pm); bool pulse_output_set_volume(PulseOutput *po, - const struct pa_cvolume *volume, Error &error); + const pa_cvolume *volume, Error &error); #endif |