[outputs] Changes to interface of outputs module

* Drop output_sessions, was just a pointer to the actual session anyway
* Drop the old write, flush and stop prototypes
* Some minor changes/renaming

Purpose of this is also to fix a race condition in player.c where it
could try to start two sessions on the same speaker. This could happen
because outputs_device_start() in line 2093 is conditional on device->session
which however is false while a device is starting up.
This commit is contained in:
ejurgensen 2019-02-10 23:20:12 +01:00
parent cee740ae51
commit 14a6d318f0
2 changed files with 59 additions and 113 deletions

View File

@ -148,7 +148,7 @@ buffer_fill(struct output_buffer *obuf, void *buf, size_t bufsize, struct media_
int n; int n;
obuf->write_counter++; obuf->write_counter++;
obuf->pts = pts; obuf->pts = *pts;
// The resampling/encoding (transcode) contexts work for a given input quality, // The resampling/encoding (transcode) contexts work for a given input quality,
// so if the quality changes we need to reset the contexts. We also do that if // so if the quality changes we need to reset the contexts. We also do that if
@ -207,49 +207,48 @@ buffer_drain(struct output_buffer *obuf)
/* ----------------------------------- API ---------------------------------- */ /* ----------------------------------- API ---------------------------------- */
int int
outputs_device_start(struct output_device *device, output_status_cb cb, uint64_t rtptime) outputs_device_start(struct output_device *device, output_status_cb cb)
{ {
if (outputs[device->type]->disabled) if (outputs[device->type]->disabled || !outputs[device->type]->device_start)
return -1; return -1;
if (outputs[device->type]->device_start) if (device->session)
return outputs[device->type]->device_start(device, cb, rtptime); {
else DPRINTF(E_LOG, L_PLAYER, "Bug! outputs_device_start() called for a device that already has a session\n");
return -1; return -1;
}
return outputs[device->type]->device_start(device, cb);
} }
int int
outputs_device_start2(struct output_device *device, output_status_cb cb) outputs_device_stop(struct output_device *device, output_status_cb cb)
{ {
if (outputs[device->type]->disabled) if (outputs[device->type]->disabled || !outputs[device->type]->device_stop)
return -1; return -1;
if (outputs[device->type]->device_start2) if (!device->session)
return outputs[device->type]->device_start2(device, cb); {
else DPRINTF(E_LOG, L_PLAYER, "Bug! outputs_device_stop() called for a device that has no session\n");
return -1; return -1;
} }
void return outputs[device->type]->device_stop(device, cb);
outputs_device_stop(struct output_session *session)
{
if (outputs[session->type]->disabled)
return;
if (outputs[session->type]->device_stop)
outputs[session->type]->device_stop(session);
} }
int int
outputs_device_probe(struct output_device *device, output_status_cb cb) outputs_device_probe(struct output_device *device, output_status_cb cb)
{ {
if (outputs[device->type]->disabled) if (outputs[device->type]->disabled || !outputs[device->type]->device_probe)
return -1; return -1;
if (outputs[device->type]->device_probe) if (device->session)
return outputs[device->type]->device_probe(device, cb); {
else DPRINTF(E_LOG, L_PLAYER, "Bug! outputs_device_probe() called for a device that already has a session\n");
return -1; return -1;
}
return outputs[device->type]->device_probe(device, cb);
} }
void void
@ -311,6 +310,16 @@ outputs_device_quality_set(struct output_device *device, struct media_quality *q
return -1; return -1;
} }
void
outputs_device_set_cb(struct output_device *device, output_status_cb cb)
{
if (outputs[device->type]->disabled)
return;
if (outputs[device->type]->device_set_cb)
outputs[device->type]->device_set_cb(device, cb);
}
void void
outputs_playback_stop(void) outputs_playback_stop(void)
{ {
@ -327,22 +336,7 @@ outputs_playback_stop(void)
} }
void void
outputs_write(uint8_t *buf, uint64_t rtptime) outputs_write(void *buf, size_t bufsize, struct media_quality *quality, int nsamples, struct timespec *pts)
{
int i;
for (i = 0; outputs[i]; i++)
{
if (outputs[i]->disabled)
continue;
if (outputs[i]->write)
outputs[i]->write(buf, rtptime);
}
}
void
outputs_write2(void *buf, size_t bufsize, struct media_quality *quality, int nsamples, struct timespec *pts)
{ {
int i; int i;
@ -353,15 +347,15 @@ outputs_write2(void *buf, size_t bufsize, struct media_quality *quality, int nsa
if (outputs[i]->disabled) if (outputs[i]->disabled)
continue; continue;
if (outputs[i]->write2) if (outputs[i]->write)
outputs[i]->write2(&output_buffer); outputs[i]->write(&output_buffer);
} }
buffer_drain(&output_buffer); buffer_drain(&output_buffer);
} }
int int
outputs_flush(output_status_cb cb, uint64_t rtptime) outputs_flush(output_status_cb cb)
{ {
int ret; int ret;
int i; int i;
@ -373,41 +367,12 @@ outputs_flush(output_status_cb cb, uint64_t rtptime)
continue; continue;
if (outputs[i]->flush) if (outputs[i]->flush)
ret += outputs[i]->flush(cb, rtptime); ret += outputs[i]->flush(cb);
} }
return ret; return ret;
} }
int
outputs_flush2(output_status_cb cb)
{
int ret;
int i;
ret = 0;
for (i = 0; outputs[i]; i++)
{
if (outputs[i]->disabled)
continue;
if (outputs[i]->flush2)
ret += outputs[i]->flush2(cb);
}
return ret;
}
void
outputs_status_cb(struct output_session *session, output_status_cb cb)
{
if (outputs[session->type]->disabled)
return;
if (outputs[session->type]->status_cb)
outputs[session->type]->status_cb(session, cb);
}
struct output_metadata * struct output_metadata *
outputs_metadata_prepare(int id) outputs_metadata_prepare(int id)
{ {

View File

@ -140,18 +140,11 @@ struct output_device
// Opaque pointers to device and session data // Opaque pointers to device and session data
void *extra_device_info; void *extra_device_info;
struct output_session *session; void *session;
struct output_device *next; struct output_device *next;
}; };
// Except for the type, sessions are opaque outside of the output backend
struct output_session
{
enum output_types type;
void *session;
};
// Linked list of metadata prepared by each output backend // Linked list of metadata prepared by each output backend
struct output_metadata struct output_metadata
{ {
@ -172,12 +165,12 @@ struct output_frame
struct output_buffer struct output_buffer
{ {
uint32_t write_counter; // REMOVE ME? not used for anything uint32_t write_counter; // REMOVE ME? not used for anything
struct timespec *pts; struct timespec pts;
struct output_frame frames[OUTPUTS_MAX_QUALITY_SUBSCRIPTIONS + 1]; struct output_frame frames[OUTPUTS_MAX_QUALITY_SUBSCRIPTIONS + 1];
} output_buffer; } output_buffer;
typedef void (*output_status_cb)(struct output_device *device, struct output_session *session, enum output_device_state status); typedef void (*output_status_cb)(struct output_device *device, enum output_device_state status);
struct output_definition struct output_definition
{ {
@ -202,11 +195,10 @@ struct output_definition
void (*deinit)(void); void (*deinit)(void);
// Prepare a playback session on device and call back // Prepare a playback session on device and call back
int (*device_start)(struct output_device *device, output_status_cb cb, uint64_t rtptime); int (*device_start)(struct output_device *device, output_status_cb cb);
int (*device_start2)(struct output_device *device, output_status_cb cb);
// Close a session prepared by device_start // Close a session prepared by device_start and call back
void (*device_stop)(struct output_session *session); int (*device_stop)(struct output_device *device, output_status_cb cb);
// Test the connection to a device and call back // Test the connection to a device and call back
int (*device_probe)(struct output_device *device, output_status_cb cb); int (*device_probe)(struct output_device *device, output_status_cb cb);
@ -223,24 +215,22 @@ struct output_definition
// Request a change of quality from the device // Request a change of quality from the device
int (*quality_set)(struct output_device *device, struct media_quality *quality); int (*quality_set)(struct output_device *device, struct media_quality *quality);
// Change the call back associated with a device
void (*device_set_cb)(struct output_device *device, output_status_cb cb);
// Start/stop playback on devices that were started // Start/stop playback on devices that were started
void (*playback_start)(uint64_t next_pkt, struct timespec *ts); void (*playback_start)(uint64_t next_pkt, struct timespec *ts);
void (*playback_stop)(void); void (*playback_stop)(void);
// Write stream data to the output devices // Write stream data to the output devices
void (*write)(uint8_t *buf, uint64_t rtptime); void (*write)(struct output_buffer *buffer);
void (*write2)(struct output_buffer *buffer);
// Flush all sessions, the return must be number of sessions pending the flush // Flush all sessions, the return must be number of sessions pending the flush
int (*flush)(output_status_cb cb, uint64_t rtptime); int (*flush)(output_status_cb cb);
int (*flush2)(output_status_cb cb);
// Authorize an output with a pin-code (probably coming from the filescanner) // Authorize an output with a pin-code (probably coming from the filescanner)
void (*authorize)(const char *pin); void (*authorize)(const char *pin);
// Change the call back associated with a session
void (*status_cb)(struct output_session *session, output_status_cb cb);
// Metadata // Metadata
void *(*metadata_prepare)(int id); void *(*metadata_prepare)(int id);
void (*metadata_send)(void *metadata, uint64_t rtptime, uint64_t offset, int startup); void (*metadata_send)(void *metadata, uint64_t rtptime, uint64_t offset, int startup);
@ -249,13 +239,10 @@ struct output_definition
}; };
int int
outputs_device_start(struct output_device *device, output_status_cb cb, uint64_t rtptime); outputs_device_start(struct output_device *device, output_status_cb cb);
int int
outputs_device_start2(struct output_device *device, output_status_cb cb); outputs_device_stop(struct output_device *device, output_status_cb cb);
void
outputs_device_stop(struct output_session *session);
int int
outputs_device_probe(struct output_device *device, output_status_cb cb); outputs_device_probe(struct output_device *device, output_status_cb cb);
@ -273,23 +260,17 @@ outputs_device_volume_to_pct(struct output_device *device, const char *value);
int int
outputs_device_quality_set(struct output_device *device, struct media_quality *quality); outputs_device_quality_set(struct output_device *device, struct media_quality *quality);
void
outputs_device_set_cb(struct output_device *device, output_status_cb cb);
void void
outputs_playback_stop(void); outputs_playback_stop(void);
void void
outputs_write(uint8_t *buf, uint64_t rtptime); outputs_write(void *buf, size_t bufsize, struct media_quality *quality, int nsamples, struct timespec *pts);
void
outputs_write2(void *buf, size_t bufsize, struct media_quality *quality, int nsamples, struct timespec *pts);
int int
outputs_flush(output_status_cb cb, uint64_t rtptime); outputs_flush(output_status_cb cb);
int
outputs_flush2(output_status_cb cb);
void
outputs_status_cb(struct output_session *session, output_status_cb cb);
struct output_metadata * struct output_metadata *
outputs_metadata_prepare(int id); outputs_metadata_prepare(int id);