mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
add infrastructure for pair-pin-start, + changing features
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
@@ -263,7 +264,6 @@ void x25519_derive_secret(unsigned char secret[X25519_KEY_SIZE], const x25519_ke
|
||||
|
||||
// ED25519
|
||||
|
||||
|
||||
struct ed25519_key_s {
|
||||
EVP_PKEY *pkey;
|
||||
unsigned char ed_secret[ED25519_KEY_SIZE];
|
||||
@@ -497,3 +497,7 @@ void sha_destroy(sha_ctx_t *ctx) {
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
int get_random_bytes(unsigned char *buf, int num) {
|
||||
return RAND_bytes(buf, num);
|
||||
}
|
||||
|
||||
79
lib/dnssd.c
79
lib/dnssd.c
@@ -145,15 +145,22 @@ struct dnssd_s {
|
||||
|
||||
char *hw_addr;
|
||||
int hw_addr_len;
|
||||
|
||||
uint32_t features1;
|
||||
uint32_t features2;
|
||||
|
||||
unsigned char require_pw;
|
||||
};
|
||||
|
||||
|
||||
|
||||
dnssd_t *
|
||||
dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len, int *error)
|
||||
dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len, int *error, int require_pw)
|
||||
{
|
||||
dnssd_t *dnssd;
|
||||
|
||||
char *end;
|
||||
unsigned long features;
|
||||
|
||||
if (error) *error = DNSSD_ERROR_NOERROR;
|
||||
|
||||
dnssd = calloc(1, sizeof(dnssd_t));
|
||||
@@ -162,6 +169,24 @@ dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dnssd->require_pw = (unsigned char) require_pw;
|
||||
|
||||
features = strtoul(FEATURES_1, &end, 16);
|
||||
if (!end || (features & 0xFFFFFFFF) != features) {
|
||||
free (dnssd);
|
||||
if (error) *error = DNSSD_ERROR_BADFEATURES;
|
||||
return NULL;
|
||||
}
|
||||
dnssd->features1 = (uint32_t) features;
|
||||
|
||||
features = strtoul(FEATURES_2, &end, 16);
|
||||
if (!end || (features & 0xFFFFFFFF) != features) {
|
||||
free (dnssd);
|
||||
if (error) *error = DNSSD_ERROR_BADFEATURES;
|
||||
return NULL;
|
||||
}
|
||||
dnssd->features2 = (uint32_t) features;
|
||||
|
||||
#ifdef WIN32
|
||||
dnssd->module = LoadLibraryA("dnssd.dll");
|
||||
if (!dnssd->module) {
|
||||
@@ -259,20 +284,27 @@ dnssd_register_raop(dnssd_t *dnssd, unsigned short port)
|
||||
{
|
||||
char servname[MAX_SERVNAME];
|
||||
DNSServiceErrorType retval;
|
||||
char features[22];
|
||||
|
||||
assert(dnssd);
|
||||
|
||||
snprintf(features, sizeof(features), "0x%X,0x%X", dnssd->features1, dnssd->features2);
|
||||
|
||||
dnssd->TXTRecordCreate(&dnssd->raop_record, 0, NULL);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "ch", strlen(RAOP_CH), RAOP_CH);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "cn", strlen(RAOP_CN), RAOP_CN);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "da", strlen(RAOP_DA), RAOP_DA);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "et", strlen(RAOP_ET), RAOP_ET);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "vv", strlen(RAOP_VV), RAOP_VV);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "ft", strlen(RAOP_FT), RAOP_FT);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "ft", strlen(features), features);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "am", strlen(GLOBAL_MODEL), GLOBAL_MODEL);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "md", strlen(RAOP_MD), RAOP_MD);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "rhd", strlen(RAOP_RHD), RAOP_RHD);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("false"), "false");
|
||||
if (dnssd->require_pw) {
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("true"), "true");
|
||||
} else {
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("false"), "false");
|
||||
}
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "sr", strlen(RAOP_SR), RAOP_SR);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "ss", strlen(RAOP_SS), RAOP_SS);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "sv", strlen(RAOP_SV), RAOP_SV);
|
||||
@@ -281,7 +313,7 @@ dnssd_register_raop(dnssd_t *dnssd, unsigned short port)
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "sf", strlen(RAOP_SF), RAOP_SF);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "vs", strlen(RAOP_VS), RAOP_VS);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "vn", strlen(RAOP_VN), RAOP_VN);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "pk", strlen(RAOP_PK), RAOP_PK);
|
||||
dnssd->TXTRecordSetValue(&dnssd->raop_record, "pk", strlen(PK), PK);
|
||||
|
||||
/* Convert hardware address to string */
|
||||
if (utils_hwaddr_raop(servname, sizeof(servname), dnssd->hw_addr, dnssd->hw_addr_len) < 0) {
|
||||
@@ -315,9 +347,12 @@ dnssd_register_airplay(dnssd_t *dnssd, unsigned short port)
|
||||
{
|
||||
char device_id[3 * MAX_HWADDR_LEN];
|
||||
DNSServiceErrorType retval;
|
||||
char features[22];
|
||||
|
||||
assert(dnssd);
|
||||
|
||||
snprintf(features, sizeof(features), "0x%X,0x%X", dnssd->features1, dnssd->features2);
|
||||
|
||||
/* Convert hardware address to string */
|
||||
if (utils_hwaddr_airplay(device_id, sizeof(device_id), dnssd->hw_addr, dnssd->hw_addr_len) < 0) {
|
||||
/* FIXME: handle better */
|
||||
@@ -327,10 +362,15 @@ dnssd_register_airplay(dnssd_t *dnssd, unsigned short port)
|
||||
|
||||
dnssd->TXTRecordCreate(&dnssd->airplay_record, 0, NULL);
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "deviceid", strlen(device_id), device_id);
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "features", strlen(AIRPLAY_FEATURES), AIRPLAY_FEATURES);
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "features", strlen(features), features);
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "flags", strlen(AIRPLAY_FLAGS), AIRPLAY_FLAGS);
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "model", strlen(GLOBAL_MODEL), GLOBAL_MODEL);
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pk", strlen(AIRPLAY_PK), AIRPLAY_PK);
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pk", strlen(PK), PK);
|
||||
if (dnssd->require_pw) {
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("true"), "true");
|
||||
} else {
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("false"), "false");
|
||||
}
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pi", strlen(AIRPLAY_PI), AIRPLAY_PI);
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "srcvers", strlen(AIRPLAY_SRCVERS), AIRPLAY_SRCVERS);
|
||||
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "vv", strlen(AIRPLAY_VV), AIRPLAY_VV);
|
||||
@@ -409,3 +449,28 @@ dnssd_unregister_airplay(dnssd_t *dnssd)
|
||||
free(dnssd->hw_addr);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t dnssd_get_airplay_features(dnssd_t *dnssd) {
|
||||
uint64_t features = ((uint64_t) dnssd->features2) << 32;
|
||||
features += (uint64_t) dnssd->features1;
|
||||
return features;
|
||||
}
|
||||
|
||||
void dnssd_set_airplay_features(dnssd_t *dnssd, int bit, int val) {
|
||||
uint32_t mask;
|
||||
uint32_t *features;
|
||||
if (bit < 0 || bit > 63) return;
|
||||
if (val < 0 || val > 1) return;
|
||||
if (bit >= 32) {
|
||||
mask = 0x1 << (bit - 32);
|
||||
features = &(dnssd->features2);
|
||||
} else {
|
||||
mask = 0x1 << bit;
|
||||
features = &(dnssd->features1);
|
||||
}
|
||||
if (val) {
|
||||
*features = *features | mask;
|
||||
} else {
|
||||
*features = *features & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#ifndef DNSSD_H
|
||||
#define DNSSD_H
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(WIN32) && defined(DLL_EXPORT)
|
||||
# define DNSSD_API __declspec(dllexport)
|
||||
@@ -30,10 +31,11 @@ extern "C" {
|
||||
#define DNSSD_ERROR_OUTOFMEM 2
|
||||
#define DNSSD_ERROR_LIBNOTFOUND 3
|
||||
#define DNSSD_ERROR_PROCNOTFOUND 4
|
||||
#define DNSSD_ERROR_BADFEATURES 5
|
||||
|
||||
typedef struct dnssd_s dnssd_t;
|
||||
|
||||
DNSSD_API dnssd_t *dnssd_init(const char *name, int name_len, const char *hw_addr, int hw_addr_len, int *error);
|
||||
DNSSD_API dnssd_t *dnssd_init(const char *name, int name_len, const char *hw_addr, int hw_addr_len, int *error, int require_pw);
|
||||
|
||||
DNSSD_API int dnssd_register_raop(dnssd_t *dnssd, unsigned short port);
|
||||
DNSSD_API int dnssd_register_airplay(dnssd_t *dnssd, unsigned short port);
|
||||
@@ -44,7 +46,9 @@ DNSSD_API void dnssd_unregister_airplay(dnssd_t *dnssd);
|
||||
DNSSD_API const char *dnssd_get_airplay_txt(dnssd_t *dnssd, int *length);
|
||||
DNSSD_API const char *dnssd_get_name(dnssd_t *dnssd, int *length);
|
||||
DNSSD_API const char *dnssd_get_hw_addr(dnssd_t *dnssd, int *length);
|
||||
|
||||
DNSSD_API void dnssd_set_airplay_features(dnssd_t *dnssd, int bit, int val);
|
||||
DNSSD_API uint64_t dnssd_get_airplay_features(dnssd_t *dnssd);
|
||||
|
||||
DNSSD_API void dnssd_destroy(dnssd_t *dnssd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -19,15 +19,17 @@
|
||||
#define DNSSDINT_H
|
||||
|
||||
#include "global.h"
|
||||
|
||||
#define PK "b07727d6f6cd6e08b58ede525ec3cdeaa252ad9f683feb212ef8a205246554e7"
|
||||
|
||||
#define RAOP_TXTVERS "1"
|
||||
#define RAOP_CH "2" /* Audio channels: 2 */
|
||||
#define RAOP_CN "0,1,2,3" /* Audio codec: PCM, ALAC, AAC, AAC ELD */
|
||||
#define RAOP_ET "0,3,5" /* Encryption type: None, FairPlay, FairPlay SAPv2.5 */
|
||||
#define RAOP_VV "2"
|
||||
//#define FEATURES_1 "0x5A7FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") ON */
|
||||
#define FEATURES_1 "0x527FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") OFF */
|
||||
#define FEATURES_2 "0x0" /* second 32 bits of features */
|
||||
#define RAOP_FT FEATURES_1 "," FEATURES_2
|
||||
#define FEATURES_1 "0x5A7FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") ON */
|
||||
//#define FEATURES_1 "0x527FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") OFF */
|
||||
#define FEATURES_2 "0x0" /* second 32 bits of features */
|
||||
#define RAOP_RHD "5.6.0.0"
|
||||
#define RAOP_SF "0x4"
|
||||
#define RAOP_SV "false"
|
||||
@@ -38,16 +40,10 @@
|
||||
#define RAOP_TP "UDP" /* Transport protocol. Possible values: UDP or TCP or TCP,UDP */
|
||||
#define RAOP_MD "0,1,2" /* Metadata: text, artwork, progress */
|
||||
#define RAOP_VN "65537"
|
||||
#define RAOP_PK "b07727d6f6cd6e08b58ede525ec3cdeaa252ad9f683feb212ef8a205246554e7"
|
||||
|
||||
/* use same features for RAOP and AIRPLAY: is this correct? */
|
||||
#define AIRPLAY_FEATURES_1 FEATURES_1
|
||||
#define AIRPLAY_FEATURES_2 FEATURES_2
|
||||
#define AIRPLAY_FEATURES AIRPLAY_FEATURES_1 "," AIRPLAY_FEATURES_2
|
||||
#define AIRPLAY_SRCVERS GLOBAL_VERSION /*defined in global.h */
|
||||
#define AIRPLAY_FLAGS "0x4"
|
||||
#define AIRPLAY_VV "2"
|
||||
#define AIRPLAY_PK "b07727d6f6cd6e08b58ede525ec3cdeaa252ad9f683feb212ef8a205246554e7"
|
||||
#define AIRPLAY_PI "2e388006-13ba-4041-9a67-25dd4a43d536"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -269,3 +269,23 @@ pairing_destroy(pairing_t *pairing)
|
||||
free(pairing);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
random_pin() {
|
||||
unsigned char random_bytes[2] = { 0 };
|
||||
unsigned short random_short = 0;
|
||||
int ret;
|
||||
/* create a random unsigned short in range 1-9999 */
|
||||
while (!random_short) {
|
||||
if ((ret = get_random_bytes(random_bytes, sizeof(random_bytes)) < 1)) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(&random_short, random_bytes, sizeof(random_bytes));
|
||||
random_short = random_short % 10000;
|
||||
}
|
||||
return (int) random_short;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ int pairing_session_check_handshake_status(pairing_session_t *session);
|
||||
int pairing_session_handshake(pairing_session_t *session, const unsigned char ecdh_key[X25519_KEY_SIZE],
|
||||
const unsigned char ed_key[ED25519_KEY_SIZE]);
|
||||
int pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_key[X25519_KEY_SIZE]);
|
||||
int random_pin();
|
||||
int pairing_session_get_signature(pairing_session_t *session, unsigned char signature[PAIRING_SIG_SIZE]);
|
||||
int pairing_session_finish(pairing_session_t *session, const unsigned char signature[PAIRING_SIG_SIZE]);
|
||||
void pairing_session_destroy(pairing_session_t *session);
|
||||
|
||||
16
lib/raop.c
16
lib/raop.c
@@ -65,6 +65,9 @@ struct raop_s {
|
||||
|
||||
int audio_delay_micros;
|
||||
int max_ntp_timeouts;
|
||||
|
||||
/* for temporary storage of pin during pair-pin start */
|
||||
unsigned short pin;
|
||||
};
|
||||
|
||||
struct raop_conn_s {
|
||||
@@ -215,11 +218,9 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
|
||||
if (!strcmp(method, "GET") && !strcmp(url, "/info")) {
|
||||
handler = &raop_handler_info;
|
||||
} else if (!strcmp(method, "POST") && !strcmp(url, "/pair-pin-start")) {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "*** ERROR: Unsupported client request %s with URL %s", method, url);
|
||||
logger_log(conn->raop->logger, LOGGER_INFO, "*** AirPlay client has requested PIN as implemented on AppleTV,");
|
||||
logger_log(conn->raop->logger, LOGGER_INFO, "*** but this implementation does not require a PIN and cannot supply one.");
|
||||
logger_log(conn->raop->logger, LOGGER_INFO, "*** This client behavior may have been required by mobile device management (MDM)");
|
||||
logger_log(conn->raop->logger, LOGGER_INFO, "*** (such as Apple Configurator or a third-party MDM tool).");
|
||||
handler = &raop_handler_pairpinstart;
|
||||
} else if (!strcmp(method, "POST") && !strcmp(url, "/pair-setup-pin")) {
|
||||
handler = &raop_handler_pairsetup_pin;
|
||||
} else if (!strcmp(method, "POST") && !strcmp(url, "/pair-setup")) {
|
||||
handler = &raop_handler_pairsetup;
|
||||
} else if (!strcmp(method, "POST") && !strcmp(url, "/pair-verify")) {
|
||||
@@ -422,6 +423,8 @@ raop_init(int max_clients, raop_callbacks_t *callbacks) {
|
||||
|
||||
/* Initialize the logger */
|
||||
raop->logger = logger_init();
|
||||
|
||||
/* create a new public key for pairing */
|
||||
pairing = pairing_init_generate();
|
||||
if (!pairing) {
|
||||
free(raop);
|
||||
@@ -461,6 +464,9 @@ raop_init(int max_clients, raop_callbacks_t *callbacks) {
|
||||
raop->maxFPS = 30;
|
||||
raop->overscanned = 0;
|
||||
|
||||
/* initialise stored pin */
|
||||
raop->pin = 0;
|
||||
|
||||
/* initialize switch for display of client's streaming data records */
|
||||
raop->clientFPSdata = 0;
|
||||
|
||||
|
||||
@@ -50,16 +50,14 @@ raop_handler_info(raop_conn_t *conn,
|
||||
utils_hwaddr_airplay(hw_addr, 3 * hw_addr_raw_len, hw_addr_raw, hw_addr_raw_len);
|
||||
|
||||
int pk_len = 0;
|
||||
char *pk = utils_parse_hex(AIRPLAY_PK, strlen(AIRPLAY_PK), &pk_len);
|
||||
|
||||
uint64_t features = ((uint64_t) strtoul(AIRPLAY_FEATURES_2, NULL, 16)) << 32;
|
||||
features += (uint64_t) strtoul(AIRPLAY_FEATURES_1, NULL, 16);
|
||||
char *pk = utils_parse_hex(PK, strlen(PK), &pk_len);
|
||||
|
||||
plist_t r_node = plist_new_dict();
|
||||
|
||||
plist_t txt_airplay_node = plist_new_data(airplay_txt, airplay_txt_len);
|
||||
plist_dict_set_item(r_node, "txtAirPlay", txt_airplay_node);
|
||||
|
||||
uint64_t features = dnssd_get_airplay_features(conn->raop->dnssd);
|
||||
plist_t features_node = plist_new_uint(features);
|
||||
plist_dict_set_item(r_node, "features", features_node);
|
||||
|
||||
@@ -94,44 +92,44 @@ raop_handler_info(raop_conn_t *conn,
|
||||
plist_t status_flags_node = plist_new_uint(68);
|
||||
plist_dict_set_item(r_node, "statusFlags", status_flags_node);
|
||||
|
||||
plist_t keep_alive_low_power_node = plist_new_uint(1);
|
||||
plist_dict_set_item(r_node, "keepAliveLowPower", keep_alive_low_power_node);
|
||||
|
||||
plist_t source_version_node = plist_new_string(GLOBAL_VERSION);
|
||||
plist_dict_set_item(r_node, "sourceVersion", source_version_node);
|
||||
|
||||
plist_t pk_node = plist_new_data(pk, pk_len);
|
||||
plist_dict_set_item(r_node, "pk", pk_node);
|
||||
|
||||
plist_t keep_alive_send_stats_as_body_node = plist_new_uint(1);
|
||||
plist_dict_set_item(r_node, "keepAliveSendStatsAsBody", keep_alive_send_stats_as_body_node);
|
||||
|
||||
plist_t device_id_node = plist_new_string(hw_addr);
|
||||
plist_dict_set_item(r_node, "deviceID", device_id_node);
|
||||
|
||||
plist_t audio_latencies_node = plist_new_array();
|
||||
plist_t audio_latencies_0_node = plist_new_dict();
|
||||
plist_t audio_latencies_0_audio_type_node = plist_new_string("default");
|
||||
plist_t audio_latencies_0_input_latency_micros_node = plist_new_uint(0);
|
||||
plist_t audio_latencies_0_output_latency_micros_node = plist_new_uint(0);
|
||||
plist_t audio_latencies_0_output_latency_micros_node = plist_new_bool(0);
|
||||
plist_t audio_latencies_0_type_node = plist_new_uint(100);
|
||||
plist_dict_set_item(audio_latencies_0_node, "audioType", audio_latencies_0_audio_type_node);
|
||||
plist_dict_set_item(audio_latencies_0_node, "inputLatencyMicros", audio_latencies_0_input_latency_micros_node);
|
||||
plist_t audio_latencies_0_audio_type_node = plist_new_string("default");
|
||||
plist_t audio_latencies_0_input_latency_micros_node = plist_new_bool(0);
|
||||
plist_dict_set_item(audio_latencies_0_node, "outputLatencyMicros", audio_latencies_0_output_latency_micros_node);
|
||||
plist_dict_set_item(audio_latencies_0_node, "type", audio_latencies_0_type_node);
|
||||
plist_dict_set_item(audio_latencies_0_node, "audioType", audio_latencies_0_audio_type_node);
|
||||
plist_dict_set_item(audio_latencies_0_node, "inputLatencyMicros", audio_latencies_0_input_latency_micros_node);
|
||||
plist_array_append_item(audio_latencies_node, audio_latencies_0_node);
|
||||
plist_t audio_latencies_1_node = plist_new_dict();
|
||||
plist_t audio_latencies_1_audio_type_node = plist_new_string("default");
|
||||
plist_t audio_latencies_1_input_latency_micros_node = plist_new_uint(0);
|
||||
plist_t audio_latencies_1_output_latency_micros_node = plist_new_uint(0);
|
||||
plist_t audio_latencies_1_output_latency_micros_node = plist_new_bool(0);
|
||||
plist_t audio_latencies_1_type_node = plist_new_uint(101);
|
||||
plist_dict_set_item(audio_latencies_1_node, "audioType", audio_latencies_1_audio_type_node);
|
||||
plist_dict_set_item(audio_latencies_1_node, "inputLatencyMicros", audio_latencies_1_input_latency_micros_node);
|
||||
plist_t audio_latencies_1_audio_type_node = plist_new_string("default");
|
||||
plist_t audio_latencies_1_input_latency_micros_node = plist_new_bool(0);
|
||||
plist_dict_set_item(audio_latencies_1_node, "outputLatencyMicros", audio_latencies_1_output_latency_micros_node);
|
||||
plist_dict_set_item(audio_latencies_1_node, "type", audio_latencies_1_type_node);
|
||||
plist_dict_set_item(audio_latencies_1_node, "audioType", audio_latencies_1_audio_type_node);
|
||||
plist_dict_set_item(audio_latencies_1_node, "inputLatencyMicros", audio_latencies_1_input_latency_micros_node);
|
||||
plist_array_append_item(audio_latencies_node, audio_latencies_1_node);
|
||||
plist_dict_set_item(r_node, "audioLatencies", audio_latencies_node);
|
||||
|
||||
plist_t keep_alive_low_power_node = plist_new_bool(1);
|
||||
plist_dict_set_item(r_node, "keepAliveLowPower", keep_alive_low_power_node);
|
||||
|
||||
plist_t keep_alive_send_stats_as_body_node = plist_new_bool(1);
|
||||
plist_dict_set_item(r_node, "keepAliveSendStatsAsBody", keep_alive_send_stats_as_body_node);
|
||||
|
||||
plist_t model_node = plist_new_string(GLOBAL_MODEL);
|
||||
plist_dict_set_item(r_node, "model", model_node);
|
||||
|
||||
@@ -152,6 +150,7 @@ raop_handler_info(raop_conn_t *conn,
|
||||
plist_t displays_0_max_fps_node = plist_new_uint(conn->raop->maxFPS);
|
||||
plist_t displays_0_overscanned_node = plist_new_bool(conn->raop->overscanned);
|
||||
plist_t displays_0_features = plist_new_uint(14);
|
||||
|
||||
plist_dict_set_item(displays_0_node, "uuid", displays_0_uuid_node);
|
||||
plist_dict_set_item(displays_0_node, "widthPhysical", displays_0_width_physical_node);
|
||||
plist_dict_set_item(displays_0_node, "heightPhysical", displays_0_height_physical_node);
|
||||
@@ -174,6 +173,41 @@ raop_handler_info(raop_conn_t *conn,
|
||||
free(hw_addr);
|
||||
}
|
||||
|
||||
static void
|
||||
raop_handler_pairpinstart(raop_conn_t *conn,
|
||||
http_request_t *request, http_response_t *response,
|
||||
char **response_data, int *response_datalen) {
|
||||
logger_log(conn->raop->logger, LOGGER_INFO, "client sent PAIR-PIN-START request");
|
||||
int pin_4 = random_pin();
|
||||
conn->raop->pin = (unsigned short) pin_4;
|
||||
if (pin_4 < 0) {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "Failed to generate random pin");
|
||||
} else {
|
||||
char pin[6];
|
||||
snprintf(pin, 5, "%04u", pin_4);
|
||||
if (conn->raop->callbacks.display_pin) {
|
||||
conn->raop->callbacks.display_pin(conn->raop->callbacks.cls, pin);
|
||||
}
|
||||
logger_log(conn->raop->logger, LOGGER_INFO, "*** CLIENT MUST NOW ENTER PIN = \"%s\" AS AIRPLAY PASSWORD", pin);
|
||||
}
|
||||
*response_data = NULL;
|
||||
response_datalen = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
raop_handler_pairsetup_pin(raop_conn_t *conn,
|
||||
http_request_t *request, http_response_t *response,
|
||||
char **response_data, int *response_datalen) {
|
||||
|
||||
/* does nothing yet */
|
||||
|
||||
|
||||
*response_data = NULL;
|
||||
response_datalen = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
raop_handler_pairsetup(raop_conn_t *conn,
|
||||
http_request_t *request, http_response_t *response,
|
||||
|
||||
@@ -126,6 +126,8 @@ static uint64_t remote_clock_offset = 0;
|
||||
static std::vector<std::string> allowed_clients;
|
||||
static std::vector<std::string> blocked_clients;
|
||||
static bool restrict_clients;
|
||||
static bool setup_legacy_pairing = true;
|
||||
static bool require_password = false;
|
||||
|
||||
/* logging */
|
||||
|
||||
@@ -607,6 +609,7 @@ static void print_info (char *name) {
|
||||
printf("Options:\n");
|
||||
printf("-n name Specify the network name of the AirPlay server\n");
|
||||
printf("-nh Do not add \"@hostname\" at the end of AirPlay server name\n");
|
||||
printf("-pair Support Airplay (legacy) client-pairing (default: not used)\n");
|
||||
printf("-vsync [x]Mirror mode: sync audio to video using timestamps (default)\n");
|
||||
printf(" x is optional audio delay: millisecs, decimal, can be neg.\n");
|
||||
printf("-vsync no Switch off audio/(server)video timestamp synchronization \n");
|
||||
|
||||
Reference in New Issue
Block a user