mirror of
https://github.com/owntone/owntone-server.git
synced 2025-11-08 21:24:57 -05:00
[player/outputs] Implement changed output interfaces in most backends
Still missing cast, alsa and pulseaudio, but these can so far just be disabled with configure. Otherwise still mostly untested.
This commit is contained in:
@@ -105,9 +105,7 @@ struct alsa_session
|
||||
struct event *deferredev;
|
||||
output_status_cb defer_cb;
|
||||
|
||||
/* Do not dereference - only passed to the status cb */
|
||||
struct output_device *device;
|
||||
struct output_session *output_session;
|
||||
output_status_cb status_cb;
|
||||
|
||||
struct alsa_session *next;
|
||||
@@ -147,7 +145,6 @@ alsa_session_free(struct alsa_session *as)
|
||||
|
||||
prebuf_free(as);
|
||||
|
||||
free(as->output_session);
|
||||
free(as);
|
||||
}
|
||||
|
||||
@@ -169,6 +166,8 @@ alsa_session_cleanup(struct alsa_session *as)
|
||||
s->next = as->next;
|
||||
}
|
||||
|
||||
as->device->session = NULL;
|
||||
|
||||
alsa_session_free(as);
|
||||
}
|
||||
|
||||
@@ -177,21 +176,7 @@ alsa_session_make(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct alsa_session *as;
|
||||
|
||||
as = calloc(1, sizeof(struct alsa_session));
|
||||
if (!as)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LAUDIO, "Out of memory for ALSA session (as)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
as->output_session = calloc(1, sizeof(struct output_session));
|
||||
if (!as->output_session)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LAUDIO, "Out of memory for ALSA session (output_session)\n");
|
||||
goto failure_cleanup;
|
||||
}
|
||||
as->output_session->session = as;
|
||||
as->output_session->type = device->type;
|
||||
CHECK_NULL(L_LAUDIO, as = calloc(1, sizeof(struct alsa_session)));
|
||||
|
||||
as->deferredev = evtimer_new(evbase_player, defer_cb, as);
|
||||
if (!as->deferredev)
|
||||
@@ -210,6 +195,9 @@ alsa_session_make(struct output_device *device, output_status_cb cb)
|
||||
|
||||
as->next = sessions;
|
||||
sessions = as;
|
||||
|
||||
device->session = as;
|
||||
|
||||
return as;
|
||||
|
||||
failure_cleanup:
|
||||
|
||||
@@ -177,9 +177,7 @@ struct cast_session
|
||||
char *session_id;
|
||||
int media_session_id;
|
||||
|
||||
/* Do not dereference - only passed to the status cb */
|
||||
struct output_device *device;
|
||||
struct output_session *output_session;
|
||||
output_status_cb status_cb;
|
||||
|
||||
struct cast_session *next;
|
||||
@@ -1327,7 +1325,6 @@ cast_device_cb(const char *name, const char *type, const char *domain, const cha
|
||||
static struct cast_session *
|
||||
cast_session_make(struct output_device *device, int family, output_status_cb cb)
|
||||
{
|
||||
struct output_session *os;
|
||||
struct cast_session *cs;
|
||||
const char *proto;
|
||||
const char *err;
|
||||
@@ -1359,25 +1356,8 @@ cast_session_make(struct output_device *device, int family, output_status_cb cb)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os = calloc(1, sizeof(struct output_session));
|
||||
if (!os)
|
||||
{
|
||||
DPRINTF(E_LOG, L_CAST, "Out of memory (os)\n");
|
||||
return NULL;
|
||||
}
|
||||
CHECK_NULL(L_CAST, cs = calloc(1, sizeof(struct cast_session)));
|
||||
|
||||
cs = calloc(1, sizeof(struct cast_session));
|
||||
if (!cs)
|
||||
{
|
||||
DPRINTF(E_LOG, L_CAST, "Out of memory (cs)\n");
|
||||
free(os);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os->session = cs;
|
||||
os->type = device->type;
|
||||
|
||||
cs->output_session = os;
|
||||
cs->state = CAST_STATE_DISCONNECTED;
|
||||
cs->device = device;
|
||||
cs->status_cb = cb;
|
||||
@@ -1440,6 +1420,8 @@ cast_session_make(struct output_device *device, int family, output_status_cb cb)
|
||||
cs->next = sessions;
|
||||
sessions = cs;
|
||||
|
||||
device->session = cs;
|
||||
|
||||
proto = gnutls_protocol_get_name(gnutls_protocol_get_version(cs->tls_session));
|
||||
|
||||
DPRINTF(E_INFO, L_CAST, "Connection to '%s' established using %s\n", cs->devname, proto);
|
||||
|
||||
@@ -47,9 +47,7 @@ struct dummy_session
|
||||
struct event *deferredev;
|
||||
output_status_cb defer_cb;
|
||||
|
||||
/* Do not dereference - only passed to the status cb */
|
||||
struct output_device *device;
|
||||
struct output_session *output_session;
|
||||
output_status_cb status_cb;
|
||||
};
|
||||
|
||||
@@ -72,7 +70,6 @@ dummy_session_free(struct dummy_session *ds)
|
||||
|
||||
event_free(ds->deferredev);
|
||||
|
||||
free(ds->output_session);
|
||||
free(ds);
|
||||
}
|
||||
|
||||
@@ -82,27 +79,20 @@ dummy_session_cleanup(struct dummy_session *ds)
|
||||
// Normally some here code to remove from linked list - here we just say:
|
||||
sessions = NULL;
|
||||
|
||||
ds->device->session = NULL;
|
||||
|
||||
dummy_session_free(ds);
|
||||
}
|
||||
|
||||
static struct dummy_session *
|
||||
dummy_session_make(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct output_session *os;
|
||||
struct dummy_session *ds;
|
||||
|
||||
os = calloc(1, sizeof(struct output_session));
|
||||
if (!os)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LAUDIO, "Out of memory for dummy session (os)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ds = calloc(1, sizeof(struct dummy_session));
|
||||
if (!ds)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LAUDIO, "Out of memory for dummy session (as)\n");
|
||||
free(os);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -110,21 +100,18 @@ dummy_session_make(struct output_device *device, output_status_cb cb)
|
||||
if (!ds->deferredev)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LAUDIO, "Out of memory for dummy deferred event\n");
|
||||
free(os);
|
||||
free(ds);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os->session = ds;
|
||||
os->type = device->type;
|
||||
|
||||
ds->output_session = os;
|
||||
ds->state = OUTPUT_STATE_CONNECTED;
|
||||
ds->device = device;
|
||||
ds->status_cb = cb;
|
||||
|
||||
sessions = ds;
|
||||
|
||||
device->session = ds;
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
@@ -139,7 +126,7 @@ defer_cb(int fd, short what, void *arg)
|
||||
struct dummy_session *ds = arg;
|
||||
|
||||
if (ds->defer_cb)
|
||||
ds->defer_cb(ds->device, ds->output_session, ds->state);
|
||||
ds->defer_cb(ds->device, ds->state);
|
||||
|
||||
if (ds->state == OUTPUT_STATE_STOPPED)
|
||||
dummy_session_cleanup(ds);
|
||||
@@ -157,7 +144,7 @@ dummy_status(struct dummy_session *ds)
|
||||
/* ------------------ INTERFACE FUNCTIONS CALLED BY OUTPUTS.C --------------- */
|
||||
|
||||
static int
|
||||
dummy_device_start(struct output_device *device, output_status_cb cb, uint64_t rtptime)
|
||||
dummy_device_start(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct dummy_session *ds;
|
||||
|
||||
@@ -170,13 +157,15 @@ dummy_device_start(struct output_device *device, output_status_cb cb, uint64_t r
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_device_stop(struct output_session *session)
|
||||
static int
|
||||
dummy_device_stop(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct dummy_session *ds = session->session;
|
||||
struct dummy_session *ds = device->session;
|
||||
|
||||
ds->state = OUTPUT_STATE_STOPPED;
|
||||
dummy_status(ds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -199,13 +188,11 @@ dummy_device_probe(struct output_device *device, output_status_cb cb)
|
||||
static int
|
||||
dummy_device_volume_set(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct dummy_session *ds;
|
||||
struct dummy_session *ds = device->session;
|
||||
|
||||
if (!device->session || !device->session->session)
|
||||
if (!ds)
|
||||
return 0;
|
||||
|
||||
ds = device->session->session;
|
||||
|
||||
ds->status_cb = cb;
|
||||
dummy_status(ds);
|
||||
|
||||
@@ -213,15 +200,11 @@ dummy_device_volume_set(struct output_device *device, output_status_cb cb)
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_playback_start(uint64_t next_pkt, struct timespec *ts)
|
||||
dummy_device_set_cb(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct dummy_session *ds = sessions;
|
||||
struct dummy_session *ds = device->session;
|
||||
|
||||
if (!sessions)
|
||||
return;
|
||||
|
||||
ds->state = OUTPUT_STATE_STREAMING;
|
||||
dummy_status(ds);
|
||||
ds->status_cb = cb;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -236,14 +219,6 @@ dummy_playback_stop(void)
|
||||
dummy_status(ds);
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_set_status_cb(struct output_session *session, output_status_cb cb)
|
||||
{
|
||||
struct dummy_session *ds = session->session;
|
||||
|
||||
ds->status_cb = cb;
|
||||
}
|
||||
|
||||
static int
|
||||
dummy_init(void)
|
||||
{
|
||||
@@ -298,7 +273,6 @@ struct output_definition output_dummy =
|
||||
.device_stop = dummy_device_stop,
|
||||
.device_probe = dummy_device_probe,
|
||||
.device_volume_set = dummy_device_volume_set,
|
||||
.playback_start = dummy_playback_start,
|
||||
.device_set_cb = dummy_device_set_cb,
|
||||
.playback_stop = dummy_playback_stop,
|
||||
.status_cb = dummy_set_status_cb,
|
||||
};
|
||||
|
||||
@@ -45,10 +45,11 @@
|
||||
struct fifo_packet
|
||||
{
|
||||
/* pcm data */
|
||||
uint8_t samples[FIFO_PACKET_SIZE];
|
||||
uint8_t *samples;
|
||||
size_t samples_size;
|
||||
|
||||
/* RTP-time of the first sample*/
|
||||
uint64_t rtptime;
|
||||
/* Presentation timestamp of the first sample */
|
||||
struct timespec pts;
|
||||
|
||||
struct fifo_packet *next;
|
||||
struct fifo_packet *prev;
|
||||
@@ -59,8 +60,11 @@ struct fifo_buffer
|
||||
struct fifo_packet *head;
|
||||
struct fifo_packet *tail;
|
||||
};
|
||||
|
||||
static struct fifo_buffer buffer;
|
||||
|
||||
static struct media_quality fifo_quality = { 44100, 16, 2 };
|
||||
|
||||
|
||||
static void
|
||||
free_buffer()
|
||||
@@ -94,9 +98,7 @@ struct fifo_session
|
||||
struct event *deferredev;
|
||||
output_status_cb defer_cb;
|
||||
|
||||
/* Do not dereference - only passed to the status cb */
|
||||
struct output_device *device;
|
||||
struct output_session *output_session;
|
||||
output_status_cb status_cb;
|
||||
};
|
||||
|
||||
@@ -242,7 +244,6 @@ fifo_session_free(struct fifo_session *fifo_session)
|
||||
|
||||
event_free(fifo_session->deferredev);
|
||||
|
||||
free(fifo_session->output_session);
|
||||
free(fifo_session);
|
||||
free_buffer();
|
||||
}
|
||||
@@ -253,43 +254,26 @@ fifo_session_cleanup(struct fifo_session *fifo_session)
|
||||
// Normally some here code to remove from linked list - here we just say:
|
||||
sessions = NULL;
|
||||
|
||||
fifo_session->device->session = NULL;
|
||||
|
||||
fifo_session_free(fifo_session);
|
||||
}
|
||||
|
||||
static struct fifo_session *
|
||||
fifo_session_make(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct output_session *output_session;
|
||||
struct fifo_session *fifo_session;
|
||||
|
||||
output_session = calloc(1, sizeof(struct output_session));
|
||||
if (!output_session)
|
||||
{
|
||||
DPRINTF(E_LOG, L_FIFO, "Out of memory (os)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fifo_session = calloc(1, sizeof(struct fifo_session));
|
||||
if (!fifo_session)
|
||||
{
|
||||
DPRINTF(E_LOG, L_FIFO, "Out of memory (fs)\n");
|
||||
free(output_session);
|
||||
return NULL;
|
||||
}
|
||||
CHECK_NULL(L_FIFO, fifo_session = calloc(1, sizeof(struct fifo_session)));
|
||||
|
||||
fifo_session->deferredev = evtimer_new(evbase_player, defer_cb, fifo_session);
|
||||
if (!fifo_session->deferredev)
|
||||
{
|
||||
DPRINTF(E_LOG, L_FIFO, "Out of memory for fifo deferred event\n");
|
||||
free(output_session);
|
||||
free(fifo_session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output_session->session = fifo_session;
|
||||
output_session->type = device->type;
|
||||
|
||||
fifo_session->output_session = output_session;
|
||||
fifo_session->state = OUTPUT_STATE_CONNECTED;
|
||||
fifo_session->device = device;
|
||||
fifo_session->status_cb = cb;
|
||||
@@ -301,6 +285,8 @@ fifo_session_make(struct output_device *device, output_status_cb cb)
|
||||
|
||||
sessions = fifo_session;
|
||||
|
||||
device->session = fifo_session;
|
||||
|
||||
return fifo_session;
|
||||
}
|
||||
|
||||
@@ -315,7 +301,7 @@ defer_cb(int fd, short what, void *arg)
|
||||
struct fifo_session *ds = arg;
|
||||
|
||||
if (ds->defer_cb)
|
||||
ds->defer_cb(ds->device, ds->output_session, ds->state);
|
||||
ds->defer_cb(ds->device, ds->state);
|
||||
|
||||
if (ds->state == OUTPUT_STATE_STOPPED)
|
||||
fifo_session_cleanup(ds);
|
||||
@@ -333,11 +319,15 @@ fifo_status(struct fifo_session *fifo_session)
|
||||
/* ------------------ INTERFACE FUNCTIONS CALLED BY OUTPUTS.C --------------- */
|
||||
|
||||
static int
|
||||
fifo_device_start(struct output_device *device, output_status_cb cb, uint64_t rtptime)
|
||||
fifo_device_start(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct fifo_session *fifo_session;
|
||||
int ret;
|
||||
|
||||
ret = outputs_quality_subscribe(&fifo_quality);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
fifo_session = fifo_session_make(device, cb);
|
||||
if (!fifo_session)
|
||||
return -1;
|
||||
@@ -351,16 +341,22 @@ fifo_device_start(struct output_device *device, output_status_cb cb, uint64_t rt
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
fifo_device_stop(struct output_session *output_session)
|
||||
static int
|
||||
fifo_device_stop(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct fifo_session *fifo_session = output_session->session;
|
||||
struct fifo_session *fifo_session = device->session;
|
||||
|
||||
outputs_quality_unsubscribe(&fifo_quality);
|
||||
|
||||
fifo_session->status_cb = cb;
|
||||
|
||||
fifo_close(fifo_session);
|
||||
free_buffer();
|
||||
|
||||
fifo_session->state = OUTPUT_STATE_STOPPED;
|
||||
fifo_status(fifo_session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -393,13 +389,11 @@ fifo_device_probe(struct output_device *device, output_status_cb cb)
|
||||
static int
|
||||
fifo_device_volume_set(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct fifo_session *fifo_session;
|
||||
struct fifo_session *fifo_session = device->session;
|
||||
|
||||
if (!device->session || !device->session->session)
|
||||
if (!fifo_session)
|
||||
return 0;
|
||||
|
||||
fifo_session = device->session->session;
|
||||
|
||||
fifo_session->status_cb = cb;
|
||||
fifo_status(fifo_session);
|
||||
|
||||
@@ -407,15 +401,11 @@ fifo_device_volume_set(struct output_device *device, output_status_cb cb)
|
||||
}
|
||||
|
||||
static void
|
||||
fifo_playback_start(uint64_t next_pkt, struct timespec *ts)
|
||||
fifo_device_set_cb(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct fifo_session *fifo_session = sessions;
|
||||
struct fifo_session *fifo_session = device->session;
|
||||
|
||||
if (!fifo_session)
|
||||
return;
|
||||
|
||||
fifo_session->state = OUTPUT_STATE_STREAMING;
|
||||
fifo_status(fifo_session);
|
||||
fifo_session->status_cb = cb;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -433,7 +423,7 @@ fifo_playback_stop(void)
|
||||
}
|
||||
|
||||
static int
|
||||
fifo_flush(output_status_cb cb, uint64_t rtptime)
|
||||
fifo_flush(output_status_cb cb)
|
||||
{
|
||||
struct fifo_session *fifo_session = sessions;
|
||||
|
||||
@@ -450,45 +440,59 @@ fifo_flush(output_status_cb cb, uint64_t rtptime)
|
||||
}
|
||||
|
||||
static void
|
||||
fifo_write(uint8_t *buf, uint64_t rtptime)
|
||||
fifo_write(struct output_buffer *obuf)
|
||||
{
|
||||
struct fifo_session *fifo_session = sessions;
|
||||
size_t length = FIFO_PACKET_SIZE;
|
||||
ssize_t bytes;
|
||||
struct fifo_packet *packet;
|
||||
uint64_t cur_pos;
|
||||
struct timespec now;
|
||||
int ret;
|
||||
ssize_t bytes;
|
||||
int i;
|
||||
|
||||
if (!fifo_session || !fifo_session->device->selected)
|
||||
return;
|
||||
|
||||
packet = (struct fifo_packet *) calloc(1, sizeof(struct fifo_packet));
|
||||
memcpy(packet->samples, buf, sizeof(packet->samples));
|
||||
packet->rtptime = rtptime;
|
||||
for (i = 0; obuf->frames[i].buffer; i++)
|
||||
{
|
||||
if (quality_is_equal(&fifo_quality, &obuf->frames[i].quality))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!obuf->frames[i].buffer)
|
||||
{
|
||||
DPRINTF(E_LOG, L_FIFO, "Bug! Did not get audio in quality required\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fifo_session->state = OUTPUT_STATE_STREAMING;
|
||||
|
||||
CHECK_NULL(L_FIFO, packet = calloc(1, sizeof(struct fifo_packet)));
|
||||
CHECK_NULL(L_FIFO, packet->samples = malloc(obuf->frames[i].bufsize));
|
||||
|
||||
memcpy(packet->samples, obuf->frames[i].buffer, obuf->frames[i].bufsize);
|
||||
packet->samples_size = obuf->frames[i].bufsize;
|
||||
packet->pts = obuf->pts;
|
||||
|
||||
if (buffer.head)
|
||||
{
|
||||
buffer.head->next = packet;
|
||||
packet->prev = buffer.head;
|
||||
}
|
||||
|
||||
buffer.head = packet;
|
||||
if (!buffer.tail)
|
||||
buffer.tail = packet;
|
||||
|
||||
ret = player_get_current_pos(&cur_pos, &now, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_FIFO, "Could not get playback position\n");
|
||||
return;
|
||||
}
|
||||
now.tv_sec = obuf->pts.tv_sec - OUTPUTS_BUFFER_DURATION;
|
||||
now.tv_nsec = obuf->pts.tv_sec;
|
||||
|
||||
while (buffer.tail && buffer.tail->rtptime <= cur_pos)
|
||||
while (buffer.tail && (timespec_cmp(buffer.tail->pts, now) == -1))
|
||||
{
|
||||
bytes = write(fifo_session->output_fd, buffer.tail->samples, length);
|
||||
bytes = write(fifo_session->output_fd, buffer.tail->samples, buffer.tail->samples_size);
|
||||
if (bytes > 0)
|
||||
{
|
||||
packet = buffer.tail;
|
||||
buffer.tail = buffer.tail->next;
|
||||
free(packet->samples);
|
||||
free(packet);
|
||||
return;
|
||||
}
|
||||
@@ -511,14 +515,6 @@ fifo_write(uint8_t *buf, uint64_t rtptime)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fifo_set_status_cb(struct output_session *session, output_status_cb cb)
|
||||
{
|
||||
struct fifo_session *fifo_session = session->session;
|
||||
|
||||
fifo_session->status_cb = cb;
|
||||
}
|
||||
|
||||
static int
|
||||
fifo_init(void)
|
||||
{
|
||||
@@ -578,9 +574,8 @@ struct output_definition output_fifo =
|
||||
.device_stop = fifo_device_stop,
|
||||
.device_probe = fifo_device_probe,
|
||||
.device_volume_set = fifo_device_volume_set,
|
||||
.playback_start = fifo_playback_start,
|
||||
.device_set_cb = fifo_device_set_cb,
|
||||
.playback_stop = fifo_playback_stop,
|
||||
.write = fifo_write,
|
||||
.flush = fifo_flush,
|
||||
.status_cb = fifo_set_status_cb,
|
||||
};
|
||||
|
||||
@@ -70,9 +70,7 @@ struct pulse_session
|
||||
|
||||
char *devname;
|
||||
|
||||
/* Do not dereference - only passed to the status cb */
|
||||
struct output_device *device;
|
||||
struct output_session *output_session;
|
||||
output_status_cb status_cb;
|
||||
|
||||
struct pulse_session *next;
|
||||
@@ -141,34 +139,18 @@ pulse_session_cleanup(struct pulse_session *ps)
|
||||
p->next = ps->next;
|
||||
}
|
||||
|
||||
ps->device->session = NULL;
|
||||
|
||||
pulse_session_free(ps);
|
||||
}
|
||||
|
||||
static struct pulse_session *
|
||||
pulse_session_make(struct output_device *device, output_status_cb cb)
|
||||
{
|
||||
struct output_session *os;
|
||||
struct pulse_session *ps;
|
||||
|
||||
os = calloc(1, sizeof(struct output_session));
|
||||
if (!os)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LAUDIO, "Out of memory (os)\n");
|
||||
return NULL;
|
||||
}
|
||||
CHECK_NULL(L_LAUDIO, ps = calloc(1, sizeof(struct pulse_session)));
|
||||
|
||||
ps = calloc(1, sizeof(struct pulse_session));
|
||||
if (!ps)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LAUDIO, "Out of memory (ps)\n");
|
||||
free(os);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os->session = ps;
|
||||
os->type = device->type;
|
||||
|
||||
ps->output_session = os;
|
||||
ps->state = PA_STREAM_UNCONNECTED;
|
||||
ps->device = device;
|
||||
ps->status_cb = cb;
|
||||
@@ -178,6 +160,8 @@ pulse_session_make(struct output_device *device, output_status_cb cb)
|
||||
ps->next = sessions;
|
||||
sessions = ps;
|
||||
|
||||
device->session = ps;
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,14 +80,6 @@
|
||||
#include "raop_verification.h"
|
||||
#endif
|
||||
|
||||
// AirTunes v2 packet interval in ns */
|
||||
// (352 samples/packet * 1e9 ns/s) / 44100 samples/s = 7981859 ns/packet
|
||||
// #define AIRTUNES_V2_STREAM_PERIOD 7981859
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a, b) ((a < b) ? a : b)
|
||||
#endif
|
||||
|
||||
#define ALAC_HEADER_LEN 3
|
||||
|
||||
#define RAOP_QUALITY_SAMPLE_RATE_DEFAULT 44100
|
||||
@@ -220,9 +212,7 @@ struct raop_session
|
||||
int volume;
|
||||
uint64_t start_rtptime;
|
||||
|
||||
/* Do not dereference - only passed to the status cb */
|
||||
struct output_device *device;
|
||||
struct output_session *output_session;
|
||||
output_status_cb status_cb;
|
||||
|
||||
/* AirTunes v2 */
|
||||
@@ -320,6 +310,14 @@ static const char *raop_devtype[] =
|
||||
"Other",
|
||||
};
|
||||
|
||||
/* Struct with default quality levels */
|
||||
static struct media_quality raop_quality_default =
|
||||
{
|
||||
RAOP_QUALITY_SAMPLE_RATE_DEFAULT,
|
||||
RAOP_QUALITY_BITS_PER_SAMPLE_DEFAULT,
|
||||
RAOP_QUALITY_CHANNELS_DEFAULT
|
||||
};
|
||||
|
||||
/* From player.c */
|
||||
extern struct event_base *evbase_player;
|
||||
|
||||
@@ -355,16 +353,10 @@ static struct timeval keep_alive_tv = { 30, 0 };
|
||||
static struct raop_master_session *raop_master_sessions;
|
||||
static struct raop_session *raop_sessions;
|
||||
|
||||
/* Struct with default quality levels */
|
||||
static struct media_quality raop_quality_default = { RAOP_QUALITY_SAMPLE_RATE_DEFAULT, RAOP_QUALITY_BITS_PER_SAMPLE_DEFAULT, RAOP_QUALITY_CHANNELS_DEFAULT };
|
||||
|
||||
// Forwards
|
||||
static int
|
||||
raop_device_start(struct output_device *rd, output_status_cb cb);
|
||||
|
||||
static void
|
||||
raop_device_stop(struct output_session *session);
|
||||
|
||||
|
||||
/* ------------------------------- MISC HELPERS ----------------------------- */
|
||||
|
||||
@@ -1763,7 +1755,7 @@ raop_status(struct raop_session *rs)
|
||||
|
||||
rs->status_cb = NULL;
|
||||
if (status_cb)
|
||||
status_cb(rs->device, rs->output_session, state);
|
||||
status_cb(rs->device, state);
|
||||
|
||||
if (rs->state == RAOP_STATE_UNVERIFIED)
|
||||
player_speaker_status_trigger();
|
||||
@@ -1882,8 +1874,6 @@ session_free(struct raop_session *rs)
|
||||
if (rs->devname)
|
||||
free(rs->devname);
|
||||
|
||||
free(rs->output_session);
|
||||
|
||||
free(rs);
|
||||
}
|
||||
|
||||
@@ -1905,6 +1895,8 @@ session_cleanup(struct raop_session *rs)
|
||||
s->next = rs->next;
|
||||
}
|
||||
|
||||
rs->device->session = NULL;
|
||||
|
||||
session_free(rs);
|
||||
}
|
||||
|
||||
@@ -1920,14 +1912,6 @@ session_failure(struct raop_session *rs)
|
||||
session_cleanup(rs);
|
||||
}
|
||||
|
||||
static void
|
||||
session_failure_cb(struct evrtsp_request *req, void *arg)
|
||||
{
|
||||
struct raop_session *rs = arg;
|
||||
|
||||
session_failure(rs);
|
||||
}
|
||||
|
||||
static void
|
||||
deferredev_cb(int fd, short what, void *arg)
|
||||
{
|
||||
@@ -1939,23 +1923,67 @@ deferredev_cb(int fd, short what, void *arg)
|
||||
}
|
||||
|
||||
static void
|
||||
raop_rtsp_close_cb(struct evrtsp_connection *evcon, void *arg)
|
||||
deferred_session_failure(struct raop_session *rs)
|
||||
{
|
||||
struct raop_session *rs = arg;
|
||||
struct timeval tv;
|
||||
|
||||
DPRINTF(E_LOG, L_RAOP, "Device '%s' closed RTSP connection\n", rs->devname);
|
||||
|
||||
rs->state = RAOP_STATE_FAILED;
|
||||
|
||||
evutil_timerclear(&tv);
|
||||
evtimer_add(rs->deferredev, &tv);
|
||||
}
|
||||
|
||||
static void
|
||||
raop_rtsp_close_cb(struct evrtsp_connection *evcon, void *arg)
|
||||
{
|
||||
struct raop_session *rs = arg;
|
||||
|
||||
DPRINTF(E_LOG, L_RAOP, "Device '%s' closed RTSP connection\n", rs->devname);
|
||||
|
||||
deferred_session_failure(rs);
|
||||
}
|
||||
|
||||
static void
|
||||
session_teardown_cb(struct evrtsp_request *req, void *arg)
|
||||
{
|
||||
struct raop_session *rs = arg;
|
||||
struct output_device *rd = rs->device;
|
||||
output_status_cb status_cb = rs->status_cb;
|
||||
|
||||
rs->reqs_in_flight--;
|
||||
|
||||
if (!req || req->response_code != RTSP_OK)
|
||||
DPRINTF(E_LOG, L_RAOP, "TEARDOWN request failed in session shutdown: %d %s\n", req->response_code, req->response_code_line);
|
||||
|
||||
// Clean up session before giving status to the user (good to get rid of it if he
|
||||
// calls back into us - e.g. tries to make a new session in the callback)
|
||||
session_cleanup(rs);
|
||||
|
||||
// Can't use raop_status() here, sadly
|
||||
if (status_cb)
|
||||
status_cb(rd, OUTPUT_STATE_STOPPED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
session_teardown(struct raop_session *rs, const char *log_caller)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = raop_send_req_teardown(rs, session_teardown_cb, log_caller);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "%s: TEARDOWN request failed!\n", log_caller);
|
||||
deferred_session_failure(rs);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct raop_session *
|
||||
session_make(struct output_device *rd, int family, output_status_cb cb, bool only_probe)
|
||||
{
|
||||
struct output_session *os;
|
||||
struct raop_session *rs;
|
||||
struct raop_extra *re;
|
||||
char *address;
|
||||
@@ -1988,25 +2016,8 @@ session_make(struct output_device *rd, int family, output_status_cb cb, bool onl
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os = calloc(1, sizeof(struct output_session));
|
||||
if (!os)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "Out of memory (os)\n");
|
||||
return NULL;
|
||||
}
|
||||
CHECK_NULL(L_PLAYER, rs = calloc(1, sizeof(struct raop_session)));
|
||||
|
||||
rs = calloc(1, sizeof(struct raop_session));
|
||||
if (!rs)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "Out of memory (rs)\n");
|
||||
free(os);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os->session = rs;
|
||||
os->type = rd->type;
|
||||
|
||||
rs->output_session = os;
|
||||
rs->state = RAOP_STATE_STOPPED;
|
||||
rs->only_probe = only_probe;
|
||||
rs->reqs_in_flight = 0;
|
||||
@@ -2135,9 +2146,13 @@ session_make(struct output_device *rd, int family, output_status_cb cb, bool onl
|
||||
goto out_free_evcon;
|
||||
}
|
||||
|
||||
// Attach to list of sessions
|
||||
rs->next = raop_sessions;
|
||||
raop_sessions = rs;
|
||||
|
||||
// rs is now the official device session
|
||||
rd->session = rs;
|
||||
|
||||
return rs;
|
||||
|
||||
out_free_evcon:
|
||||
@@ -2717,15 +2732,10 @@ raop_cb_set_volume(struct evrtsp_request *req, void *arg)
|
||||
static int
|
||||
raop_set_volume_one(struct output_device *rd, output_status_cb cb)
|
||||
{
|
||||
struct raop_session *rs;
|
||||
struct raop_session *rs = rd->session;
|
||||
int ret;
|
||||
|
||||
if (!rd->session || !rd->session->session)
|
||||
return 0;
|
||||
|
||||
rs = rd->session->session;
|
||||
|
||||
if (!(rs->state & RAOP_STATE_F_CONNECTED))
|
||||
if (!rs || !(rs->state & RAOP_STATE_F_CONNECTED))
|
||||
return 0;
|
||||
|
||||
ret = raop_set_volume_internal(rs, rd->volume, raop_cb_set_volume);
|
||||
@@ -2813,12 +2823,7 @@ raop_flush_timer_cb(int fd, short what, void *arg)
|
||||
DPRINTF(E_DBG, L_RAOP, "Flush timer expired; tearing down RAOP sessions\n");
|
||||
|
||||
for (rs = raop_sessions; rs; rs = rs->next)
|
||||
{
|
||||
if (!(rs->state & RAOP_STATE_F_CONNECTED))
|
||||
continue;
|
||||
|
||||
raop_device_stop(rs->output_session);
|
||||
}
|
||||
session_teardown(rs, "raop_flush_timer_cb");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2882,7 +2887,6 @@ packet_prepare(struct rtp_packet *pkt, uint8_t *rawbuf, size_t rawbuf_size, bool
|
||||
static int
|
||||
packet_send(struct raop_session *rs, struct rtp_packet *pkt)
|
||||
{
|
||||
struct timeval tv;
|
||||
int ret;
|
||||
|
||||
if (!rs)
|
||||
@@ -2893,12 +2897,9 @@ packet_send(struct raop_session *rs, struct rtp_packet *pkt)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "Send error for '%s': %s\n", rs->devname, strerror(errno));
|
||||
|
||||
rs->state = RAOP_STATE_FAILED;
|
||||
|
||||
// Can't free it right away, it would make the ->next in the calling
|
||||
// master_session and session loops invalid
|
||||
evutil_timerclear(&tv);
|
||||
evtimer_add(rs->deferredev, &tv);
|
||||
deferred_session_failure(rs);
|
||||
return -1;
|
||||
}
|
||||
else if (ret != pkt->data_len)
|
||||
@@ -2943,8 +2944,6 @@ control_packet_send(struct raop_session *rs, struct rtp_packet *pkt)
|
||||
ret = sendto(rs->control_svc->fd, pkt->data, pkt->data_len, 0, &rs->sa.sa, len);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_RAOP, "Could not send playback sync to device '%s': %s\n", rs->devname, strerror(errno));
|
||||
|
||||
DPRINTF(E_DBG, L_PLAYER, "SYNC PACKET SENT\n");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2990,7 +2989,6 @@ packets_send(struct raop_master_session *rms)
|
||||
{
|
||||
pkt->header[1] = 0xe0;
|
||||
packet_send(rs, pkt);
|
||||
rs->state = RAOP_STATE_STREAMING;
|
||||
}
|
||||
else if (rs->state == RAOP_STATE_STREAMING)
|
||||
{
|
||||
@@ -3006,7 +3004,7 @@ packets_send(struct raop_master_session *rms)
|
||||
}
|
||||
|
||||
static void
|
||||
packets_sync_send(struct raop_master_session *rms, struct timespec *pts)
|
||||
packets_sync_send(struct raop_master_session *rms, struct timespec pts)
|
||||
{
|
||||
struct rtp_packet *sync_pkt;
|
||||
struct raop_session *rs;
|
||||
@@ -3022,9 +3020,9 @@ packets_sync_send(struct raop_master_session *rms, struct timespec *pts)
|
||||
// OUTPUTS_BUFFER_DURATION secs into the future. However, in the sync packet
|
||||
// we want to tell the device what it should be playing right now. So we give
|
||||
// it a cur_time where we subtract this duration.
|
||||
// TODO do we need this? could we just send the future timestamp?
|
||||
cur_stamp.ts.tv_sec = pts->tv_sec - OUTPUTS_BUFFER_DURATION;
|
||||
cur_stamp.ts.tv_nsec = pts->tv_nsec;
|
||||
cur_stamp.ts.tv_sec = pts.tv_sec - OUTPUTS_BUFFER_DURATION;
|
||||
cur_stamp.ts.tv_nsec = pts.tv_nsec;
|
||||
|
||||
// The cur_pos will be the rtptime of the coming packet, minus
|
||||
// OUTPUTS_BUFFER_DURATION in samples (output_buffer_samples). Because we
|
||||
// might also have some data lined up in rms->evbuf, we also need to account
|
||||
@@ -3041,6 +3039,8 @@ packets_sync_send(struct raop_master_session *rms, struct timespec *pts)
|
||||
{
|
||||
sync_pkt = rtp_sync_packet_next(rms->rtp_session, &cur_stamp, 0x90);
|
||||
control_packet_send(rs, sync_pkt);
|
||||
|
||||
DPRINTF(E_DBG, L_PLAYER, "Start sync packet sent to '%s': cur_pos=%" PRIu32 ", rtptime=%" PRIu32 "\n", rs->devname, cur_stamp.pos, rms->rtp_session->pos);
|
||||
}
|
||||
else if (is_sync_time && rs->state == RAOP_STATE_STREAMING)
|
||||
{
|
||||
@@ -3553,9 +3553,32 @@ raop_v2_control_start(int v6enabled)
|
||||
|
||||
/* ------------------------------ Session startup --------------------------- */
|
||||
|
||||
static void
|
||||
raop_cb_startup_retry(struct evrtsp_request *req, void *arg)
|
||||
{
|
||||
struct raop_session *rs = arg;
|
||||
struct output_device *rd = rs->device;
|
||||
output_status_cb cb = rs->status_cb;
|
||||
|
||||
session_cleanup(rs);
|
||||
raop_device_start(rd, cb);
|
||||
}
|
||||
|
||||
static void
|
||||
raop_cb_startup_cancel(struct evrtsp_request *req, void *arg)
|
||||
{
|
||||
struct raop_session *rs = arg;
|
||||
|
||||
session_failure(rs);
|
||||
}
|
||||
|
||||
static void
|
||||
raop_startup_cancel(struct raop_session *rs)
|
||||
{
|
||||
struct output_device *rd = rs->device;
|
||||
output_status_cb cb;
|
||||
int ret;
|
||||
|
||||
if (!rs->session)
|
||||
{
|
||||
session_failure(rs);
|
||||
@@ -3567,20 +3590,24 @@ raop_startup_cancel(struct raop_session *rs)
|
||||
if (rs->family == AF_INET6 && !(rs->state & RAOP_STATE_F_FAILED))
|
||||
{
|
||||
// This flag is permanent and will not be overwritten by mdns advertisements
|
||||
rs->device->v6_disabled = 1;
|
||||
rd->v6_disabled = 1;
|
||||
|
||||
// Be nice to our peer + session_failure_cb() cleans up old session
|
||||
raop_send_req_teardown(rs, session_failure_cb, "startup_cancel");
|
||||
// Stop current session and wait for call back
|
||||
ret = raop_send_req_teardown(rs, raop_cb_startup_retry, "startup_cancel");
|
||||
if (ret < 0)
|
||||
{
|
||||
// No connection at all, lets clean up and try again
|
||||
cb = rs->status_cb;
|
||||
session_cleanup(rs);
|
||||
raop_device_start(rd, cb);
|
||||
}
|
||||
|
||||
// Try to start a new session
|
||||
raop_device_start(rs->device, rs->status_cb);
|
||||
|
||||
// Don't let the failed session make a negative status callback
|
||||
rs->status_cb = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
raop_send_req_teardown(rs, session_failure_cb, "startup_cancel");
|
||||
ret = raop_send_req_teardown(rs, raop_cb_startup_cancel, "startup_cancel");
|
||||
if (ret < 0)
|
||||
session_failure(rs);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -4069,41 +4096,6 @@ raop_cb_startup_options(struct evrtsp_request *req, void *arg)
|
||||
raop_startup_cancel(rs);
|
||||
}
|
||||
|
||||
static void
|
||||
raop_cb_shutdown_teardown(struct evrtsp_request *req, void *arg)
|
||||
{
|
||||
struct raop_session *rs = arg;
|
||||
int ret;
|
||||
|
||||
rs->reqs_in_flight--;
|
||||
|
||||
if (!req)
|
||||
goto error;
|
||||
|
||||
if (req->response_code != RTSP_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "TEARDOWN request failed in session shutdown: %d %s\n", req->response_code, req->response_code_line);
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = raop_check_cseq(rs, req);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
rs->state = RAOP_STATE_STOPPED;
|
||||
|
||||
/* Session shut down, tell our user */
|
||||
raop_status(rs);
|
||||
|
||||
session_cleanup(rs);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
session_failure(rs);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- tvOS device verification ----------------------- */
|
||||
/* e.g. for the ATV4 (read it from the bottom and up) */
|
||||
@@ -4801,51 +4793,51 @@ raop_device_probe(struct output_device *rd, output_status_cb cb)
|
||||
static int
|
||||
raop_device_start(struct output_device *rd, output_status_cb cb)
|
||||
{
|
||||
event_del(flush_timer);
|
||||
evtimer_add(keep_alive_timer, &keep_alive_tv);
|
||||
|
||||
return raop_device_start_generic(rd, cb, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
raop_device_stop(struct output_session *session)
|
||||
static int
|
||||
raop_device_stop(struct output_device *rd, output_status_cb cb)
|
||||
{
|
||||
struct raop_session *rs = session->session;
|
||||
struct raop_session *rs = rd->session;
|
||||
|
||||
if (rs->state & RAOP_STATE_F_CONNECTED)
|
||||
raop_send_req_teardown(rs, raop_cb_shutdown_teardown, "device_stop");
|
||||
else
|
||||
session_cleanup(rs);
|
||||
rs->status_cb = cb;
|
||||
|
||||
return session_teardown(rs, "device_stop");
|
||||
}
|
||||
|
||||
static void
|
||||
raop_device_free_extra(struct output_device *device)
|
||||
raop_device_free_extra(struct output_device *rd)
|
||||
{
|
||||
struct raop_extra *re = device->extra_device_info;
|
||||
struct raop_extra *re = rd->extra_device_info;
|
||||
|
||||
free(re);
|
||||
}
|
||||
|
||||
static void
|
||||
raop_device_set_cb(struct output_device *rd, output_status_cb cb)
|
||||
{
|
||||
struct raop_session *rs = rd->session;
|
||||
|
||||
rs->status_cb = cb;
|
||||
}
|
||||
|
||||
static void
|
||||
raop_playback_stop(void)
|
||||
{
|
||||
struct raop_session *rs;
|
||||
int ret;
|
||||
|
||||
evtimer_del(keep_alive_timer);
|
||||
|
||||
for (rs = raop_sessions; rs; rs = rs->next)
|
||||
{
|
||||
ret = raop_send_req_teardown(rs, raop_cb_shutdown_teardown, "playback_stop");
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_RAOP, "playback_stop: TEARDOWN request failed!\n");
|
||||
}
|
||||
session_teardown(rs, "playback_stop");
|
||||
}
|
||||
|
||||
static void
|
||||
raop_write(struct output_buffer *obuf)
|
||||
{
|
||||
struct raop_master_session *rms;
|
||||
struct raop_session *rs;
|
||||
int i;
|
||||
|
||||
for (rms = raop_master_sessions; rms; rms = rms->next)
|
||||
@@ -4871,6 +4863,19 @@ raop_write(struct output_buffer *obuf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for devices that have joined since last write (we have already sent them
|
||||
// initialization sync and rtp packets via packets_sync_send and packets_send)
|
||||
for (rs = raop_sessions; rs; rs = rs->next)
|
||||
{
|
||||
if (rs->state != RAOP_STATE_CONNECTED)
|
||||
continue;
|
||||
|
||||
event_del(flush_timer); // In case playback was stopped but then restarted again
|
||||
|
||||
rs->state = RAOP_STATE_STREAMING;
|
||||
// Make a cb?
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -4894,7 +4899,6 @@ raop_flush(output_status_cb cb)
|
||||
if (ret < 0)
|
||||
{
|
||||
session_failure(rs);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4912,14 +4916,6 @@ raop_flush(output_status_cb cb)
|
||||
return pending;
|
||||
}
|
||||
|
||||
static void
|
||||
raop_set_status_cb(struct output_session *session, output_status_cb cb)
|
||||
{
|
||||
struct raop_session *rs = session->session;
|
||||
|
||||
rs->status_cb = cb;
|
||||
}
|
||||
|
||||
static int
|
||||
raop_init(void)
|
||||
{
|
||||
@@ -5035,7 +5031,6 @@ raop_init(void)
|
||||
goto out_stop_control;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
out_stop_control:
|
||||
@@ -5087,16 +5082,16 @@ struct output_definition output_raop =
|
||||
.disabled = 0,
|
||||
.init = raop_init,
|
||||
.deinit = raop_deinit,
|
||||
.device_start2 = raop_device_start,
|
||||
.device_start = raop_device_start,
|
||||
.device_stop = raop_device_stop,
|
||||
.device_probe = raop_device_probe,
|
||||
.device_free_extra = raop_device_free_extra,
|
||||
.device_volume_set = raop_set_volume_one,
|
||||
.device_volume_to_pct = raop_volume_to_pct,
|
||||
.device_set_cb = raop_device_set_cb,
|
||||
.playback_stop = raop_playback_stop,
|
||||
.write2 = raop_write,
|
||||
.flush2 = raop_flush,
|
||||
.status_cb = raop_set_status_cb,
|
||||
.write = raop_write,
|
||||
.flush = raop_flush,
|
||||
.metadata_prepare = raop_metadata_prepare,
|
||||
.metadata_send = raop_metadata_send,
|
||||
.metadata_purge = raop_metadata_purge,
|
||||
|
||||
@@ -252,14 +252,14 @@ rtp_sync_packet_next(struct rtp_session *session, struct rtcp_timestamp *cur_sta
|
||||
rtptime = htobe32(session->pos);
|
||||
memcpy(session->sync_packet_next.data + 16, &rtptime, 4);
|
||||
|
||||
DPRINTF(E_DBG, L_PLAYER, "SYNC PACKET cur_ts:%ld.%ld, next_pkt:%u, cur_pos:%u, type:0x%x, sync_counter:%d\n",
|
||||
/* DPRINTF(E_DBG, L_PLAYER, "SYNC PACKET cur_ts:%ld.%ld, next_pkt:%u, cur_pos:%u, type:0x%x, sync_counter:%d\n",
|
||||
cur_stamp->ts.tv_sec, cur_stamp->ts.tv_nsec,
|
||||
session->pos,
|
||||
cur_stamp->pos,
|
||||
session->sync_packet_next.data[0],
|
||||
session->sync_counter
|
||||
);
|
||||
|
||||
*/
|
||||
return &session->sync_packet_next;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "outputs.h"
|
||||
#include "httpd_streaming.h"
|
||||
|
||||
|
||||
struct output_definition output_streaming =
|
||||
{
|
||||
.name = "mp3 streaming",
|
||||
|
||||
Reference in New Issue
Block a user