Begin to get SPS to give a unique shm interface name to nqptp. Also clang format
This commit is contained in:
@@ -152,7 +152,7 @@ typedef struct {
|
||||
int mqtt_publish_cover;
|
||||
int mqtt_enable_remote;
|
||||
#endif
|
||||
uint8_t hw_addr[8]; // only needs 6 but 8 is handy when converting this to a number
|
||||
uint8_t hw_addr[8]; // only needs 6 but 8 is handy when converting this to a number
|
||||
int port;
|
||||
int udp_port_base;
|
||||
int udp_port_range;
|
||||
@@ -302,6 +302,7 @@ typedef struct {
|
||||
char *airplay_device_id; // for the Bonjour advertisement and the GETINFO PList
|
||||
char *airplay_pin; // non-NULL, 4 char PIN, if required for pairing
|
||||
char *airplay_pi; // UUID in the Bonjour advertisement and the GETINFO Plist
|
||||
char *nqptp_shared_memory_interface_name; // client name for nqptp service
|
||||
#endif
|
||||
} shairport_cfg;
|
||||
|
||||
|
||||
@@ -199,7 +199,6 @@ void mqtt_process_metadata(uint32_t type, uint32_t code, char *data, uint32_t le
|
||||
case 'svip':
|
||||
mqtt_publish("server_ip", data, length);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,12 @@
|
||||
#ifndef NQPTP_SHM_STRUCTURES_H
|
||||
#define NQPTP_SHM_STRUCTURES_H
|
||||
|
||||
#define STORAGE_ID "/nqptp"
|
||||
#define MAX_CLOCKS 32
|
||||
#define NQPTP_SHM_STRUCTURES_VERSION 6
|
||||
#define NQPTP_SHM_STRUCTURES_VERSION 7
|
||||
#define NQPTP_CONTROL_PORT 9000
|
||||
|
||||
// the control port will accept a UDP packet with the first letter being:
|
||||
// "T", followed by a space and then a space-delimited
|
||||
// list of ip numbers, either IPv4 or IPv6
|
||||
// The control port will accept a UDP packet with the first letter being:
|
||||
// "T", followed by the name of the shared memory interface, followed by
|
||||
// a space and then a space-delimited list of ip numbers, either IPv4 or IPv6
|
||||
// the whole not to exceed 4096 characters in total
|
||||
// The IPs will become the new list of timing peers, replacing any previous
|
||||
|
||||
@@ -37,7 +35,6 @@
|
||||
struct shm_structure {
|
||||
pthread_mutex_t shm_mutex; // for safely accessing the structure
|
||||
uint16_t version; // check this is equal to NQPTP_SHM_STRUCTURES_VERSION
|
||||
uint32_t flags; // unused
|
||||
uint64_t master_clock_id; // the current master clock
|
||||
char master_clock_ip[64]; // where it's coming from
|
||||
uint64_t local_time; // the time when the offset was calculated
|
||||
|
||||
@@ -1064,21 +1064,23 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
int64_t lt = conn->first_packet_time_to_play - local_time_now;
|
||||
|
||||
if (lt < 130000000) {
|
||||
debug(1, "Connection %d: Short lead time for first frame %" PRId64 ": %f seconds. Flushing 0.5 seconds",
|
||||
conn->connection_number, conn->first_packet_timestamp, lt * 0.000000001);
|
||||
debug(1,
|
||||
"Connection %d: Short lead time for first frame %" PRId64
|
||||
": %f seconds. Flushing 0.5 seconds",
|
||||
conn->connection_number, conn->first_packet_timestamp, lt * 0.000000001);
|
||||
do_flush(conn->first_packet_timestamp + 5 * 4410, conn);
|
||||
} else {
|
||||
debug(2, "Connection %d: Lead time for first frame %" PRId64 ": %f seconds.",
|
||||
conn->connection_number, conn->first_packet_timestamp, lt * 0.000000001);
|
||||
conn->connection_number, conn->first_packet_timestamp, lt * 0.000000001);
|
||||
}
|
||||
/*
|
||||
int64_t lateness = local_time_now - conn->first_packet_time_to_play;
|
||||
if (lateness > 0) {
|
||||
debug(1, "First packet is %" PRId64 " nanoseconds late! Flushing 0.5 seconds",
|
||||
lateness);
|
||||
/*
|
||||
int64_t lateness = local_time_now - conn->first_packet_time_to_play;
|
||||
if (lateness > 0) {
|
||||
debug(1, "First packet is %" PRId64 " nanoseconds late! Flushing 0.5
|
||||
seconds", lateness);
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (conn->first_packet_time_to_play != 0) {
|
||||
|
||||
+36
-21
@@ -30,6 +30,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#ifdef COMPILE_FOR_FREEBSD
|
||||
@@ -148,27 +149,41 @@ int ptp_shm_interface_close() {
|
||||
}
|
||||
|
||||
void ptp_send_control_message_string(const char *msg) {
|
||||
debug(2, "Send control message to NQPTP: \"%s\"", msg);
|
||||
int s;
|
||||
unsigned short port = htons(NQPTP_CONTROL_PORT);
|
||||
struct sockaddr_in server;
|
||||
size_t full_message_size =
|
||||
strlen(config.nqptp_shared_memory_interface_name) + strlen(" ") + strlen(msg) + 1;
|
||||
char *full_message = malloc(full_message_size);
|
||||
if (full_message != NULL) {
|
||||
*full_message = '\0';
|
||||
snprintf(full_message, full_message_size, "%s %s", config.nqptp_shared_memory_interface_name,
|
||||
msg);
|
||||
debug(1, "Send control message to NQPTP: \"%s\"", full_message);
|
||||
int s;
|
||||
unsigned short port = htons(NQPTP_CONTROL_PORT);
|
||||
struct sockaddr_in server;
|
||||
|
||||
/* Create a datagram socket in the internet domain and use the
|
||||
* default protocol (UDP).
|
||||
*/
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
die("Can't open a socket to NQPTP");
|
||||
/* Create a datagram socket in the internet domain and use the
|
||||
* default protocol (UDP).
|
||||
*/
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
die("Can't open a socket to NQPTP");
|
||||
}
|
||||
|
||||
/* Set up the server name */
|
||||
server.sin_family = AF_INET; /* Internet Domain */
|
||||
server.sin_port = port; /* Server Port */
|
||||
server.sin_addr.s_addr = 0; /* Server's Address */
|
||||
|
||||
/* Send the message in buf to the server */
|
||||
if (sendto(s, full_message, full_message_size, 0, (struct sockaddr *)&server, sizeof(server)) <
|
||||
0) {
|
||||
die("error sending timing_peer_list to NQPTP");
|
||||
}
|
||||
/* Deallocate the socket */
|
||||
close(s);
|
||||
|
||||
/* deallocate the message string */
|
||||
free(full_message);
|
||||
} else {
|
||||
debug(1, "Couldn't allocate memory to prepare a qualified ptp control message string.");
|
||||
}
|
||||
|
||||
/* Set up the server name */
|
||||
server.sin_family = AF_INET; /* Internet Domain */
|
||||
server.sin_port = port; /* Server Port */
|
||||
server.sin_addr.s_addr = 0; /* Server's Address */
|
||||
|
||||
/* Send the message in buf to the server */
|
||||
if (sendto(s, msg, (strlen(msg) + 1), 0, (struct sockaddr *)&server, sizeof(server)) < 0) {
|
||||
die("error sending timing_peer_list to NQPTP");
|
||||
}
|
||||
/* Deallocate the socket */
|
||||
close(s);
|
||||
}
|
||||
|
||||
@@ -290,8 +290,8 @@ void *rtp_control_receiver(void *arg) {
|
||||
obfp += 2;
|
||||
};
|
||||
*obfp = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
// get raw timestamp information
|
||||
// I think that a good way to understand these timestamps is that
|
||||
// (1) the rtlt below is the timestamp of the frame that should be playing at the
|
||||
@@ -302,19 +302,19 @@ void *rtp_control_receiver(void *arg) {
|
||||
// Thus, (3) the latency can be calculated by subtracting the second from the
|
||||
// first.
|
||||
// There must be more to it -- there something missing.
|
||||
|
||||
|
||||
// In addition, it seems that if the value of the short represented by the second
|
||||
// pair of bytes in the packet is 7
|
||||
// then an extra time lag is expected to be added, presumably by
|
||||
// the AirPort Express.
|
||||
|
||||
|
||||
// Best guess is that this delay is 11,025 frames.
|
||||
|
||||
|
||||
uint32_t rtlt = nctohl(&packet[4]); // raw timestamp less latency
|
||||
uint32_t rt = nctohl(&packet[16]); // raw timestamp
|
||||
|
||||
|
||||
uint32_t fl = nctohs(&packet[2]); //
|
||||
|
||||
|
||||
debug(1,"Sync Packet of %d bytes received: \"%s\", flags: %d, timestamps %u and %u,
|
||||
giving a latency of %d frames.",plen,obf,fl,rt,rtlt,rt-rtlt);
|
||||
//debug(1,"Monotonic timestamps are: %" PRId64 " and %" PRId64 "
|
||||
|
||||
@@ -536,7 +536,7 @@ void release_play_lock(rtsp_conn_info *conn) {
|
||||
}
|
||||
|
||||
int get_play_lock(rtsp_conn_info *conn) {
|
||||
debug(2, "Connection %d: request play lock.", conn->connection_number);
|
||||
debug(2, "Connection %d: request play lock.", conn->connection_number);
|
||||
// returns -1 if it failed, 0 if it succeeded and 1 if it succeeded but
|
||||
// interrupted an existing session
|
||||
int response = 0;
|
||||
@@ -1176,9 +1176,9 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
|
||||
ssize_t buflen = 4096;
|
||||
#ifdef CONFIG_METADATA
|
||||
if ((config.metadata_enabled != 0) && (config.get_coverart != 0))
|
||||
buflen = 1024 * 256; // big enough for typical picture data, which will be base64 encoded
|
||||
buflen = 1024 * 256; // big enough for typical picture data, which will be base64 encoded
|
||||
#endif
|
||||
int release_buffer = 0; // on exit, don't deallocate the buffer if everything was okay
|
||||
int release_buffer = 0; // on exit, don't deallocate the buffer if everything was okay
|
||||
char *buf = malloc(buflen + 1); // add a NUL at the end
|
||||
if (!buf) {
|
||||
warn("Connection %d: rtsp_read_request: can't get a buffer.", conn->connection_number);
|
||||
@@ -1348,9 +1348,12 @@ int msg_write_response(rtsp_conn_info *conn, rtsp_message *resp) {
|
||||
char *string;
|
||||
};
|
||||
|
||||
struct response_t responses[] = {
|
||||
{200, "OK"}, {400, "Bad Request"}, {403, "Unauthorized"}, {451, "Unavailable"}, {501, "Not Implemented"}};
|
||||
// 451 is really "Unavailable For Legal Reasons"!
|
||||
struct response_t responses[] = {{200, "OK"},
|
||||
{400, "Bad Request"},
|
||||
{403, "Unauthorized"},
|
||||
{451, "Unavailable"},
|
||||
{501, "Not Implemented"}};
|
||||
// 451 is really "Unavailable For Legal Reasons"!
|
||||
int found = 0;
|
||||
char *respcode_text = "Unauthorized";
|
||||
for (i = 0; i < sizeof(responses) / sizeof(struct response_t); i++) {
|
||||
@@ -2302,7 +2305,8 @@ void handle_command(__attribute__((unused)) rtsp_conn_info *conn, rtsp_message *
|
||||
uint64_t length = 0;
|
||||
plist_get_data_val(the_item, &buff, &length);
|
||||
// debug(1,"Item %d, length: %" PRId64 " bytes", item_number, length);
|
||||
if ((buff != NULL) && (length >= strlen("bplist00")) && (strstr(buff, "bplist00") == buff)) {
|
||||
if ((buff != NULL) && (length >= strlen("bplist00")) &&
|
||||
(strstr(buff, "bplist00") == buff)) {
|
||||
// debug(1,"Contains a plist.");
|
||||
plist_t subsidiary_plist = NULL;
|
||||
plist_from_memory(buff, length, &subsidiary_plist);
|
||||
@@ -2756,9 +2760,9 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
|
||||
memset(buf, 0, sizeof(buf));
|
||||
inet_ntop(AF_INET6, (void *)&addr6->sin6_addr, buf, sizeof(buf));
|
||||
// don't insist there are in the same subnet...
|
||||
//if (!different) {
|
||||
// debug(1, "%s is in the same subnet as %s.", buf, ip_address);
|
||||
plist_array_append_item(addresses, plist_new_string(buf));
|
||||
// if (!different) {
|
||||
// debug(1, "%s is in the same subnet as %s.", buf, ip_address);
|
||||
plist_array_append_item(addresses, plist_new_string(buf));
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -2773,12 +2777,12 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
|
||||
// struct sockaddr_in *mask = (struct sockaddr_in *)(iap->ifa_netmask);
|
||||
// if ((addr->sin_addr.s_addr & mask->sin_addr.s_addr) ==
|
||||
// (pa4->sin_addr.s_addr & mask->sin_addr.s_addr)) {
|
||||
char buf[32];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
inet_ntop(AF_INET, (void *)&addr->sin_addr, buf, sizeof(buf));
|
||||
// no longer insisting they are in the same subnet
|
||||
// debug(1, "%s is in the same subnet as %s.", buf, ip_address);
|
||||
plist_array_append_item(addresses, plist_new_string(buf));
|
||||
char buf[32];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
inet_ntop(AF_INET, (void *)&addr->sin_addr, buf, sizeof(buf));
|
||||
// no longer insisting they are in the same subnet
|
||||
// debug(1, "%s is in the same subnet as %s.", buf, ip_address);
|
||||
plist_array_append_item(addresses, plist_new_string(buf));
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -2838,8 +2842,6 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
|
||||
get_category_string(conn->airplay_stream_category));
|
||||
mdns_update(NULL, secondary_txt_records);
|
||||
|
||||
|
||||
|
||||
resp->respcode = 200;
|
||||
} else {
|
||||
debug(1, "SETUP on Connection %d: PTP setup -- no timingPeerInfo plist.",
|
||||
@@ -2875,8 +2877,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
|
||||
|
||||
plist_dict_set_item(setupResponsePlist, "eventPort",
|
||||
plist_new_uint(conn->local_event_port));
|
||||
plist_dict_set_item(setupResponsePlist, "timingPort",
|
||||
plist_new_uint(0));
|
||||
plist_dict_set_item(setupResponsePlist, "timingPort", plist_new_uint(0));
|
||||
cancel_all_RTSP_threads(
|
||||
remote_control_stream,
|
||||
conn->connection_number); // kill all the other remote control listeners
|
||||
|
||||
+37
-17
@@ -289,7 +289,8 @@ void usage(char *progname) {
|
||||
#ifdef CONFIG_METADATA
|
||||
printf(" -M, --metadata-enable ask for metadata from the source and process it.\n");
|
||||
printf(" --metadata-pipename=PIPE send metadata to PIPE, e.g. "
|
||||
"--metadata-pipename=/tmp/%s-metadata.\n", config.appName);
|
||||
"--metadata-pipename=/tmp/%s-metadata.\n",
|
||||
config.appName);
|
||||
printf(" The default is /tmp/%s-metadata.\n", config.appName);
|
||||
printf(" -g, --get-coverart send cover art through the metadata pipe.\n");
|
||||
#endif
|
||||
@@ -1262,7 +1263,7 @@ int parse_options(int argc, char **argv) {
|
||||
strcat(temp_metadata_pipe_name, config.appName);
|
||||
strcat(temp_metadata_pipe_name, "-metadata");
|
||||
config.metadata_pipename = strdup(temp_metadata_pipe_name);
|
||||
debug(1,"default metadata_pipename is \"%s\".", temp_metadata_pipe_name);
|
||||
debug(1, "default metadata_pipename is \"%s\".", temp_metadata_pipe_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1320,7 +1321,7 @@ int parse_options(int argc, char **argv) {
|
||||
char temp_pid_dir[4096];
|
||||
strcpy(temp_pid_dir, "/var/run/");
|
||||
strcat(temp_pid_dir, config.appName);
|
||||
debug(1,"default pid filename is \"%s\".", temp_pid_dir);
|
||||
debug(1, "default pid filename is \"%s\".", temp_pid_dir);
|
||||
char *use_this_pid_dir = temp_pid_dir;
|
||||
#endif
|
||||
// debug(1,"config.piddir \"%s\".",config.piddir);
|
||||
@@ -1445,6 +1446,14 @@ void exit_function() {
|
||||
#ifdef CONFIG_AIRPLAY_2
|
||||
if (config.regtype2)
|
||||
free(config.regtype2);
|
||||
if (config.nqptp_shared_memory_interface_name)
|
||||
free(config.nqptp_shared_memory_interface_name);
|
||||
if (config.airplay_device_id)
|
||||
free(config.airplay_device_id);
|
||||
if (config.airplay_pin)
|
||||
free(config.airplay_pin);
|
||||
if (config.airplay_pi)
|
||||
free(config.airplay_pi);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
@@ -1462,6 +1471,7 @@ void exit_function() {
|
||||
config_destroy(config.cfg);
|
||||
if (config.appName)
|
||||
free(config.appName);
|
||||
|
||||
// probably should be freeing malloc'ed memory here, including strdup-created strings...
|
||||
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
@@ -1833,32 +1843,39 @@ int main(int argc, char **argv) {
|
||||
// use the start of the config.hw_addr and the PID to generate the default airplay_device_id
|
||||
uint64_t apid = nctoh64(config.hw_addr);
|
||||
apid = apid >> 16; // we only use the first 6 bytes but have imported 8.
|
||||
|
||||
|
||||
int64_t aid;
|
||||
|
||||
|
||||
// add the airplay_device_id_offset if provided
|
||||
if (config_lookup_int64(config.cfg, "general.airplay_device_id_offset", &aid)) {
|
||||
apid += aid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// replace the airplay_device_id with this, if provided
|
||||
if (config_lookup_int64(config.cfg, "general.airplay_device_id", &aid)) {
|
||||
apid = aid;
|
||||
}
|
||||
|
||||
char apids[6*2+5+1]; // six pairs of digits, 5 colons and a NUL
|
||||
apids[6*2+5] = 0; // NUL termination
|
||||
|
||||
char shared_memory_interface_name[256] = "";
|
||||
snprintf(shared_memory_interface_name, sizeof(shared_memory_interface_name), "/%s-%" PRIx64 "",
|
||||
config.appName, apid);
|
||||
debug(1, "smi name: \"%s\"", shared_memory_interface_name);
|
||||
|
||||
config.nqptp_shared_memory_interface_name = strdup(shared_memory_interface_name);
|
||||
|
||||
char apids[6 * 2 + 5 + 1]; // six pairs of digits, 5 colons and a NUL
|
||||
apids[6 * 2 + 5] = 0; // NUL termination
|
||||
int i;
|
||||
char hexchar[] = "0123456789abcdef";
|
||||
for (i = 5; i >= 0; i--) {
|
||||
apids[i*3+1] = hexchar[apid & 0xF];
|
||||
apids[i * 3 + 1] = hexchar[apid & 0xF];
|
||||
apid = apid >> 4;
|
||||
apids[i*3] = hexchar[apid & 0xF];
|
||||
apids[i * 3] = hexchar[apid & 0xF];
|
||||
apid = apid >> 4;
|
||||
if (i != 0)
|
||||
apids[i*3-1] = ':';
|
||||
apids[i * 3 - 1] = ':';
|
||||
}
|
||||
|
||||
|
||||
config.airplay_device_id = strdup(apids);
|
||||
|
||||
// now generate a UUID
|
||||
@@ -2017,9 +2034,12 @@ int main(int argc, char **argv) {
|
||||
debug(1, "run_this_after_play_ends action is \"%s\".", strnull(config.cmd_stop));
|
||||
debug(1, "wait-cmd status is %d.", config.cmd_blocking);
|
||||
debug(1, "run_this_before_play_begins may return output is %d.", config.cmd_start_returns_output);
|
||||
debug(1, "run_this_if_an_unfixable_error_is_detected action is \"%s\".", strnull(config.cmd_unfixable));
|
||||
debug(1, "run_this_before_entering_active_state action is \"%s\".", strnull(config.cmd_active_start));
|
||||
debug(1, "run_this_after_exiting_active_state action is \"%s\".", strnull(config.cmd_active_stop));
|
||||
debug(1, "run_this_if_an_unfixable_error_is_detected action is \"%s\".",
|
||||
strnull(config.cmd_unfixable));
|
||||
debug(1, "run_this_before_entering_active_state action is \"%s\".",
|
||||
strnull(config.cmd_active_start));
|
||||
debug(1, "run_this_after_exiting_active_state action is \"%s\".",
|
||||
strnull(config.cmd_active_stop));
|
||||
debug(1, "active_state_timeout is %f seconds.", config.active_state_timeout);
|
||||
debug(1, "mdns backend \"%s\".", strnull(config.mdns_name));
|
||||
debug(2, "userSuppliedLatency is %d.", config.userSuppliedLatency);
|
||||
|
||||
Reference in New Issue
Block a user