mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-26 23:25:56 -05:00
ab0a6055b9
Previously input_metadata_get() would retrieve artwork from the source being read currently, which might not be the one that triggered the FLAG_METADATA event. So to fix this the metadata is now read by the input module itself when the METADATA event happens, and the result is stored with the marker. The commit also includes a timer so that the input thread does loop forever if the player never starts reading. Also some refactoring of metadata + abolish input_metadata_get and input_quality_get. The latter in an attempt to treat the two in the same way.
238 lines
6.0 KiB
C
238 lines
6.0 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,
|
|
#ifdef HAVE_SPOTIFY_H
|
|
INPUT_TYPE_SPOTIFY,
|
|
#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;
|
|
// 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
|
|
// FIXME only implemented for Airplay speakers currently
|
|
uint32_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;
|
|
|
|
// Indicates whether we are starting playback. Just passed on to output.
|
|
int startup;
|
|
};
|
|
|
|
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 and spotify */
|
|
|
|
/*
|
|
* 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.
|
|
*
|
|
* @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 input_buffer to be ready for
|
|
* writing. The wait is max INPUT_LOOP_TIMEOUT, which allows the event base to
|
|
* loop and process pending commands once in a while.
|
|
*/
|
|
int
|
|
input_wait(void);
|
|
|
|
/*
|
|
* Async switch to the next song in the queue. Mostly for internal use, but
|
|
* might be relevant some day externally?
|
|
*/
|
|
//void
|
|
//input_next(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);
|
|
|
|
/*
|
|
* 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().
|
|
*/
|
|
void
|
|
input_flush(short *flags);
|
|
|
|
/*
|
|
* Free the entire struct
|
|
*/
|
|
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__ */
|