raop : whitespace cleanup

This commit is contained in:
F. Duncanh
2025-08-08 11:03:47 -04:00
parent 3e1d83d7d6
commit c8ce350226
4 changed files with 233 additions and 231 deletions

View File

@@ -60,9 +60,9 @@ raop_handler_info(raop_conn_t *conn,
printf("qualifier: %s\n", qualifier_string);
txtAirPlay = true;
}
if (qualifier_string) {
if (qualifier_string) {
free(qualifier_string);
}
}
}
#endif
plist_t res_node = plist_new_dict();
@@ -265,9 +265,9 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
if (PLIST_IS_STRING(req_method_node) && PLIST_IS_STRING(req_user_node)) {
/* this is the initial pair-setup-pin request */
const char *salt;
char pin[6];
const char *pk;
int len_pk, len_salt;
char pin[6];
const char *pk;
int len_pk, len_salt;
char *method = NULL;
char *user = NULL;
plist_get_string_val(req_method_node, &method);
@@ -280,13 +280,13 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
return;
}
free (method);
plist_get_string_val(req_user_node, &user);
plist_get_string_val(req_user_node, &user);
logger_log(conn->raop->logger, LOGGER_INFO, "pair-setup-pin: device_id = %s", user);
snprintf(pin, 6, "%04u", conn->raop->pin % 10000);
if (conn->raop->pin < 10000) {
conn->raop->pin = 0;
}
int ret = srp_new_user(conn->session, conn->raop->pairing, (const char *) user,
int ret = srp_new_user(conn->session, conn->raop->pairing, (const char *) user,
(const char *) pin, &salt, &len_salt, &pk, &len_pk);
free(user);
plist_free(req_root_node);
@@ -302,19 +302,19 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
plist_to_bin(res_root_node, response_data, (uint32_t*) response_datalen);
plist_free(res_root_node);
http_response_add_header(response, "Content-Type", "application/x-apple-binary-plist");
return;
return;
} else if (PLIST_IS_DATA(req_pk_node) && PLIST_IS_DATA(req_proof_node)) {
/* this is the second part of pair-setup-pin request */
char *client_pk = NULL;
char *client_proof = NULL;
unsigned char proof[64];
memset(proof, 0, sizeof(proof));
unsigned char proof[64];
memset(proof, 0, sizeof(proof));
uint64_t client_pk_len;
uint64_t client_proof_len;
plist_get_data_val(req_pk_node, &client_pk, &client_pk_len);
plist_get_data_val(req_proof_node, &client_proof, &client_proof_len);
if (logger_debug) {
char *str = utils_data_to_string((const unsigned char *) client_proof, client_proof_len, 20);
char *str = utils_data_to_string((const unsigned char *) client_proof, client_proof_len, 20);
logger_log(conn->raop->logger, LOGGER_DEBUG, "client SRP6a proof <M> :\n%s", str);
free (str);
}
@@ -339,7 +339,7 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
plist_to_bin(res_root_node, response_data, (uint32_t*) response_datalen);
plist_free(res_root_node);
http_response_add_header(response, "Content-Type", "application/x-apple-binary-plist");
return;
return;
} else if (PLIST_IS_DATA(req_epk_node) && PLIST_IS_DATA(req_authtag_node)) {
/* this is the third part of pair-setup-pin request */
char *client_epk = NULL;
@@ -347,25 +347,25 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
uint64_t client_epk_len;
uint64_t client_authtag_len;
unsigned char epk[ED25519_KEY_SIZE];
unsigned char authtag[GCM_AUTHTAG_SIZE];
int ret;
unsigned char authtag[GCM_AUTHTAG_SIZE];
int ret;
plist_get_data_val(req_epk_node, &client_epk, &client_epk_len);
plist_get_data_val(req_authtag_node, &client_authtag, &client_authtag_len);
if (logger_debug) {
if (logger_debug) {
char *str = utils_data_to_string((const unsigned char *) client_epk, client_epk_len, 16);
logger_log(conn->raop->logger, LOGGER_DEBUG, "client_epk %d:\n%s\n", (int) client_epk_len, str);
str = utils_data_to_string((const unsigned char *) client_authtag, client_authtag_len, 16);
logger_log(conn->raop->logger, LOGGER_DEBUG, "client_authtag %d:\n%s\n", (int) client_authtag_len, str);
free (str);
}
}
memcpy(epk, client_epk, ED25519_KEY_SIZE);
memcpy(authtag, client_authtag, GCM_AUTHTAG_SIZE);
memcpy(epk, client_epk, ED25519_KEY_SIZE);
memcpy(authtag, client_authtag, GCM_AUTHTAG_SIZE);
free (client_authtag);
free (client_epk);
plist_free(req_root_node);
ret = srp_confirm_pair_setup(conn->session, conn->raop->pairing, epk, authtag);
ret = srp_confirm_pair_setup(conn->session, conn->raop->pairing, epk, authtag);
if (ret < 0) {
logger_log(conn->raop->logger, LOGGER_ERR, "pair-pin-setup (step 3): client authentication failed\n");
goto authentication_failed;
@@ -375,13 +375,13 @@ raop_handler_pairsetup_pin(raop_conn_t *conn,
pairing_session_set_setup_status(conn->session);
plist_t res_root_node = plist_new_dict();
plist_t res_epk_node = plist_new_data((const char *) epk, 32);
plist_t res_authtag_node = plist_new_data((const char *) authtag, 16);
plist_t res_authtag_node = plist_new_data((const char *) authtag, 16);
plist_dict_set_item(res_root_node, "epk", res_epk_node);
plist_dict_set_item(res_root_node, "authTag", res_authtag_node);
plist_to_bin(res_root_node, response_data, (uint32_t*) response_datalen);
plist_free(res_root_node);
http_response_add_header(response, "Content-Type", "application/x-apple-binary-plist");
return;
return;
}
authentication_failed:;
http_response_init(response, "RTSP/1.0", 470, "Client Authentication Failure");
@@ -439,58 +439,58 @@ raop_handler_pairverify(raop_conn_t *conn,
return;
}
switch (data[0]) {
case 1:
if (datalen != 4 + X25519_KEY_SIZE + ED25519_KEY_SIZE) {
logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data");
return;
}
/* We can fall through these errors, the result will just be garbage... */
if (pairing_session_handshake(conn->session, data + 4, data + 4 + X25519_KEY_SIZE)) {
logger_log(conn->raop->logger, LOGGER_ERR, "Error initializing pair-verify handshake");
}
if (pairing_session_get_public_key(conn->session, public_key)) {
logger_log(conn->raop->logger, LOGGER_ERR, "Error getting ECDH public key");
}
if (pairing_session_get_signature(conn->session, signature)) {
logger_log(conn->raop->logger, LOGGER_ERR, "Error getting ED25519 signature");
}
if (register_check) {
bool registered_client = true;
if (conn->raop->callbacks.check_register) {
const unsigned char *pk = data + 4 + X25519_KEY_SIZE;
char *pk64;
ed25519_pk_to_base64(pk, &pk64);
registered_client = conn->raop->callbacks.check_register(conn->raop->callbacks.cls, pk64);
free (pk64);
}
if (!registered_client) {
return;
}
}
*response_data = malloc(sizeof(public_key) + sizeof(signature));
if (*response_data) {
http_response_add_header(response, "Content-Type", "application/octet-stream");
memcpy(*response_data, public_key, sizeof(public_key));
memcpy(*response_data + sizeof(public_key), signature, sizeof(signature));
*response_datalen = sizeof(public_key) + sizeof(signature);
}
break;
case 0:
logger_log(conn->raop->logger, LOGGER_DEBUG, "2nd pair-verify step: checking signature");
if (datalen != 4 + PAIRING_SIG_SIZE) {
logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data");
return;
case 1:
if (datalen != 4 + X25519_KEY_SIZE + ED25519_KEY_SIZE) {
logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data");
return;
}
/* We can fall through these errors, the result will just be garbage... */
if (pairing_session_handshake(conn->session, data + 4, data + 4 + X25519_KEY_SIZE)) {
logger_log(conn->raop->logger, LOGGER_ERR, "Error initializing pair-verify handshake");
}
if (pairing_session_get_public_key(conn->session, public_key)) {
logger_log(conn->raop->logger, LOGGER_ERR, "Error getting ECDH public key");
}
if (pairing_session_get_signature(conn->session, signature)) {
logger_log(conn->raop->logger, LOGGER_ERR, "Error getting ED25519 signature");
}
if (register_check) {
bool registered_client = true;
if (conn->raop->callbacks.check_register) {
const unsigned char *pk = data + 4 + X25519_KEY_SIZE;
char *pk64;
ed25519_pk_to_base64(pk, &pk64);
registered_client = conn->raop->callbacks.check_register(conn->raop->callbacks.cls, pk64);
free (pk64);
}
if (pairing_session_finish(conn->session, data + 4)) {
logger_log(conn->raop->logger, LOGGER_ERR, "Incorrect pair-verify signature");
http_response_set_disconnect(response, 1);
if (!registered_client) {
return;
}
logger_log(conn->raop->logger, LOGGER_DEBUG, "pair-verify: signature is verified");
}
*response_data = malloc(sizeof(public_key) + sizeof(signature));
if (*response_data) {
http_response_add_header(response, "Content-Type", "application/octet-stream");
break;
memcpy(*response_data, public_key, sizeof(public_key));
memcpy(*response_data + sizeof(public_key), signature, sizeof(signature));
*response_datalen = sizeof(public_key) + sizeof(signature);
}
break;
case 0:
logger_log(conn->raop->logger, LOGGER_DEBUG, "2nd pair-verify step: checking signature");
if (datalen != 4 + PAIRING_SIG_SIZE) {
logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data");
return;
}
if (pairing_session_finish(conn->session, data + 4)) {
logger_log(conn->raop->logger, LOGGER_ERR, "Incorrect pair-verify signature");
http_response_set_disconnect(response, 1);
return;
}
logger_log(conn->raop->logger, LOGGER_DEBUG, "pair-verify: signature is verified");
http_response_add_header(response, "Content-Type", "application/octet-stream");
break;
}
}
@@ -618,7 +618,7 @@ raop_handler_setup(raop_conn_t *conn,
logger_log(conn->raop->logger, LOGGER_ERR, "Failed to generate random pin");
pin_4 = 1234;
}
conn->raop->random_pw = (char *) malloc(pin_len + 1 + 18);
conn->raop->random_pw = (char *) malloc(pin_len + 1 + 18);
char *pin = conn->raop->random_pw;
snprintf(pin, pin_len + 1, "%04u", pin_4 % 10000);
pin[pin_len] = '\0';
@@ -661,7 +661,7 @@ raop_handler_setup(raop_conn_t *conn,
if (conn->authenticated && conn->raop->random_pw) {
free (conn->raop->random_pw);
conn->raop->random_pw = NULL;
}
}
if (conn->raop->nonce) {
free(conn->raop->nonce);
conn->raop->nonce = NULL;
@@ -691,17 +691,17 @@ raop_handler_setup(raop_conn_t *conn,
char* eiv = NULL;
uint64_t eiv_len = 0;
char *model = NULL;
char *model = NULL;
char *name = NULL;
bool admit_client = true;
plist_t req_model_node = plist_dict_get_item(req_root_node, "model");
plist_get_string_val(req_model_node, &model);
plist_t req_name_node = plist_dict_get_item(req_root_node, "name");
plist_get_string_val(req_name_node, &name);
if (conn->raop->callbacks.report_client_request) {
if (conn->raop->callbacks.report_client_request) {
conn->raop->callbacks.report_client_request(conn->raop->callbacks.cls, deviceID, model, name, &admit_client);
}
if (admit_client && deviceID && name && conn->raop->callbacks.register_client) {
if (admit_client && deviceID && name && conn->raop->callbacks.register_client) {
char *client_device_id = NULL;
char *client_pk = NULL; /* encoded as null-terminated base64 string, must be freed*/
get_pairing_session_client_data(conn->session, &client_device_id, &client_pk);
@@ -709,7 +709,7 @@ raop_handler_setup(raop_conn_t *conn,
conn->raop->callbacks.register_client(conn->raop->callbacks.cls, client_device_id, client_pk, name);
free (client_pk);
}
}
}
if (deviceID) {
free (deviceID);
deviceID = NULL;
@@ -727,17 +727,17 @@ raop_handler_setup(raop_conn_t *conn,
plist_free(res_root_node);
plist_free(req_root_node);
return;
}
}
plist_get_data_val(req_eiv_node, &eiv, &eiv_len);
memcpy(aesiv, eiv, 16);
free(eiv);
logger_log(conn->raop->logger, LOGGER_DEBUG, "eiv_len = %llu", eiv_len);
if (logger_debug) {
if (logger_debug) {
char* str = utils_data_to_string(aesiv, 16, 16);
logger_log(conn->raop->logger, LOGGER_DEBUG, "16 byte aesiv (needed for AES-CBC audio decryption iv):\n%s", str);
free(str);
}
}
char* ekey = NULL;
uint64_t ekey_len = 0;
@@ -746,7 +746,7 @@ raop_handler_setup(raop_conn_t *conn,
free(ekey);
logger_log(conn->raop->logger, LOGGER_DEBUG, "ekey_len = %llu", ekey_len);
// eaeskey is 72 bytes, aeskey is 16 bytes
if (logger_debug) {
if (logger_debug) {
char *str = utils_data_to_string((unsigned char *) eaeskey, ekey_len, 16);
logger_log(conn->raop->logger, LOGGER_DEBUG, "ekey:\n%s", str);
free (str);
@@ -814,9 +814,9 @@ raop_handler_setup(raop_conn_t *conn,
logger_log(conn->raop->logger, LOGGER_ERR, "Client specified AirPlay2 \"Remote Control\" protocol\n"
" Only AirPlay v1 protocol (using NTP and timing port) is supported");
}
}
}
char *timing_protocol = NULL;
timing_protocol_t time_protocol = TP_NONE;
timing_protocol_t time_protocol = TP_NONE;
plist_t req_timing_protocol_node = plist_dict_get_item(req_root_node, "timingProtocol");
plist_get_string_val(req_timing_protocol_node, &timing_protocol);
if (timing_protocol) {
@@ -841,7 +841,7 @@ raop_handler_setup(raop_conn_t *conn,
}
uint64_t timing_rport = 0;
plist_t req_timing_port_node = plist_dict_get_item(req_root_node, "timingPort");
if (req_timing_port_node) {
if (req_timing_port_node) {
plist_get_uint_val(req_timing_port_node, &timing_rport);
}
if (timing_rport) {
@@ -897,106 +897,107 @@ raop_handler_setup(raop_conn_t *conn,
logger_log(conn->raop->logger, LOGGER_DEBUG, "type = %llu", type);
switch (type) {
case 110: {
// Mirroring
unsigned short dport = conn->raop->mirror_data_lport;
plist_t stream_id_node = plist_dict_get_item(req_stream_node, "streamConnectionID");
uint64_t stream_connection_id = 0;
plist_get_uint_val(stream_id_node, &stream_connection_id);
logger_log(conn->raop->logger, LOGGER_DEBUG, "streamConnectionID (needed for AES-CTR video decryption"
" key and iv): %llu", stream_connection_id);
case 110: {
// Mirroring
unsigned short dport = conn->raop->mirror_data_lport;
plist_t stream_id_node = plist_dict_get_item(req_stream_node, "streamConnectionID");
uint64_t stream_connection_id = 0;
plist_get_uint_val(stream_id_node, &stream_connection_id);
logger_log(conn->raop->logger, LOGGER_DEBUG, "streamConnectionID (needed for AES-CTR video decryption"
" key and iv): %llu", stream_connection_id);
if (conn->raop_rtp_mirror) {
raop_rtp_mirror_init_aes(conn->raop_rtp_mirror, &stream_connection_id);
raop_rtp_mirror_start(conn->raop_rtp_mirror, &dport, conn->raop->clientFPSdata);
logger_log(conn->raop->logger, LOGGER_DEBUG, "Mirroring initialized successfully");
} else {
logger_log(conn->raop->logger, LOGGER_ERR, "Mirroring not initialized at SETUP, playing will fail!");
http_response_set_disconnect(response, 1);
}
plist_t res_stream_node = plist_new_dict();
plist_t res_stream_data_port_node = plist_new_uint(dport);
plist_t res_stream_type_node = plist_new_uint(110);
plist_dict_set_item(res_stream_node, "dataPort", res_stream_data_port_node);
plist_dict_set_item(res_stream_node, "type", res_stream_type_node);
plist_array_append_item(res_streams_node, res_stream_node);
break;
} case 96: {
// Audio
unsigned short cport = conn->raop->control_lport, dport = conn->raop->data_lport;
unsigned short remote_cport = 0;
unsigned char ct = 0;
unsigned int sr = AUDIO_SAMPLE_RATE; /* all AirPlay audio formats supported so far have sample rate 44.1kHz */
uint64_t uint_val = 0;
plist_t req_stream_control_port_node = plist_dict_get_item(req_stream_node, "controlPort");
plist_get_uint_val(req_stream_control_port_node, &uint_val);
remote_cport = (unsigned short) uint_val; /* must != 0 to activate audio resend requests */
plist_t req_stream_ct_node = plist_dict_get_item(req_stream_node, "ct");
plist_get_uint_val(req_stream_ct_node, &uint_val);
ct = (unsigned char) uint_val;
if (conn->raop->callbacks.audio_get_format) {
/* get additional audio format parameters */
uint64_t audioFormat = 0;
unsigned short spf = 0;
bool isMedia = false;
bool usingScreen = false;
uint8_t bool_val = 0;
plist_t req_stream_spf_node = plist_dict_get_item(req_stream_node, "spf");
plist_get_uint_val(req_stream_spf_node, &uint_val);
spf = (unsigned short) uint_val;
plist_t req_stream_audio_format_node = plist_dict_get_item(req_stream_node, "audioFormat");
plist_get_uint_val(req_stream_audio_format_node, &audioFormat);
plist_t req_stream_is_media_node = plist_dict_get_item(req_stream_node, "isMedia");
if (req_stream_is_media_node) {
plist_get_bool_val(req_stream_is_media_node, &bool_val);
isMedia = (bool) bool_val;
} else {
isMedia = false;
}
plist_t req_stream_using_screen_node = plist_dict_get_item(req_stream_node, "usingScreen");
if (req_stream_using_screen_node) {
plist_get_bool_val(req_stream_using_screen_node, &bool_val);
usingScreen = (bool) bool_val;
} else {
usingScreen = false;
}
conn->raop->callbacks.audio_get_format(conn->raop->callbacks.cls, &ct, &spf, &usingScreen, &isMedia, &audioFormat);
}
if (conn->raop_rtp) {
raop_rtp_start_audio(conn->raop_rtp, &remote_cport, &cport, &dport, &ct, &sr);
logger_log(conn->raop->logger, LOGGER_DEBUG, "RAOP initialized success");
} else {
logger_log(conn->raop->logger, LOGGER_ERR, "RAOP not initialized at SETUP, playing will fail!");
http_response_set_disconnect(response, 1);
}
plist_t res_stream_node = plist_new_dict();
plist_t res_stream_data_port_node = plist_new_uint(dport);
plist_t res_stream_control_port_node = plist_new_uint(cport);
plist_t res_stream_type_node = plist_new_uint(96);
plist_dict_set_item(res_stream_node, "dataPort", res_stream_data_port_node);
plist_dict_set_item(res_stream_node, "controlPort", res_stream_control_port_node);
plist_dict_set_item(res_stream_node, "type", res_stream_type_node);
plist_array_append_item(res_streams_node, res_stream_node);
break;
if (conn->raop_rtp_mirror) {
raop_rtp_mirror_init_aes(conn->raop_rtp_mirror, &stream_connection_id);
raop_rtp_mirror_start(conn->raop_rtp_mirror, &dport, conn->raop->clientFPSdata);
logger_log(conn->raop->logger, LOGGER_DEBUG, "Mirroring initialized successfully");
} else {
logger_log(conn->raop->logger, LOGGER_ERR, "Mirroring not initialized at SETUP, playing will fail!");
http_response_set_disconnect(response, 1);
}
default:
logger_log(conn->raop->logger, LOGGER_ERR, "SETUP tries to setup stream of unknown type %llu", type);
plist_t res_stream_node = plist_new_dict();
plist_t res_stream_data_port_node = plist_new_uint(dport);
plist_t res_stream_type_node = plist_new_uint(110);
plist_dict_set_item(res_stream_node, "dataPort", res_stream_data_port_node);
plist_dict_set_item(res_stream_node, "type", res_stream_type_node);
plist_array_append_item(res_streams_node, res_stream_node);
break;
}
case 96: {
// Audio
unsigned short cport = conn->raop->control_lport, dport = conn->raop->data_lport;
unsigned short remote_cport = 0;
unsigned char ct = 0;
unsigned int sr = AUDIO_SAMPLE_RATE; /* all AirPlay audio formats supported so far have sample rate 44.1kHz */
uint64_t uint_val = 0;
plist_t req_stream_control_port_node = plist_dict_get_item(req_stream_node, "controlPort");
plist_get_uint_val(req_stream_control_port_node, &uint_val);
remote_cport = (unsigned short) uint_val; /* must != 0 to activate audio resend requests */
plist_t req_stream_ct_node = plist_dict_get_item(req_stream_node, "ct");
plist_get_uint_val(req_stream_ct_node, &uint_val);
ct = (unsigned char) uint_val;
if (conn->raop->callbacks.audio_get_format) {
/* get additional audio format parameters */
uint64_t audioFormat = 0;
unsigned short spf = 0;
bool isMedia = false;
bool usingScreen = false;
uint8_t bool_val = 0;
plist_t req_stream_spf_node = plist_dict_get_item(req_stream_node, "spf");
plist_get_uint_val(req_stream_spf_node, &uint_val);
spf = (unsigned short) uint_val;
plist_t req_stream_audio_format_node = plist_dict_get_item(req_stream_node, "audioFormat");
plist_get_uint_val(req_stream_audio_format_node, &audioFormat);
plist_t req_stream_is_media_node = plist_dict_get_item(req_stream_node, "isMedia");
if (req_stream_is_media_node) {
plist_get_bool_val(req_stream_is_media_node, &bool_val);
isMedia = (bool) bool_val;
} else {
isMedia = false;
}
plist_t req_stream_using_screen_node = plist_dict_get_item(req_stream_node, "usingScreen");
if (req_stream_using_screen_node) {
plist_get_bool_val(req_stream_using_screen_node, &bool_val);
usingScreen = (bool) bool_val;
} else {
usingScreen = false;
}
conn->raop->callbacks.audio_get_format(conn->raop->callbacks.cls, &ct, &spf, &usingScreen, &isMedia, &audioFormat);
}
if (conn->raop_rtp) {
raop_rtp_start_audio(conn->raop_rtp, &remote_cport, &cport, &dport, &ct, &sr);
logger_log(conn->raop->logger, LOGGER_DEBUG, "RAOP initialized success");
} else {
logger_log(conn->raop->logger, LOGGER_ERR, "RAOP not initialized at SETUP, playing will fail!");
http_response_set_disconnect(response, 1);
break;
}
plist_t res_stream_node = plist_new_dict();
plist_t res_stream_data_port_node = plist_new_uint(dport);
plist_t res_stream_control_port_node = plist_new_uint(cport);
plist_t res_stream_type_node = plist_new_uint(96);
plist_dict_set_item(res_stream_node, "dataPort", res_stream_data_port_node);
plist_dict_set_item(res_stream_node, "controlPort", res_stream_control_port_node);
plist_dict_set_item(res_stream_node, "type", res_stream_type_node);
plist_array_append_item(res_streams_node, res_stream_node);
break;
}
default:
logger_log(conn->raop->logger, LOGGER_ERR, "SETUP tries to setup stream of unknown type %llu", type);
http_response_set_disconnect(response, 1);
break;
}
}
@@ -1036,7 +1037,7 @@ raop_handler_get_parameter(raop_conn_t *conn,
char volume[25] = "volume: 0.0\r\n";
if (conn->raop->callbacks.audio_set_client_volume) {
snprintf(volume, 25, "volume: %9.6f\r\n", conn->raop->callbacks.audio_set_client_volume(conn->raop->callbacks.cls));
}
}
http_response_add_header(response, "Content-Type", "text/parameters");
*response_data = strdup(volume);
if (*response_data) {
@@ -1045,9 +1046,11 @@ raop_handler_get_parameter(raop_conn_t *conn,
return;
}
for (next = current ; (datalen - (next - data) > 0) ; ++next)
if (*next == '\r')
for (next = current ; (datalen - (next - data) > 0) ; ++next) {
if (*next == '\r') {
break;
}
}
if ((datalen - (next - data) >= 2) && !strncmp(next, "\r\n", 2)) {
if ((next - current) > 0) {
@@ -1187,7 +1190,7 @@ raop_handler_teardown(raop_conn_t *conn,
if (val == 96) {
teardown_96 = true;
} else if (val == 110) {
teardown_110 = true;
teardown_110 = true;
}
}
}

View File

@@ -352,7 +352,7 @@ raop_ntp_thread(void *arg)
(double) t2 / SECOND_IN_NSECS, str);
free(str);
}
// The iOS client device sends its time in seconds relative to an arbitrary Epoch (the last boot).
// The iOS client device sends its time in seconds relative to an arbitrary Epoch (the last boot).
// For a little bonus confusion, they add SECONDS_FROM_1900_TO_1970.
// This means we have to expect some rather huge offset, but its growth or shrink over time should be small.

View File

@@ -195,7 +195,6 @@ raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, raop_ntp_t *ntp, co
return raop_rtp;
}
void
raop_rtp_destroy(raop_rtp_t *raop_rtp)
{
@@ -515,7 +514,7 @@ raop_rtp_thread_udp(void *arg)
} else {
client_ntp_sync_prev = raop_rtp->client_ntp_sync;
rtp_sync_prev = raop_rtp->rtp_sync;
}
}
raop_rtp->rtp_sync = byteutils_get_int_be(packet, 4);
uint64_t sync_ntp_raw = byteutils_get_long_be(packet, 8);
raop_rtp->client_ntp_sync = raop_remote_timestamp_to_nano_seconds(raop_rtp->ntp, sync_ntp_raw);
@@ -564,20 +563,20 @@ raop_rtp_thread_udp(void *arg)
* three times; the secnum and rtp_timestamp increment according to the same pattern as
* AAC-ELD packets with audio content.*/
/* When the ALAC audio stream starts, the initial packets are length-44 packets with
* the same 32-byte encrypted payload which after decryption is the beginning of a
* 32-byte ALAC packet, presumably with format information, but not actual audio data.
* The secnum and rtp_timestamp in the packet header increment according to the same
* pattern as ALAC packets with audio content */
/* When the ALAC audio stream starts, the initial packets are length-44 packets with
* the same 32-byte encrypted payload which after decryption is the beginning of a
* 32-byte ALAC packet, presumably with format information, but not actual audio data.
* The secnum and rtp_timestamp in the packet header increment according to the same
* pattern as ALAC packets with audio content */
/* The first ALAC packet with data seems to be decoded just before the first sync event
* so its dequeuing should be delayed until the first rtp sync has occurred */
/* The first ALAC packet with data seems to be decoded just before the first sync event
* so its dequeuing should be delayed until the first rtp sync has occurred */
if (FD_ISSET(raop_rtp->dsock, &rfds)) {
if (!raop_rtp->initial_sync && !video_arrival_offset) {
if (FD_ISSET(raop_rtp->dsock, &rfds)) {
if (!raop_rtp->initial_sync && !video_arrival_offset) {
video_arrival_offset = raop_ntp_get_video_arrival_offset(raop_rtp->ntp);
}
}
//logger_log(raop_rtp->logger, LOGGER_INFO, "Would have data packet in queue");
// Receiving audio data here
saddrlen = sizeof(saddr);
@@ -594,17 +593,17 @@ raop_rtp_thread_udp(void *arg)
free (str);
}
continue;
}
}
if (!raop_rtp->initial_sync && raop_rtp->ct == 8 && video_arrival_offset) {
if (!raop_rtp->initial_sync && raop_rtp->ct == 8 && video_arrival_offset) {
/* estimate a fake initial remote timestamp for video synchronization with AAC audio before the first rtp sync */
uint64_t ts = raop_ntp_get_local_time() - video_arrival_offset;
double delay = DELAY_AAC;
ts += (uint64_t) (delay * SEC);
raop_rtp->client_ntp_sync = ts;
raop_rtp->rtp_sync = byteutils_get_int_be(packet, 4);
raop_rtp->initial_sync = true;
}
uint64_t ts = raop_ntp_get_local_time() - video_arrival_offset;
double delay = DELAY_AAC;
ts += (uint64_t) (delay * SEC);
raop_rtp->client_ntp_sync = ts;
raop_rtp->rtp_sync = byteutils_get_int_be(packet, 4);
raop_rtp->initial_sync = true;
}
if (packetlen == 16 && memcmp(packet + 12, no_data_marker, 4) == 0) {
/* this is a "no data" packet */
@@ -612,12 +611,12 @@ raop_rtp_thread_udp(void *arg)
continue;
}
if (raop_rtp->ct == 2 && packetlen == 44) continue; /* ignore the ALAC packets with format information only. */
if (raop_rtp->ct == 2 && packetlen == 44) continue; /* ignore the ALAC packets with format information only. */
int result = raop_buffer_enqueue(raop_rtp->buffer, packet, packetlen, 1);
assert(result >= 0);
if (!raop_rtp->initial_sync) {
if (!raop_rtp->initial_sync) {
/* wait until the first sync before dequeing ALAC */
continue;
} else {

View File

@@ -330,13 +330,13 @@ raop_rtp_mirror_thread(void *arg)
/*packet[0:3] contains the payload size */
int payload_size = byteutils_get_int(packet, 0);
char packet_description[13] = {0};
char *p = packet_description;
char *p = packet_description;
int n = sizeof(packet_description);
for (int i = 4; i < 8; i++) {
for (int i = 4; i < 8; i++) {
snprintf(p, n, "%2.2x ", (unsigned int) packet[i]);
n -= 3;
p += 3;
}
}
ntp_timestamp_raw = byteutils_get_long(packet, 8);
ntp_timestamp_remote = raop_ntp_timestamp_to_nano_seconds(ntp_timestamp_raw, false);
if (first_packet) {
@@ -345,14 +345,14 @@ raop_rtp_mirror_thread(void *arg)
first_packet = false;
}
/* packet[4] + packet[5] identify the payload type: values seen are: *
/* packet[4] + packet[5] identify the payload type: values seen are: *
* 0x00 0x00: encrypted packet containing a non-IDR type 1 VCL NAL unit *
* 0x00 0x10: encrypted packet containing an IDR type 5 VCL NAL unit *
* 0x01 0x00: unencrypted packet containing a type 7 SPS NAL + a type 8 PPS NAL unit *
* 0x02 0x00: unencrypted packet (old protocol) no payload, sent once every second *
* 0x05 0x00 unencrypted packet with a "streaming report", sent once per second. */
/* packet[6] + packet[7] may list a payload "option": values seen are: *
/* packet[6] + packet[7] may list a payload "option": values seen are: *
* 0x00 0x00 : encrypted and "streaming report" packets *
* 0x1e 0x00 : old protocol (seen in AirMyPC) no-payload once-per-second packets *
* 0x16 0x01 : seen in most unencrypted h264 SPS+PPS packets *
@@ -395,7 +395,7 @@ raop_rtp_mirror_thread(void *arg)
break;
}
switch (packet[4]) {
switch (packet[4]) {
case 0x00:
// Normal video data (VCL NAL)
@@ -415,7 +415,7 @@ raop_rtp_mirror_thread(void *arg)
}
unsigned char* payload_out;
unsigned char* payload_decrypted;
unsigned char* payload_decrypted;
/*
* nal_types:1 Coded non-partitioned slice of a non-IDR picture
* 5 Coded non-partitioned slice of an IDR picture
@@ -437,7 +437,7 @@ raop_rtp_mirror_thread(void *arg)
"raop_rtp_mirror: prepended sps_pps timestamp does not match timestamp of "
"video payload\n%llu\n%llu , discarding", ntp_timestamp_raw, ntp_timestamp_nal);
free (sps_pps);
sps_pps = NULL;
sps_pps = NULL;
prepend_sps_pps = false;
}
@@ -447,7 +447,7 @@ raop_rtp_mirror_thread(void *arg)
payload_decrypted = payload_out + sps_pps_len;
memcpy(payload_out, sps_pps, sps_pps_len);
free (sps_pps);
sps_pps = NULL;
sps_pps = NULL;
} else {
payload_out = (unsigned char*) malloc(payload_size);
payload_decrypted = payload_out;
@@ -474,11 +474,11 @@ raop_rtp_mirror_thread(void *arg)
valid_data = false;
break;
}
int nalu_type;
if (h265_video) {
int nalu_type;
if (h265_video) {
nalu_type = payload_decrypted[nalu_size] & 0x7e >> 1;;
//logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG," h265 video, NALU type %d, size %d", nalu_type, nc_len);
} else {
} else {
nalu_type = payload_decrypted[nalu_size] & 0x1f;
int ref_idc = (payload_decrypted[nalu_size] >> 5);
switch (nalu_type) {
@@ -486,7 +486,7 @@ raop_rtp_mirror_thread(void *arg)
case 5: /*IDR, slice_layer_without_partitioning */
case 1: /*non-IDR, slice_layer_without_partitioning */
break;
case 2: /* slice data partition A */
case 2: /* slice data partition A */
case 3: /* slice data partition B */
case 4: /* slice data partition C */
logger_log(raop_rtp_mirror->logger, LOGGER_INFO,
@@ -526,9 +526,9 @@ raop_rtp_mirror_thread(void *arg)
"unexpected non-VCL NAL unit: nalu_type = %d, ref_idc = %d, nalu_size = %d,"
"processed bytes %d, payloadsize = %d nalus_count = %d",
nalu_type, ref_idc, nc_len, nalu_size, payload_size, nalus_count);
break;
}
}
break;
}
}
nalu_size += nc_len;
}
if (nalu_size != payload_size) valid_data = false;
@@ -540,7 +540,7 @@ raop_rtp_mirror_thread(void *arg)
payload_decrypted = NULL;
video_decode_struct video_data;
video_data.is_h265 = h265_video;
video_data.is_h265 = h265_video;
video_data.ntp_time_local = ntp_timestamp_local;
video_data.ntp_time_remote = ntp_timestamp_remote;
video_data.nal_count = nalus_count; /*nal_count will be the number of nal units in the packet */
@@ -571,13 +571,13 @@ raop_rtp_mirror_thread(void *arg)
bytes 56-59 width
bytes 60-63 height
bytes 64-127 all 0x0
*/
*/
// The information in the payload contains an SPS and a PPS NAL
// The sps_pps is not encrypted
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived unencrypted codec packet from client:"
" payload_size %d header %s ts_client = %8.6f",
payload_size, packet_description, (double) ntp_timestamp_remote / SEC);
payload_size, packet_description, (double) ntp_timestamp_remote / SEC);
if (packet[6] == 0x56 || packet[6] == 0x5e) {
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "This packet indicates video stream is stopping");
@@ -614,7 +614,7 @@ raop_rtp_mirror_thread(void *arg)
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror width_source = %f height_source = %f width = %f height = %f",
width_source, height_source, width, height);
if (payload_size == 0) {
if (payload_size == 0) {
logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror: received type 0x01 packet with no payload:\n"
"this indicates non-h264 video but Airplay features bit 42 (SupportsScreenMultiCodec) is not set\n"
"use startup option \"-h265\" to set this bit and support h265 (4K) video");
@@ -625,7 +625,7 @@ raop_rtp_mirror_thread(void *arg)
free(sps_pps);
sps_pps = NULL;
}
/* test for a H265 VPS/SPS/PPS */
/* test for a H265 VPS/SPS/PPS */
unsigned char hvc1[] = { 0x68, 0x76, 0x63, 0x31 };
if (!memcmp(payload + 4, hvc1, 4)) {
@@ -677,7 +677,7 @@ raop_rtp_mirror_thread(void *arg)
break;
}
sps_size = byteutils_get_short_be(ptr, 3);
ptr += 5;
ptr += 5;
sps = ptr;
if (logger_debug) {
char *str = utils_data_to_string(sps, sps_size, 16);
@@ -690,12 +690,12 @@ raop_rtp_mirror_thread(void *arg)
raop_rtp_mirror->callbacks.video_pause(raop_rtp_mirror->callbacks.cls);
break;
}
pps_size = byteutils_get_short_be(ptr, 3);
pps_size = byteutils_get_short_be(ptr, 3);
ptr += 5;
pps = ptr;
if (logger_debug) {
char *str = utils_data_to_string(pps, pps_size, 16);
logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "h265 pps size %d\n%s",pps_size, str);
logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "h265 pps size %d\n%s",pps_size, str);
free(str);
}
@@ -802,7 +802,7 @@ raop_rtp_mirror_thread(void *arg)
int plist_size = payload_size;
if (payload_size > 25000) {
plist_size = payload_size - 25000;
plist_size = payload_size - 25000;
if (logger_debug) {
char *str = utils_data_to_string(payload + plist_size, 16, 16);
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG,
@@ -848,7 +848,7 @@ raop_rtp_mirror_thread(void *arg)
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror exiting TCP thread");
if (conn_reset&& raop_rtp_mirror->callbacks.conn_reset) {
raop_rtp_mirror->callbacks.conn_reset(raop_rtp_mirror->callbacks.cls, 1);
raop_rtp_mirror->callbacks.conn_reset(raop_rtp_mirror->callbacks.cls, 1);
}
if (unsupported_codec) {