#ifndef PERSONAL_PLAYER_H #define PERSONAL_PLAYER_H #include #include #ifdef __cplusplus extern "C" { #endif typedef struct Player Player; typedef enum PlayerStatus { PLAYER_EMPTY, PLAYER_OPENING, PLAYER_PAUSED, PLAYER_PLAYING, PLAYER_ENDED, PLAYER_ERROR } PlayerStatus; typedef struct PlayerState { PlayerStatus status; double position; double duration; // Contiguous retained/playable network range on the position timeline. // The start may include reusable rewind history; the end includes read-ahead. // Empty/unavailable (including local playback and pending seeks) is 0, 0. double buffered_start; double buffered_end; bool has_audio; bool has_video; // False for live/non-seekable inputs; reflects both inputs for separate streams. bool can_seek; // Network playback is waiting for media; the authoritative clock remains stalled. bool buffering; // True until all accepted seeks/frame steps on this timeline finish. bool seek_pending; // Display width / height, including sample aspect ratio; zero without video. double video_aspect_ratio; uint64_t revision; char error[512]; } PlayerState; // Playback commands are asynchronous. False means invalid input or a full command queue. // Paths are copied before returning. All other calls require a live handle. Player *player_create(void); // Opt-in reporting must be initialized before opening media. Creates a new 0600 // file exclusively; errors never change playback state. Error buffers hold 512 bytes. bool player_set_progress_file(Player *player, const char *path, char *error); bool player_get_progress_error(Player *player, char *error); // Stops the worker and drains final reporting, allowing errors to be shown before // destroying the handle. Idempotent; do not call from an audio callback. bool player_shutdown(Player *player, char *progress_error); typedef struct PlayerNetworkSource { // Primary video or combined audio/video HTTP(S) URL; audio_url is optional. const char *video_url; const char *audio_url; // Optional HTTP headers encoded as "Name: value\r\n"; copied with the URLs. const char *video_headers; const char *audio_headers; double duration; bool is_live; // Canonical YouTube webpage or stable miruro:: // identity, never an extracted stream/CDN URL. // NULL/empty means no reporting for this source. const char *media_url; // Initial restored position, applied before publishing ready state. Zero // starts at the beginning; out-of-duration bookmarks also start at zero. double initial_position; } PlayerNetworkSource; bool player_open(Player *player, const char *path); // Streams directly; never downloads or muxes the entire media file before opening. bool player_open_network(Player *player, const PlayerNetworkSource *source); bool player_play(Player *player); bool player_pause(Player *player); bool player_seek(Player *player, double seconds); // Direction must be -1 (previous) or +1 (next). Requires ready video media. // Pauses playback and selects the adjacent decoded presentation frame. bool player_step_frame(Player *player, int direction); bool player_close(Player *player); // Receiver-confirmed Cast facts replace decoder facts in progress reporting until // the next open/close. The local decoder must be paused before submitting them. bool player_report_remote_state(Player *player, const PlayerState *state); // Synchronous, thread-safe gain; survives open, seek, and close. Zero mutes. // Rejects null handles and non-finite/out-of-range values without changing gain. bool player_set_volume(Player *player, float normalized0to1); // Returns the target gain immediately; zero for a null handle. float player_get_volume(Player *player); PlayerState player_get_state(Player *player); // Joins the worker and stops audio; never invoke from an audio callback. void player_destroy(Player *player); #ifdef __cplusplus } #endif #endif