1 /* the Music Player Daemon (MPD)
2 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3 * This project's homepage is: http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "../audioOutput.h"
35 #include <sys/types.h>
37 #define FIFO_BUFFER_SIZE 65536 /* pipe capacity on Linux >= 2.6.11 */
39 typedef struct _FifoData
{
47 static FifoData
*newFifoData()
51 ret
= xmalloc(sizeof(FifoData
));
62 static void freeFifoData(FifoData
*fd
)
68 timer_free(fd
->timer
);
73 static void removeFifo(FifoData
*fd
)
75 DEBUG("Removing FIFO \"%s\"\n", fd
->path
);
77 if (unlink(fd
->path
) < 0) {
78 ERROR("Could not remove FIFO \"%s\": %s\n",
79 fd
->path
, strerror(errno
));
86 static void closeFifo(FifoData
*fd
)
95 if (fd
->output
>= 0) {
100 if (fd
->created
&& (stat(fd
->path
, &st
) == 0))
104 static int makeFifo(FifoData
*fd
)
106 if (mkfifo(fd
->path
, 0666) < 0) {
107 ERROR("Couldn't create FIFO \"%s\": %s\n",
108 fd
->path
, strerror(errno
));
117 static int checkFifo(FifoData
*fd
)
121 if (stat(fd
->path
, &st
) < 0) {
122 if (errno
== ENOENT
) {
123 /* Path doesn't exist */
127 ERROR("Failed to stat FIFO \"%s\": %s\n",
128 fd
->path
, strerror(errno
));
132 if (!S_ISFIFO(st
.st_mode
)) {
133 ERROR("\"%s\" already exists, but is not a FIFO\n", fd
->path
);
140 static int openFifo(FifoData
*fd
)
142 if (checkFifo(fd
) < 0)
145 fd
->input
= open(fd
->path
, O_RDONLY
|O_NONBLOCK
);
147 ERROR("Could not open FIFO \"%s\" for reading: %s\n",
148 fd
->path
, strerror(errno
));
153 fd
->output
= open(fd
->path
, O_WRONLY
|O_NONBLOCK
);
154 if (fd
->output
< 0) {
155 ERROR("Could not open FIFO \"%s\" for writing: %s\n",
156 fd
->path
, strerror(errno
));
164 static int fifo_initDriver(AudioOutput
*audioOutput
, ConfigParam
*param
)
167 BlockParam
*blockParam
;
170 blockParam
= getBlockParam(param
, "path");
172 FATAL("No \"path\" parameter specified for fifo output "
173 "defined at line %i\n", param
->line
);
176 path
= parsePath(blockParam
->value
);
178 FATAL("Could not parse \"path\" parameter for fifo output "
179 "at line %i\n", blockParam
->line
);
184 audioOutput
->data
= fd
;
186 if (openFifo(fd
) < 0) {
194 static void fifo_finishDriver(AudioOutput
*audioOutput
)
196 FifoData
*fd
= (FifoData
*)audioOutput
->data
;
202 static int fifo_openDevice(AudioOutput
*audioOutput
)
204 FifoData
*fd
= (FifoData
*)audioOutput
->data
;
207 timer_free(fd
->timer
);
209 fd
->timer
= timer_new(&audioOutput
->outAudioFormat
);
211 audioOutput
->open
= 1;
216 static void fifo_closeDevice(AudioOutput
*audioOutput
)
218 FifoData
*fd
= (FifoData
*)audioOutput
->data
;
221 timer_free(fd
->timer
);
225 audioOutput
->open
= 0;
228 static void fifo_dropBufferedAudio(AudioOutput
*audioOutput
)
230 FifoData
*fd
= (FifoData
*)audioOutput
->data
;
231 char buf
[FIFO_BUFFER_SIZE
];
234 timer_reset(fd
->timer
);
236 while (bytes
> 0 && errno
!= EINTR
)
237 bytes
= read(fd
->input
, buf
, FIFO_BUFFER_SIZE
);
239 if (bytes
< 0 && errno
!= EAGAIN
) {
240 WARNING("Flush of FIFO \"%s\" failed: %s\n",
241 fd
->path
, strerror(errno
));
245 static int fifo_playAudio(AudioOutput
*audioOutput
, char *playChunk
, int size
)
247 FifoData
*fd
= (FifoData
*)audioOutput
->data
;
251 if (!fd
->timer
->started
)
252 timer_start(fd
->timer
);
254 timer_sync(fd
->timer
);
256 timer_add(fd
->timer
, size
);
259 bytes
= write(fd
->output
, playChunk
+ offset
, size
);
263 /* The pipe is full, so empty it */
264 fifo_dropBufferedAudio(audioOutput
);
270 ERROR("Closing FIFO output \"%s\" due to write error: "
271 "%s\n", fd
->path
, strerror(errno
));
272 fifo_closeDevice(audioOutput
);
283 AudioOutputPlugin fifoPlugin
= {
285 NULL
, /* testDefaultDeviceFunc */
290 fifo_dropBufferedAudio
,
292 NULL
, /* sendMetadataFunc */
295 #else /* HAVE_FIFO */
297 DISABLED_AUDIO_OUTPUT_PLUGIN(fifoPlugin
)
299 #endif /* !HAVE_FIFO */