From 6062ca014b9c8109550952180223202445cbac18 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Mon, 31 Mar 2014 13:10:18 +0200 Subject: [PATCH] Make the player able to stream from pipes --- src/Makefile.am | 1 + src/pipe.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ src/pipe.h | 17 +++++++ src/player.c | 44 +++++++++++++---- src/player.h | 3 +- 5 files changed, 180 insertions(+), 11 deletions(-) create mode 100644 src/pipe.c create mode 100644 src/pipe.h diff --git a/src/Makefile.am b/src/Makefile.am index fa1f7ad2..a8af5493 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -94,6 +94,7 @@ forked_daapd_SOURCES = main.c \ httpd_dacp.c httpd_dacp.h \ dmap_common.c dmap_common.h \ transcode.c transcode.h \ + pipe.c pipe.h \ artwork.c artwork.h \ misc.c misc.h \ rng.c rng.h \ diff --git a/src/pipe.c b/src/pipe.c new file mode 100644 index 00000000..e3c605e9 --- /dev/null +++ b/src/pipe.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2014 Espen Jürgensen + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pipe.h" +#include "logger.h" + +#define PIPE_BUFFER_SIZE 8192 + +static int g_fd = -1; +static void *g_buf = NULL; + +int +pipe_setup(struct media_file_info *mfi) +{ + struct stat sb; + + if (!mfi->path) + { + DPRINTF(E_LOG, L_PLAYER, "Path to pipe is NULL\n"); + return -1; + } + + DPRINTF(E_DBG, L_PLAYER, "Setting up pipe: %s\n", mfi->path); + + if (lstat(mfi->path, &sb) < 0) + { + DPRINTF(E_LOG, L_PLAYER, "Could not lstat() '%s': %s\n", mfi->path, strerror(errno)); + return -1; + } + + if (!S_ISFIFO(sb.st_mode)) + { + DPRINTF(E_LOG, L_PLAYER, "Source type is pipe, but path is not a fifo: %s\n", mfi->path); + return -1; + } + + g_fd = open(mfi->path, O_RDONLY); + if (g_fd < 0) + { + DPRINTF(E_LOG, L_PLAYER, "Could not open pipe for reading '%s': %s\n", mfi->path, strerror(errno)); + return -1; + } + + g_buf = (void *)malloc(PIPE_BUFFER_SIZE); + if (!g_buf) + { + DPRINTF(E_LOG, L_PLAYER, "Out of memory for buffer\n"); + return -1; + } + + return 1; +} + +void +pipe_cleanup(void) +{ + if (g_fd >= 0) + close(g_fd); + g_fd = -1; + + if (g_buf) + free(g_buf); + g_buf = NULL; + + return; +} + +int +pipe_audio_get(struct evbuffer *evbuf, int wanted) +{ + int got; + + if (wanted > PIPE_BUFFER_SIZE) + wanted = PIPE_BUFFER_SIZE; + + got = read(g_fd, g_buf, wanted); + + if (got < 0) + { + DPRINTF(E_LOG, L_PLAYER, "Could not read from pipe: %s\n", strerror(errno)); + return -1; + } + + // If the other end of the pipe is not writing we just return silence + if (got == 0) + { + memset(g_buf, 0, wanted); + got = wanted; + } + + evbuffer_add(evbuf, g_buf, got); + + return got; +} + diff --git a/src/pipe.h b/src/pipe.h new file mode 100644 index 00000000..ba57a814 --- /dev/null +++ b/src/pipe.h @@ -0,0 +1,17 @@ + +#ifndef __PIPE_H__ +#define __PIPE_H__ + +#include "db.h" +#include + +int +pipe_setup(struct media_file_info *mfi); + +void +pipe_cleanup(void); + +int +pipe_audio_get(struct evbuffer *evbuf, int wanted); + +#endif /* !__PIPE_H__ */ diff --git a/src/player.c b/src/player.c index b4264d62..f4df9526 100644 --- a/src/player.c +++ b/src/player.c @@ -54,11 +54,13 @@ #include "conffile.h" #include "misc.h" #include "rng.h" -#include "transcode.h" #include "player.h" #include "raop.h" #include "laudio.h" +/* These handle getting the media data */ +#include "transcode.h" +#include "pipe.h" #ifdef HAVE_SPOTIFY_H # include "spotify.h" #endif @@ -921,6 +923,10 @@ source_free(struct player_source *ps) spotify_playback_stop(); #endif break; + + case SOURCE_PIPE: + pipe_cleanup(); + break; } free(ps); @@ -948,6 +954,10 @@ source_stop(struct player_source *ps) spotify_playback_stop(); #endif break; + + case SOURCE_PIPE: + pipe_cleanup(); + break; } tmp = ps; @@ -1064,19 +1074,26 @@ source_open(struct player_source *ps, int no_md) DPRINTF(E_INFO, L_PLAYER, "Opening '%s' (%s)\n", mfi->title, mfi->path); - if (strncmp(mfi->path, "spotify:", strlen("spotify:")) == 0) + // Setup the source type responsible for getting the audio + switch (mfi->data_kind) { - ps->type = SOURCE_SPOTIFY; + case 2: + ps->type = SOURCE_SPOTIFY; #ifdef HAVE_SPOTIFY_H - ret = spotify_playback_play(mfi); + ret = spotify_playback_play(mfi); #else - ret = -1; + ret = -1; #endif - } - else - { - ps->type = SOURCE_FFMPEG; - ret = transcode_setup(&ps->ctx, mfi, NULL, 0); + break; + + case 3: + ps->type = SOURCE_PIPE; + ret = pipe_setup(mfi); + break; + + default: + ps->type = SOURCE_FFMPEG; + ret = transcode_setup(&ps->ctx, mfi, NULL, 0); } free_mfi(mfi, 0); @@ -1455,6 +1472,10 @@ source_read(uint8_t *buf, int len, uint64_t rtptime) break; #endif + case SOURCE_PIPE: + ret = pipe_audio_get(audio_buf, len - nbytes); + break; + default: ret = -1; } @@ -2652,6 +2673,9 @@ playback_seek_bh(struct player_command *cmd) ret = spotify_playback_seek(ms); break; #endif + case SOURCE_PIPE: + ret = 1; + break; default: ret = -1; } diff --git a/src/player.h b/src/player.h index 879b6901..0c62e674 100644 --- a/src/player.h +++ b/src/player.h @@ -35,7 +35,8 @@ enum repeat_mode { enum source_type { SOURCE_FFMPEG = 0, - SOURCE_SPOTIFY = 1, + SOURCE_SPOTIFY, + SOURCE_PIPE, }; struct spk_flags {