aboutsummaryrefslogtreecommitdiffstats
path: root/src/output
diff options
context:
space:
mode:
Diffstat (limited to 'src/output')
-rw-r--r--src/output/AlsaOutputPlugin.cxx11
-rw-r--r--src/output/FifoOutputPlugin.cxx3
-rw-r--r--src/output/HttpdClient.cxx71
-rw-r--r--src/output/HttpdClient.hxx25
-rw-r--r--src/output/HttpdInternal.hxx68
-rw-r--r--src/output/HttpdOutputPlugin.cxx218
-rw-r--r--src/output/JackOutputPlugin.cxx4
-rw-r--r--src/output/NullOutputPlugin.cxx2
-rw-r--r--src/output/OSXOutputPlugin.cxx49
-rw-r--r--src/output/PulseOutputPlugin.hxx2
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 &param, Error &error);
+
+ void Finish() {
+ ao_base_finish(&base);
+ }
+
bool Configure(const config_param &param, Error &error);
+ audio_output *InitAndConfigure(const config_param &param,
+ 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 &param, Error &error)
return true;
}
+inline bool
+HttpdOutput::Init(const config_param &param, Error &error)
+{
+ return ao_base_init(&base, &httpd_output_plugin, param, error);
+}
+
static struct audio_output *
httpd_output_init(const config_param &param, 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 &param)
}
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