]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add tentative raw PCM input facility. Clean up some messages.
authorMike Brady <mikebrady@eircom.net>
Wed, 27 Mar 2019 11:44:58 +0000 (11:44 +0000)
committerMike Brady <mikebrady@eircom.net>
Wed, 27 Mar 2019 11:44:58 +0000 (11:44 +0000)
1  2 
audio_alsa.c
rtsp.c

diff --cc audio_alsa.c
index 484917176204bdc393369ca990663f5ff09ce838,99dcf405b98a30ce9c40a432a94c1f35652fcbde..8bb54584a1188f655d66044c0ee4aa1b56bbada5
@@@ -1584,62 -1548,11 +1584,75 @@@ void alsa_buffer_monitor_thread_cleanup
  }
  */
  
-     debug(1,"alsa: precision_delay_available starting check...");
 +// this will return true if the DAC can return precision delay information and false if not
 +// if it is not yet known, it will test the output device to find out
 +
++// note -- once it has done the test, it decides -- even if the delay comes back with
++// "don't know", it will take that as a "No" and remember it.
++// If you want it to check again, set precision_delay_available_status to YNDK_DONT_KNOW
++// first.
++
++
 +int precision_delay_available() {
 +  if (precision_delay_available_status == YNDK_DONT_KNOW) {
-       debug(1,"alsa: precision_delay_available asking for delay and status with a return status of %d, a delay of %ld and a uses_update_timestamps of %d.", ret, delay, uses_update_timestamps);     
 +    // At present, the only criterion as to whether precision delay is available
 +    // is whether the device driver returns non-zero update timestamps
 +    // If it does, it is considered precision delay is available
 +    // Otherwise, it's considered to be unavailable
 +    
 +    // To test, we play a silence buffer (fairly large to avoid underflow)
 +    // and then we check the delay return. It will tell us if it 
 +    // was able to use the (non-zero) update timestamps
 +        
 +    int frames_of_silence = 4410;
 +    size_t size_of_silence_buffer = frames_of_silence * frame_size;
 +    void *silence = malloc(size_of_silence_buffer);
 +    if (silence == NULL) {
 +      debug(1, "alsa: precision_delay_available -- failed to "
 +               "allocate memory for a "
 +               "silent frame buffer.");
 +    } else {
 +      pthread_cleanup_push(malloc_cleanup, silence);
 +      int use_dither = 0;
 +      if ((hardware_mixer == 0) && (config.ignore_volume_control == 0) &&
 +          (config.airplay_volume != 0.0))
 +        use_dither = 1;
 +      dither_random_number_store =
 +          generate_zero_frames(silence, frames_of_silence, config.output_format,
 +                               use_dither, // i.e. with dither
 +                               dither_random_number_store);
 +      // debug(1,"Play %d frames of silence with most_recent_write_time of
 +      // %" PRIx64 ".",
 +      //    frames_of_silence,most_recent_write_time);
 +      do_play(silence, frames_of_silence);
 +      pthread_cleanup_pop(1);
 +      // now we can get the delay, and we'll note if it uses update timestamps
 +      enum yndk_type uses_update_timestamps;
 +      snd_pcm_state_t state;
 +      snd_pcm_sframes_t delay;     
 +      int ret = delay_and_status(&state, &delay, &uses_update_timestamps);
-         precision_delay_available_status = uses_update_timestamps;
++      // debug(3,"alsa: precision_delay_available asking for delay and status with a return status of %d, a delay of %ld and a uses_update_timestamps of %d.", ret, delay, uses_update_timestamps);     
 +      if (ret == 0) {
++        if (uses_update_timestamps == YNDK_YES) {
++          precision_delay_available_status = YNDK_YES;
++          debug(2,"alsa: precision delay timing available.");
++        } else {
++          precision_delay_available_status = YNDK_NO;
++          inform("Note: the alsa output device \"%s\" is not capable of precision delay timing. Could it be a virtual device?", snd_pcm_name(alsa_handle));
++          if (config.disable_standby_mode != disable_standby_off)
++            inform("Note: disable_standby_mode has been turned off because the output device is not capable of precision delay timing.");
++        }
 +      }
 +    }
 +  }
 +  return (precision_delay_available_status == YNDK_YES);
 +}
 +
  void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) {
    int okb = -1;
    while (1) {
      if (okb != config.keep_dac_busy) {
--      debug(1,"keep_dac_busy is now \"%s\"",config.keep_dac_busy == 0 ? "no" : "yes");
++      debug(2,"keep_dac_busy is now \"%s\"",config.keep_dac_busy == 0 ? "no" : "yes");
        okb = config.keep_dac_busy;
      }
      if ((config.keep_dac_busy != 0) && (alsa_device_initialised == 0)) {
diff --cc rtsp.c
index 8de83de3319791dcc49a258a9b55262eeba2007d,8962d344d5c18b2c2f9a56f0c353a8dcaedbce0a..74372dbb9606523c93e84ab6e1fc005e8e28208b
--- 1/rtsp.c
--- 2/rtsp.c
+++ b/rtsp.c
@@@ -1776,6 -1788,35 +1788,35 @@@ static void handle_announce(rtsp_conn_i
        cp = next;
      }
  
 -      debug(1, "pUncompressedCDAudio detected.");
+     if (pUncompressedCDAudio) {
++      debug(1, "An uncompressed PCM stream has been detected.");
+       conn->stream.type = ast_uncompressed;
+       conn->max_frames_per_packet = 352; // number of audio frames per packet.
+       conn->input_rate = 44100;
+       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);
+       /*
+       int y = strlen(pAudioMediaInfo);
+       if (y > 0) {
+         char obf[4096];
+         if (y > 4096)
+           y = 4096;
+         char *p = pAudioMediaInfo;
+         char *obfp = obf;
+         int obfc;
+         for (obfc = 0; obfc < y; obfc++) {
+           snprintf(obfp, 3, "%02X", (unsigned int)*p);
+           p++;
+           obfp += 2;
+         };
+         *obfp = 0;
+         debug(1, "AudioMediaInfo: \"%s\".", obf);
+       }
+       */
+     }
      if (pssid) {
        uint32_t ssid = uatoi(pssid);
        debug(3, "Synchronisation Source Identifier: %08X,%u", ssid, ssid);
        memcpy(conn->stream.aeskey, aeskey, 16);
        free(aeskey);
      }
-     unsigned int i;
-     for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++)
-       conn->stream.fmtp[i] = atoi(strsep(&pfmtp, " \t"));
-     // here we should check the sanity ot the fmtp values
-     // for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++)
-     //  debug(1,"  fmtp[%2d] is: %10d",i,conn->stream.fmtp[i]);
+     if (pfmtp) {
+       conn->stream.type = ast_apple_lossless;
 -      debug(1, "pAppleLossless detected.");
++      debug(1, "An ALAC stream has been detected.");
+       unsigned int i;
+       for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++)
+         conn->stream.fmtp[i] = atoi(strsep(&pfmtp, " \t"));
+       // here we should check the sanity ot the fmtp values
+       // for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++)
+       //  debug(1,"  fmtp[%2d] is: %10d",i,conn->stream.fmtp[i]);
+       // set the parameters of the player (as distinct from the parameters of the decoder -- that's
+       // done later).
+       conn->max_frames_per_packet = conn->stream.fmtp[1]; // number of audio frames per packet.
+       conn->input_rate = conn->stream.fmtp[11];
+       conn->input_num_channels = conn->stream.fmtp[7];
+       conn->input_bit_depth = conn->stream.fmtp[3];
+       conn->input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8);
+     }
+     if (conn->stream.type == ast_unknown) {
+       warn("Can not process the following ANNOUNCE message:");
+       // print each line of the request content
+       // the problem is that nextline has replace all returns, newlines, etc. by
+       // NULLs
+       char *cp = req->content;
+       int cp_left = req->contentlength;
+       while (cp_left > 1) {
+         if (strlen(cp) != 0)
+           warn("    %s", cp);
+         cp += strlen(cp) + 1;
+         cp_left -= strlen(cp) + 1;
+       }
+       goto out;
+     }
  
      char *hdr = msg_get_header(req, "X-Apple-Client-Name");
      if (hdr) {