mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
more fixes? for hls
This commit is contained in:
@@ -31,8 +31,8 @@ static void
|
||||
|
||||
static 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]))) {
|
||||
for (int i = 0 ;i < MAX_AIRPLAY_VIDEO; i++) {
|
||||
if (raop->airplay_video[i] && !strcmp(uuid, get_playback_uuid(raop->airplay_video[i]))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -385,7 +385,7 @@ http_handler_playback_info(raop_conn_t *conn, http_request_t *request, http_resp
|
||||
logger_log(raop->logger, LOGGER_DEBUG, "playback_info not available (finishing)");
|
||||
//httpd_remove_known_connections(raop->httpd);
|
||||
http_response_set_disconnect(response,1);
|
||||
raop->callbacks.video_reset(raop->callbacks.cls, true, false);
|
||||
raop->callbacks.video_reset(raop->callbacks.cls, RESET_TYPE_HLS_SHUTDOWN);
|
||||
return;
|
||||
} else if (playback_info.position == -1.0) {
|
||||
logger_log(raop->logger, LOGGER_DEBUG, "playback_info not available");
|
||||
@@ -536,14 +536,9 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
if (id == raop->current_video) {
|
||||
raop->current_video = -1;
|
||||
float position = raop->callbacks.on_video_playlist_remove(raop->callbacks.cls);
|
||||
float duration = get_duration(airplay_video);
|
||||
if (duration < (float) MIN_STORED_AIRPLAY_VIDEO_DURATION_SECONDS) {
|
||||
airplay_video_destroy(airplay_video); /* short duration == probably advertisements */
|
||||
raop->airplay_video[id] = NULL;
|
||||
} else {
|
||||
set_resume_position_seconds(airplay_video, position);
|
||||
raop->interrupted_video = id;
|
||||
}
|
||||
/* keep the playlist (until space is needed for another one) in case its playback_uuid is re-requested
|
||||
the video will then be restarted at its previous position */
|
||||
set_resume_position_seconds(airplay_video, position);
|
||||
} else {
|
||||
logger_log(raop->logger, LOGGER_WARNING, "playlistRemove uuid %s does not match current_video\n", remove_uuid);
|
||||
}
|
||||
@@ -575,7 +570,7 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
logger_log(raop->logger, LOGGER_ERR, "FIXME: playlistInsert is not yet implemented");
|
||||
|
||||
} else if (!strcmp(type, "unhandledURLResponse")) {
|
||||
/* handling type "unhandledURLResponse" (case 1)*/
|
||||
/* handling type "unhandledURLResponse" */
|
||||
uint_val = 0;
|
||||
int fcup_response_datalen = 0;
|
||||
|
||||
@@ -709,21 +704,6 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
|
||||
"start position in seconds". Once this request is received by the Sever, the Server sends a POST /event
|
||||
"FCUP Request" request to the Client on the reverse http channel, to request the HLS Master Playlist */
|
||||
|
||||
static void
|
||||
delete_short_playlist(raop_t *raop, int id) {
|
||||
if (!raop->airplay_video[id]) {
|
||||
return;
|
||||
}
|
||||
float duration = get_duration(raop->airplay_video[id]);
|
||||
if (duration < (float) MIN_STORED_AIRPLAY_VIDEO_DURATION_SECONDS ) { //likely to be an advertisement
|
||||
logger_log(raop->logger, LOGGER_INFO,
|
||||
"deleting playlist playback_uuid %s duration (seconds) %f",
|
||||
get_playback_uuid(raop->airplay_video[id]), duration);
|
||||
airplay_video_destroy(raop->airplay_video[id]);
|
||||
raop->airplay_video[id] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *response,
|
||||
char **response_data, int *response_datalen) {
|
||||
@@ -782,15 +762,11 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
int id = -1;
|
||||
id = get_playlist_by_uuid(raop, playback_uuid);
|
||||
|
||||
/* check if playlist is already downloaded and stored (may have been interruoted by advertisements ) */
|
||||
/* check if playlist is already downloaded and stored (may have been interrupted by advertisements ) */
|
||||
if (id >= 0) {
|
||||
//printf("====use EXISTING airplay_video[%d] %p %s %s\n", id, raop->airplay_video[id], playback_uuid, get_playback_uuid(raop->airplay_video[id]));
|
||||
//printf("====use EXISTING airplay_video[%d] %p %s %s\n", id, raop->airplay_video[id], playback_uuid, get_playback_uuid(raop->airplay_video[id]));
|
||||
plist_mem_free(playback_uuid);
|
||||
plist_free(req_root_node);
|
||||
int current_video = raop->current_video;
|
||||
if (current_video >= 0 && current_video != id) {
|
||||
delete_short_playlist(raop, current_video);
|
||||
}
|
||||
raop->current_video = id;
|
||||
airplay_video = hls_get_current_video(raop);
|
||||
assert(airplay_video);
|
||||
@@ -803,18 +779,26 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
resume_pos > start_pos ? resume_pos : start_pos);
|
||||
return;
|
||||
}
|
||||
|
||||
/* remove short stort playlists (probably advertisements */
|
||||
|
||||
/* initialize a new playlist (airplay_video structure) */
|
||||
/* first delete any short stored playlists (probably advertisements */
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||
if (raop->airplay_video[i]) {
|
||||
delete_short_playlist(raop, i);
|
||||
}
|
||||
if (raop->airplay_video[i]) {
|
||||
count++;
|
||||
float duration = get_duration(raop->airplay_video[i]);
|
||||
if (duration < (float) MIN_STORED_AIRPLAY_VIDEO_DURATION_SECONDS ) { //likely to be an advertisement
|
||||
logger_log(raop->logger, LOGGER_INFO,
|
||||
"deleting playlist playback_uuid %s duration (seconds) %f",
|
||||
get_playback_uuid(raop->airplay_video[i]), duration);
|
||||
raop_destroy_airplay_video(raop, i);
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert (count < MAX_AIRPLAY_VIDEO);
|
||||
assert(id == -1);
|
||||
/* initialize new airplay_video structure to hold playlist */
|
||||
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||
if (raop->airplay_video[i]) {
|
||||
@@ -823,23 +807,16 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
if (id == -1) {
|
||||
logger_log(raop->logger, LOGGER_ERR, "no unused airplay_video structures are available"
|
||||
" MAX_AIRPLAY_VIDEO = %d\n", MAX_AIRPLAY_VIDEO);
|
||||
exit(1);
|
||||
}
|
||||
assert(id >= 0);
|
||||
|
||||
raop->current_video = id;
|
||||
raop->airplay_video[id] = airplay_video_init(raop, raop->port, raop->lang);
|
||||
airplay_video = hls_get_current_video(raop);
|
||||
if (airplay_video) {
|
||||
set_playback_uuid(airplay_video, playback_uuid, strlen(playback_uuid));
|
||||
plist_mem_free (playback_uuid);
|
||||
count++;
|
||||
} else {
|
||||
logger_log(raop->logger, LOGGER_ERR, "failed to allocate airplay_video[%d]\n", id);
|
||||
exit(-1);
|
||||
}
|
||||
assert(airplay_video);
|
||||
set_apple_session_id(airplay_video, apple_session_id, strlen(apple_session_id));
|
||||
set_playback_uuid(airplay_video, playback_uuid, strlen(playback_uuid));
|
||||
plist_mem_free (playback_uuid);
|
||||
count++;
|
||||
|
||||
/* ensure that space will always be available for adding future playlists */
|
||||
|
||||
@@ -859,7 +836,6 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
get_duration(raop->airplay_video[i]));
|
||||
}
|
||||
#endif
|
||||
set_apple_session_id(airplay_video, apple_session_id, strlen(apple_session_id));
|
||||
|
||||
plist_t req_content_location_node = plist_dict_get_item(req_root_node, "Content-Location");
|
||||
if (!req_content_location_node) {
|
||||
@@ -890,6 +866,7 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
|
||||
}
|
||||
set_start_position_seconds(airplay_video, (float) start_position_seconds);
|
||||
|
||||
/* we only support HLS if the playback location is terminated by "/master.m3u8" */
|
||||
const char *uri_suffix = strstr(playback_location, "/master.m3u8");
|
||||
if (!uri_suffix) {
|
||||
logger_log(raop->logger, LOGGER_ERR, "Content-Location has unsupported form:\n%s\n", playback_location);
|
||||
|
||||
35
lib/raop.c
35
lib/raop.c
@@ -1,5 +1,4 @@
|
||||
/**
|
||||
* Copyright (C) 2011-2012 Juho Vähä-Herttua
|
||||
/** Copyright (C) 2011-2012 Juho Vähä-Herttua
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -85,7 +84,6 @@ struct raop_s {
|
||||
/* place to store media_data_store */
|
||||
airplay_video_t *airplay_video[MAX_AIRPLAY_VIDEO];
|
||||
int current_video;
|
||||
int interrupted_video;
|
||||
|
||||
/* activate support for HLS live streaming */
|
||||
bool hls_support;
|
||||
@@ -248,7 +246,7 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
|
||||
logger_log(raop->logger, LOGGER_INFO, "*****\"nohold\" feature: switch to new connection request from %s", ipaddr);
|
||||
httpd_remove_known_connections(raop->httpd);
|
||||
if (raop->callbacks.video_reset) {
|
||||
raop->callbacks.video_reset(raop->callbacks.cls, false, true);
|
||||
raop->callbacks.video_reset(raop->callbacks.cls, RESET_TYPE_NOHOLD);
|
||||
}
|
||||
} else {
|
||||
logger_log(raop->logger, LOGGER_WARNING, "rejecting new connection request from %s", ipaddr);
|
||||
@@ -601,7 +599,6 @@ raop_init(raop_callbacks_t *callbacks) {
|
||||
|
||||
/* initialize airplay_video */
|
||||
raop->current_video = -1;
|
||||
raop->interrupted_video = -1;
|
||||
for (int i= 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||
raop->airplay_video[i] = NULL;
|
||||
}
|
||||
@@ -839,28 +836,20 @@ void raop_destroy_airplay_video(raop_t *raop, int id) {
|
||||
if (raop->airplay_video[i]) {
|
||||
airplay_video_destroy(raop->airplay_video[i]);
|
||||
raop->airplay_video[i] = NULL;
|
||||
if (i == raop->current_video) {
|
||||
raop->current_video = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void raop_playlist_remove(raop_t *raop, void *opaque, float position_seconds) {
|
||||
airplay_video_t *airplay_video = (airplay_video_t *) opaque;
|
||||
|
||||
int id = -1;
|
||||
for (int i = 0; i < MAX_AIRPLAY_VIDEO; i++) {
|
||||
if (airplay_video == raop->airplay_video[i]) {
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id >= 0) {
|
||||
set_resume_position_seconds(airplay_video, position_seconds);
|
||||
raop->current_video = -1;
|
||||
float pos = get_resume_position_seconds(airplay_video);
|
||||
assert(pos == position_seconds);
|
||||
} else {
|
||||
logger_log(raop->logger, LOGGER_ERR, "raop_playlist_remove: failed to identify removed_video");
|
||||
exit(0);
|
||||
}
|
||||
void raop_handle_eos(raop_t *raop) {
|
||||
int id = raop->current_video;
|
||||
assert (id >= 0);
|
||||
raop_destroy_airplay_video(raop, id);
|
||||
raop->current_video = -1;
|
||||
/* reset video without deleting raop->airplay_video */
|
||||
raop->callbacks.video_reset(raop->callbacks.cls, RESET_TYPE_HLS_EOS);
|
||||
}
|
||||
|
||||
uint64_t get_local_time() {
|
||||
|
||||
10
lib/raop.h
10
lib/raop.h
@@ -60,6 +60,13 @@ typedef enum video_codec_e {
|
||||
VIDEO_CODEC_H265
|
||||
} video_codec_t;
|
||||
|
||||
typedef enum reset_type_e {
|
||||
RESET_TYPE_NOHOLD,
|
||||
RESET_TYPE_RTP_SHUTDOWN,
|
||||
RESET_TYPE_HLS_SHUTDOWN,
|
||||
RESET_TYPE_HLS_EOS
|
||||
} reset_type_t;
|
||||
|
||||
struct raop_callbacks_s {
|
||||
void* cls;
|
||||
|
||||
@@ -69,7 +76,7 @@ struct raop_callbacks_s {
|
||||
void (*video_resume)(void *cls);
|
||||
void (*conn_feedback) (void *cls);
|
||||
void (*conn_reset) (void *cls, int reason);
|
||||
void (*video_reset) (void *cls, bool hls_shutdown, bool nohold);
|
||||
void (*video_reset) (void *cls, reset_type_t reset_type);
|
||||
|
||||
|
||||
/* Optional but recommended callback functions (probably not optional, check this)*/
|
||||
@@ -112,6 +119,7 @@ raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const c
|
||||
airplay_video_t *airplay_video_init(raop_t *raop, unsigned short port, const char *lang);
|
||||
char *raop_get_lang(raop_t *raop);
|
||||
uint64_t get_local_time();
|
||||
void raop_handle_eos(raop_t *raop);
|
||||
|
||||
RAOP_API raop_t *raop_init(raop_callbacks_t *callbacks);
|
||||
RAOP_API int raop_init2(raop_t *raop, int nohold, const char *device_id, const char *keyfile);
|
||||
|
||||
@@ -1278,7 +1278,7 @@ raop_handler_teardown(raop_conn_t *conn,
|
||||
}
|
||||
}
|
||||
} else if (teardown_110) {
|
||||
raop->callbacks.video_reset(raop->callbacks.cls, false, false);
|
||||
raop->callbacks.video_reset(raop->callbacks.cls, RESET_TYPE_RTP_SHUTDOWN);
|
||||
if (conn->raop_rtp_mirror) {
|
||||
/* Stop our video RTP session */
|
||||
raop_rtp_mirror_stop(conn->raop_rtp_mirror);
|
||||
@@ -1296,7 +1296,7 @@ raop_handler_teardown(raop_conn_t *conn,
|
||||
/* shut down any HLS connections */
|
||||
int hls_count = httpd_count_connection_type(raop->httpd, CONNECTION_TYPE_HLS);
|
||||
if (hls_count) {
|
||||
raop->callbacks.video_reset(raop->callbacks.cls, true, false);
|
||||
raop->callbacks.video_reset(raop->callbacks.cls, RESET_TYPE_HLS_SHUTDOWN);
|
||||
}
|
||||
}
|
||||
if (raop->callbacks.conn_teardown) {
|
||||
|
||||
@@ -852,7 +852,7 @@ raop_rtp_mirror_thread(void *arg)
|
||||
if (unsupported_codec) {
|
||||
closesocket(raop_rtp_mirror->mirror_data_sock);
|
||||
raop_rtp_mirror_stop(raop_rtp_mirror);
|
||||
raop_rtp_mirror->callbacks.video_reset(raop_rtp_mirror->callbacks.cls, false, false);
|
||||
raop_rtp_mirror->callbacks.video_reset(raop_rtp_mirror->callbacks.cls, RESET_TYPE_RTP_SHUTDOWN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
37
uxplay.cpp
37
uxplay.cpp
@@ -639,8 +639,7 @@ static gboolean video_eos_watch_callback (gpointer loop) {
|
||||
/* HLS video has sent EOS */
|
||||
LOGI("hls video has sent EOS");
|
||||
video_renderer_hls_ready();
|
||||
video_renderer_start();
|
||||
/* if raop->interrupted_video exists, we should reset video without deleting raop->airplay_video */
|
||||
raop_handle_eos(raop);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -2056,33 +2055,33 @@ static bool check_blocked_client(char *deviceid) {
|
||||
|
||||
// Server callbacks
|
||||
|
||||
extern "C" void video_reset(void *cls, bool hls_shutdown, bool nohold) {
|
||||
extern "C" void video_reset(void *cls, reset_type_t type) {
|
||||
LOGD("video_reset");
|
||||
if (use_video) {
|
||||
video_renderer_stop();
|
||||
}
|
||||
if (hls_shutdown) {
|
||||
if (hls_support && (type == RESET_TYPE_HLS_SHUTDOWN || type == RESET_TYPE_NOHOLD)) {
|
||||
url.erase();
|
||||
raop_destroy_airplay_video(raop, -1);
|
||||
}
|
||||
if (type == RESET_TYPE_HLS_SHUTDOWN) {
|
||||
raop_remove_hls_connections(raop);
|
||||
preserve_connections = true;
|
||||
} else if (nohold) {
|
||||
if (use_video) {
|
||||
/* reset the video renderer immediately to avoid a timing issue if we wait for main_loop to reset */
|
||||
video_renderer_destroy();
|
||||
video_renderer_init(render_logger, server_name.c_str(), videoflip, video_parser.c_str(), rtp_pipeline.c_str(),
|
||||
video_decoder.c_str(), video_converter.c_str(), videosink.c_str(),
|
||||
videosink_options.c_str(), fullscreen, video_sync, h265_support,
|
||||
render_coverart, playbin_version, NULL);
|
||||
video_renderer_start();
|
||||
}
|
||||
if (hls_support && !url.empty()) {
|
||||
url.erase();
|
||||
raop_destroy_airplay_video(raop, -1);
|
||||
}
|
||||
}
|
||||
if (use_video && (type == RESET_TYPE_NOHOLD || type == RESET_TYPE_HLS_EOS)) {
|
||||
/* reset the video renderer immediately to avoid a timing issue if we wait for main_loop to reset */
|
||||
video_renderer_destroy();
|
||||
video_renderer_init(render_logger, server_name.c_str(), videoflip, video_parser.c_str(), rtp_pipeline.c_str(),
|
||||
video_decoder.c_str(), video_converter.c_str(), videosink.c_str(),
|
||||
videosink_options.c_str(), fullscreen, video_sync, h265_support,
|
||||
render_coverart, playbin_version, NULL);
|
||||
video_renderer_start();
|
||||
close_window = false; // we already closed the window
|
||||
}
|
||||
if (type == RESET_TYPE_NOHOLD) {
|
||||
preserve_connections = false; //we already closed all other connections
|
||||
}
|
||||
|
||||
remote_clock_offset = 0;
|
||||
relaunch_video = true;
|
||||
reset_loop = true;
|
||||
@@ -2400,7 +2399,7 @@ extern "C" void audio_set_coverart(void *cls, const void *buffer, int buflen) {
|
||||
|
||||
extern "C" void audio_stop_coverart_rendering(void *cls) {
|
||||
if (render_coverart) {
|
||||
video_reset(cls, false, false);
|
||||
video_reset(cls, RESET_TYPE_RTP_SHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user