return TRUE;
}
+static gboolean on_handle_quit(ShairportSync *skeleton, GDBusMethodInvocation *invocation,
+ __attribute__((unused)) const gchar *command,
+ __attribute__((unused)) gpointer user_data) {
+ debug(1, "quit requested (native interface)");
+ shairport_sync_complete_quit(skeleton, invocation);
+ return TRUE;
+}
+
static gboolean on_handle_remote_command(ShairportSync *skeleton, GDBusMethodInvocation *invocation,
const gchar *command,
__attribute__((unused)) gpointer user_data) {
g_signal_connect(shairportSyncSkeleton, "notify::loudness-threshold",
G_CALLBACK(notify_loudness_threshold_callback), NULL);
+ g_signal_connect(shairportSyncSkeleton, "handle-quit",
+ G_CALLBACK(on_handle_quit), NULL);
+
g_signal_connect(shairportSyncSkeleton, "handle-remote-command",
G_CALLBACK(on_handle_remote_command), NULL);
// media_player2_player_set_volume(mprisPlayerPlayerSkeleton, metadata_store.speaker_volume);
}
+static gboolean on_handle_quit(MediaPlayer2 *skeleton, GDBusMethodInvocation *invocation,
+ __attribute__((unused)) gpointer user_data) {
+ debug(1,"quit requested (MPRIS interface).");
+ media_player2_complete_quit(skeleton, invocation);
+ return TRUE;
+}
+
static gboolean on_handle_next(MediaPlayer2Player *skeleton, GDBusMethodInvocation *invocation,
__attribute__((unused)) gpointer user_data) {
send_simple_dacp_command("nextitem");
media_player2_set_desktop_entry(mprisPlayerSkeleton, "shairport-sync");
media_player2_set_identity(mprisPlayerSkeleton, "Shairport Sync");
- media_player2_set_can_quit(mprisPlayerSkeleton, FALSE);
+ media_player2_set_can_quit(mprisPlayerSkeleton, TRUE);
media_player2_set_can_raise(mprisPlayerSkeleton, FALSE);
media_player2_set_has_track_list(mprisPlayerSkeleton, FALSE);
media_player2_set_supported_uri_schemes(mprisPlayerSkeleton, empty_string_array);
media_player2_player_set_can_seek(mprisPlayerPlayerSkeleton, FALSE);
media_player2_player_set_can_control(mprisPlayerPlayerSkeleton, TRUE);
+ g_signal_connect(mprisPlayerSkeleton, "handle-quit", G_CALLBACK(on_handle_quit), NULL);
+
g_signal_connect(mprisPlayerPlayerSkeleton, "handle-play", G_CALLBACK(on_handle_play), NULL);
g_signal_connect(mprisPlayerPlayerSkeleton, "handle-pause", G_CALLBACK(on_handle_pause), NULL);
g_signal_connect(mprisPlayerPlayerSkeleton, "handle-play-pause", G_CALLBACK(on_handle_play_pause),
if (padding)
*padding = 0;
- msg_add_header(resp, "Apple-Response", encoded);
+ msg_add_header(resp, "Apple-Response", encoded); // will be freed when the response is freed.
free(challresp);
free(encoded);
}
if (read(fd, random, sizeof(random)) != sizeof(random))
debug(1, "Error reading /dev/random");
close(fd);
- return base64_enc(random, 8);
+ return base64_enc(random, 8); // returns a pointer to malloc'ed memory
}
static int rtsp_auth(char **nonce, rtsp_message *req, rtsp_message *resp) {
return 1;
}
+void rtsp_conversation_thread_cleanup_function(void *arg) {
+ debug(1,"rtsp_conversation_thread_func_cleanup_function called.");
+ rtsp_conn_info *conn = (rtsp_conn_info *)arg;
+ if (conn->fd > 0)
+ close(conn->fd);
+ if (conn->auth_nonce) {
+ free(conn->auth_nonce);
+ conn->auth_nonce = NULL;
+ }
+ rtp_terminate(conn);
+ if (playing_conn == conn) {
+ debug(3, "Unlocking play lock on RTSP conversation thread %d.", conn->connection_number);
+ playing_conn = NULL;
+ pthread_mutex_unlock(&play_lock);
+ }
+
+ if (conn->dacp_id) {
+ free(conn->dacp_id);
+ conn->dacp_id = NULL;
+ }
+
+ debug(2, "Connection %d: RTSP thread terminated.", conn->connection_number);
+ conn->running = 0;
+
+ // remove flow control and mutexes
+ int rc = pthread_cond_destroy(&conn->flowcontrol);
+ if (rc)
+ debug(1, "Connection %d: error %d destroying flow control condition variable.",
+ conn->connection_number, rc);
+ rc = pthread_mutex_destroy(&conn->ab_mutex);
+ if (rc)
+ debug(1, "Connection %d: error %d destroying ab_mutex.", conn->connection_number, rc);
+ rc = pthread_mutex_destroy(&conn->flush_mutex);
+ if (rc)
+ debug(1, "Connection %d: error %d destroying flush_mutex.", conn->connection_number, rc);
+ }
+
+void msg_cleanup_function(void *arg) {
+ debug(1,"msg_cleanup_function called.");
+ msg_free((rtsp_message *)arg);
+}
+
static void *rtsp_conversation_thread_func(void *pconn) {
rtsp_conn_info *conn = pconn;
conn->connection_number, rc);
rtp_initialise(conn);
-
- rtsp_message *req, *resp;
- char *hdr, *auth_nonce = NULL;
+ char *hdr = NULL;
enum rtsp_read_request_response reply;
int rtsp_read_request_attempt_count = 1; // 1 means exit immediately
+ rtsp_message *req, *resp;
+ pthread_cleanup_push(rtsp_conversation_thread_cleanup_function,(void *)conn);
while (conn->stop == 0) {
int debug_level = 3; // for printing the request and response
- reply = rtsp_read_request(conn, &req);
+ reply = rtsp_read_request(conn,&req);
if (reply == rtsp_read_request_response_ok) {
+ pthread_cleanup_push(msg_cleanup_function,(void*)req);
+ resp = msg_init();
+ pthread_cleanup_push(msg_cleanup_function,(void*)resp);
+ resp->respcode = 400;
+
if (strcmp(req->method, "OPTIONS") !=
0) // the options message is very common, so don't log it until level 3
debug_level = 2;
debug(debug_level, "RTSP thread %d received an RTSP Packet of type \"%s\":",
conn->connection_number, req->method),
debug_print_msg_headers(debug_level, req);
- resp = msg_init();
- resp->respcode = 400;
apple_challenge(conn->fd, req, resp);
hdr = msg_get_header(req, "CSeq");
// msg_add_header(resp, "Audio-Jack-Status", "connected; type=analog");
msg_add_header(resp, "Server", "AirTunes/105.1");
- if ((conn->authorized == 1) || (rtsp_auth(&auth_nonce, req, resp)) == 0) {
+ if ((conn->authorized == 1) || (rtsp_auth(&conn->auth_nonce, req, resp)) == 0) {
conn->authorized = 1; // it must have been authorized or didn't need a password
struct method_handler *mh;
int method_selected = 0;
if (conn->stop == 0) {
msg_write_response(conn->fd, resp);
}
- msg_free(req);
- msg_free(resp);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
} else {
int tstop = 0;
if (reply == rtsp_read_request_response_immediate_shutdown_requested)
}
}
}
-
- if (conn->fd > 0)
- close(conn->fd);
- if (auth_nonce)
- free(auth_nonce);
- rtp_terminate(conn);
- if (playing_conn == conn) {
- debug(3, "Unlocking play lock on RTSP conversation thread %d.", conn->connection_number);
- playing_conn = NULL;
- pthread_mutex_unlock(&play_lock);
- }
-
- if (conn->dacp_id) {
- free(conn->dacp_id);
- conn->dacp_id = NULL;
- }
-
- debug(2, "Connection %d: RTSP thread terminated.", conn->connection_number);
- conn->running = 0;
-
- // remove flow control and mutexes
- rc = pthread_cond_destroy(&conn->flowcontrol);
- if (rc)
- debug(1, "Connection %d: error %d destroying flow control condition variable.",
- conn->connection_number, rc);
- rc = pthread_mutex_destroy(&conn->ab_mutex);
- if (rc)
- debug(1, "Connection %d: error %d destroying ab_mutex.", conn->connection_number, rc);
- rc = pthread_mutex_destroy(&conn->flush_mutex);
- if (rc)
- debug(1, "Connection %d: error %d destroying flush_mutex.", conn->connection_number, rc);
+ pthread_cleanup_pop(1);
pthread_exit(NULL);
}