diff --git a/lib/airplay_video.c b/lib/airplay_video.c index 8c853e2..b992ae2 100644 --- a/lib/airplay_video.c +++ b/lib/airplay_video.c @@ -36,7 +36,7 @@ struct media_item_s { struct airplay_video_s { raop_t *raop; - char apple_session_id[37]; + char *apple_session_id; char playback_uuid[37]; char *uri_prefix; char *language_name; @@ -56,8 +56,7 @@ struct airplay_video_s { }; // initialize airplay_video service. -airplay_video_t *airplay_video_init(raop_t *raop, unsigned short http_port, - const char *lang, const char *session_id) { +airplay_video_t *airplay_video_init(raop_t *raop, unsigned short http_port, const char *lang) { char uri[] = "http://localhost:xxxxx"; 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->FCUP_RequestID = 0; - size_t len = strlen(session_id); - assert(len == 36); - strncpy(airplay_video->apple_session_id, session_id, len); + airplay_video->apple_session_id = NULL; 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 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) { 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); + 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) { + if (!airplay_video || !airplay_video->apple_session_id) { + return NULL; + } return airplay_video->apple_session_id; } 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; } @@ -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) { - 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) { diff --git a/lib/airplay_video.h b/lib/airplay_video.h index 5666607..179cb25 100644 --- a/lib/airplay_video.h +++ b/lib/airplay_video.h @@ -26,6 +26,7 @@ typedef struct airplay_video_s airplay_video_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); 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); diff --git a/lib/http_handlers.h b/lib/http_handlers.h index 9f6b79c..732cbaa 100644 --- a/lib/http_handlers.h +++ b/lib/http_handlers.h @@ -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; bool data_is_binary_plist = false; char supported_hls_proc_names[] = "YouTube;"; - + airplay_video_t *airplay_video = NULL; + logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_play"); 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; 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; + 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++) { if (conn->raop->airplay_video[i]) { continue; @@ -738,36 +782,39 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r exit(1); } - /* ensure that space will always be available */ - 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); + airplay_video = airplay_video_init(conn->raop, conn->raop->port, conn->raop->lang); if (airplay_video) { + set_playback_uuid(airplay_video, playback_uuid); + plist_mem_free (playback_uuid); conn->raop->current_video = id; 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 { logger_log(conn->raop->logger, LOGGER_ERR, "failed to allocate airplay_video[%d]\n", id); 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"); if (!req_content_location_node) { 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_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)); plist_mem_free(playback_location); diff --git a/lib/raop.c b/lib/raop.c index e7f4fe2..b755e10 100644 --- a/lib/raop.c +++ b/lib/raop.c @@ -877,6 +877,16 @@ int raop_current_playlist_delete(raop_t *raop) { 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() { return raop_ntp_get_local_time(); } + diff --git a/lib/raop.h b/lib/raop.h index 95714d4..4d537bf 100644 --- a/lib/raop.h +++ b/lib/raop.h @@ -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, 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); uint64_t get_local_time();