0001-output-plugins-Add-UNIX-domain-socket-output.patch (8843B)
1 From 73246507075f772c40e717a741459d31b5a3a784 Mon Sep 17 00:00:00 2001 2 From: Dimitris Papastamos <sin@2f30.org> 3 Date: Sun, 12 Jun 2016 15:06:55 +0100 4 Subject: [PATCH] output/plugins: Add UNIX domain socket output 5 6 Signed-off-by: Dimitris Papastamos <sin@2f30.org> 7 Tested-by: Lazaros Koromilas <lostd@2f30.org> 8 --- 9 Makefile.am | 6 + 10 configure.ac | 16 +++ 11 src/output/Registry.cxx | 4 + 12 src/output/plugins/UnixOutputPlugin.cxx | 188 ++++++++++++++++++++++++++++++++ 13 src/output/plugins/UnixOutputPlugin.hxx | 26 +++++ 14 5 files changed, 240 insertions(+) 15 create mode 100644 src/output/plugins/UnixOutputPlugin.cxx 16 create mode 100644 src/output/plugins/UnixOutputPlugin.hxx 17 18 diff --git a/Makefile.am b/Makefile.am 19 index 2cf8e05..bd94ae1 100644 20 --- a/Makefile.am 21 +++ b/Makefile.am 22 @@ -1409,6 +1409,12 @@ liboutput_plugins_a_SOURCES += \ 23 src/output/plugins/SndioOutputPlugin.hxx 24 endif 25 26 +if HAVE_UNIX 27 +liboutput_plugins_a_SOURCES += \ 28 + src/output/plugins/UnixOutputPlugin.cxx \ 29 + src/output/plugins/UnixOutputPlugin.hxx 30 +endif 31 + 32 if HAVE_HAIKU 33 liboutput_plugins_a_SOURCES += \ 34 src/output/plugins/HaikuOutputPlugin.cxx \ 35 diff --git a/configure.ac b/configure.ac 36 index 51ab2e0..51f99a2 100644 37 --- a/configure.ac 38 +++ b/configure.ac 39 @@ -339,6 +339,11 @@ AC_ARG_ENABLE(sndio, 40 [enable support for sndio output plugin (default: auto)]),, 41 enable_sndio=auto) 42 43 +AC_ARG_ENABLE(unix, 44 + AS_HELP_STRING([--disable-unix], 45 + [disable support for UNIX domain socket output (default: enable)]),, 46 + enable_unix=yes) 47 + 48 AC_ARG_ENABLE(haiku, 49 AS_HELP_STRING([--enable-haiku], 50 [enable the Haiku output plugin (default: auto)]),, 51 @@ -1128,6 +1133,16 @@ fi 52 53 AM_CONDITIONAL(HAVE_SNDIO, test x$enable_sndio = xyes) 54 55 +dnl ----------------------------------- UNIX ---------------------------------- 56 +if test x$enable_unix = xyes; then 57 + AC_CHECK_HEADER(sys/un.h, 58 + [enable_unix=yes], 59 + [enable_unix=no;AC_MSG_WARN([sys/un.h not found -- disabling support for UNIX domain socket output])]) 60 +fi 61 + 62 +MPD_DEFINE_CONDITIONAL(enable_unix, HAVE_UNIX, 63 + [support for UNIX domain socket output]) 64 + 65 dnl ----------------------------------- Haiku --------------------------------- 66 if test x$enable_haiku = xauto; then 67 AC_CHECK_HEADER(media/MediaDefs.h, 68 @@ -1449,6 +1464,7 @@ printf '\nPlayback support:\n\t' 69 results(alsa,ALSA) 70 results(fifo,FIFO) 71 results(sndio,[SNDIO]) 72 +results(unix,[UNIX domain socket]) 73 results(recorder_output,[File Recorder]) 74 results(haiku,[Haiku]) 75 results(httpd_output,[HTTP Daemon]) 76 diff --git a/src/output/Registry.cxx b/src/output/Registry.cxx 77 index 9d8d826..3961710 100644 78 --- a/src/output/Registry.cxx 79 +++ b/src/output/Registry.cxx 80 @@ -24,6 +24,7 @@ 81 #include "plugins/AoOutputPlugin.hxx" 82 #include "plugins/FifoOutputPlugin.hxx" 83 #include "plugins/SndioOutputPlugin.hxx" 84 +#include "plugins/UnixOutputPlugin.hxx" 85 #include "plugins/httpd/HttpdOutputPlugin.hxx" 86 #include "plugins/HaikuOutputPlugin.hxx" 87 #include "plugins/JackOutputPlugin.hxx" 88 @@ -56,6 +57,9 @@ const AudioOutputPlugin *const audio_output_plugins[] = { 89 #ifdef HAVE_SNDIO 90 &sndio_output_plugin, 91 #endif 92 +#ifdef HAVE_UNIX 93 + &unix_output_plugin, 94 +#endif 95 #ifdef HAVE_HAIKU 96 &haiku_output_plugin, 97 #endif 98 diff --git a/src/output/plugins/UnixOutputPlugin.cxx b/src/output/plugins/UnixOutputPlugin.cxx 99 new file mode 100644 100 index 0000000..2b85d64 101 --- /dev/null 102 +++ b/src/output/plugins/UnixOutputPlugin.cxx 103 @@ -0,0 +1,188 @@ 104 +/* 105 + * Copyright (C) 2016 The Music Player Daemon Project 106 + * http://www.musicpd.org 107 + * 108 + * This program is free software; you can redistribute it and/or modify 109 + * it under the terms of the GNU General Public License as published by 110 + * the Free Software Foundation; either version 2 of the License, or 111 + * (at your option) any later version. 112 + * 113 + * This program is distributed in the hope that it will be useful, 114 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 115 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 116 + * GNU General Public License for more details. 117 + * 118 + * You should have received a copy of the GNU General Public License along 119 + * with this program; if not, write to the Free Software Foundation, Inc., 120 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 121 + */ 122 + 123 +#include <sys/socket.h> 124 +#include <sys/stat.h> 125 +#include <sys/un.h> 126 + 127 +#include <errno.h> 128 +#include <string.h> 129 +#include <unistd.h> 130 + 131 +#include "config.h" 132 +#include "UnixOutputPlugin.hxx" 133 +#include "config/ConfigError.hxx" 134 +#include "../OutputAPI.hxx" 135 +#include "../Wrapper.hxx" 136 +#include "fs/AllocatedPath.hxx" 137 +#include "util/Error.hxx" 138 +#include "util/Domain.hxx" 139 +#include "Log.hxx" 140 + 141 +class UnixOutput { 142 + friend struct AudioOutputWrapper<UnixOutput>; 143 + AudioOutput base; 144 + AllocatedPath path; 145 + std::string path_utf8; 146 + int sock; 147 + 148 + bool Connect(Error &error); 149 + void Disconnect(); 150 +public: 151 + UnixOutput() 152 + :base(unix_output_plugin), 153 + path(AllocatedPath::Null()), sock(-1) {} 154 + ~UnixOutput() { 155 + Disconnect(); 156 + } 157 + 158 + bool Initialize(const ConfigBlock &block, Error &error) { 159 + return base.Configure(block, error); 160 + } 161 + 162 + static UnixOutput *Create(const ConfigBlock &block, Error &error); 163 + 164 + bool Open(AudioFormat &audio_format, Error &error); 165 + void Close(); 166 + size_t Play(const void *chunk, size_t size, Error &error); 167 +}; 168 + 169 +static constexpr Domain unix_output_domain("unix_output"); 170 + 171 +bool 172 +UnixOutput::Connect(Error &error) 173 +{ 174 + struct sockaddr_un sun; 175 + socklen_t len; 176 + int ret; 177 + 178 + sock = socket(AF_UNIX, SOCK_STREAM, 0); 179 + if (sock == -1) { 180 + error.FormatErrno("Could not create UNIX socket"); 181 + return false; 182 + } 183 + 184 + memset(&sun, 0, sizeof(sun)); 185 + sun.sun_family = AF_UNIX; 186 + snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", path_utf8.c_str()); 187 + len = sizeof(sun); 188 + ret = connect(sock, (struct sockaddr *)&sun, len); 189 + if (ret == -1) { 190 + error.FormatErrno("Could not connect to UNIX socket \"%s\"", 191 + path_utf8.c_str()); 192 + Disconnect(); 193 + return false; 194 + } 195 + 196 + return true; 197 +} 198 + 199 +void 200 +UnixOutput::Disconnect() 201 +{ 202 + if (sock >= 0) { 203 + close(sock); 204 + sock = -1; 205 + } 206 +} 207 + 208 +UnixOutput * 209 +UnixOutput::Create(const ConfigBlock &block, Error &error) 210 +{ 211 + UnixOutput *ao = new UnixOutput(); 212 + 213 + ao->path = block.GetBlockPath("path", error); 214 + if (ao->path.IsNull()) { 215 + delete ao; 216 + 217 + if (!error.IsDefined()) 218 + error.Set(config_domain, 219 + "No \"path\" parameter specified"); 220 + return nullptr; 221 + } 222 + 223 + ao->path_utf8 = ao->path.ToUTF8(); 224 + 225 + if (!ao->Initialize(block, error)) { 226 + delete ao; 227 + return nullptr; 228 + } 229 + 230 + return ao; 231 +} 232 + 233 +bool 234 +UnixOutput::Open(gcc_unused AudioFormat &audio_format, 235 + gcc_unused Error &error) 236 +{ 237 + if (sock == -1 && !Connect(error)) 238 + return false; 239 + audio_format.sample_rate = 44100; 240 + audio_format.format = SampleFormat::S16; 241 + audio_format.channels = 2; 242 + return true; 243 +} 244 + 245 +void 246 +UnixOutput::Close() 247 +{ 248 + Disconnect(); 249 +} 250 + 251 +size_t 252 +UnixOutput::Play(const void *chunk, size_t size, Error &error) 253 +{ 254 + ssize_t bytes; 255 + 256 + while (true) { 257 + bytes = write(sock, chunk, size); 258 + if (bytes > 0) 259 + return (size_t)bytes; 260 + if (bytes < 0) { 261 + switch (errno) { 262 + case EAGAIN: 263 + case EINTR: 264 + continue; 265 + } 266 + error.FormatErrno("Failed to write to UNIX socket%s", 267 + path_utf8.c_str()); 268 + return 0; 269 + } 270 + } 271 +} 272 + 273 +typedef AudioOutputWrapper<UnixOutput> Wrapper; 274 + 275 +const struct AudioOutputPlugin unix_output_plugin = { 276 + "unix", 277 + nullptr, 278 + &Wrapper::Init, 279 + &Wrapper::Finish, 280 + nullptr, 281 + nullptr, 282 + &Wrapper::Open, 283 + &Wrapper::Close, 284 + nullptr, 285 + nullptr, 286 + &Wrapper::Play, 287 + nullptr, 288 + nullptr, 289 + nullptr, 290 + nullptr, 291 +}; 292 diff --git a/src/output/plugins/UnixOutputPlugin.hxx b/src/output/plugins/UnixOutputPlugin.hxx 293 new file mode 100644 294 index 0000000..3fda10b 295 --- /dev/null 296 +++ b/src/output/plugins/UnixOutputPlugin.hxx 297 @@ -0,0 +1,26 @@ 298 +/* 299 + * Copyright (C) 2016 The Music Player Daemon Project 300 + * http://www.musicpd.org 301 + * 302 + * This program is free software; you can redistribute it and/or modify 303 + * it under the terms of the GNU General Public License as published by 304 + * the Free Software Foundation; either version 2 of the License, or 305 + * (at your option) any later version. 306 + * 307 + * This program is distributed in the hope that it will be useful, 308 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 309 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 310 + * GNU General Public License for more details. 311 + * 312 + * You should have received a copy of the GNU General Public License along 313 + * with this program; if not, write to the Free Software Foundation, Inc., 314 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 315 + */ 316 + 317 +#ifndef MPD_UNIX_OUTPUT_PLUGIN_HXX 318 +#define MPD_UNIX_OUTPUT_PLUGIN_HXX 319 + 320 +extern const struct AudioOutputPlugin unix_output_plugin; 321 + 322 +#endif 323 + 324 -- 325 2.9.0 326