[outputs] Make a wrapper for mp3 streaming so it can be included in

the generic outputs interface and so special handling in player.c can
be removed
This commit is contained in:
ejurgensen 2016-03-22 22:59:50 +01:00
parent a07c24d625
commit 36755031cb
8 changed files with 80 additions and 65 deletions

View File

@ -110,7 +110,7 @@ forked_daapd_SOURCES = main.c \
outputs.h outputs.c \
laudio_dummy.c \
laudio.c laudio.h \
outputs/raop.c \
outputs/raop.c outputs/streaming.c \
evrtsp/rtsp.c evrtp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h \
$(SPOTIFY_SRC) \
$(LASTFM_SRC) \

View File

@ -52,7 +52,7 @@ extern struct event_base *evbase_httpd;
// Should prevent that we keep transcoding to dead connections
#define STREAMING_CONNECTION_TIMEOUT 60
// Linked list of Icecast requests
// Linked list of mp3 streaming requests
struct streaming_session {
struct evhttp_request *req;
struct streaming_session *next;
@ -108,7 +108,6 @@ streaming_fail_cb(struct evhttp_connection *evcon, void *arg)
{
DPRINTF(E_INFO, L_STREAMING, "No more clients, will stop streaming\n");
event_del(streamingev);
player_streaming_stop();
}
}
@ -122,16 +121,16 @@ streaming_send_cb(evutil_socket_t fd, short event, void *arg)
int len;
int ret;
if (!streaming_sessions)
return;
// Callback from player (EV_READ)
// Player wrote data to the pipe (EV_READ)
if (event & EV_READ)
{
ret = read(streaming_pipe[0], &streaming_rawbuf, STREAMING_RAWBUF_SIZE);
if (ret < 0)
return;
if (!streaming_sessions)
return;
decoded = transcode_raw2frame(streaming_rawbuf, STREAMING_RAWBUF_SIZE);
if (!decoded)
{
@ -153,6 +152,9 @@ streaming_send_cb(evutil_socket_t fd, short event, void *arg)
player_get_status(&streaming_player_status);
}
if (!streaming_sessions)
return;
if (streaming_player_status.status != PLAY_PAUSED)
return;
@ -177,22 +179,6 @@ streaming_send_cb(evutil_socket_t fd, short event, void *arg)
evbuffer_free(evbuf);
}
// Thread: player
static int
streaming_cb(uint8_t *rawbuf, size_t size)
{
if (size != STREAMING_RAWBUF_SIZE)
{
DPRINTF(E_LOG, L_STREAMING, "Bug! Buffer size in streaming_cb does not equal input from player\n");
return -1;
}
if (write(streaming_pipe[1], rawbuf, size) < 0)
return -1;
return 0;
}
// Thread: player (not fully thread safe, but hey...)
static void
player_change_cb(enum listener_event_type type)
@ -200,6 +186,20 @@ player_change_cb(enum listener_event_type type)
streaming_player_changed = 1;
}
// Thread: player (also prone to race conditions, mostly during deinit)
void
streaming_write(uint8_t *buf, uint64_t rtptime)
{
int ret;
if (!streaming_sessions)
return;
ret = write(streaming_pipe[1], buf, STREAMING_RAWBUF_SIZE);
if (ret < 0)
DPRINTF(E_LOG, L_STREAMING, "Error writing to streaming pipe\n");
}
int
streaming_is_request(struct evhttp_request *req, char *uri)
{
@ -269,8 +269,6 @@ streaming_request(struct evhttp_request *req)
evhttp_connection_set_timeout(evcon, STREAMING_CONNECTION_TIMEOUT);
evhttp_connection_set_closecb(evcon, streaming_fail_cb, session);
player_streaming_start(streaming_cb);
return 0;
}
@ -403,18 +401,20 @@ streaming_deinit(void)
if (!streaming_initialized)
return;
player_streaming_stop();
event_free(streamingev);
session = streaming_sessions;
streaming_sessions = NULL; // Stops writing and sending
next = NULL;
for (session = streaming_sessions; session; session = next)
while (session)
{
evhttp_send_reply_end(session->req);
next = session->next;
free(session);
session = next;
}
event_free(streamingev);
listener_remove(player_change_cb);
close(streaming_pipe[0]);

View File

