2016-01-23 19:14:07 -05:00
|
|
|
|
|
|
|
#ifndef __OUTPUTS_H__
|
|
|
|
#define __OUTPUTS_H__
|
|
|
|
|
2016-05-05 12:49:27 -04:00
|
|
|
#include <time.h>
|
|
|
|
|
2016-01-23 19:14:07 -05:00
|
|
|
/* Outputs is a generic interface between the player and a media output method,
|
|
|
|
* like for instance AirPlay (raop) or ALSA. The purpose of the interface is to
|
|
|
|
* make it easier to add new outputs without messing too much with the player or
|
|
|
|
* existing output methods.
|
|
|
|
*
|
|
|
|
* An output method will have a general type, and it will be able to detect
|
|
|
|
* supported devices that are available for output. A device will be typically
|
|
|
|
* be something like an AirPlay speaker.
|
|
|
|
*
|
|
|
|
* When a device is started the output backend will typically create a session.
|
|
|
|
* This session is only passed around as an opaque object in this interface.
|
|
|
|
*
|
2016-04-04 10:58:07 -04:00
|
|
|
* Here is the sequence of commands from the player to the outputs, and the
|
|
|
|
* callback from the output once the command has been executed. Commands marked
|
|
|
|
* with * may make multiple callbacks if multiple sessions are affected.
|
|
|
|
* (TODO should callbacks always be deferred?)
|
|
|
|
*
|
|
|
|
* PLAYER OUTPUT PLAYER CB
|
|
|
|
* speaker_activate -> device_start -> device_activate_cb
|
|
|
|
* -> (if playback) -> playback_start -> device_streaming_cb* (or no cb)
|
|
|
|
* -> (else if playback not active) -> device_streaming_cb
|
|
|
|
* -> (fail) -> device_stop -> device_lost_cb
|
|
|
|
* speaker_activate -> device_probe -> device_probe_cb
|
|
|
|
* speaker_deactivate -> device_stop -> device_shutdown_cb
|
|
|
|
* volume_set -> device_volume_set -> device_command_cb
|
|
|
|
* -> -> device_streaming_cb
|
|
|
|
* (volume_setrel/abs_speaker is the same)
|
|
|
|
* playback_start_item -> device_start -> device_restart_cb
|
|
|
|
* -> (success) -> device_streaming_cb
|
|
|
|
* -> (fail) -> device_stop -> device_lost_cb
|
|
|
|
* playback_start_bh -> playback_start -> device_streaming_cb* (or no cb)
|
|
|
|
* playback_stop -> flush -> device_command_cb*
|
|
|
|
* -> -> device_streaming_cb*
|
|
|
|
* -> -> playback_stop -> device_streaming_cb*
|
|
|
|
* playback_pause -> flush -> device_command_cb*
|
|
|
|
* -> -> device_streaming_cb*
|
|
|
|
* -> -> playback_stop -> device_streaming_cb*
|
|
|
|
* playback_abort -> playback_stop -> device_streaming_cb* (or no cb)
|
|
|
|
* device_streaming_cb -> device_streaming_cb (re-add)
|
|
|
|
*
|
2016-01-23 19:14:07 -05:00
|
|
|
*/
|
|
|
|
|
2016-01-24 16:19:15 -05:00
|
|
|
// Must be in sync with outputs[] in outputs.c
|
2016-01-23 19:14:07 -05:00
|
|
|
enum output_types
|
|
|
|
{
|
|
|
|
OUTPUT_TYPE_RAOP,
|
2016-04-04 10:58:07 -04:00
|
|
|
OUTPUT_TYPE_STREAMING,
|
2016-04-04 17:43:34 -04:00
|
|
|
OUTPUT_TYPE_DUMMY,
|
2016-10-25 15:23:09 -04:00
|
|
|
OUTPUT_TYPE_FIFO,
|
2017-01-06 03:44:18 -05:00
|
|
|
#ifdef HAVE_ALSA
|
2016-01-24 16:19:15 -05:00
|
|
|
OUTPUT_TYPE_ALSA,
|
2016-04-04 10:58:07 -04:00
|
|
|
#endif
|
2017-01-06 03:44:18 -05:00
|
|
|
#ifdef HAVE_LIBPULSE
|
2016-07-21 16:13:32 -04:00
|
|
|
OUTPUT_TYPE_PULSE,
|
|
|
|
#endif
|
2016-04-04 17:43:34 -04:00
|
|
|
#ifdef CHROMECAST
|
|
|
|
OUTPUT_TYPE_CAST,
|
|
|
|
#endif
|
2016-01-23 19:14:07 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Output session state */
|
|
|
|
enum output_device_state
|
|
|
|
{
|
2016-02-12 15:59:26 -05:00
|
|
|
// Device is stopped (no session)
|
2016-01-23 19:14:07 -05:00
|
|
|
OUTPUT_STATE_STOPPED = 0,
|
2016-02-12 15:59:26 -05:00
|
|
|
// Device is starting up
|
|
|
|
OUTPUT_STATE_STARTUP = 1,
|
|
|
|
// Session established (streaming ready and commands are possible)
|
|
|
|
OUTPUT_STATE_CONNECTED = 2,
|
|
|
|
// Media data is being sent
|
|
|
|
OUTPUT_STATE_STREAMING = 3,
|
2016-01-24 16:19:15 -05:00
|
|
|
// Session is failed, couldn't startup or error occurred
|
2016-01-23 19:14:07 -05:00
|
|
|
OUTPUT_STATE_FAILED = -1,
|
2016-01-24 16:19:15 -05:00
|
|
|
// Password issue: unknown password or bad password
|
2016-01-23 19:14:07 -05:00
|
|
|
OUTPUT_STATE_PASSWORD = -2,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Linked list of device info used by the player for each device
|
|
|
|
*/
|
|
|
|
struct output_device
|
|
|
|
{
|
|
|
|
// Device id
|
|
|
|
uint64_t id;
|
|
|
|
|
|
|
|
// Name of the device, e.g. "Living Room"
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
// Type of the device, will be used to determine which output backend to call
|
|
|
|
enum output_types type;
|
|
|
|
|
|
|
|
// Type of output (string)
|
|
|
|
const char *type_name;
|
|
|
|
|
|
|
|
// Misc device flags
|
|
|
|
unsigned selected:1;
|
|
|
|
unsigned advertised:1;
|
|
|
|
unsigned has_password:1;
|
|
|
|
unsigned has_video:1;
|
2017-06-19 15:52:01 -04:00
|
|
|
unsigned requires_auth:1;
|
2016-01-23 19:14:07 -05:00
|
|
|
|
2017-06-19 15:52:01 -04:00
|
|
|
// Credentials if relevant
|
2016-01-23 19:14:07 -05:00
|
|
|
const char *password;
|
2017-06-19 15:52:01 -04:00
|
|
|
char *auth_key;
|
2016-01-23 19:14:07 -05:00
|
|
|
|
|
|
|
// Device volume
|
|
|
|
int volume;
|
|
|
|
int relvol;
|
|
|
|
|
|
|
|
// Address
|
|
|
|
char *v4_address;
|
|
|
|
char *v6_address;
|
|
|
|
short v4_port;
|
|
|
|
short v6_port;
|
|
|
|
|
|
|
|
// Opaque pointers to device and session data
|
|
|
|
void *extra_device_info;
|
|
|
|
struct output_session *session;
|
|
|
|
|
|
|
|
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
|
|
|
|
struct output_metadata
|
|
|
|
{
|
|
|
|
enum output_types type;
|
|
|
|
void *metadata;
|
|
|
|
struct output_metadata *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef void (*output_status_cb)(struct output_device *device, struct output_session *session, enum output_device_state status);
|
|
|
|
|
|
|
|
struct output_definition
|
|
|
|
{
|
|
|
|
// Name of the output
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
// Type of output
|
|
|
|
enum output_types type;
|
|
|
|
|
|
|
|
// Priority to give this output when autoselecting an output, 1 is highest
|
|
|
|
// 1 = highest priority, 0 = don't autoselect
|
|
|
|
int priority;
|
|
|
|
|
|
|
|
// Set to 1 if the output initialization failed
|
|
|
|
int disabled;
|
|
|
|
|
|
|
|
// Initialization function called during startup
|
|
|
|
// Output must call device_cb when an output device becomes available/unavailable
|
|
|
|
int (*init)(void);
|
|
|
|
|
|
|
|
// Deinitialization function called at shutdown
|
|
|
|
void (*deinit)(void);
|
|
|
|
|
|
|
|
// Prepare a playback session on device and call back
|
|
|
|
int (*device_start)(struct output_device *device, output_status_cb cb, uint64_t rtptime);
|
|
|
|
|
|
|
|
// Close a session prepared by device_start
|
|
|
|
void (*device_stop)(struct output_session *session);
|
|
|
|
|
|
|
|
// Test the connection to a device and call back
|
|
|
|
int (*device_probe)(struct output_device *device, output_status_cb cb);
|
|
|
|
|
|
|
|
// Free the private device data
|
|
|
|
void (*device_free_extra)(struct output_device *device);
|
|
|
|
|
|
|
|
// Set the volume and call back
|
|
|
|
int (*device_volume_set)(struct output_device *device, output_status_cb cb);
|
|
|
|
|
2018-05-26 19:42:39 -04:00
|
|
|
// Convert device internal representation of volume to our pct scale
|
|
|
|
int (*device_volume_to_pct)(struct output_device *device, const char *volume);
|
|
|
|
|
2016-01-23 19:14:07 -05:00
|
|
|
// Start/stop playback on devices that were started
|
|
|
|
void (*playback_start)(uint64_t next_pkt, struct timespec *ts);
|
|
|
|
void (*playback_stop)(void);
|
|
|
|
|
|
|
|
// Write stream data to the output devices
|
|
|
|
void (*write)(uint8_t *buf, uint64_t rtptime);
|
|
|
|
|
2016-01-31 12:42:32 -05:00
|
|
|
// Flush all sessions, the return must be number of sessions pending the flush
|
2016-01-23 19:14:07 -05:00
|
|
|
int (*flush)(output_status_cb cb, uint64_t rtptime);
|
|
|
|
|
2017-06-19 15:52:01 -04:00
|
|
|
// Authorize an output with a pin-code (probably coming from the filescanner)
|
|
|
|
void (*authorize)(const char *pin);
|
|
|
|
|
2016-01-23 19:14:07 -05:00
|
|
|
// Change the call back associated with a session
|
|
|
|
void (*status_cb)(struct output_session *session, output_status_cb cb);
|
|
|
|
|
|
|
|
// Metadata
|
|
|
|
void *(*metadata_prepare)(int id);
|
|
|
|
void (*metadata_send)(void *metadata, uint64_t rtptime, uint64_t offset, int startup);
|
|
|
|
void (*metadata_purge)(void);
|
|
|
|
void (*metadata_prune)(uint64_t rtptime);
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
outputs_device_start(struct output_device *device, output_status_cb cb, uint64_t rtptime);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_device_stop(struct output_session *session);
|
|
|
|
|
|
|
|
int
|
|
|
|
outputs_device_probe(struct output_device *device, output_status_cb cb);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_device_free(struct output_device *device);
|
|
|
|
|
|
|
|
int
|
|
|
|
outputs_device_volume_set(struct output_device *device, output_status_cb cb);
|
|
|
|
|
2018-05-26 19:42:39 -04:00
|
|
|
int
|
|
|
|
outputs_device_volume_to_pct(struct output_device *device, const char *value);
|
|
|
|
|
2016-01-23 19:14:07 -05:00
|
|
|
void
|
|
|
|
outputs_playback_start(uint64_t next_pkt, struct timespec *ts);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_playback_stop(void);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_write(uint8_t *buf, uint64_t rtptime);
|
|
|
|
|
|
|
|
int
|
|
|
|
outputs_flush(output_status_cb cb, uint64_t rtptime);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_status_cb(struct output_session *session, output_status_cb cb);
|
|
|
|
|
|
|
|
struct output_metadata *
|
|
|
|
outputs_metadata_prepare(int id);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_metadata_send(struct output_metadata *omd, uint64_t rtptime, uint64_t offset, int startup);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_metadata_purge(void);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_metadata_prune(uint64_t rtptime);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_metadata_free(struct output_metadata *omd);
|
|
|
|
|
2017-06-19 15:52:01 -04:00
|
|
|
void
|
|
|
|
outputs_authorize(enum output_types type, const char *pin);
|
|
|
|
|
2016-04-04 15:54:37 -04:00
|
|
|
int
|
|
|
|
outputs_priority(struct output_device *device);
|
|
|
|
|
2016-01-23 19:14:07 -05:00
|
|
|
const char *
|
|
|
|
outputs_name(enum output_types type);
|
|
|
|
|
|
|
|
int
|
|
|
|
outputs_init(void);
|
|
|
|
|
|
|
|
void
|
|
|
|
outputs_deinit(void);
|
|
|
|
|
|
|
|
#endif /* !__OUTPUTS_H__ */
|