mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-15 00:34:05 +09:00
improvements to hls support
This commit is contained in:
@@ -36,7 +36,7 @@ struct media_item_s {
|
|||||||
|
|
||||||
struct airplay_video_s {
|
struct airplay_video_s {
|
||||||
raop_t *raop;
|
raop_t *raop;
|
||||||
char apple_session_id[37];
|
char *apple_session_id;
|
||||||
char playback_uuid[37];
|
char playback_uuid[37];
|
||||||
char *uri_prefix;
|
char *uri_prefix;
|
||||||
char *language_name;
|
char *language_name;
|
||||||
@@ -56,8 +56,7 @@ struct airplay_video_s {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// initialize airplay_video service.
|
// initialize airplay_video service.
|
||||||
airplay_video_t *airplay_video_init(raop_t *raop, unsigned short http_port,
|
airplay_video_t *airplay_video_init(raop_t *raop, unsigned short http_port, const char *lang) {
|
||||||
const char *lang, const char *session_id) {
|
|
||||||
char uri[] = "http://localhost:xxxxx";
|
char uri[] = "http://localhost:xxxxx";
|
||||||
assert(raop);
|
assert(raop);
|
||||||
|
|
||||||
@@ -84,9 +83,7 @@ airplay_video_t *airplay_video_init(raop_t *raop, unsigned short http_port,
|
|||||||
airplay_video->raop = raop;
|
airplay_video->raop = raop;
|
||||||
airplay_video->FCUP_RequestID = 0;
|
airplay_video->FCUP_RequestID = 0;
|
||||||
|
|
||||||
size_t len = strlen(session_id);
|
airplay_video->apple_session_id = NULL;
|
||||||
assert(len == 36);
|
|
||||||
strncpy(airplay_video->apple_session_id, session_id, len);
|
|
||||||
|
|
||||||
airplay_video->start_position_seconds = 0.0f;
|
airplay_video->start_position_seconds = 0.0f;
|
||||||
|
|
||||||
@@ -103,8 +100,10 @@ airplay_video_t *airplay_video_init(raop_t *raop, unsigned short http_port,
|
|||||||
|
|
||||||
// destroy the airplay_video service
|
// destroy the airplay_video service
|
||||||
void
|
void
|
||||||
airplay_video_destroy(airplay_video_t *airplay_video)
|
airplay_video_destroy(airplay_video_t *airplay_video) {
|
||||||
{
|
if (airplay_video->apple_session_id) {
|
||||||
|
free(airplay_video->apple_session_id);
|
||||||
|
}
|
||||||
if (airplay_video->uri_prefix) {
|
if (airplay_video->uri_prefix) {
|
||||||
free(airplay_video->uri_prefix);
|
free(airplay_video->uri_prefix);
|
||||||
}
|
}
|
||||||
@@ -121,13 +120,28 @@ airplay_video_destroy(airplay_video_t *airplay_video)
|
|||||||
free (airplay_video->master_playlist);
|
free (airplay_video->master_playlist);
|
||||||
}
|
}
|
||||||
free (airplay_video);
|
free (airplay_video);
|
||||||
|
airplay_video = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_apple_session_id(airplay_video_t *airplay_video, const char * apple_session_id) {
|
||||||
|
if (airplay_video->apple_session_id) {
|
||||||
|
free (airplay_video->apple_session_id);
|
||||||
|
}
|
||||||
|
airplay_video->apple_session_id = (char *) calloc(strlen(apple_session_id) + 1, sizeof(char));
|
||||||
|
memcpy(airplay_video->apple_session_id, apple_session_id, strlen(apple_session_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *get_apple_session_id(airplay_video_t *airplay_video) {
|
const char *get_apple_session_id(airplay_video_t *airplay_video) {
|
||||||
|
if (!airplay_video || !airplay_video->apple_session_id) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return airplay_video->apple_session_id;
|
return airplay_video->apple_session_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
float get_duration(airplay_video_t *airplay_video) {
|
float get_duration(airplay_video_t *airplay_video) {
|
||||||
|
if (!airplay_video || !airplay_video->media_data_store || !airplay_video->media_data_store->duration) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
return airplay_video->media_data_store->duration;
|
return airplay_video->media_data_store->duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +169,7 @@ void set_playback_uuid(airplay_video_t *airplay_video, const char *playback_uuid
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *get_playback_uuid(airplay_video_t *airplay_video) {
|
const char *get_playback_uuid(airplay_video_t *airplay_video) {
|
||||||
return (const char *) airplay_video->playback_uuid;
|
return (const char *) (!airplay_video ? NULL : airplay_video->playback_uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_uri_prefix(airplay_video_t *airplay_video, char *uri_prefix) {
|
void set_uri_prefix(airplay_video_t *airplay_video, char *uri_prefix) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
typedef struct airplay_video_s airplay_video_t;
|
typedef struct airplay_video_s airplay_video_t;
|
||||||
typedef struct media_item_s media_item_t;
|
typedef struct media_item_s media_item_t;
|
||||||
|
|
||||||
|
void set_apple_session_id(airplay_video_t *airplay_video, const char *apple_session_id);
|
||||||
const char *get_apple_session_id(airplay_video_t *airplay_video);
|
const char *get_apple_session_id(airplay_video_t *airplay_video);
|
||||||
void set_start_position_seconds(airplay_video_t *airplay_video, float start_position_seconds);
|
void set_start_position_seconds(airplay_video_t *airplay_video, float start_position_seconds);
|
||||||
void set_resume_position_seconds(airplay_video_t *airplay_video, float resume_position_seconds);
|
void set_resume_position_seconds(airplay_video_t *airplay_video, float resume_position_seconds);
|
||||||
|
|||||||
@@ -688,7 +688,8 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
|||||||
float start_position_seconds = 0.0f;
|
float start_position_seconds = 0.0f;
|
||||||
bool data_is_binary_plist = false;
|
bool data_is_binary_plist = false;
|
||||||
char supported_hls_proc_names[] = "YouTube;";
|
char supported_hls_proc_names[] = "YouTube;";
|
||||||
|
airplay_video_t *airplay_video = NULL;
|
||||||
|
|
||||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_play");
|
logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_play");
|
||||||
|
|
||||||
const char* apple_session_id = http_request_get_header(request, "X-Apple-Session-ID");
|
const char* apple_session_id = http_request_get_header(request, "X-Apple-Session-ID");
|
||||||
@@ -722,9 +723,52 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
|||||||
char* playback_uuid = NULL;
|
char* playback_uuid = NULL;
|
||||||
plist_get_string_val(req_uuid_node, &playback_uuid);
|
plist_get_string_val(req_uuid_node, &playback_uuid);
|
||||||
|
|
||||||
/* initialize new airplay_video structure to hold playlist */
|
/* check if playlist is already dowloaded and stored (may have been interruoted by advertisements ) */
|
||||||
|
#if 0
|
||||||
|
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||||
|
printf("old: airplay_video[%d] %p %s %f\n", i, conn->raop->airplay_video[i],
|
||||||
|
get_playback_uuid(conn->raop->airplay_video[i]),
|
||||||
|
get_duration(conn->raop->airplay_video[i]));
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
printf("new playback_uuid %s\n\n", playback_uuid);
|
||||||
|
#endif
|
||||||
|
|
||||||
int id = -1;
|
int id = -1;
|
||||||
|
id = get_playlist_by_uuid(conn->raop, playback_uuid);
|
||||||
|
if (id >= 0) {
|
||||||
|
printf("use: airplay_video[%d] %p %s %s\n", id, airplay_video, playback_uuid, get_playback_uuid(airplay_video));
|
||||||
|
airplay_video = conn->raop->airplay_video[id];
|
||||||
|
assert(airplay_video);
|
||||||
|
set_apple_session_id(airplay_video, apple_session_id);
|
||||||
|
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(airplay_video));
|
||||||
|
plist_mem_free(playback_uuid);
|
||||||
|
plist_free(req_root_node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove short stort playlists (probably advertisements */
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||||
|
if (conn->raop->airplay_video[i]) {
|
||||||
|
float duration = get_duration(conn->raop->airplay_video[i]);
|
||||||
|
if (duration < (float) MIN_STORED_AIRPLAY_VIDEO_DURATION_SECONDS ) {
|
||||||
|
logger_log(conn->raop->logger, LOGGER_INFO,
|
||||||
|
"deleting playlist playback_uuid %s duration (seconds) %f",
|
||||||
|
get_playback_uuid(conn->raop->airplay_video[i]), duration);
|
||||||
|
airplay_video_destroy(conn->raop->airplay_video[i]);
|
||||||
|
conn->raop->airplay_video[i] = NULL;
|
||||||
|
} else {
|
||||||
|
count++;
|
||||||
|
//printf(" %d %d duration %f : keep\n", i, count, duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize new airplay_video structure to hold playlist */
|
||||||
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||||
if (conn->raop->airplay_video[i]) {
|
if (conn->raop->airplay_video[i]) {
|
||||||
continue;
|
continue;
|
||||||
@@ -738,36 +782,39 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ensure that space will always be available */
|
airplay_video = airplay_video_init(conn->raop, conn->raop->port, conn->raop->lang);
|
||||||
int count = 1;
|
|
||||||
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
|
||||||
if (conn->raop->airplay_video[i]) {
|
|
||||||
if (get_duration(conn->raop->airplay_video[i]) < (float) MIN_STORED_AIRPLAY_VIDEO_DURATION_SECONDS ) {
|
|
||||||
airplay_video_destroy(conn->raop->airplay_video[i]);
|
|
||||||
} else {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert (count <= MAX_AIRPLAY_VIDEO);
|
|
||||||
if (count == MAX_AIRPLAY_VIDEO) {
|
|
||||||
int next = (id + 1) % (int) MAX_AIRPLAY_VIDEO;
|
|
||||||
airplay_video_destroy(conn->raop->airplay_video[next]);
|
|
||||||
}
|
|
||||||
|
|
||||||
airplay_video_t *airplay_video = airplay_video_init(conn->raop, conn->raop->port, conn->raop->lang, apple_session_id);
|
|
||||||
if (airplay_video) {
|
if (airplay_video) {
|
||||||
|
set_playback_uuid(airplay_video, playback_uuid);
|
||||||
|
plist_mem_free (playback_uuid);
|
||||||
conn->raop->current_video = id;
|
conn->raop->current_video = id;
|
||||||
conn->raop->airplay_video[id] = airplay_video;
|
conn->raop->airplay_video[id] = airplay_video;
|
||||||
|
count++;
|
||||||
|
//printf("created new airplay_video %p %s\n\n", airplay_video, get_playback_uuid(airplay_video));
|
||||||
} else {
|
} else {
|
||||||
logger_log(conn->raop->logger, LOGGER_ERR, "failed to allocate airplay_video[%d]\n", id);
|
logger_log(conn->raop->logger, LOGGER_ERR, "failed to allocate airplay_video[%d]\n", id);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_playback_uuid(airplay_video, playback_uuid);
|
|
||||||
plist_mem_free (playback_uuid);
|
|
||||||
|
|
||||||
|
/* ensure that space will always be available for adding future playlists */
|
||||||
|
|
||||||
|
if (count == MAX_AIRPLAY_VIDEO) {
|
||||||
|
int next = (id + 1) % (int) MAX_AIRPLAY_VIDEO;
|
||||||
|
logger_log(conn->raop->logger, LOGGER_INFO,
|
||||||
|
"deleting playlist playback_uuid %s duration (seconds) %f",
|
||||||
|
get_playback_uuid(conn->raop->airplay_video[next]),
|
||||||
|
get_duration(conn->raop->airplay_video[next]));
|
||||||
|
airplay_video_destroy(conn->raop->airplay_video[next]);
|
||||||
|
conn->raop->airplay_video[next] = NULL;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||||
|
printf("new: airplay_video[%d] %p %s %f\n", i, conn->raop->airplay_video[i],
|
||||||
|
get_playback_uuid(conn->raop->airplay_video[i]),
|
||||||
|
get_duration(conn->raop->airplay_video[i]));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
set_apple_session_id(airplay_video, apple_session_id);
|
||||||
|
|
||||||
plist_t req_content_location_node = plist_dict_get_item(req_root_node, "Content-Location");
|
plist_t req_content_location_node = plist_dict_get_item(req_root_node, "Content-Location");
|
||||||
if (!req_content_location_node) {
|
if (!req_content_location_node) {
|
||||||
goto play_error;
|
goto play_error;
|
||||||
@@ -808,6 +855,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
|||||||
set_uri_prefix(airplay_video, uri_prefix);
|
set_uri_prefix(airplay_video, uri_prefix);
|
||||||
}
|
}
|
||||||
set_next_media_uri_id(airplay_video, 0);
|
set_next_media_uri_id(airplay_video, 0);
|
||||||
|
printf("FCUP REQUEST\n");
|
||||||
fcup_request((void *) conn, playback_location, apple_session_id, get_next_FCUP_RequestID(airplay_video));
|
fcup_request((void *) conn, playback_location, apple_session_id, get_next_FCUP_RequestID(airplay_video));
|
||||||
|
|
||||||
plist_mem_free(playback_location);
|
plist_mem_free(playback_location);
|
||||||
|
|||||||
10
lib/raop.c
10
lib/raop.c
@@ -877,6 +877,16 @@ int raop_current_playlist_delete(raop_t *raop) {
|
|||||||
return current_video;
|
return current_video;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_playlist_by_uuid(raop_t *raop, const char *uuid) {
|
||||||
|
for (int i = 0 ;i < MAX_AIRPLAY_VIDEO && raop->airplay_video[i]; i++) {
|
||||||
|
if (!strcmp(uuid, get_playback_uuid(raop->airplay_video[i]))) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t get_local_time() {
|
uint64_t get_local_time() {
|
||||||
return raop_ntp_get_local_time();
|
return raop_ntp_get_local_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,8 @@ raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const c
|
|||||||
int remote_addr_len, unsigned short timing_rport,
|
int remote_addr_len, unsigned short timing_rport,
|
||||||
timing_protocol_t *time_protocol);
|
timing_protocol_t *time_protocol);
|
||||||
|
|
||||||
airplay_video_t *airplay_video_init(raop_t *raop, unsigned short port, const char *lang, const char *session_id);
|
airplay_video_t *airplay_video_init(raop_t *raop, unsigned short port, const char *lang);
|
||||||
|
int get_playlist_by_uuid(raop_t *raop, const char *uuid);
|
||||||
char *raop_get_lang(raop_t *raop);
|
char *raop_get_lang(raop_t *raop);
|
||||||
uint64_t get_local_time();
|
uint64_t get_local_time();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user