@ -10,6 +10,9 @@
* if a suitable ffmpeg/libav encoder is not present at runtime.
*/
void
streaming_write(uint8_t *buf, uint64_t rtptime);
int
streaming_is_request(struct evhttp_request *req, char *uri);

View File

@ -35,8 +35,8 @@ extern struct output_definition output_raop;
#ifdef CHROMECAST
extern struct output_definition output_cast;
#endif
/* TODO
extern struct output_definition output_streaming;
/* TODO
#ifdef ALSA
extern struct output_definition output_alsa;
#endif
@ -52,8 +52,8 @@ static struct output_definition *outputs[] = {
#ifdef CHROMECAST
&output_cast,
#endif
/* TODO
&output_streaming,
/* TODO
#ifdef ALSA
&output_alsa,
#endif
@ -338,6 +338,9 @@ outputs_init(void)
return -1;
}
if (!outputs[i]->init)
continue;
ret = outputs[i]->init();
if (ret < 0)
outputs[i]->disabled = 1;
@ -358,7 +361,10 @@ outputs_deinit(void)
for (i = 0; outputs[i]; i++)
{
if (!outputs[i]->disabled)
if (outputs[i]->disabled)
continue;
if (outputs[i]->deinit)
outputs[i]->deinit();
}
}

View File

@ -23,8 +23,8 @@ enum output_types
#ifdef CHROMECAST
OUTPUT_TYPE_CAST,
#endif
/* TODO
OUTPUT_TYPE_STREAMING,
/* TODO
OUTPUT_TYPE_ALSA,
OUTPUT_TYPE_OSS,
OUTPUT_TYPE_DUMMY,

35
src/outputs/streaming.c Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2016 Espen Jürgensen <espenjurgensen@gmail.com>
*
* 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include "outputs.h"
#include "httpd_streaming.h"
struct output_definition output_streaming =
{
.name = "mp3 streaming",
.type = OUTPUT_TYPE_STREAMING,
.priority = 0,
.disabled = 0,
.write = streaming_write,
};

View File

@ -291,9 +291,6 @@ static int laudio_selected;
static int laudio_volume;
static int laudio_relvol;
static int output_sessions;
static int streaming_selected;
static player_streaming_cb streaming_write;
/* Commands */
static struct player_command *cur_cmd;
@ -1606,14 +1603,10 @@ playback_write(void)
return;
}
if (streaming_selected)
streaming_write(rawbuf, sizeof(rawbuf));
if (laudio_status & LAUDIO_F_STARTED)
laudio_write(rawbuf, last_rtptime);
if (output_sessions > 0)
outputs_write(rawbuf, last_rtptime);
outputs_write(rawbuf, last_rtptime);
}
static void
@ -2170,8 +2163,7 @@ playback_abort(void)
if (laudio_status != LAUDIO_CLOSED)
laudio_close();
if (output_sessions > 0)
outputs_playback_stop();
outputs_playback_stop();
pb_timer_stop();
@ -2423,8 +2415,7 @@ playback_start_bh(struct player_command *cmd)
goto out_fail;
/* Everything OK, start outputs */
if (output_sessions > 0)
outputs_playback_start(last_rtptime + AIRTUNES_V2_PACKET_SAMPLES, &pb_pos_stamp);
outputs_playback_start(last_rtptime + AIRTUNES_V2_PACKET_SAMPLES, &pb_pos_stamp);
status_update(PLAY_PLAYING);
@ -4014,19 +4005,6 @@ player_playback_prev(void)
return ret;
}
void
player_streaming_start(player_streaming_cb cb)
{
streaming_write = cb;
streaming_selected = 1;
}
void
player_streaming_stop(void)
{
streaming_selected = 0;
}
void
player_speaker_enumerate(spk_enum_cb cb, void *arg)

View File

@ -70,7 +70,6 @@ struct player_status {
};
typedef void (*spk_enum_cb)(uint64_t id, const char *name, int relvol, struct spk_flags flags, void *arg);
typedef int (*player_streaming_cb)(uint8_t *rawbuf, size_t size);
struct player_history
{
@ -131,12 +130,6 @@ player_playback_next(void);
int
player_playback_prev(void);
void
player_streaming_start(player_streaming_cb cb);
void
player_streaming_stop(void);
int
player_volume_set(int vol);