Lot of changes here.
1. check_classic_mac_basic.yml — update to latest macOS-latest 2. docker-on-push-tag-or-pr — dependant updates 3. FFTConvolver — fix a compilation warning when the DEBUG flag is turned off 4. Reorganise some source files — e.g. move most of the metadata stuff into a subdirectory 5. Remove unused special-purpose AirPlay 2 RC event handler. 6. Reorganise source files and source code relating to the standard event handler. 7. Check configuration settings a little more carefully to offer more meaningful diagnostics. 8. Add password to AirPlay 2 and reorganise initialisation to set AirPlay 2 flags accordingly. Also, remove redundant airplay_pin. 9. Remove redundant debug facility definitions from common.h 10. Make it possible to omit all the dacp stuff from a build. 11. Make it possible to omit metadata multicast from a build. 12. Add AP2-native metadata by setting bit 50 of features to true. 13. Improve stability when pre-empting an existing play session. 14. Fix a few compiler warnings in the pair_ap library. 15. Ensure that the audio format is known before starting synchronisation. 16. Improve handle_configure to set/clear a new config setting. Doesn’t seem to do anything… 17. Experimentally turn off bit 46 of AirPlay 2 features — seems to stop failing pair-verify attempts.
This commit is contained in:
+95
-26
@@ -23,6 +23,7 @@ SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
#include <ctype.h> // for isprint()
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
@@ -64,13 +65,9 @@ void debug_init(int level, int show_elapsed_time, int show_relative_time, int sh
|
||||
debugger_show_file_and_line = show_file_and_line;
|
||||
}
|
||||
|
||||
int debug_level() {
|
||||
return debuglev;
|
||||
};
|
||||
int debug_level() { return debuglev; };
|
||||
|
||||
void set_debug_level(int level) {
|
||||
debuglev = level;
|
||||
}
|
||||
void set_debug_level(int level) { debuglev = level; }
|
||||
|
||||
void increase_debug_level() {
|
||||
if (debuglev < 3)
|
||||
@@ -82,28 +79,15 @@ void decrease_debug_level() {
|
||||
debuglev--;
|
||||
}
|
||||
|
||||
int get_show_elapsed_time() {
|
||||
return debugger_show_elapsed_time;
|
||||
|
||||
}
|
||||
void set_show_elapsed_time(int setting) {
|
||||
debugger_show_elapsed_time = setting;
|
||||
}
|
||||
int get_show_relative_timel() {
|
||||
return debugger_show_relative_time;
|
||||
}
|
||||
int get_show_elapsed_time() { return debugger_show_elapsed_time; }
|
||||
void set_show_elapsed_time(int setting) { debugger_show_elapsed_time = setting; }
|
||||
int get_show_relative_timel() { return debugger_show_relative_time; }
|
||||
|
||||
void set_show_relative_time(int setting) {
|
||||
debugger_show_relative_time = setting;
|
||||
}
|
||||
void set_show_relative_time(int setting) { debugger_show_relative_time = setting; }
|
||||
|
||||
int get_show_file_and_line() {
|
||||
return debugger_show_file_and_line;
|
||||
}
|
||||
int get_show_file_and_line() { return debugger_show_file_and_line; }
|
||||
|
||||
void set_show_file_and_line(int setting) {
|
||||
debugger_show_file_and_line = setting;
|
||||
}
|
||||
void set_show_file_and_line(int setting) { debugger_show_file_and_line = setting; }
|
||||
|
||||
char *generate_preliminary_string(char *buffer, size_t buffer_length, double tss, double tsl,
|
||||
const char *filename, const int linenumber, const char *prefix) {
|
||||
@@ -244,10 +228,94 @@ void _inform(const char *filename, const int linenumber, const char *format, ...
|
||||
pthread_setcancelstate(oldState, NULL);
|
||||
}
|
||||
|
||||
|
||||
void _debug_print_buffer(const char *thefilename, const int linenumber, int level, void *ibuf,
|
||||
size_t buf_len) {
|
||||
|
||||
if (level > debuglev)
|
||||
return;
|
||||
|
||||
char *vbuf = (char *)ibuf; // this to stop the compiler complaining about indexing through a void
|
||||
unsigned int i;
|
||||
unsigned int hexdump_cols = 16;
|
||||
|
||||
// 0x123456: <hexdump_cols * 3> <hexdump_cols>\n
|
||||
const size_t buffer_size = 2 + 6 + 2 + hexdump_cols * 3 + hexdump_cols + 1;
|
||||
char *buf = malloc(buffer_size);
|
||||
if (buf) {
|
||||
//char *bufp = buf;
|
||||
// *buf = '\0';
|
||||
|
||||
// if (msg)
|
||||
// printf("%s", msg);
|
||||
|
||||
#define ADDR_PREFIX_LEN 10 // "0x000000: "
|
||||
|
||||
// each complete row
|
||||
for (i = 0; i < (buf_len / hexdump_cols); i++) {
|
||||
char *bufp = buf;
|
||||
*buf = '\0';
|
||||
snprintf(bufp, ADDR_PREFIX_LEN + 1,"0x%06x ", (i * hexdump_cols) & 0xFFFFFF);
|
||||
bufp += ADDR_PREFIX_LEN;
|
||||
|
||||
unsigned int j;
|
||||
for (j = 0; j < hexdump_cols; j++) {
|
||||
snprintf(bufp, strlen("12 ") + 1, "%02x ", 0xFF & vbuf[i * hexdump_cols + j]);
|
||||
bufp += strlen("12 ");
|
||||
}
|
||||
|
||||
for (j = 0; j < hexdump_cols; j++) {
|
||||
if (isprint(vbuf[i * hexdump_cols + j])) {
|
||||
*bufp = 0xFF & vbuf[i * hexdump_cols + j];
|
||||
} else {
|
||||
*bufp = '.';
|
||||
}
|
||||
bufp++;
|
||||
}
|
||||
*bufp = '\0';
|
||||
_debug(thefilename, linenumber, level, "%s", buf);
|
||||
}
|
||||
|
||||
size_t remaining = buf_len % hexdump_cols;
|
||||
if (remaining != 0) {
|
||||
size_t starting_offset = buf_len - remaining;
|
||||
char *bufp = buf;
|
||||
*buf = '\0';
|
||||
snprintf(bufp, ADDR_PREFIX_LEN + 1,"0x%06zx ", starting_offset & 0xFFFFFF);
|
||||
bufp += ADDR_PREFIX_LEN;
|
||||
|
||||
unsigned int j;
|
||||
for (j = 0; j < hexdump_cols; j++) {
|
||||
if (j < remaining) {
|
||||
snprintf(bufp, strlen("12 ") + 1, "%02x ", 0xFF & vbuf[starting_offset + j]);
|
||||
} else {
|
||||
snprintf(bufp, strlen(" ") + 1, " "); // fille with blanks
|
||||
}
|
||||
bufp += strlen("12 ");
|
||||
}
|
||||
|
||||
for (j = 0; j < remaining; j++) {
|
||||
if (isprint(vbuf[i * hexdump_cols + j])) {
|
||||
*bufp = 0xFF & vbuf[starting_offset + j];
|
||||
} else {
|
||||
*bufp = '.';
|
||||
}
|
||||
bufp++;
|
||||
}
|
||||
*bufp = '\0';
|
||||
_debug(thefilename, linenumber, level, "%s", buf);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void _debug_print_buffer(const char *thefilename, const int linenumber, int level, void *vbuf,
|
||||
size_t buf_len) {
|
||||
if (level > debuglev)
|
||||
return;
|
||||
new_debug_print_buffer(thefilename, linenumber, level, vbuf, buf_len);
|
||||
char *buf = (char *)vbuf;
|
||||
char *obf =
|
||||
malloc(buf_len * 4 + 1); // to be on the safe side -- 4 characters on average for each byte
|
||||
@@ -274,4 +342,5 @@ void _debug_print_buffer(const char *thefilename, const int linenumber, int leve
|
||||
_debug(thefilename, linenumber, level, "%s", obf);
|
||||
free(obf);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Generate a device-related UUID. This file is part of Shairport Sync
|
||||
* Copyright (c) Mike Brady 2026
|
||||
|
||||
* Modifications, including those associated with audio synchronization, multithreading and
|
||||
* metadata handling copyright (c) Mike Brady 2014--2025
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "generate_device_uuid.h"
|
||||
#include "definitions.h"
|
||||
|
||||
// user is responsible for deallocating returned string
|
||||
char *generate_device_uuid(const char *device_id) {
|
||||
uuid_t namespace_uuid;
|
||||
uuid_t derived_uuid;
|
||||
|
||||
uuid_parse(SHAIRPORT_SYNC_DEVICE_NAMESPACE, namespace_uuid);
|
||||
uuid_generate_sha1(derived_uuid, namespace_uuid, device_id, strlen(device_id));
|
||||
|
||||
char *uuid = malloc(UUID_STR_LEN + 1);
|
||||
uuid_unparse_lower(derived_uuid, uuid);
|
||||
return uuid;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
char *generate_device_uuid(const char *device_id);
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Generate a random UUID. This file is part of Shairport Sync
|
||||
* Copyright (c) Mike Brady 2026
|
||||
|
||||
* Modifications, including those associated with audio synchronization, multithreading and
|
||||
* metadata handling copyright (c) Mike Brady 2014--2025
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "generate_random_uuid.h"
|
||||
|
||||
// user is responsible for deallocating returned string
|
||||
char *generate_random_uuid() {
|
||||
// generate a UUID
|
||||
// from https://stackoverflow.com/questions/51053568/generating-a-random-uuid-in-c
|
||||
// with thanks
|
||||
uuid_t binuuid;
|
||||
uuid_generate_random(binuuid);
|
||||
|
||||
char *uuid = malloc(UUID_STR_LEN + 1); // leave space for the NUL at the end
|
||||
// Produces a UUID string at uuid consisting of lower-case letters
|
||||
uuid_unparse_lower(binuuid, uuid);
|
||||
return uuid;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _GENERATE_RANDOM_UUID_H
|
||||
#define _GENERATE_RANDOM_UUID_H
|
||||
|
||||
char *generate_random_uuid();
|
||||
|
||||
#endif // _GENERATE_RANDOM_UUID_H
|
||||
@@ -38,8 +38,8 @@ int eintr_checked_accept(int sockfd, struct sockaddr *addr,
|
||||
char errorstring[1024];
|
||||
strerror_r(errno, (char *)errorstring, sizeof(errorstring));
|
||||
debug(1,
|
||||
"error %d accept()ing a socketin ap2_event_receiver: \"%s\". (Note: error %d will be ignored.)",
|
||||
errno, errorstring, EINTR);
|
||||
"error %d accept()ing a socket %d: \"%s\". (Note: error %d will be ignored.)",
|
||||
errno, sockfd, errorstring, EINTR);
|
||||
}
|
||||
|
||||
} while((response == -1) && (errno == EINTR));
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <plist/plist.h>
|
||||
#include "rtsp_message_utilities.h"
|
||||
#include "../rtsp.h"
|
||||
#include "../common.h"
|
||||
|
||||
#ifdef HAVE_LIBPLIST_GE_2_3_0
|
||||
#define plist_from_memory(plist_data, length, plist) \
|
||||
plist_from_memory((plist_data), (length), (plist), NULL)
|
||||
#endif
|
||||
|
||||
// every time we want to retain or release a reference count, lock it with this
|
||||
// if a reference count is read as zero, it means the it's being deallocated.
|
||||
static pthread_mutex_t reference_counter_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int msg_indexes = 1;
|
||||
|
||||
void msg_retain(rtsp_message *msg) {
|
||||
int rc = debug_mutex_lock(&reference_counter_lock, 500000, 4);
|
||||
if (rc)
|
||||
debug(1, "Error %d locking reference counter lock", rc);
|
||||
if (msg > (rtsp_message *)0x00010000) {
|
||||
msg->referenceCount++;
|
||||
debug(4, "msg_free increment reference counter message %d to %d.", msg->index_number,
|
||||
msg->referenceCount);
|
||||
// debug(1,"msg_retain -- item %d reference count %d.", msg->index_number, msg->referenceCount);
|
||||
rc = pthread_mutex_unlock(&reference_counter_lock);
|
||||
if (rc)
|
||||
debug(1, "Error %d unlocking reference counter lock", rc);
|
||||
} else {
|
||||
debug(1, "invalid rtsp_message pointer 0x%" PRIxPTR " passed to retain", (uintptr_t)msg);
|
||||
}
|
||||
}
|
||||
|
||||
rtsp_message *msg_init(void) {
|
||||
// no thread cancellation points here
|
||||
int rc = debug_mutex_lock(&reference_counter_lock, 500000, 4);
|
||||
if (rc)
|
||||
debug(1, "Error %d locking reference counter lock", rc);
|
||||
|
||||
rtsp_message *msg = malloc(sizeof(rtsp_message));
|
||||
if (msg) {
|
||||
memset(msg, 0, sizeof(rtsp_message));
|
||||
msg->referenceCount = 1; // from now on, any access to this must be protected with the lock
|
||||
msg->index_number = msg_indexes++;
|
||||
debug(4, "msg_init message %d", msg->index_number);
|
||||
} else {
|
||||
die("msg_init -- can not allocate memory for rtsp_message %d.", msg_indexes);
|
||||
}
|
||||
// debug(1,"msg_init -- create item %d.", msg->index_number);
|
||||
|
||||
rc = pthread_mutex_unlock(&reference_counter_lock);
|
||||
if (rc)
|
||||
debug(1, "Error %d unlocking reference counter lock", rc);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
int msg_add_header(rtsp_message *msg, char *name, char *value) {
|
||||
if (msg->nheaders >= sizeof(msg->name) / sizeof(char *)) {
|
||||
warn("too many headers?!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
msg->name[msg->nheaders] = strdup(name);
|
||||
msg->value[msg->nheaders] = strdup(value);
|
||||
msg->nheaders++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *msg_get_header(rtsp_message *msg, char *name) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < msg->nheaders; i++)
|
||||
if (!strcasecmp(msg->name[i], name))
|
||||
return msg->value[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _debug_print_msg_headers(rtsp_conn_info *conn, const char *filename, const int linenumber, int level,
|
||||
rtsp_message *msg) {
|
||||
unsigned int i;
|
||||
if (conn != NULL) {
|
||||
if (msg->respcode != 0)
|
||||
_debug(filename, linenumber, level, "Connection: %d, Response Code: %d.", conn->connection_number, msg->respcode);
|
||||
for (i = 0; i < msg->nheaders; i++) {
|
||||
_debug(filename, linenumber, level, "Connection: %d, Type: \"%s\", content: \"%s\"", conn->connection_number, msg->name[i],
|
||||
msg->value[i]);
|
||||
}
|
||||
} else {
|
||||
if (msg->respcode != 0)
|
||||
_debug(filename, linenumber, level, " Response Code: %d.", msg->respcode);
|
||||
for (i = 0; i < msg->nheaders; i++) {
|
||||
_debug(filename, linenumber, level, " Type: \"%s\", content: \"%s\"", msg->name[i],
|
||||
msg->value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void msg_free(rtsp_message **msgh) {
|
||||
debug_mutex_lock(&reference_counter_lock, 1000, 0);
|
||||
if (*msgh > (rtsp_message *)0x00010000) {
|
||||
rtsp_message *msg = *msgh;
|
||||
msg->referenceCount--;
|
||||
if (msg->referenceCount)
|
||||
debug(4, "msg_free decrement reference counter message %d to %d", msg->index_number,
|
||||
msg->referenceCount);
|
||||
if (msg->referenceCount == 0) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < msg->nheaders; i++) {
|
||||
free(msg->name[i]);
|
||||
free(msg->value[i]);
|
||||
}
|
||||
if (msg->content)
|
||||
free(msg->content);
|
||||
// debug(1,"msg_free item %d -- free.",msg->index_number);
|
||||
uintptr_t index = (msg->index_number) & 0xFFFF;
|
||||
if (index == 0)
|
||||
index = 0x10000; // ensure it doesn't fold to zero.
|
||||
*msgh =
|
||||
(rtsp_message *)(index); // put a version of the index number of the freed message in here
|
||||
debug(4, "msg_free freed message %d", msg->index_number);
|
||||
free(msg);
|
||||
} else {
|
||||
// debug(1,"msg_free item %d -- decrement reference to
|
||||
// %d.",msg->index_number,msg->referenceCount);
|
||||
}
|
||||
} else if (*msgh != NULL) {
|
||||
debug(1,
|
||||
"msg_free: error attempting to free an allocated but already-freed rtsp_message, number "
|
||||
"%" PRIxPTR ".",
|
||||
(uintptr_t)*msgh);
|
||||
}
|
||||
debug_mutex_unlock(&reference_counter_lock, 0);
|
||||
}
|
||||
|
||||
int msg_handle_line(rtsp_message **pmsg, char *line) {
|
||||
rtsp_message *msg = *pmsg;
|
||||
|
||||
if (!msg) {
|
||||
msg = msg_init();
|
||||
*pmsg = msg;
|
||||
char *sp, *p;
|
||||
sp = NULL; // this is to quieten a compiler warning
|
||||
|
||||
debug(4, "RTSP/HTTP Message Received: \"%s\".", line);
|
||||
|
||||
p = strtok_r(line, " ", &sp);
|
||||
if (!p)
|
||||
goto fail;
|
||||
strncpy(msg->method, p, sizeof(msg->method) - 1);
|
||||
|
||||
p = strtok_r(NULL, " ", &sp);
|
||||
if (!p)
|
||||
goto fail;
|
||||
strncpy(msg->path, p, sizeof(msg->path) - 1);
|
||||
|
||||
p = strtok_r(NULL, " ", &sp);
|
||||
if (!p)
|
||||
goto fail;
|
||||
if ((strcmp(p, "RTSP/1.0") != 0) && (strcmp(p, "HTTP/1.1") != 0)) {
|
||||
debug(1, "Problem with Message: \"%s\"", p);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(line)) {
|
||||
char *p;
|
||||
p = strstr(line, ": ");
|
||||
if (!p) {
|
||||
warn("bad header: >>%s<<", line);
|
||||
goto fail;
|
||||
}
|
||||
*p = 0;
|
||||
p += 2;
|
||||
msg_add_header(msg, line, p);
|
||||
debug(4, " %s: %s.", line, p);
|
||||
return -1;
|
||||
} else {
|
||||
char *cl = msg_get_header(msg, "Content-Length");
|
||||
if (cl)
|
||||
return atoi(cl);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
fail:
|
||||
debug(1, "msg_handle_line fail");
|
||||
msg_free(pmsg);
|
||||
*pmsg = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AIRPLAY_2
|
||||
|
||||
int rtsp_message_contains_plist(rtsp_message *message) {
|
||||
int reply = 0; // assume there is no plist in the message
|
||||
if ((message->contentlength >= strlen("bplist00")) &&
|
||||
(strstr(message->content, "bplist00") == message->content))
|
||||
reply = 1;
|
||||
return reply;
|
||||
}
|
||||
|
||||
plist_t plist_from_rtsp_content(rtsp_message *message) {
|
||||
plist_t the_plist = NULL;
|
||||
if (rtsp_message_contains_plist(message)) {
|
||||
plist_from_memory(message->content, message->contentlength, &the_plist);
|
||||
}
|
||||
return the_plist;
|
||||
}
|
||||
|
||||
char *plist_as_xml_text(plist_t the_plist) {
|
||||
// caller must free the returned character buffer
|
||||
// convert it to xml format
|
||||
uint32_t size;
|
||||
char *plist_out = NULL;
|
||||
plist_to_xml(the_plist, &plist_out, &size);
|
||||
|
||||
// put it into a NUL-terminated string
|
||||
char *reply = malloc(size + 1);
|
||||
if (reply) {
|
||||
memcpy(reply, plist_out, size);
|
||||
reply[size] = '\0';
|
||||
}
|
||||
if (plist_out)
|
||||
free(plist_out);
|
||||
return reply;
|
||||
}
|
||||
|
||||
// caller must free the returned character buffer
|
||||
char *rtsp_plist_content(rtsp_message *message) {
|
||||
char *reply = NULL;
|
||||
// first, check if it has binary plist content
|
||||
if (rtsp_message_contains_plist(message))
|
||||
reply = plist_as_xml_text(plist_from_rtsp_content(message));
|
||||
return reply;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void _debug_log_rtsp_message(rtsp_conn_info *conn, const char *filename, const int linenumber, int level, char *prompt,
|
||||
rtsp_message *message) {
|
||||
if (level > debug_level())
|
||||
return;
|
||||
if ((prompt) && (*prompt != '\0')) // okay to pass NULL or an empty list...
|
||||
_debug(filename, linenumber, level, "%s", prompt);
|
||||
_debug_print_msg_headers(conn, filename, linenumber, level, message);
|
||||
#ifdef CONFIG_AIRPLAY_2
|
||||
char *plist_content = rtsp_plist_content(message);
|
||||
if (plist_content) {
|
||||
_debug(filename, linenumber, level, " Content length: %u. Content Plist (as XML):\n--\n%s--", message->contentlength, plist_content);
|
||||
free(plist_content);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
_debug(filename, linenumber, level, " No Content Plist. Content length: %u.",
|
||||
message->contentlength);
|
||||
if (message->contentlength > 0) {
|
||||
_debug_print_buffer(filename, linenumber, level, message->content, message->contentlength);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "player.h"
|
||||
#include "rtsp.h"
|
||||
|
||||
rtsp_message *msg_init(void);
|
||||
int msg_handle_line(rtsp_message **pmsg, char *line);
|
||||
int msg_add_header(rtsp_message *msg, char *name, char *value);
|
||||
char *msg_get_header(rtsp_message *msg, char *name);
|
||||
|
||||
void _debug_log_rtsp_message(rtsp_conn_info *conn, const char *filename, const int linenumber, int level, char *prompt,
|
||||
rtsp_message *message);
|
||||
|
||||
#define debug_log_rtsp_message_conn(conn, level, prompt, message) \
|
||||
_debug_log_rtsp_message(conn, __FILE__, __LINE__, level, prompt, message)
|
||||
|
||||
#define debug_log_rtsp_message(level, prompt, message) \
|
||||
_debug_log_rtsp_message(NULL, __FILE__, __LINE__, level, prompt, message)
|
||||
|
||||
|
||||
void _debug_print_msg_headers(rtsp_conn_info *conn, const char *filename, const int linenumber, int level,
|
||||
rtsp_message *msg);
|
||||
#define debug_print_msg_headers(level, message) \
|
||||
_debug_print_msg_headers(NULL, __FILE__, __LINE__, level, message)
|
||||
|
||||
#define debug_print_msg_headers_conn(level, message) \
|
||||
_debug_print_msg_headers(conn, __FILE__, __LINE__, level, message)
|
||||
|
||||
|
||||
#ifdef CONFIG_AIRPLAY_2
|
||||
int rtsp_message_contains_plist(rtsp_message *message);
|
||||
plist_t plist_from_rtsp_content(rtsp_message *message);
|
||||
#endif
|
||||
Reference in New Issue
Block a user