mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
rework airplay_video to store multiple playlists
This commit is contained in:
@@ -52,21 +52,17 @@ struct airplay_video_s {
|
||||
};
|
||||
|
||||
// initialize airplay_video service.
|
||||
int airplay_video_service_init(raop_t *raop, unsigned short http_port,
|
||||
airplay_video_t *airplay_video_service_init(raop_t *raop, unsigned short http_port,
|
||||
const char *lang, const char *session_id) {
|
||||
char uri[] = "http://localhost:xxxxx";
|
||||
assert(raop);
|
||||
|
||||
airplay_video_t *airplay_video = deregister_airplay_video(raop);
|
||||
if (airplay_video) {
|
||||
airplay_video_service_destroy(airplay_video);
|
||||
}
|
||||
|
||||
/* calloc guarantees that the 36-character strings apple_session_id and
|
||||
playback_uuid are null-terminated */
|
||||
airplay_video = (airplay_video_t *) calloc(1, sizeof(airplay_video_t));
|
||||
airplay_video_t *airplay_video = (airplay_video_t *) calloc(1, sizeof(airplay_video_t));
|
||||
|
||||
if (!airplay_video) {
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
airplay_video->lang = lang;
|
||||
@@ -79,10 +75,6 @@ int airplay_video_service_init(raop_t *raop, unsigned short http_port,
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
if (!register_airplay_video(raop, airplay_video)) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
//printf(" %p %p\n", airplay_video, get_airplay_video(raop));
|
||||
|
||||
airplay_video->raop = raop;
|
||||
@@ -99,7 +91,7 @@ int airplay_video_service_init(raop_t *raop, unsigned short http_port,
|
||||
airplay_video->master_playlist = NULL;
|
||||
airplay_video->num_uri = 0;
|
||||
airplay_video->next_uri = 0;
|
||||
return 0;
|
||||
return airplay_video;
|
||||
}
|
||||
|
||||
// destroy the airplay_video service
|
||||
|
||||
@@ -84,8 +84,28 @@ http_handler_server_info(raop_conn_t *conn, http_request_t *request, http_respon
|
||||
/* initialize the airplay video service */
|
||||
const char *session_id = http_request_get_header(request, "X-Apple-Session-ID");
|
||||
|
||||
airplay_video_service_init(conn->raop, conn->raop->port, conn->raop->lang, session_id);
|
||||
int id = -1;
|
||||
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||
if (conn->raop->airplay_video[i]) {
|
||||
continue;
|
||||
}
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
if (id == -1) {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "no unused airplay_video structures are available"
|
||||
" MAX_AIRPLAY_VIDEO = %d\n", MAX_AIRPLAY_VIDEO);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
airplay_video_t *airplay_video = airplay_video_service_init(conn->raop, conn->raop->port, conn->raop->lang, session_id);
|
||||
if (airplay_video) {
|
||||
conn->raop->current_video = id;
|
||||
conn->raop->airplay_video[id] = airplay_video;
|
||||
} else {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "failed to allocate airplay_video[%d]\n", id);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -123,7 +143,7 @@ http_handler_rate(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
float value = strtof(rate, &end);
|
||||
if (end && end != rate) {
|
||||
rate_value = value;
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_rate: got rate = %.6f", rate_value);
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_rate: got rate = %.6f", rate_value);
|
||||
}
|
||||
}
|
||||
conn->raop->callbacks.on_video_rate(conn->raop->callbacks.cls, rate_value);
|
||||
@@ -360,6 +380,7 @@ static void
|
||||
http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t *response,
|
||||
char **response_data, int *response_datalen) {
|
||||
|
||||
airplay_video_t *airplay_video = conn->raop->airplay_video[conn->raop->current_video];
|
||||
bool data_is_plist = false;
|
||||
plist_t req_root_node = NULL;
|
||||
uint64_t uint_val;
|
||||
@@ -372,7 +393,7 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Play request had no X-Apple-Session-ID");
|
||||
goto post_action_error;
|
||||
}
|
||||
const char *apple_session_id = get_apple_session_id(conn->raop->airplay_video);
|
||||
const char *apple_session_id = get_apple_session_id(airplay_video);
|
||||
if (strcmp(session_id, apple_session_id)){
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "X-Apple-Session-ID has changed:\n was:\"%s\"\n now:\"%s\"",
|
||||
apple_session_id, session_id);
|
||||
@@ -433,7 +454,7 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
plist_t req_params_item_uuid_node = plist_dict_get_item(req_params_item_node, "uuid");
|
||||
char* remove_uuid = NULL;
|
||||
plist_get_string_val(req_params_item_uuid_node, &remove_uuid);
|
||||
const char *playback_uuid = get_playback_uuid(conn->raop->airplay_video);
|
||||
const char *playback_uuid = get_playback_uuid(airplay_video);
|
||||
if (strcmp(remove_uuid, playback_uuid)) {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "uuid of playlist removal action request did not match current playlist:\n"
|
||||
" current: %s\n remove: %s", playback_uuid, remove_uuid);
|
||||
@@ -557,25 +578,25 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
char *ptr = strstr(fcup_response_url, "/master.m3u8");
|
||||
if (ptr) {
|
||||
/* this is a master playlist */
|
||||
char *uri_prefix = get_uri_prefix(conn->raop->airplay_video);
|
||||
char *uri_prefix = get_uri_prefix(airplay_video);
|
||||
char ** media_data_store = NULL;
|
||||
int num_uri = 0;
|
||||
|
||||
char *uri_local_prefix = get_uri_local_prefix(conn->raop->airplay_video);
|
||||
char *uri_local_prefix = get_uri_local_prefix(airplay_video);
|
||||
char *new_master = adjust_master_playlist (fcup_response_data, fcup_response_datalen, uri_prefix, uri_local_prefix);
|
||||
store_master_playlist(conn->raop->airplay_video, new_master);
|
||||
store_master_playlist(airplay_video, new_master);
|
||||
create_media_uri_table(uri_prefix, fcup_response_data, fcup_response_datalen, &media_data_store, &num_uri);
|
||||
create_media_data_store(conn->raop->airplay_video, media_data_store, num_uri);
|
||||
num_uri = get_num_media_uri(conn->raop->airplay_video);
|
||||
set_next_media_uri_id(conn->raop->airplay_video, 0);
|
||||
create_media_data_store(airplay_video, media_data_store, num_uri);
|
||||
num_uri = get_num_media_uri(airplay_video);
|
||||
set_next_media_uri_id(airplay_video, 0);
|
||||
} else {
|
||||
/* this is a media playlist */
|
||||
assert(fcup_response_data);
|
||||
char *playlist = (char *) calloc(fcup_response_datalen + 1, sizeof(char));
|
||||
memcpy(playlist, fcup_response_data, fcup_response_datalen);
|
||||
int uri_num = get_next_media_uri_id(conn->raop->airplay_video);
|
||||
int uri_num = get_next_media_uri_id(airplay_video);
|
||||
--uri_num; // (next num is current num + 1)
|
||||
store_media_playlist(conn->raop->airplay_video, playlist, uri_num);
|
||||
store_media_playlist(airplay_video, playlist, uri_num);
|
||||
float duration = 0.0f;
|
||||
int count = analyze_media_playlist(playlist, &duration);
|
||||
if (count) {
|
||||
@@ -590,18 +611,18 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
}
|
||||
plist_mem_free(fcup_response_url);
|
||||
|
||||
int num_uri = get_num_media_uri(conn->raop->airplay_video);
|
||||
int uri_num = get_next_media_uri_id(conn->raop->airplay_video);
|
||||
int num_uri = get_num_media_uri(airplay_video);
|
||||
int uri_num = get_next_media_uri_id(airplay_video);
|
||||
if (uri_num < num_uri) {
|
||||
fcup_request((void *) conn, get_media_uri_by_num(conn->raop->airplay_video, uri_num),
|
||||
apple_session_id,
|
||||
get_next_FCUP_RequestID(conn->raop->airplay_video));
|
||||
set_next_media_uri_id(conn->raop->airplay_video, ++uri_num);
|
||||
fcup_request((void *) conn, get_media_uri_by_num(airplay_video, uri_num),
|
||||
apple_session_id,
|
||||
get_next_FCUP_RequestID(airplay_video));
|
||||
set_next_media_uri_id(airplay_video, ++uri_num);
|
||||
} else {
|
||||
char * uri_local_prefix = get_uri_local_prefix(conn->raop->airplay_video);
|
||||
char * uri_local_prefix = get_uri_local_prefix(airplay_video);
|
||||
conn->raop->callbacks.on_video_play(conn->raop->callbacks.cls,
|
||||
strcat(uri_local_prefix, "/master.m3u8"),
|
||||
get_start_position_seconds(conn->raop->airplay_video));
|
||||
strcat(uri_local_prefix, "/master.m3u8"),
|
||||
get_start_position_seconds(airplay_video));
|
||||
}
|
||||
|
||||
finish:
|
||||
@@ -626,6 +647,7 @@ static void
|
||||
http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *response,
|
||||
char **response_data, int *response_datalen) {
|
||||
|
||||
airplay_video_t *airplay_video = conn->raop->airplay_video[conn->raop->current_video];
|
||||
char* playback_location = NULL;
|
||||
char* client_proc_name = NULL;
|
||||
plist_t req_root_node = NULL;
|
||||
@@ -642,7 +664,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Play request had no X-Apple-Session-ID");
|
||||
goto play_error;
|
||||
}
|
||||
const char *apple_session_id = get_apple_session_id(conn->raop->airplay_video);
|
||||
const char *apple_session_id = get_apple_session_id(airplay_video);
|
||||
if (strcmp(session_id, apple_session_id)){
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "X-Apple-Session-ID has changed:\n was:\"%s\"\n now:\"%s\"",
|
||||
apple_session_id, session_id);
|
||||
@@ -684,7 +706,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
} else {
|
||||
char* playback_uuid = NULL;
|
||||
plist_get_string_val(req_uuid_node, &playback_uuid);
|
||||
set_playback_uuid(conn->raop->airplay_video, playback_uuid);
|
||||
set_playback_uuid(airplay_video, playback_uuid);
|
||||
plist_mem_free (playback_uuid);
|
||||
}
|
||||
|
||||
@@ -715,7 +737,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
plist_get_real_val(req_start_position_seconds_node, &start_position);
|
||||
start_position_seconds = (float) start_position;
|
||||
}
|
||||
set_start_position_seconds(conn->raop->airplay_video, (float) start_position_seconds);
|
||||
set_start_position_seconds(airplay_video, (float) start_position_seconds);
|
||||
}
|
||||
|
||||
char *ptr = strstr(playback_location, "/master.m3u8");
|
||||
@@ -724,9 +746,9 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
goto play_error;
|
||||
}
|
||||
int prefix_len = (int) (ptr - playback_location);
|
||||
set_uri_prefix(conn->raop->airplay_video, playback_location, prefix_len);
|
||||
set_next_media_uri_id(conn->raop->airplay_video, 0);
|
||||
fcup_request((void *) conn, playback_location, apple_session_id, get_next_FCUP_RequestID(conn->raop->airplay_video));
|
||||
set_uri_prefix(airplay_video, playback_location, prefix_len);
|
||||
set_next_media_uri_id(airplay_video, 0);
|
||||
fcup_request((void *) conn, playback_location, apple_session_id, get_next_FCUP_RequestID(airplay_video));
|
||||
|
||||
plist_mem_free(playback_location);
|
||||
|
||||
@@ -757,6 +779,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
static void
|
||||
http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *response,
|
||||
char **response_data, int *response_datalen) {
|
||||
airplay_video_t *airplay_video = conn->raop->airplay_video[conn->raop->current_video];
|
||||
const char *method = http_request_get_method(request);
|
||||
assert (!strcmp(method, "GET"));
|
||||
const char *url = http_request_get_url(request);
|
||||
@@ -772,7 +795,7 @@ http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
}
|
||||
|
||||
if (!strcmp(url, "/master.m3u8")){
|
||||
char * master_playlist = get_master_playlist(conn->raop->airplay_video);
|
||||
char * master_playlist = get_master_playlist(airplay_video);
|
||||
if (master_playlist) {
|
||||
size_t len = strlen(master_playlist);
|
||||
char * data = (char *) malloc(len + 1);
|
||||
@@ -786,7 +809,7 @@ http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
}
|
||||
|
||||
} else {
|
||||
char *media_playlist = get_media_playlist(conn->raop->airplay_video, url);
|
||||
char *media_playlist = get_media_playlist(airplay_video, url);
|
||||
if (media_playlist) {
|
||||
char *data = adjust_yt_condensed_playlist(media_playlist);
|
||||
*response_data = data;
|
||||
|
||||
44
lib/raop.c
44
lib/raop.c
@@ -73,8 +73,10 @@ struct raop_s {
|
||||
char pk_str[2*ED25519_KEY_SIZE + 1];
|
||||
|
||||
/* place to store media_data_store */
|
||||
airplay_video_t *airplay_video;
|
||||
|
||||
airplay_video_t *airplay_video[MAX_AIRPLAY_VIDEO];
|
||||
int current_video;
|
||||
int removed_video;
|
||||
|
||||
/* activate support for HLS live streaming */
|
||||
bool hls_support;
|
||||
|
||||
@@ -94,7 +96,6 @@ struct raop_conn_s {
|
||||
raop_rtp_mirror_t *raop_rtp_mirror;
|
||||
fairplay_t *fairplay;
|
||||
pairing_session_t *session;
|
||||
airplay_video_t *airplay_video;
|
||||
|
||||
unsigned char *local;
|
||||
int locallen;
|
||||
@@ -165,7 +166,6 @@ conn_init(void *opaque, unsigned char *local, int locallen, unsigned char *remot
|
||||
|
||||
conn->connection_type = CONNECTION_TYPE_UNKNOWN;
|
||||
conn->client_session_id = NULL;
|
||||
conn->airplay_video = NULL;
|
||||
|
||||
conn->authenticated = false;
|
||||
|
||||
@@ -535,9 +535,6 @@ conn_destroy(void *ptr) {
|
||||
if (conn->client_session_id) {
|
||||
free(conn->client_session_id);
|
||||
}
|
||||
if (conn->airplay_video) {
|
||||
airplay_video_service_destroy(conn->airplay_video);
|
||||
}
|
||||
|
||||
free(conn);
|
||||
}
|
||||
@@ -592,6 +589,13 @@ raop_init(raop_callbacks_t *callbacks) {
|
||||
/* initialize switch for display of client's streaming data records */
|
||||
raop->clientFPSdata = 0;
|
||||
|
||||
/* initialize airplay_video */
|
||||
raop->current_video = -1;
|
||||
raop->removed_video = -1;
|
||||
for (int i= 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||
raop->airplay_video[i] = NULL;
|
||||
}
|
||||
|
||||
raop->audio_delay_micros = 250000;
|
||||
|
||||
raop->hls_support = false;
|
||||
@@ -816,28 +820,12 @@ void raop_remove_hls_connections(raop_t * raop) {
|
||||
httpd_remove_connections_by_type(raop->httpd, CONNECTION_TYPE_AIRPLAY);
|
||||
}
|
||||
|
||||
airplay_video_t *deregister_airplay_video(raop_t *raop) {
|
||||
airplay_video_t *airplay_video = raop->airplay_video;
|
||||
raop->airplay_video = NULL;
|
||||
return airplay_video;
|
||||
}
|
||||
|
||||
bool register_airplay_video(raop_t *raop, airplay_video_t *airplay_video) {
|
||||
if (raop->airplay_video) {
|
||||
return false;
|
||||
}
|
||||
raop->airplay_video = airplay_video;
|
||||
return true;
|
||||
}
|
||||
|
||||
airplay_video_t * get_airplay_video(raop_t *raop) {
|
||||
return raop->airplay_video;
|
||||
}
|
||||
|
||||
void raop_destroy_airplay_video(raop_t *raop) {
|
||||
if (raop->airplay_video) {
|
||||
airplay_video_service_destroy(raop->airplay_video);
|
||||
raop->airplay_video = NULL;
|
||||
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||
if (raop->airplay_video[i]) {
|
||||
airplay_video_service_destroy(raop->airplay_video[i]);
|
||||
raop->airplay_video[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
#include "raop_ntp.h"
|
||||
#include "airplay_video.h"
|
||||
|
||||
# define RAOP_API
|
||||
#define RAOP_API
|
||||
#define MAX_AIRPLAY_VIDEO 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -104,11 +105,8 @@ raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const c
|
||||
int remote_addr_len, unsigned short timing_rport,
|
||||
timing_protocol_t *time_protocol);
|
||||
|
||||
int airplay_video_service_init(raop_t *raop, unsigned short port, const char *lang, const char *session_id);
|
||||
bool register_airplay_video(raop_t *raop, airplay_video_t *airplay_video);
|
||||
airplay_video_t *airplay_video_service_init(raop_t *raop, unsigned short port, const char *lang, const char *session_id);
|
||||
char *raop_get_lang(raop_t *raop);
|
||||
airplay_video_t *get_airplay_video(raop_t *raop);
|
||||
airplay_video_t *deregister_airplay_video(raop_t *raop);
|
||||
uint64_t get_local_time();
|
||||
|
||||
RAOP_API raop_t *raop_init(raop_callbacks_t *callbacks);
|
||||
|
||||
Reference in New Issue
Block a user