From: Mike Brady Date: Wed, 27 Mar 2019 11:44:58 +0000 (+0000) Subject: Add tentative raw PCM input facility. Clean up some messages. X-Git-Tag: 3.3RC2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d8835759162704b22a6dbb1007bc9360b7b9bb25;p=thirdparty%2Fshairport-sync.git Add tentative raw PCM input facility. Clean up some messages. --- d8835759162704b22a6dbb1007bc9360b7b9bb25 diff --cc audio_alsa.c index 48491717,99dcf405..8bb54584 --- a/audio_alsa.c +++ b/audio_alsa.c @@@ -1584,62 -1548,11 +1584,75 @@@ void alsa_buffer_monitor_thread_cleanup } */ +// 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 starting check..."); + // 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); - 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); ++ // 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) { - precision_delay_available_status = uses_update_timestamps; ++ 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 8de83de3,8962d344..74372dbb --- a/rtsp.c +++ b/rtsp.c @@@ -1776,6 -1788,35 +1788,35 @@@ static void handle_announce(rtsp_conn_i cp = next; } + if (pUncompressedCDAudio) { - debug(1, "pUncompressedCDAudio detected."); ++ 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); @@@ -1837,12 -1862,41 +1862,41 @@@ 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) {