// successive rtptimes, at worst
conn->output_sample_ratio = config.output_rate / conn->input_rate;
-
-
-// Sign extending rtptime calculations to 64 bit is needed from time to time.
-// The standard rtptime is unsigned 32 bits,
-// so you can do modulo 2^32 difference calculations
-// and get a signed result simply by typing the result as a signed 32-bit number.
+ // Sign extending rtptime calculations to 64 bit is needed from time to time.
-// So long as you can be sure the numbers are within 2^31 of each other,
-// the sign of the result calculated in this way indicates the order of the operands.
-// For example, if you subtract a from b and the result is positive, you can conclude
-// b is the same as or comes after a in module 2^32 order.
+ // The standard rtptime is unsigned 32 bits,
+ // so you can do modulo 2^32 difference calculations
+ // and get a signed result simply by typing the result as a signed 32-bit number.
-// We want to do the same with the rtptime calculations for multiples of
-// the rtptimes (1, 2, 4 or 8 times), and we want to do this in signed 64-bit/
-// Therefore we need to sign extend these modulo 2^32, 2^33, 2^34, or 2^35 bit unsigned
-// numbers on the same basis.
+ // So long as you can be sure the numbers are within 2^31 of each other,
+ // the sign of the result calculated in this way indicates the order of the operands.
+ // For example, if you subtract a from b and the result is positive, you can conclude
+ // b is the same as or comes after a in module 2^32 order.
-// That is what the output_rtptime_sign_bit, output_rtptime_mask, output_rtptime_mask_not and
-// output_rtptime_sign_mask are for -- see later, calculating the sync error.
+ // We want to do the same with the rtptime calculations for multiples of
+ // the rtptimes (1, 2, 4 or 8 times), and we want to do this in signed 64-bit/
+ // Therefore we need to sign extend these modulo 2^32, 2^33, 2^34, or 2^35 bit unsigned
+ // numbers on the same basis.
+ // That is what the output_rtptime_sign_bit, output_rtptime_mask, output_rtptime_mask_not and
+ // output_rtptime_sign_mask are for -- see later, calculating the sync error.
int output_rtptime_sign_bit;
switch (conn->output_sample_ratio) {
}
#endif
-
#ifdef CONFIG_AIRPLAY_2
if (conn->timing_type == ts_ntp) {
#endif
// if it's both, we haven't decided whether hw or sw should be on top
// we have to consider the settings ignore_volume_control and mute.
- if (config.ignore_volume_control == 0) {
- if (airplay_volume == -144.0) {
-
- if ((config.output->mute) && (config.output->mute(1) == 0))
- debug(2,
- "player_volume_without_notification: volume mode is %d, airplay_volume is %f, "
- "hardware mute is enabled.",
- volume_mode, airplay_volume);
- else {
- conn->software_mute_enabled = 1;
- debug(2,
- "player_volume_without_notification: volume mode is %d, airplay_volume is %f, "
- "software mute is enabled.",
- volume_mode, airplay_volume);
- }
+ if (airplay_volume == -144.0) {
+
+ if ((config.output->mute) && (config.output->mute(1) == 0))
+ debug(2,
+ "player_volume_without_notification: volume mode is %d, airplay_volume is %f, "
+ "hardware mute is enabled.",
+ volume_mode, airplay_volume);
+ else {
+ conn->software_mute_enabled = 1;
+ debug(2,
+ "player_volume_without_notification: volume mode is %d, airplay_volume is %f, "
+ "software mute is enabled.",
+ volume_mode, airplay_volume);
+ }
+
+ } else {
+ int32_t max_db = 0, min_db = 0;
+ switch (volume_mode) {
+ case vol_hw_only:
+ max_db = hw_max_db;
+ min_db = hw_min_db;
+ break;
+ case vol_sw_only:
+ max_db = sw_max_db;
+ min_db = sw_min_db;
+ break;
+ case vol_both:
+ // debug(1, "dB range passed is hw: %d, sw: %d, total: %d", hw_max_db - hw_min_db,
+ // sw_max_db - sw_min_db, (hw_max_db - hw_min_db) + (sw_max_db - sw_min_db));
+ max_db =
+ (hw_max_db - hw_min_db) + (sw_max_db - sw_min_db); // this should be the range requested
+ min_db = 0;
+ break;
+ default:
+ debug(1, "player_volume_without_notification: error: not in a volume mode");
+ break;
+ }
+ double scaled_attenuation = max_db;
+ if (config.ignore_volume_control == 0) {
- } else {
- int32_t max_db = 0, min_db = 0;
- switch (volume_mode) {
- case vol_hw_only:
- max_db = hw_max_db;
- min_db = hw_min_db;
- break;
- case vol_sw_only:
- max_db = sw_max_db;
- min_db = sw_min_db;
- break;
- case vol_both:
- // debug(1, "dB range passed is hw: %d, sw: %d, total: %d", hw_max_db - hw_min_db,
- // sw_max_db - sw_min_db, (hw_max_db - hw_min_db) + (sw_max_db - sw_min_db));
- max_db =
- (hw_max_db - hw_min_db) + (sw_max_db - sw_min_db); // this should be the range requested
- min_db = 0;
- break;
- default:
- debug(1, "player_volume_without_notification: error: not in a volume mode");
- break;
- }
- double scaled_attenuation = 0.0;
if (config.volume_control_profile == VCP_standard)
scaled_attenuation = vol2attn(airplay_volume, max_db, min_db); // no cancellation points
else if (config.volume_control_profile == VCP_flat)
flat_vol2attn(airplay_volume, max_db, min_db); // no cancellation points
else
debug(1, "player_volume_without_notification: unrecognised volume control profile");
+ }
+ // so here we have the scaled attenuation. If it's for hw or sw only, it's straightforward.
+ double hardware_attenuation = 0.0;
+ double software_attenuation = 0.0;
- // so here we have the scaled attenuation. If it's for hw or sw only, it's straightforward.
- double hardware_attenuation = 0.0;
- double software_attenuation = 0.0;
-
- switch (volume_mode) {
- case vol_hw_only:
- hardware_attenuation = scaled_attenuation;
- break;
- case vol_sw_only:
- software_attenuation = scaled_attenuation;
- break;
- case vol_both:
- // here, we now the attenuation required, so we have to apportion it to the sw and hw mixers
- // if we give the hw priority, that means when lowering the volume, set the hw volume to its
- // lowest
- // before using the sw attenuation.
- // similarly, if we give the sw priority, that means when lowering the volume, set the sw
- // volume to its lowest
- // before using the hw attenuation.
- // one imagines that hw priority is likely to be much better
- // if (config.volume_range_hw_priority) {
- if (config.volume_range_hw_priority != 0) {
- // hw priority
- if ((sw_max_db - sw_min_db) > scaled_attenuation) {
- software_attenuation = sw_min_db + scaled_attenuation;
- hardware_attenuation = hw_min_db;
- } else {
- software_attenuation = sw_max_db;
- hardware_attenuation = hw_min_db + scaled_attenuation - (sw_max_db - sw_min_db);
- }
+ switch (volume_mode) {
+ case vol_hw_only:
+ hardware_attenuation = scaled_attenuation;
+ break;
+ case vol_sw_only:
+ software_attenuation = scaled_attenuation;
+ break;
+ case vol_both:
+ // here, we now the attenuation required, so we have to apportion it to the sw and hw mixers
+ // if we give the hw priority, that means when lowering the volume, set the hw volume to its
+ // lowest
+ // before using the sw attenuation.
+ // similarly, if we give the sw priority, that means when lowering the volume, set the sw
+ // volume to its lowest
+ // before using the hw attenuation.
+ // one imagines that hw priority is likely to be much better
+ // if (config.volume_range_hw_priority) {
+ if (config.volume_range_hw_priority != 0) {
+ // hw priority
+ if ((sw_max_db - sw_min_db) > scaled_attenuation) {
+ software_attenuation = sw_min_db + scaled_attenuation;
+ hardware_attenuation = hw_min_db;
} else {
- // sw priority
- if ((hw_max_db - hw_min_db) > scaled_attenuation) {
- hardware_attenuation = hw_min_db + scaled_attenuation;
- software_attenuation = sw_min_db;
- } else {
- hardware_attenuation = hw_max_db;
- software_attenuation = sw_min_db + scaled_attenuation - (hw_max_db - hw_min_db);
- }
+ software_attenuation = sw_max_db;
+ hardware_attenuation = hw_min_db + scaled_attenuation - (sw_max_db - sw_min_db);
+ }
+ } else {
+ // sw priority
+ if ((hw_max_db - hw_min_db) > scaled_attenuation) {
+ hardware_attenuation = hw_min_db + scaled_attenuation;
+ software_attenuation = sw_min_db;
+ } else {
+ hardware_attenuation = hw_max_db;
+ software_attenuation = sw_min_db + scaled_attenuation - (hw_max_db - hw_min_db);
}
- break;
- default:
- debug(1, "player_volume_without_notification: error: not in a volume mode");
- break;
- }
-
- if (((volume_mode == vol_hw_only) || (volume_mode == vol_both)) && (config.output->volume)) {
- config.output->volume(hardware_attenuation); // otherwise set the output to the lowest value
- // debug(1,"Hardware attenuation set to %f for airplay volume of
- // %f.",hardware_attenuation,airplay_volume);
- if (volume_mode == vol_hw_only)
- conn->fix_volume = 0x10000;
}
+ break;
+ default:
+ debug(1, "player_volume_without_notification: error: not in a volume mode");
+ break;
+ }
- if ((volume_mode == vol_sw_only) || (volume_mode == vol_both)) {
- double temp_fix_volume = 65536.0 * pow(10, software_attenuation / 2000);
- // debug(1,"Software attenuation set to %f, i.e %f out of 65,536, for airplay volume of
- // %f",software_attenuation,temp_fix_volume,airplay_volume);
+ if (((volume_mode == vol_hw_only) || (volume_mode == vol_both)) && (config.output->volume)) {
+ config.output->volume(hardware_attenuation); // otherwise set the output to the lowest value
+ // debug(1,"Hardware attenuation set to %f for airplay volume of
+ // %f.",hardware_attenuation,airplay_volume);
+ if (volume_mode == vol_hw_only)
+ conn->fix_volume = 0x10000;
+ }
- conn->fix_volume = temp_fix_volume;
+ if ((volume_mode == vol_sw_only) || (volume_mode == vol_both)) {
+ double temp_fix_volume = 65536.0 * pow(10, software_attenuation / 2000);
- // if (config.loudness)
- loudness_set_volume(software_attenuation / 100);
- }
-
- if (config.logOutputLevel) {
- inform("Output Level set to: %.2f dB.", scaled_attenuation / 100.0);
- }
+ if (config.ignore_volume_control == 0)
+ debug(2, "Software attenuation set to %f, i.e %f out of 65,536, for airplay volume of %f",
+ software_attenuation, temp_fix_volume, airplay_volume);
+ else
+ debug(2, "Software attenuation set to %f, i.e %f out of 65,536. Volume control is ignored.",
+ software_attenuation, temp_fix_volume);
-#ifdef CONFIG_METADATA
- // here, send the 'pvol' metadata message when the airplay volume information
- // is being used by shairport sync to control the output volume
- char dv[128];
- memset(dv, 0, 128);
- if (volume_mode == vol_both) {
- // normalise the maximum output to the hardware device's max output
- snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
- (scaled_attenuation - max_db + hw_max_db) / 100.0,
- (min_db - max_db + hw_max_db) / 100.0, (max_db - max_db + hw_max_db) / 100.0);
- } else {
- snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, scaled_attenuation / 100.0,
- min_db / 100.0, max_db / 100.0);
- }
- send_ssnc_metadata('pvol', dv, strlen(dv), 1);
-#endif
+ conn->fix_volume = temp_fix_volume;
- if (config.output->mute)
- config.output->mute(0);
- conn->software_mute_enabled = 0;
+ // if (config.loudness)
+ loudness_set_volume(software_attenuation / 100);
+ }
- debug(2,
- "player_volume_without_notification: volume mode is %d, airplay volume is %f, "
- "software_attenuation: %f, hardware_attenuation: %f, muting "
- "is disabled.",
- volume_mode, airplay_volume, software_attenuation, hardware_attenuation);
+ if (config.logOutputLevel) {
+ inform("Output Level set to: %.2f dB.", scaled_attenuation / 100.0);
}
- }
#ifdef CONFIG_METADATA
- else {
// here, send the 'pvol' metadata message when the airplay volume information
// is being used by shairport sync to control the output volume
char dv[128];
memset(dv, 0, 128);
- snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, 0.0, 0.0, 0.0);
+ if (volume_mode == vol_both) {
+ // normalise the maximum output to the hardware device's max output
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
+ (scaled_attenuation - max_db + hw_max_db) / 100.0,
+ (min_db - max_db + hw_max_db) / 100.0, (max_db - max_db + hw_max_db) / 100.0);
+ } else {
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, scaled_attenuation / 100.0,
+ min_db / 100.0, max_db / 100.0);
+ }
send_ssnc_metadata('pvol', dv, strlen(dv), 1);
- }
#endif
+ if (config.output->mute)
+ config.output->mute(0);
+ conn->software_mute_enabled = 0;
+
+ debug(2,
+ "player_volume_without_notification: volume mode is %d, airplay volume is %f, "
+ "software_attenuation: %f, hardware_attenuation: %f, muting "
+ "is disabled.",
+ volume_mode, airplay_volume, software_attenuation, hardware_attenuation);
+ }
+ /*
+ }
+
+ #ifdef CONFIG_METADATA
+ else {
+ // here, send the 'pvol' metadata message when the airplay volume information
+ // is being used by shairport sync to control the output volume
+ char dv[128];
+ memset(dv, 0, 128);
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, 0.0, 0.0, 0.0);
+ send_ssnc_metadata('pvol', dv, strlen(dv), 1);
+ }
+ #endif
+ */
// here, store the volume for possible use in the future
config.airplay_volume = airplay_volume;
debug_mutex_unlock(&conn->volume_control_mutex, 3);
#include <sys/ioctl.h>
-#include "config.h"
#include "activity_monitor.h"
+#include "config.h"
#ifdef CONFIG_OPENSSL
#include <openssl/md5.h>
uint8_t public_key[32];
struct pairings *next;
-} *pairings;
+} * pairings;
-static struct pairings * pairing_find(const char *device_id)
-{
+static struct pairings *pairing_find(const char *device_id) {
for (struct pairings *pairing = pairings; pairing; pairing = pairing->next) {
if (strcmp(device_id, pairing->device_id) == 0)
return pairing;
free(pairing);
}
-static int pairing_add_cb(uint8_t public_key[32], const char *device_id, void *cb_arg __attribute__((unused))) {
+static int pairing_add_cb(uint8_t public_key[32], const char *device_id,
+ void *cb_arg __attribute__((unused))) {
debug(1, "pair-add cb for %s", device_id);
struct pairings *pairing = pairing_find(device_id);
return 0;
}
-static int pairing_remove_cb(uint8_t public_key[32] __attribute__((unused)), const char *device_id, void *cb_arg __attribute__((unused))) {
+static int pairing_remove_cb(uint8_t public_key[32] __attribute__((unused)), const char *device_id,
+ void *cb_arg __attribute__((unused))) {
debug(1, "pair-remove cb for %s", device_id);
struct pairings *pairing = pairing_find(device_id);
return 0;
}
-static void pairing_list_cb(pair_cb enum_cb, void *enum_cb_arg, void *cb_arg __attribute__((unused))) {
+static void pairing_list_cb(pair_cb enum_cb, void *enum_cb_arg,
+ void *cb_arg __attribute__((unused))) {
debug(1, "pair-list cb");
for (struct pairings *pairing = pairings; pairing; pairing = pairing->next) {
}
}
-void handle_pair_add(rtsp_conn_info *conn __attribute__((unused)), rtsp_message *req, rtsp_message *resp) {
+void handle_pair_add(rtsp_conn_info *conn __attribute__((unused)), rtsp_message *req,
+ rtsp_message *resp) {
uint8_t *body = NULL;
size_t body_len = 0;
- int ret = pair_add(PAIR_SERVER_HOMEKIT, &body, &body_len, pairing_add_cb, NULL, (const uint8_t *)req->content, req->contentlength);
+ int ret = pair_add(PAIR_SERVER_HOMEKIT, &body, &body_len, pairing_add_cb, NULL,
+ (const uint8_t *)req->content, req->contentlength);
if (ret < 0) {
debug(1, "pair-add returned an error");
resp->respcode = 451;
debug_log_rtsp_message(2, "pair-add response", resp);
}
-void handle_pair_list(rtsp_conn_info *conn __attribute__((unused)), rtsp_message *req, rtsp_message *resp) {
+void handle_pair_list(rtsp_conn_info *conn __attribute__((unused)), rtsp_message *req,
+ rtsp_message *resp) {
uint8_t *body = NULL;
size_t body_len = 0;
- int ret = pair_list(PAIR_SERVER_HOMEKIT, &body, &body_len, pairing_list_cb, NULL, (const uint8_t *)req->content, req->contentlength);
+ int ret = pair_list(PAIR_SERVER_HOMEKIT, &body, &body_len, pairing_list_cb, NULL,
+ (const uint8_t *)req->content, req->contentlength);
if (ret < 0) {
debug(1, "pair-list returned an error");
resp->respcode = 451;
debug_log_rtsp_message(2, "pair-list response", resp);
}
-void handle_pair_remove(rtsp_conn_info *conn __attribute__((unused)), rtsp_message *req, rtsp_message *resp) {
+void handle_pair_remove(rtsp_conn_info *conn __attribute__((unused)), rtsp_message *req,
+ rtsp_message *resp) {
uint8_t *body = NULL;
size_t body_len = 0;
- int ret = pair_remove(PAIR_SERVER_HOMEKIT, &body, &body_len, pairing_remove_cb, NULL, (const uint8_t *)req->content, req->contentlength);
+ int ret = pair_remove(PAIR_SERVER_HOMEKIT, &body, &body_len, pairing_remove_cb, NULL,
+ (const uint8_t *)req->content, req->contentlength);
if (ret < 0) {
debug(1, "pair-remove returned an error");
resp->respcode = 451;
}
/*
- <key>Identifier</key>
- <string>21cc689d-d5de-4814-872c-71d1426b57e0</string>
- <key>Enable_HK_Access_Control</key>
- <true/>
- <key>PublicKey</key>
- <data>
- qXJDhhL5F3OACL+HO7LVLQVdy0OJtavepjpF720PaOQ=
- </data>
- <key>Device_Name</key>
- <string>MyDevice</string>
- <key>Access_Control_Level</key>
- <integer>0</integer>
+ <key>Identifier</key>
+ <string>21cc689d-d5de-4814-872c-71d1426b57e0</string>
+ <key>Enable_HK_Access_Control</key>
+ <true/>
+ <key>PublicKey</key>
+ <data>
+ qXJDhhL5F3OACL+HO7LVLQVdy0OJtavepjpF720PaOQ=
+ </data>
+ <key>Device_Name</key>
+ <string>MyDevice</string>
+ <key>Access_Control_Level</key>
+ <integer>0</integer>
*/
-void handle_configure(rtsp_conn_info *conn __attribute__((unused)), rtsp_message *req __attribute__((unused)), rtsp_message *resp) {
+void handle_configure(rtsp_conn_info *conn __attribute__((unused)),
+ rtsp_message *req __attribute__((unused)), rtsp_message *resp) {
uint8_t public_key[32];
pair_public_key_get(PAIR_SERVER_HOMEKIT, public_key, config.airplay_device_id);
plist_dict_set_item(response_plist, "Identifier", plist_new_string(config.airplay_pi));
plist_dict_set_item(response_plist, "Enable_HK_Access_Control", plist_new_bool(1));
- plist_dict_set_item(response_plist, "PublicKey", plist_new_data((const char *)public_key, sizeof(public_key)));
+ plist_dict_set_item(response_plist, "PublicKey",
+ plist_new_data((const char *)public_key, sizeof(public_key)));
plist_dict_set_item(response_plist, "Device_Name", plist_new_string(config.service_name));
plist_dict_set_item(response_plist, "Access_Control_Level", plist_new_uint(0));
// hack.
conn->max_frames_per_packet = 352; // number of audio frames per packet.
- conn->input_rate = 44100; // we are stuck with this for the moment.
+ conn->input_rate = 44100; // we are stuck with this for the moment.
conn->input_num_channels = 2;
conn->input_bit_depth = 16;
conn->input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8);
plist_dict_set_item(stream0dict, "audioBufferSize",
plist_new_uint(conn->ap2_audio_buffer_size));
-
// this should be cancelled by an activity_monitor_signify_activity(1)
// call in the SETRATEANCHORI handler, which should come up right away
activity_monitor_signify_activity(0);
*p++ = ap1_featuresString;
*p++ = firmware_version;
*p++ = "md=2";
- *p++ = "am=SPS";
+ *p++ = "am=Shairport Sync";
*p++ = "sf=0x4";
*p++ = "tp=UDP";
*p++ = "vn=65537";
*p++ = "acl=0";
*p++ = "rsf=0x0";
*p++ = firmware_version;
- *p++ = "model=SPS";
+ *p++ = "model=Shairport Sync";
char piString[64];
snprintf(piString, sizeof(piString), "pi=%s", config.airplay_pi);
*p++ = piString;