]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Honour max_output_db setting even when ignore_volume_control is true. Spell out ...
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Fri, 16 Jul 2021 14:04:51 +0000 (15:04 +0100)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Fri, 16 Jul 2021 14:04:51 +0000 (15:04 +0100)
player.c
rtsp.c

index 70ba36ec2d942e407e4d124c2318edcaf0e6d160..ac332a4366d955fdfc363812fae094fc833b87e1 100644 (file)
--- a/player.c
+++ b/player.c
@@ -1760,27 +1760,25 @@ void *player_thread_func(void *arg) {
                                                             // 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) {
@@ -2022,7 +2020,6 @@ void *player_thread_func(void *arg) {
   }
 #endif
 
-
 #ifdef CONFIG_AIRPLAY_2
   if (conn->timing_type == ts_ntp) {
 #endif
@@ -2940,45 +2937,46 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
   // 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)
@@ -2986,116 +2984,122 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
             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);
diff --git a/rtsp.c b/rtsp.c
index ba09ce15643e66c94efaa546645c090f1b912310..7e6ff7cf025d4f49f330f73414f40649618f3e5b 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -50,8 +50,8 @@
 
 #include <sys/ioctl.h>
 
-#include "config.h"
 #include "activity_monitor.h"
+#include "config.h"
 
 #ifdef CONFIG_OPENSSL
 #include <openssl/md5.h>
@@ -1560,10 +1560,9 @@ struct pairings {
   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;
@@ -1595,7 +1594,8 @@ static void pairing_remove(struct pairings *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);
@@ -1608,7 +1608,8 @@ static int pairing_add_cb(uint8_t public_key[32], const char *device_id, void *c
   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);
@@ -1621,7 +1622,8 @@ static int pairing_remove_cb(uint8_t public_key[32] __attribute__((unused)), con
   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) {
@@ -1629,10 +1631,12 @@ static void pairing_list_cb(pair_cb enum_cb, void *enum_cb_arg, void *cb_arg __a
   }
 }
 
-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;
@@ -1644,10 +1648,12 @@ void handle_pair_add(rtsp_conn_info *conn __attribute__((unused)), rtsp_message
   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;
@@ -1659,10 +1665,12 @@ void handle_pair_list(rtsp_conn_info *conn __attribute__((unused)), rtsp_message
   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;
@@ -1867,20 +1875,21 @@ void handle_fp_setup(__attribute__((unused)) rtsp_conn_info *conn, rtsp_message
 }
 
 /*
-       <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);
@@ -1889,7 +1898,8 @@ void handle_configure(rtsp_conn_info *conn __attribute__((unused)), rtsp_message
 
   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));
 
@@ -2238,7 +2248,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
 
       // 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);
@@ -2254,7 +2264,6 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
       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);
@@ -4414,7 +4423,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
     *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";
@@ -4475,7 +4484,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
     *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;