mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-27 23:55:57 -05:00
6f0fef6179
Select use of either libspotify or librespot-c as streaming backend via config option. librespot-c (renamed/improved spotifyc) impl has the following: - sync interface - seek support - honor bitrate config, set client and thread name - use web access token with "streaming" scope for login - fix issue with podcast playback Also say goodbye to file-based Spotify login.
248 lines
6.3 KiB
C
248 lines
6.3 KiB
C
|
|
#ifndef __INPUT_H__
|
|
#define __INPUT_H__
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
#include <event2/buffer.h>
|
|
#include "db.h"
|
|
#include "misc.h"
|
|
|
|
// Must be in sync with inputs[] in input.c
|
|
enum input_types
|
|
{
|
|
INPUT_TYPE_FILE,
|
|
INPUT_TYPE_HTTP,
|
|
INPUT_TYPE_PIPE,
|
|
INPUT_TYPE_TIMER,
|
|
#ifdef SPOTIFY_LIBRESPOTC
|
|
INPUT_TYPE_SPOTIFY,
|
|
#endif
|
|
#ifdef SPOTIFY_LIBSPOTIFY
|
|
INPUT_TYPE_LIBSPOTIFY,
|
|
#endif
|
|
};
|
|
|
|
enum input_flags
|
|
{
|
|
// Flags that input is closing current source
|
|
INPUT_FLAG_START_NEXT = (1 << 0),
|
|
// Flags end of file
|
|
INPUT_FLAG_EOF = (1 << 1),
|
|
// Flags error reading file
|
|
INPUT_FLAG_ERROR = (1 << 2),
|
|
// Flags possible new stream metadata
|
|
INPUT_FLAG_METADATA = (1 << 3),
|
|
// Flags new stream quality
|
|
INPUT_FLAG_QUALITY = (1 << 4),
|
|
};
|
|
|
|
struct input_source
|
|
{
|
|
// Type of input
|
|
enum input_types type;
|
|
|
|
// Item-Id of the file/item in the queue
|
|
uint32_t item_id;
|
|
|
|
// Id of the file/item in the files database
|
|
uint32_t id;
|
|
|
|
// Length of the file/item in milliseconds
|
|
uint32_t len_ms;
|
|
|
|
enum data_kind data_kind;
|
|
enum media_kind media_kind;
|
|
char *path;
|
|
|
|
// Flags that the input has been opened (i.e. needs to be closed)
|
|
bool open;
|
|
|
|
// The below is private data for the input backend. It is optional for the
|
|
// backend to use, so nothing in the input or player should depend on it!
|
|
//
|
|
// Opaque pointer to data that the input backend sets up when start() is
|
|
// called, and that is cleaned up by the backend when stop() is called
|
|
void *input_ctx;
|
|
|
|
// The input's event base that the input backend can use for own events
|
|
struct event_base *evbase;
|
|
|
|
// Private evbuf. Alloc'ed by backend at start() and free'd at stop()
|
|
struct evbuffer *evbuf;
|
|
// Private source quality storage
|
|
struct media_quality quality;
|
|
};
|
|
|
|
typedef int (*input_cb)(void);
|
|
|
|
struct input_metadata
|
|
{
|
|
// queue_item id
|
|
uint32_t item_id;
|
|
|
|
// Input can override the default player progress by setting this. For the
|
|
// other fields the receiver can check whether an update happened by checking
|
|
// if it is non-zero/null, but not for pos_ms since 0 and even negative values
|
|
// are valid.
|
|
bool pos_is_updated;
|
|
int32_t pos_ms;
|
|
|
|
// Sets new song length (input will also update queue_item)
|
|
uint32_t len_ms;
|
|
|
|
// Input can update queue_item with the below
|
|
char *artist;
|
|
char *title;
|
|
char *album;
|
|
char *genre;
|
|
char *artwork_url;
|
|
};
|
|
|
|
struct input_definition
|
|
{
|
|
// Name of the input
|
|
const char *name;
|
|
|
|
// Type of input
|
|
enum input_types type;
|
|
|
|
// Set to 1 if the input initialization failed
|
|
char disabled;
|
|
|
|
// Prepare a playback session
|
|
int (*setup)(struct input_source *source);
|
|
|
|
// One iteration of the playback loop (= a read operation from source)
|
|
int (*play)(struct input_source *source);
|
|
|
|
// Cleans up (only required when stopping source before it ends itself)
|
|
int (*stop)(struct input_source *source);
|
|
|
|
// Changes the playback position
|
|
int (*seek)(struct input_source *source, int seek_ms);
|
|
|
|
// Return metadata
|
|
int (*metadata_get)(struct input_metadata *metadata, struct input_source *source);
|
|
|
|
// Initialization function called during startup
|
|
int (*init)(void);
|
|
|
|
// Deinitialization function called at shutdown
|
|
void (*deinit)(void);
|
|
};
|
|
|
|
|
|
/* ---------------------- Interface towards input backends ------------------ */
|
|
/* Thread: input */
|
|
|
|
/*
|
|
* Transfer stream data to the player's input buffer. Data must be PCM-LE
|
|
* samples. The input evbuf will be drained on succesful write. This is to avoid
|
|
* copying memory. Thread-safe.
|
|
*
|
|
* @in evbuf Raw PCM_LE audio data to write
|
|
* @in evbuf Quality of the PCM (sample rate etc.)
|
|
* @in flags One or more INPUT_FLAG_*
|
|
* @return 0 on success, EAGAIN if buffer was full, -1 on error
|
|
*/
|
|
int
|
|
input_write(struct evbuffer *evbuf, struct media_quality *quality, short flags);
|
|
|
|
/*
|
|
* Input modules can use this to wait for the player to read, so the module's
|
|
* playback-loop doesn't spin out of control.
|
|
*/
|
|
int
|
|
input_wait(void);
|
|
|
|
/* ---------------------- Interface towards player thread ------------------- */
|
|
/* Thread: player */
|
|
|
|
/*
|
|
* Move a chunk of stream data from the player's input buffer to an output
|
|
* buffer. Should only be called by the player thread. Will not block.
|
|
*
|
|
* @in data Output buffer
|
|
* @in size How much data to move to the output buffer
|
|
* @out flag Flag INPUT_FLAG_*
|
|
* @out flagdata Data associated with the flag, e.g. quality or metadata struct
|
|
* @return Number of bytes moved, -1 on error
|
|
*/
|
|
int
|
|
input_read(void *data, size_t size, short *flag, void **flagdata);
|
|
|
|
/*
|
|
* Player can set this to get a callback from the input when the input buffer
|
|
* is full. The player may use this to resume playback after an underrun.
|
|
*
|
|
* @in cb The callback
|
|
*/
|
|
void
|
|
input_buffer_full_cb(input_cb cb);
|
|
|
|
/*
|
|
* Tells the input to start, i.e. after calling this function the input buffer
|
|
* will begin to fill up, and should be read periodically with input_read(). If
|
|
* called while another item is still open, it will be closed and the input
|
|
* buffer will be flushed. This operation blocks.
|
|
*
|
|
* @in item_id Queue item id to start playing
|
|
* @in seek_ms Position to start playing
|
|
* @return Actual seek position if seekable, 0 otherwise, -1 on error
|
|
*/
|
|
int
|
|
input_seek(uint32_t item_id, int seek_ms);
|
|
|
|
/*
|
|
* Same as input_seek(), just non-blocking and does not offer seek.
|
|
*
|
|
* @in item_id Queue item id to start playing
|
|
*/
|
|
void
|
|
input_start(uint32_t item_id);
|
|
|
|
/*
|
|
* Same as input_seek(), but non-blocking and if the item is already being read
|
|
* we don't do anything (no flush & seek)
|
|
*
|
|
* @in item_id Queue item id to start playing
|
|
* @in seek_ms Position to start playing
|
|
*/
|
|
void
|
|
input_resume(uint32_t item_id, int seek_ms);
|
|
|
|
/*
|
|
* Stops the input and clears everything. Flushes the input buffer.
|
|
*/
|
|
void
|
|
input_stop(void);
|
|
|
|
/*
|
|
* Flush input buffer. Output flags will be the same as input_read(). Call with
|
|
* null pointer is valid.
|
|
*/
|
|
void
|
|
input_flush(short *flags);
|
|
|
|
/*
|
|
* Free input_metadata
|
|
*/
|
|
void
|
|
input_metadata_free(struct input_metadata *metadata, int content_only);
|
|
|
|
/*
|
|
* Called by player_init (so will run in main thread)
|
|
*/
|
|
int
|
|
input_init(void);
|
|
|
|
/*
|
|
* Called by player_deinit (so will run in main thread)
|
|
*/
|
|
void
|
|
input_deinit(void);
|
|
|
|
#endif /* !__INPUT_H__ */
|