Files
shairport-sync/player.c
T

5114 lines
215 KiB
C

/*
* Slave-clocked ALAC stream player. This file is part of Shairport.
* Copyright (c) James Laird 2011, 2013
* All rights reserved.
*
* Modifications for audio synchronisation, AirPlay 2
* and related work, copyright (c) Mike Brady 2014--2025
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syslog.h>
#include <sys/types.h>
#include <unistd.h>
#include "config.h"
#ifdef CONFIG_MBEDTLS
#include <mbedtls/aes.h>
#endif
#ifdef CONFIG_POLARSSL
#include <polarssl/aes.h>
#include <polarssl/havege.h>
#endif
#ifdef CONFIG_OPENSSL
#include <openssl/aes.h> // needed for older AES stuff
#include <openssl/bio.h> // needed for BIO_new_mem_buf
#include <openssl/err.h> // needed for ERR_error_string, ERR_get_error
#include <openssl/evp.h> // needed for EVP_PKEY_CTX_new, EVP_PKEY_sign_init, EVP_PKEY_sign
#include <openssl/pem.h> // needed for PEM_read_bio_RSAPrivateKey, EVP_PKEY_CTX_set_rsa_padding
#include <openssl/rsa.h> // needed for EVP_PKEY_CTX_set_rsa_padding
#endif
#ifdef CONFIG_SOXR
#include <soxr.h>
#endif
#ifdef CONFIG_CONVOLUTION
#include <FFTConvolver/convolver.h>
#endif
#ifdef CONFIG_METADATA_HUB
#include "metadata_hub.h"
#endif
#ifdef CONFIG_DACP_CLIENT
#include "dacp.h"
#endif
#include "common.h"
#include "mdns.h"
#include "player.h"
#include "rtp.h"
#include "rtsp.h"
#include "alac.h"
#ifdef CONFIG_APPLE_ALAC
#include "apple_alac.h"
#endif
#ifdef CONFIG_AIRPLAY_2
#include "ptp-utilities.h"
#endif
#ifdef CONFIG_FFMPEG
#include <libavutil/version.h>
#endif
#include "loudness.h"
#include "activity_monitor.h"
const unsigned int silent_channel_index = 65;
const unsigned int front_mono_channel_index = 66;
// default buffer size
// needs to be a power of 2 because of the way BUFIDX(seqno) works
// #define BUFFER_FRAMES 512
// DAC buffer occupancy stuff
#define DAC_BUFFER_QUEUE_MINIMUM_LENGTH 2500
// static abuf_t audio_buffer[BUFFER_FRAMES];
#define BUFIDX(seqno) ((seq_t)(seqno) % BUFFER_FRAMES)
void do_flush(uint32_t timestamp, rtsp_conn_info *conn);
#ifdef CONFIG_FFMPEG
size_t avflush(rtsp_conn_info *conn);
#endif
int free_audio_buffer_payload(abuf_t *abuf) {
int items_freed = 0;
if (abuf) {
if (abuf->data != NULL) {
free(abuf->data);
items_freed++;
abuf->data = NULL;
}
#ifdef CONFIG_FFMPEG
if (abuf->avframe != NULL) {
av_frame_free(&abuf->avframe);
items_freed++;
abuf->avframe = NULL;
abuf->ssrc = SSRC_NONE;
}
#endif
} else {
debug(1, "null buffer pointer!");
}
return items_freed;
}
void ab_resync(rtsp_conn_info *conn) {
int i;
for (i = 0; i < BUFFER_FRAMES; i++) {
free_audio_buffer_payload(&conn->audio_buffer[i]);
conn->audio_buffer[i].ready = 0;
conn->audio_buffer[i].resend_request_number = 0;
conn->audio_buffer[i].resend_time =
0; // this is either zero or the time the last resend was requested.
conn->audio_buffer[i].initialisation_time =
0; // this is either the time the packet was received or the time it was noticed the packet
// was missing.
conn->audio_buffer[i].sequence_number = 0;
}
conn->ab_synced = 0;
conn->last_seqno_valid = 0;
conn->ab_buffering = 1;
}
void reset_input_flow_metrics(rtsp_conn_info *conn) {
conn->play_number_after_flush = 0;
conn->packet_count_since_flush = 0;
conn->input_frame_rate_starting_point_is_valid = 0;
conn->initial_reference_time = 0;
conn->initial_reference_timestamp = 0;
}
void unencrypted_packet_decode(rtsp_conn_info *conn, unsigned char *packet, int length,
short *dest) {
if (conn->stream.type == ast_apple_lossless) {
#ifdef CONFIG_APPLE_ALAC
if (config.decoder_in_use == 1 << decoder_apple_alac) {
int frames_decoded;
apple_alac_decode_frame(packet, length, (unsigned char *)dest, &frames_decoded);
} else
#endif
#ifdef CONFIG_HAMMERTON
if (config.decoder_in_use == 1 << decoder_hammerton) {
int buffer_size = conn->frames_per_packet * conn->input_bytes_per_frame;
alac_decode_frame(conn->decoder_info, packet, (unsigned char *)dest, &buffer_size);
} else
#endif
{
die("No ALAC decoder included!");
}
} else if (conn->stream.type == ast_uncompressed) {
int i;
short *source = (short *)packet;
for (i = 0; i < length / 2; i++) {
// assuming each input sample is 16 bits.
*dest = ntohs(*source);
dest++;
source++;
}
}
}
#ifdef CONFIG_HAMMERTON
static int init_alac_decoder(int32_t fmtp[12], rtsp_conn_info *conn) {
// clang-format off
// This is a guess, but the format of the fmtp looks identical to the format of an
// ALACSpecificCOnfig which is detailed in the file ALACMagicCookieDescription.txt
// in the Apple ALAC sample implementation
// Here it is:
/*
* ALAC Specific Info (24 bytes) (mandatory)
__________________________________________________________________________________________________________________________________
The Apple Lossless codec stores specific information about the encoded stream in the ALACSpecificConfig. This
info is vended by the encoder and is used to setup the decoder for a given encoded bitstream.
When read from and written to a file, the fields of this struct must be in big-endian order.
When vended by the encoder (and received by the decoder) the struct values will be in big-endian order.
struct ALACSpecificConfig (defined in ALACAudioTypes.h)
abstract This struct is used to describe codec provided information about the encoded Apple Lossless bitstream.
It must accompany the encoded stream in the containing audio file and be provided to the decoder.
field frameLength uint32_t indicating the frames per packet when no explicit frames per packet setting is
present in the packet header. The encoder frames per packet can be explicitly set
but for maximum compatibility, the default encoder setting of 4096 should be used.
field compatibleVersion uint8_t indicating compatible version,
value must be set to 0
field bitDepth uint8_t describes the bit depth of the source PCM data (maximum value = 32)
field pb uint8_t currently unused tuning parameter.
value should be set to 40
field mb uint8_t currently unused tuning parameter.
value should be set to 10
field kb uint8_t currently unused tuning parameter.
value should be set to 14
field numChannels uint8_t describes the channel count (1 = mono, 2 = stereo, etc...)
when channel layout info is not provided in the 'magic cookie', a channel count > 2
describes a set of discreet channels with no specific ordering
field maxRun uint16_t currently unused.
value should be set to 255
field maxFrameBytes uint32_t the maximum size of an Apple Lossless packet within the encoded stream.
value of 0 indicates unknown
field avgBitRate uint32_t the average bit rate in bits per second of the Apple Lossless stream.
value of 0 indicates unknown
field sampleRate uint32_t sample rate of the encoded stream
typedef struct ALACSpecificConfig
{
uint32_t frameLength;
uint8_t compatibleVersion;
uint8_t bitDepth;
uint8_t pb;
uint8_t mb;
uint8_t kb;
uint8_t numChannels;
uint16_t maxRun;
uint32_t maxFrameBytes;
uint32_t avgBitRate;
uint32_t sampleRate;
} ALACSpecificConfig;
*/
// We are going to go on that basis
// clang-format on
alac_file *alac;
alac = alac_create(conn->input_bit_depth,
conn->input_num_channels); // no pthread cancellation point in here
if (!alac)
return 1;
conn->decoder_info = alac;
alac->setinfo_max_samples_per_frame = conn->frames_per_packet;
alac->setinfo_7a = fmtp[2];
alac->setinfo_sample_size = conn->input_bit_depth;
alac->setinfo_rice_historymult = fmtp[4];
alac->setinfo_rice_initialhistory = fmtp[5];
alac->setinfo_rice_kmodifier = fmtp[6];
alac->setinfo_7f = fmtp[7];
alac->setinfo_80 = fmtp[8];
alac->setinfo_82 = fmtp[9];
alac->setinfo_86 = fmtp[10];
alac->setinfo_8a_rate = fmtp[11];
alac_allocate_buffers(alac); // no pthread cancellation point in here
return 0;
}
#endif
static void init_buffer(rtsp_conn_info *conn) {
int i;
for (i = 0; i < BUFFER_FRAMES; i++) {
conn->audio_buffer[i].data = NULL;
#ifdef CONFIG_FFMPEG
conn->audio_buffer[i].avframe = NULL;
conn->audio_buffer[i].ssrc = SSRC_NONE;
#endif
}
}
static void free_audio_buffers(rtsp_conn_info *conn) {
int i;
for (i = 0; i < BUFFER_FRAMES; i++) {
free_audio_buffer_payload(&conn->audio_buffer[i]);
}
}
int first_possibly_missing_frame = -1;
void reset_buffer(rtsp_conn_info *conn) {
debug_mutex_lock(&conn->ab_mutex, 30000, 0);
ab_resync(conn);
debug_mutex_unlock(&conn->ab_mutex, 0);
#if CONFIG_FFMPEG
avflush(conn);
#endif
if (config.output->flush) {
config.output->flush(); // no cancellation points
// debug(1, "reset_buffer: flush output device.");
}
}
// returns the total number of blocks and the number occupied, but not their size,
// because the size is determined by the block size sent
void get_audio_buffer_size_and_occupancy(unsigned int *size, unsigned int *occupancy,
rtsp_conn_info *conn) {
debug_mutex_lock(&conn->ab_mutex, 30000, 0);
*size = BUFFER_FRAMES;
if (conn->ab_synced) {
int16_t occ =
conn->ab_write - conn->ab_read; // will be zero or positive if read and write are within
// 2^15 of each other and write is at or after read
*occupancy = occ;
} else {
*occupancy = 0;
}
debug_mutex_unlock(&conn->ab_mutex, 0);
}
#ifdef CONFIG_FFMPEG
static void avcodec_alloc_context3_cleanup_handler(void *arg) {
debug(3, "avcodec_alloc_context3_cleanup_handler");
AVCodecContext *codec_context = arg;
av_free(codec_context);
}
static void avcodec_open2_cleanup_handler(__attribute__((unused)) void *arg) {
debug(3, "avcodec_open2_cleanup_handler");
// AVCodecContext *codec_context = arg;
// avcodec_close(codec_context);
}
static void swr_alloc_cleanup_handler(void *arg) {
debug(3, "swr_alloc_cleanup_handler");
SwrContext **swr = arg;
swr_free(swr);
}
static void av_packet_alloc_cleanup_handler(void *arg) {
debug(3, "av_packet_alloc_cleanup_handler");
AVPacket **pkt = arg;
av_packet_free(pkt);
}
/*
static void av_frame_alloc_cleanup_handler(void *arg) {
debug(3, "av_frame_alloc_cleanup_handler");
AVFrame **frame = arg;
av_frame_free(frame);
}
*/
void clear_decoding_chain(rtsp_conn_info *conn) {
if (conn->incoming_ssrc != 0) {
// debug_mutex_lock(&conn->ab_mutex, 30000, 0);
// ab_resync(conn);
// debug_mutex_unlock(&conn->ab_mutex, 0);
pthread_cleanup_push(avcodec_alloc_context3_cleanup_handler, conn->codec_context);
pthread_cleanup_push(malloc_cleanup, &conn->codec_context->extradata);
pthread_cleanup_push(avcodec_open2_cleanup_handler, conn->codec_context);
pthread_cleanup_pop(1); // avcodec_open2_cleanup_handler
pthread_cleanup_pop(1); // deallocate the malloc
pthread_cleanup_pop(1); // avcodec_alloc_context3_cleanup_handler
conn->incoming_ssrc = 0;
}
}
void clear_software_resampler(rtsp_conn_info *conn) {
if (conn->swr != NULL) {
debug(2, "clear_software_resampler");
pthread_cleanup_push(swr_alloc_cleanup_handler, &conn->swr);
pthread_cleanup_pop(1); // deallocate the swr
conn->swr = NULL;
conn->resampler_ssrc = SSRC_NONE;
}
}
int ssrc_is_recognised(ssrc_t ssrc) {
int response = 0;
switch (ssrc) {
case ALAC_44100_S16_2:
case ALAC_48000_S24_2:
case AAC_44100_F24_2:
case AAC_48000_F24_2:
case AAC_48000_F24_5P1:
case AAC_48000_F24_7P1:
response = 1;
break;
default:
break;
}
return response;
}
int ssrc_is_aac(ssrc_t ssrc) {
int response = 0;
switch (ssrc) {
case AAC_44100_F24_2:
case AAC_48000_F24_2:
case AAC_48000_F24_5P1:
case AAC_48000_F24_7P1:
response = 1;
break;
default:
break;
}
return response;
}
char ssrc_name[1024];
const char *get_ssrc_name(ssrc_t ssrc) {
const char *response = NULL;
switch (ssrc) {
case ALAC_44100_S16_2:
response = "ALAC/44100/S16_LE/2";
break;
case ALAC_48000_S24_2:
response = "ALAC/48000/S24_LE/2";
break;
case AAC_44100_F24_2:
response = "AAC/44100/F24/2";
break;
case AAC_48000_F24_2:
response = "AAC/48000/F24/2";
break;
case AAC_48000_F24_5P1:
response = "AAC/48000/F24/5.1";
break;
case AAC_48000_F24_7P1:
response = "AAC/48000/F24/7.1";
break;
case SSRC_NONE:
response = "None (0)";
break;
default: {
snprintf(ssrc_name, sizeof(ssrc_name), "<unknown ssrc> (0x%" PRIx32 ")", ssrc);
response = ssrc_name;
} break;
}
return response;
}
uint32_t get_ssrc_rate(ssrc_t ssrc) {
uint32_t response = 0;
switch (ssrc) {
case ALAC_44100_S16_2:
case AAC_44100_F24_2:
response = 44100;
break;
case ALAC_48000_S24_2:
case AAC_48000_F24_2:
case AAC_48000_F24_5P1:
case AAC_48000_F24_7P1:
response = 48000;
break;
default:
break;
}
return response;
}
int setup_software_resampler(rtsp_conn_info *conn, ssrc_t ssrc) {
int response = 0;
unsigned int channels;
// the output from the software resampler will be the input to the rest of
// the player chain, so we need to set those parameters according to the SSRC:
// default values...
conn->input_bit_depth = 16;
conn->input_effective_bit_depth = 16;
conn->input_bytes_per_frame = 4;
conn->frames_per_packet = 352;
// most common values first, changed in the switch statement
conn->input_rate = 48000;
channels = 2;
conn->frames_per_packet = 1024;
sps_format_t suggested_output_format = SPS_FORMAT_S32; // this may be ignored
switch (ssrc) {
case ALAC_44100_S16_2:
conn->input_rate = 44100;
conn->frames_per_packet = 352;
suggested_output_format = SPS_FORMAT_S16;
break;
case ALAC_48000_S24_2:
conn->frames_per_packet = 352;
suggested_output_format = SPS_FORMAT_S24;
break;
case AAC_44100_F24_2:
conn->input_rate = 44100;
break;
case AAC_48000_F24_2:
break;
case AAC_48000_F24_5P1:
channels = 6;
break;
case AAC_48000_F24_7P1:
channels = 8;
break;
default:
debug(1, "Can't set rate for %s.", get_ssrc_name(ssrc));
break;
}
// Now we ask the backend for its best format, giving it the channels, rate and format
// default format is S32_LE/48000/2 for AP2, S16_LE/44100/2 otherwise
#ifdef CONFIG_AIRPLAY_2
uint32_t output_configuration = CHANNELS_TO_ENCODED_FORMAT(2) | RATE_TO_ENCODED_FORMAT(48000) |
FORMAT_TO_ENCODED_FORMAT(SPS_FORMAT_S32_LE);
#else
uint32_t output_configuration = CHANNELS_TO_ENCODED_FORMAT(2) | RATE_TO_ENCODED_FORMAT(44100) |
FORMAT_TO_ENCODED_FORMAT(SPS_FORMAT_S16_LE);
#endif
int output_configuration_changed = 0;
if (config.output->get_configuration) {
output_configuration =
config.output->get_configuration(channels, conn->input_rate, suggested_output_format);
}
// if you can set up a configuration...
if (output_configuration != 0) {
if (config.current_output_configuration != output_configuration) {
output_configuration_changed = 1;
debug(2, "Connection %d: outgoing audio switching to: %s.", conn->connection_number,
short_format_description(output_configuration));
}
config.current_output_configuration = output_configuration;
char *output_device_channel_map = NULL;
if (config.output->configure) {
config.output->configure(output_configuration, &output_device_channel_map);
}
// create a software resampler
if (conn->swr != NULL) {
debug(3, "software resampler already set up");
if (swr_is_initialized(conn->swr)) {
debug(3, "software resampler already initialised -- close it...");
swr_close(conn->swr);
}
debug(3, "software resampler free it...");
swr_free(&conn->swr);
if (conn->swr == NULL) {
debug(3, "software resampler released");
}
}
// input channels to the player
conn->input_num_channels = CHANNELS_FROM_ENCODED_FORMAT(output_configuration);
SwrContext *swr = swr_alloc();
conn->swr = swr;
if (swr == NULL) {
die("can not allocate an swr context");
}
// push a deallocator -- av_packet_free(pkt);
pthread_cleanup_push(swr_alloc_cleanup_handler, &conn->swr);
enum AVSampleFormat input_format = AV_SAMPLE_FMT_FLTP; // default
int64_t input_layout = AV_CH_LAYOUT_STEREO; // default
int64_t output_layout = AV_CH_LAYOUT_STEREO; // default
switch (ssrc) {
case ALAC_44100_S16_2:
case ALAC_48000_S24_2: {
// seems as if the codec_context is correctly set up for ALAC but not for AAC-LC
input_format = conn->codec_context->sample_fmt;
} break;
case AAC_44100_F24_2:
case AAC_48000_F24_2: {
// defaults are fine...
} break;
case AAC_48000_F24_5P1: {
input_layout = config.six_channel_layout;
output_layout = config.six_channel_layout; // assume no mixdown
} break;
case AAC_48000_F24_7P1: {
input_layout = config.eight_channel_layout;
output_layout = config.eight_channel_layout; // assume no mixdown
} break;
default:
debug(1, "unexpected SSRC: 0x%0x", ssrc);
break;
}
av_opt_set_sample_fmt(swr, "in_sample_fmt", input_format, 0);
// remember that if mixdown is enabled,
// set the resampler's channel layout either automatically or use the
// setting that has been given
#if LIBAVUTIL_VERSION_MAJOR >= 57
{
AVChannelLayout input_channel_layout;
av_channel_layout_from_mask(&input_channel_layout, input_layout);
av_opt_set_chlayout(swr, "in_chlayout", &input_channel_layout, 0);
av_channel_layout_uninit(&input_channel_layout);
AVChannelLayout output_channel_layout;
if (config.mixdown_enable != 0) {
if (config.mixdown_channel_layout == 0) {
av_channel_layout_default(&output_channel_layout,
CHANNELS_FROM_ENCODED_FORMAT(output_configuration));
} else {
av_channel_layout_from_mask(&output_channel_layout, config.mixdown_channel_layout);
}
} else {
av_channel_layout_from_mask(&output_channel_layout, output_layout);
}
av_opt_set_chlayout(swr, "out_chlayout", &output_channel_layout, 0);
av_channel_layout_uninit(&output_channel_layout);
}
#else
av_opt_set_int(swr, "in_channel_layout", input_layout, 0);
if (config.mixdown_enable != 0) {
if (config.mixdown_channel_layout == 0) {
output_layout =
av_get_default_channel_layout(CHANNELS_FROM_ENCODED_FORMAT(output_configuration));
} else {
output_layout = config.mixdown_channel_layout;
}
}
av_opt_set_int(swr, "out_channel_layout", output_layout, 0); // assume no mixdown
#endif
av_opt_set_int(swr, "in_sample_rate", conn->input_rate, 0);
// now set the resampler's output rate to match the output device's rate
av_opt_set_int(swr, "out_sample_rate", RATE_FROM_ENCODED_FORMAT(output_configuration), 0);
// Ask for S16 output for AAC/S16 input and for S32 output from resampler for F24 and S24.
// This is to avoid FFmpeg unnecessarily transcoding S16 to S32.
// Dither will be added by Shairport Sync itself later, if needed.
if (ssrc == ALAC_44100_S16_2) {
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
conn->input_bytes_per_frame =
2 * CHANNELS_FROM_ENCODED_FORMAT(
output_configuration); // the output from the decoder will be input to the player
conn->input_bit_depth = 16;
conn->input_effective_bit_depth = 16;
} else {
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S32, 0);
conn->input_bytes_per_frame =
4 * CHANNELS_FROM_ENCODED_FORMAT(
output_configuration); // the output from the decoder will be input to the player
conn->input_bit_depth = 32;
// this is important when it comes to deciding on dither
// AFAIK 24-bit ALAC comes out in 32-bit format but is actually 24 bit
// so don't dither if it is truncated from 32 to 24 bit
if (ssrc == ALAC_48000_S24_2)
conn->input_effective_bit_depth = 24;
else
conn->input_effective_bit_depth = 32;
}
// now, having set up the resampler, we can initialise it
// disabling this, as the soxr-based resampler seems not to give exactly the right number of
// frames going from 44100 to 48000 and requires stuffing to compensate.
// also, the soxr resampling engine isn't included in the Docker image.
// #ifdef CONFIG_SOXR
// av_opt_set(swr, "resampler", "soxr", 0);
// #endif
int sres = swr_init(swr);
if (sres != 0)
debug(1, "swr_init returned %d with SSRC of 0x%0x and LIBAVUTIL_VERSION_MAJOR of %u.", sres,
ssrc, LIBAVUTIL_VERSION_MAJOR);
typedef struct {
char *name;
int allocated;
} channel_info_t;
char resampler_channel_list[1024] = "";
unsigned int c;
channel_info_t resampler_channels[64]; // can't be more than 64. This will list the channel
// names in the order they appear in the output from
// the software resampler.
for (c = 0; c < sizeof(resampler_channels) / sizeof(channel_info_t); c++) {
resampler_channels[c].name = NULL;
resampler_channels[c].allocated = 0;
}
// get information about the output from the resampler
int64_t resampler_output_format = 0;
int resampler_channels_found = 0;
#if LIBAVUTIL_VERSION_MAJOR >= 57
AVChannelLayout output_channel_layout;
av_opt_get_chlayout(swr, "out_chlayout", 0, &output_channel_layout);
conn->resampler_output_channels = output_channel_layout.nb_channels;
for (c = 0; c < 64; c++) {
enum AVChannel channel = av_channel_layout_channel_from_index(&output_channel_layout, c);
if (channel != AV_CHAN_NONE) {
char buffer[32];
if (av_channel_name(buffer, 32, channel) > 0) {
if (resampler_channels_found == 0) {
strcat(resampler_channel_list, "\"");
} else {
strcat(resampler_channel_list, "\", \"");
}
strcat(resampler_channel_list, buffer);
resampler_channels[resampler_channels_found].name = strdup(buffer);
resampler_channels_found++;
}
}
}
av_channel_layout_uninit(&output_channel_layout);
#else
int64_t resampler_output_channel_layout = 0;
{
int res = av_opt_get_int(swr, "out_channel_layout", 0, &resampler_output_channel_layout);
if (res == 0) {
conn->resampler_output_channels =
(int64_t)av_get_channel_layout_nb_channels((uint64_t)resampler_output_channel_layout);
} else {
debug(1, "Error %d getting resampler output channel layout.", res);
}
}
int64_t mask = 1;
for (c = 0; c < 64; c++) {
if ((resampler_output_channel_layout & mask) != 0) {
if (resampler_channels_found == 0) {
strcat(resampler_channel_list, "\"");
} else {
strcat(resampler_channel_list, "\", \"");
}
strcat(resampler_channel_list, av_get_channel_name(1 << c));
resampler_channels[resampler_channels_found].name = strdup(av_get_channel_name(1 << c));
resampler_channels_found++;
}
mask = mask << 1;
}
#endif
if (resampler_channels_found != 0) {
strcat(resampler_channel_list, "\"");
}
if (strlen(resampler_channel_list) == 0) {
debug(3, "resampler output channel list is empty.");
} else {
debug(3, "resampler output channel list: %s.", resampler_channel_list);
}
if (output_device_channel_map != NULL) {
debug(3, "output device's channel map is: \"%s\".", output_device_channel_map);
// free(output_device_channel_map);
// output_device_channel_map = NULL;
}
int output_channel_map_faulty = 0;
if (resampler_channels_found != 0) {
// now we have the names of the channels produced by the resampler in the order they
// appear in the output from the resampler. We need to map them to the channel ordering
// of the output device.
// create an output channel list. It will be 64 channels long.
// It may not have names for all channels.
// In fact, it will have no names at all if mapping is disabled or set to auto
// with no device channel map. That will be okay, as unallocated resampler
// channels will be assigned to unused output channels at the end anyway
channel_info_t
output_channels[64]; // can't be more than 64. This will list the output channel names
// in the order they appear in the device channel map.
for (c = 0; c < sizeof(output_channels) / sizeof(channel_info_t); c++) {
output_channels[c].name = NULL;
output_channels[c].allocated = 0;
}
// if channel mapping is enabled
if (config.output_channel_mapping_enable != 0) {
// if a channel map is given
if (config.output_channel_map_size != 0) {
for (c = 0; c < config.output_channel_map_size; c++) {
output_channels[c].name = strdup(config.output_channel_map[c]);
}
} else if (output_device_channel_map != NULL) { // if there is a device channel map...
char *device_channels = strdup(output_device_channel_map);
char delim[] = " ";
char *ptr = strtok(device_channels, delim);
c = 0;
while (ptr != NULL) {
output_channels[c].name = strdup(ptr);
if (strcasecmp(ptr, "UNKNOWN") == 0)
output_channel_map_faulty = 1;
ptr = strtok(NULL, delim);
c++;
}
free(device_channels);
}
}
if (output_channel_map_faulty != 0) {
once(inform("The output device's %u-channel map is incomplete or faulty: \"%s\".",
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration),
output_device_channel_map));
}
// at this point, we should have two arrays
// the first is all the resampler channels
// the second is device channel map channels, which may be empty or incomplete
for (c = 0; c < 64; c++)
if (resampler_channels[c].name != NULL)
debug(3, "audio channel %u is \"%s\".", c, resampler_channels[c].name);
for (c = 0; c < 64; c++)
if (output_channels[c].name != NULL)
debug(3, "output device channel %u is \"%s\".", c, output_channels[c].name);
conn->output_channel_map_size =
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration);
// construct a map to match named resampler channels to named output channels
unsigned int cmi;
for (cmi = 0; cmi < conn->output_channel_map_size; cmi++) {
// debug(1,"checking output channel %u, (\"%s\").", cmi, output_channels[cmi].name);
conn->output_channel_to_resampler_channel_map[cmi] =
silent_channel_index; // by default the channel is silent
if ((output_channels[cmi].name != NULL) && (strcmp(output_channels[cmi].name, "--") == 0)) {
conn->output_channel_to_resampler_channel_map[cmi] = silent_channel_index;
output_channels[cmi].allocated = 1;
debug(1, "output device channel %u (\"--\") will be silent.", cmi);
} else {
int resampler_channel_index;
int found = 0;
for (resampler_channel_index = 0;
((resampler_channel_index < resampler_channels_found) && (found == 0));
resampler_channel_index++) {
if ((output_channels[cmi].name != NULL) &&
(resampler_channels[resampler_channel_index].name != NULL) &&
(strcmp(output_channels[cmi].name,
resampler_channels[resampler_channel_index].name) == 0)) {
conn->output_channel_to_resampler_channel_map[cmi] = resampler_channel_index;
output_channels[cmi].allocated = 1;
resampler_channels[resampler_channel_index].allocated = 1;
found = 1;
if ((resampler_channels_found > 2) && (output_configuration_changed != 0)) {
if (output_channel_map_faulty != 0)
debug(3, "%s -> %s/%u.", resampler_channels[resampler_channel_index].name,
output_channels[cmi].name, cmi);
else
debug(3, "%s -> %s/%u.", resampler_channels[resampler_channel_index].name,
output_channels[cmi].name, cmi);
}
}
}
}
}
// now there may be unmapped resampler channels and unallocated output channels
// allocate them on a first-come-first-served basis
for (cmi = 0; cmi < conn->output_channel_map_size; cmi++) {
if (output_channels[cmi].allocated == 0)
debug(3, "output device channel %u (\"%s\") is unallocated.", cmi,
output_channels[cmi].name);
}
for (c = 0; c < 64; c++) {
if ((resampler_channels[c].name != NULL) && (resampler_channels[c].allocated == 0))
debug(3, "audio channel %u (\"%s\") is unmapped.", c, resampler_channels[c].name);
}
c = 0; // for indexing through the unmapped resampler channels
for (cmi = 0; (cmi < conn->output_channel_map_size) && (c < 64); cmi++) {
if (output_channels[cmi].allocated == 0) {
do {
if ((resampler_channels[c].name != NULL) && (resampler_channels[c].allocated == 0)) {
output_channels[cmi].allocated = 1;
resampler_channels[c].allocated = 1;
conn->output_channel_to_resampler_channel_map[cmi] = c;
if (output_channel_map_faulty != 0)
debug(3, "%s -> %s/%u.", resampler_channels[c].name, output_channels[cmi].name,
cmi);
else
debug(3, "%s -> %s/%u.", resampler_channels[c].name, output_channels[cmi].name,
cmi);
} else {
c++;
}
} while ((output_channels[cmi].allocated == 0) && (c < 64));
}
}
if (output_configuration_changed != 0) {
char channel_mapping_list[256] = "";
for (c = 0; c < 8; c++) {
if ((output_channels[c].allocated != 0) &&
(conn->output_channel_to_resampler_channel_map[c] != silent_channel_index)) {
char channel_mapping[32] = "";
if (output_channels[c].name != NULL)
snprintf(channel_mapping, sizeof(channel_mapping) - 1, " %u (\"%s\") <- %s |", c,
output_channels[c].name,
resampler_channels[conn->output_channel_to_resampler_channel_map[c]].name);
else
snprintf(channel_mapping, sizeof(channel_mapping) - 1, " %u <- %s |", c,
resampler_channels[conn->output_channel_to_resampler_channel_map[c]].name);
strncat(channel_mapping_list, channel_mapping,
sizeof(channel_mapping_list) - 1 - strlen(channel_mapping_list));
}
}
debug(1, "Channel Mapping: |%s", channel_mapping_list);
}
for (c = 0; c < 64; c++) {
if (output_channels[c].name != NULL)
free(output_channels[c].name);
}
for (c = 0; c < 64; c++) {
if (resampler_channels[c].name != NULL)
free(resampler_channels[c].name);
}
}
{
int res = av_opt_get_int(swr, "out_sample_fmt", 0, &resampler_output_format);
if (res == 0) {
conn->resampler_output_bytes_per_sample = av_get_bytes_per_sample(resampler_output_format);
debug(3, "resampler output bytes per sample in swr: %d.",
conn->resampler_output_bytes_per_sample);
} else {
debug(1, "Error %d getting resampler output bytes per sample.", res);
}
}
conn->resampler_ssrc = ssrc;
pthread_cleanup_pop(0); // successful exit -- don't deallocate the swr
} else {
debug(1, "Error setting the configuration of the output backend.");
}
return response; // 0 if everything is okay
}
void prepare_decoding_chain(rtsp_conn_info *conn, ssrc_t ssrc) {
if ((ssrc_is_recognised(ssrc)) && (ssrc != conn->incoming_ssrc)) {
if ((config.statistics_requested != 0) && (ssrc != SSRC_NONE) &&
(conn->incoming_ssrc != SSRC_NONE)) {
debug(1, "Connection %d: incoming audio switching to \"%s\".", conn->connection_number,
get_ssrc_name(ssrc));
#ifdef CONFIG_METADATA
send_ssnc_metadata('sdsc', get_ssrc_name(ssrc), strlen(get_ssrc_name(ssrc)), 1);
#endif
}
// the ssrc of the incoming packet is different to the ssrc of the decoding chain
// so the decoding chain must be rebuilt
clear_decoding_chain(conn);
// create the new decoding chain
conn->incoming_ssrc = ssrc;
if (conn->incoming_ssrc != SSRC_NONE) {
// get a codec
// ideas and some code from https://rodic.fr/blog/libavcodec-tutorial-decode-audio-file/
// with thanks
// Set up the decoder depending on the ssrc code.
switch (ssrc) {
case ALAC_44100_S16_2:
case ALAC_48000_S24_2:
conn->codec = avcodec_find_decoder(AV_CODEC_ID_ALAC);
break;
case AAC_44100_F24_2:
case AAC_48000_F24_2:
case AAC_48000_F24_5P1:
case AAC_48000_F24_7P1:
conn->codec = avcodec_find_decoder(AV_CODEC_ID_AAC);
break;
default:
die("Can't find a suitable codec for SSRC: %s", get_ssrc_name(ssrc));
break;
}
// Get a decoder-dependent codec context
conn->codec_context = avcodec_alloc_context3(conn->codec);
if (conn->codec_context == NULL) {
debug(1, "Could not allocate a codec context!");
}
// push a deallocator -- av_free(codec_context)
pthread_cleanup_push(avcodec_alloc_context3_cleanup_handler, conn->codec_context);
// prepare to open the codec context with that codec
// but first, if it's the ALAC decoder, prepare a magic cookie
if ((ssrc == ALAC_48000_S24_2) || (ssrc == ALAC_44100_S16_2)) {
alac_ffmpeg_magic_cookie *extradata =
malloc(sizeof(alac_ffmpeg_magic_cookie)); // might not use it
if (extradata == NULL)
die("Could not allocate memory for a magic cookie.");
// creata a magic cookie preceded by the 12-byte "atom" (?) expected by FFMPEG (?)
memset(extradata, 0, sizeof(alac_ffmpeg_magic_cookie));
extradata->cookie_size = htonl(sizeof(alac_ffmpeg_magic_cookie));
extradata->cookie_tag = htonl('alac');
extradata->alac_config.frameLength = htonl(352);
if (ssrc == ALAC_48000_S24_2) {
extradata->alac_config.bitDepth = 24; // Seems to be S24
extradata->alac_config.sampleRate = htonl(48000);
} else {
extradata->alac_config.bitDepth = 16; // Seems to be S16
extradata->alac_config.sampleRate = htonl(44100);
}
extradata->alac_config.pb = 40;
extradata->alac_config.mb = 10;
extradata->alac_config.kb = 14;
extradata->alac_config.numChannels = 2;
extradata->alac_config.maxRun = htons(255);
conn->codec_context->extradata = (uint8_t *)extradata;
conn->codec_context->extradata_size = sizeof(alac_ffmpeg_magic_cookie);
} else {
conn->codec_context->extradata = NULL;
}
pthread_cleanup_push(malloc_cleanup, &conn->codec_context->extradata);
if (avcodec_open2(conn->codec_context, conn->codec, NULL) < 0) {
die("Could not initialise the codec context");
}
// push a closer -- avcodec_close(codec_context);
pthread_cleanup_push(avcodec_open2_cleanup_handler, conn->codec_context);
conn->input_rate = get_ssrc_rate(ssrc);
conn->codec_context->sample_rate = conn->input_rate;
conn->ffmpeg_decoding_chain_initialised = 1;
pthread_cleanup_pop(0); // successful exit -- don't run the avcodec_open2_cleanup_handler
pthread_cleanup_pop(0); // successful exit -- don't deallocate the malloc
pthread_cleanup_pop(
0); // successful exit -- don't run the avcodec_alloc_context3_cleanup_handler
}
}
}
// take an AV Frame, run it through the swr resampler and map the output to the
// appropriate channels for the output device
// returns the length of time in nanoseconds associated with the frames that are being retained
int64_t avframe_to_audio(rtsp_conn_info *conn, AVFrame *decoded_frame, uint8_t **decoded_audio,
size_t *decoded_audio_data_length, size_t *decoded_audio_samples_count) {
uint8_t *pcm_audio = NULL;
int dst_linesize;
int number_of_output_samples_expected = swr_get_out_samples(conn->swr, decoded_frame->nb_samples);
debug(3, "A maximum of %d output samples expected for %d input samples.",
number_of_output_samples_expected, decoded_frame->nb_samples);
// allocate enough space for the required number of output channels
// and the number of samples decoded
// the format is always S32
av_samples_alloc(&pcm_audio, &dst_linesize, conn->resampler_output_channels,
number_of_output_samples_expected, AV_SAMPLE_FMT_S32, 0);
uint64_t conversion_start_time = get_absolute_time_in_ns();
int samples_generated =
swr_convert(conn->swr, &pcm_audio, number_of_output_samples_expected,
(const uint8_t **)decoded_frame->extended_data, decoded_frame->nb_samples);
debug(3, "conversion time for %u incoming samples: %.3f milliseconds.", decoded_frame->nb_samples,
(get_absolute_time_in_ns() - conversion_start_time) * 0.000001);
if (samples_generated > 0) {
debug(3, "swr generated %d frames of %" PRId64 " channels.", samples_generated,
conn->resampler_output_channels);
// samples_generated will be different from
// the number of samples input if the output rate is different from the input
// now, allocate a buffer and transfer the audio into it.
ssize_t sample_buffer_size = conn->resampler_output_bytes_per_sample *
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) *
samples_generated;
void *sample_buffer = malloc(sample_buffer_size);
memset(sample_buffer, 0, sample_buffer_size); // silence
unsigned int input_stride = conn->resampler_output_channels;
unsigned int output_stride = CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration);
unsigned int channels_to_map =
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration); // the output width
// if (conn->output_channel_map_size < channels_to_map)
// channels_to_map = conn->output_channel_map_size; // or the channel map given
switch (conn->resampler_output_bytes_per_sample) {
case 4: {
int32_t *inframe = (int32_t *)pcm_audio;
int32_t *outframe = (int32_t *)sample_buffer;
int i;
for (i = 0; i < samples_generated; i++) {
unsigned int j;
for (j = 0; j < channels_to_map; j++) {
if (conn->output_channel_to_resampler_channel_map[j] == front_mono_channel_index) {
// asking for the "FM" channel, which is a made-up name for
// Front Mono
int32_t monoValue = (inframe[0] / 2) + (inframe[1] / 2);
outframe[j] = monoValue;
} else if (conn->output_channel_to_resampler_channel_map[j] !=
silent_channel_index) // means you're asking for the
// silent channel
outframe[j] = inframe[conn->output_channel_to_resampler_channel_map[j]];
}
inframe += input_stride; // address increment is scaled by the
// size of an int32_t
outframe += output_stride; // address increment is scaled by the
// size of an int32_t
}
} break;
case 2: {
int16_t *inframe = (int16_t *)pcm_audio;
int16_t *outframe = (int16_t *)sample_buffer;
int i;
for (i = 0; i < samples_generated; i++) {
unsigned int j;
for (j = 0; j < channels_to_map; j++) {
if (conn->output_channel_to_resampler_channel_map[j] == front_mono_channel_index) {
// asking for the "FM" channel, which is a made-up name for
// Front Mono
int16_t monoValue = (inframe[0] / 2) + (inframe[1] / 2);
outframe[j] = monoValue;
} else if (conn->output_channel_to_resampler_channel_map[j] !=
silent_channel_index) // means you're asking for the
// silent channel
outframe[j] = inframe[conn->output_channel_to_resampler_channel_map[j]];
}
inframe += input_stride; // address increment is scaled by the
// size of an int16_t
outframe += output_stride; // address increment is scaled by the
// size of an int16_t
}
} break;
default:
debug(1, "resampler output byte size of %u not handled.",
conn->resampler_output_bytes_per_sample);
break;
}
*decoded_audio = sample_buffer;
*decoded_audio_data_length = sample_buffer_size;
*decoded_audio_samples_count = samples_generated;
} else {
// samples_generated contains the negative of the error code
debug(1, "swr_convert error %d. No samples generated from this avframe", -samples_generated);
*decoded_audio = NULL;
*decoded_audio_data_length = 0;
*decoded_audio_samples_count = 0;
}
av_freep(&pcm_audio);
return swr_get_delay(
conn->swr,
RATE_FROM_ENCODED_FORMAT(
config.current_output_configuration)); // number of frames left in the resampler
}
// take a block of incoming data and decode it.
// it might get decoded into fltp ot lpcm or something -- it'll be
// transcoded and maybe resampled later
AVFrame *block_to_avframe(rtsp_conn_info *conn, uint8_t *incoming_data,
size_t incoming_data_length) {
AVFrame *decoded_frame = NULL;
if (incoming_data_length > 8) {
AVPacket *pkt = av_packet_alloc();
if (pkt) {
// push a deallocator -- av_packet_free(pkt);
pthread_cleanup_push(av_packet_alloc_cleanup_handler, &pkt);
pkt->data = incoming_data;
pkt->size = incoming_data_length;
int ret = avcodec_send_packet(conn->codec_context, pkt);
if (ret == 0) {
decoded_frame = av_frame_alloc();
if (decoded_frame == NULL) {
debug(1, "Can't allocate an AVFrame!");
} else {
ret = avcodec_receive_frame(conn->codec_context, decoded_frame);
if (ret < 0) {
av_frame_free(&decoded_frame);
decoded_frame = NULL;
debug(1, "error %d during decoding. Data size: %d", ret, incoming_data_length);
/*
char *obf = malloc(incoming_data_length * 3);
char *obfp = obf;
unsigned int obfc;
for (obfc = 0; obfc < incoming_data_length; obfc++) {
snprintf(obfp, 3, "%02X", incoming_data[obfc]);
obfp += 2;
if ((obfc & 7) == 7) {
snprintf(obfp, 2, " ");
obfp += 1;
}
};
*obfp = 0;
debug(1, "%s...", obf);
free(obf);
*/
}
}
} else {
debug(1, "error %d during decoding. Gross data size: %d", ret, incoming_data_length);
/*
char obf[128];
char *obfp = obf;
int obfc;
for (obfc = 0; obfc < 32; obfc++) {
snprintf(obfp, 3, "%02X", incoming_data[obfc]);
obfp += 2;
if ((obfc & 7) == 7) {
snprintf(obfp, 2, " ");
obfp += 1;
}
}
*obfp = 0;
debug(1, "%s", obf);
*/
}
pthread_cleanup_pop(1); // deallocate the AVPacket;
} else {
debug(1, "Can't allocate an AVPacket!");
}
}
return decoded_frame;
}
size_t avflush(rtsp_conn_info *conn) {
size_t response = 0;
if (conn->swr != NULL) {
int number_of_output_samples_expected = swr_get_out_samples(conn->swr, 0);
debug(3, "avflush of %d samples.", number_of_output_samples_expected);
int ret = swr_init(conn->swr);
if (ret)
debug(1, "error %d in swr_init().", ret);
response = (size_t)number_of_output_samples_expected;
}
return response;
}
#endif
#ifdef CONFIG_OPENSSL
// Thanks to
// https://stackoverflow.com/questions/27558625/how-do-i-use-aes-cbc-encrypt-128-openssl-properly-in-ubuntu
// for inspiration. Changed to a 128-bit key and no padding.
int openssl_aes_decrypt_cbc(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
unsigned char *iv, unsigned char *plaintext) {
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len = 0;
ctx = EVP_CIPHER_CTX_new();
if (ctx != NULL) {
if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1) {
EVP_CIPHER_CTX_set_padding(ctx, 0); // no padding -- always returns 1
// no need to allow space for padding in the output, as padding is disabled
if (EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len) == 1) {
plaintext_len = len;
if (EVP_DecryptFinal_ex(ctx, plaintext + len, &len) == 1) {
plaintext_len += len;
} else {
debug(1, "EVP_DecryptFinal_ex error \"%s\".", ERR_error_string(ERR_get_error(), NULL));
}
} else {
debug(1, "EVP_DecryptUpdate error \"%s\".", ERR_error_string(ERR_get_error(), NULL));
}
} else {
debug(1, "EVP_DecryptInit_ex error \"%s\".", ERR_error_string(ERR_get_error(), NULL));
}
EVP_CIPHER_CTX_free(ctx);
} else {
debug(1, "EVP_CIPHER_CTX_new error \"%s\".", ERR_error_string(ERR_get_error(), NULL));
}
return plaintext_len;
}
#endif
#ifdef CONFIG_FFMPEG
uint32_t player_put_packet(uint32_t ssrc, seq_t seqno, uint32_t actual_timestamp, uint8_t *data,
size_t len, int mute, int32_t timestamp_gap, rtsp_conn_info *conn) {
#else
uint32_t player_put_packet(uint32_t ssrc, seq_t seqno, uint32_t actual_timestamp, uint8_t *data,
size_t len, __attribute__((unused)) int mute, int32_t timestamp_gap,
rtsp_conn_info *conn) {
#endif
// clang-format off
// The timestamp_gap is the difference between the timestamp and the expected timestamp.
// It should normally be zero.
// It can be decoded by the Hammerton or Apple ALAC decoders, or my the FFmpeg decoder.
// The SSRC signifies the encoding used for that block of audio.
// It is used to select the type of decoding to be done by the FFMPEG-based
// decoding chain
// If mute is true, then decode the packet to get its length, but mute it -- i.e.
// replace it with the same duration of silence.
// This is useful because the first block of an AAC play sequence usually contains
// noisy transients.
// Not needed in Classic airPlay as there's no AAC in it.
// Function returns the number of samples in the packet so that callers can watch for
// anomalies in sequencing.
// clang-format on
uint32_t input_packets_used = 0;
// ignore a request to flush that has been made before the first packet...
if (conn->packet_count == 0) {
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
conn->flush_requested = 0;
conn->flush_rtp_timestamp = 0;
debug_mutex_unlock(&conn->flush_mutex, 3);
}
debug_mutex_lock(&conn->ab_mutex, 30000, 0);
uint64_t time_now = get_absolute_time_in_ns();
conn->packet_count++;
conn->packet_count_since_flush++;
conn->time_of_last_audio_packet = time_now;
if (conn->connection_state_to_output) { // if we are supposed to be processing these packets
abuf_t *abuf = 0;
if (!conn->ab_synced) {
conn->ab_write = seqno;
conn->ab_read = seqno;
conn->ab_synced = 1;
conn->first_packet_timestamp = 0;
debug(2, "Connection %d: synced by first packet, timestamp %u, seqno %u.",
conn->connection_number, actual_timestamp, seqno);
}
if (conn->ab_write ==
seqno) { // if this is the expected packet (which could be the first packet...)
if (conn->input_frame_rate_starting_point_is_valid == 0) {
if ((conn->packet_count_since_flush >= 500) && (conn->packet_count_since_flush <= 510)) {
conn->frames_inward_measurement_start_time = time_now;
conn->frames_inward_frames_received_at_measurement_start_time = actual_timestamp;
conn->input_frame_rate_starting_point_is_valid = 1; // valid now
}
}
conn->frames_inward_measurement_time = time_now;
conn->frames_inward_frames_received_at_measurement_time = actual_timestamp;
abuf = conn->audio_buffer + BUFIDX(seqno);
conn->ab_write = seqno + 1; // move the write pointer to the next free space
} else {
int16_t after_ab_write_gap = seqno - conn->ab_write;
if (after_ab_write_gap > 0) {
int i;
for (i = 0; i < after_ab_write_gap; i++) {
abuf = conn->audio_buffer + BUFIDX(conn->ab_write + i);
abuf->ready = 0; // to be sure, to be sure
abuf->resend_request_number = 0;
abuf->initialisation_time =
time_now; // this represents when the packet was noticed to be missing
abuf->status = 1 << 0; // signifying missing
abuf->resend_time = 0;
abuf->timestamp = 0;
abuf->sequence_number = 0;
}
abuf = conn->audio_buffer + BUFIDX(seqno);
// rtp_request_resend(ab_write, gap);
// resend_requests++;
conn->ab_write = seqno + 1;
} else {
int16_t after_ab_read_gap = seqno - conn->ab_read;
if (after_ab_read_gap >= 0) { // older than expected but not too late
debug(3, "buffer %u is older than expected but not too late", seqno);
conn->late_packets++;
abuf = conn->audio_buffer + BUFIDX(seqno);
} else { // too late.
debug(3, "buffer %u is too late", seqno);
conn->too_late_packets++;
}
}
}
if (abuf) {
if (free_audio_buffer_payload(abuf)) {
if (seqno == abuf->sequence_number)
debug(3, "audio block %u received for a second (or more) time?", seqno);
else
debug(3, "audio block %u with prior sequence number %u -- payload not freed until now!",
seqno, abuf->sequence_number);
}
abuf->initialisation_time = time_now;
abuf->resend_time = 0;
abuf->length = 0; // may not be needed
if (ssrc == ALAC_44100_S16_2) {
// This could be a Classic AirPlay or an AirPlay 2 Realtime packet.
// It always has a length of 352 frames per packet.
// And it's always 16-bit interleaved stereo.
uint8_t *data_to_use = data;
uint8_t *intermediate_buffer = malloc(len); // encryption is not compression...
// decrypt it if necessary
if (conn->stream.encrypted) {
unsigned char iv[16];
int aeslen = len & ~0xf;
memcpy(iv, conn->stream.aesiv, sizeof(iv));
#ifdef CONFIG_MBEDTLS
mbedtls_aes_crypt_cbc(&conn->dctx, MBEDTLS_AES_DECRYPT, aeslen, iv, data,
intermediate_buffer);
#endif
#ifdef CONFIG_POLARSSL
aes_crypt_cbc(&conn->dctx, AES_DECRYPT, aeslen, iv, data, intermediate_buffer);
#endif
#ifdef CONFIG_OPENSSL
openssl_aes_decrypt_cbc(data, aeslen, conn->stream.aeskey, iv, intermediate_buffer);
// AES_cbc_encrypt(data, intermediate_buffer, aeslen, &conn->aes, iv, AES_DECRYPT);
#endif
memcpy(intermediate_buffer + aeslen, data + aeslen, len - aeslen);
data_to_use = intermediate_buffer;
}
// Use the selected decoder
if ((config.decoder_in_use == 1 << decoder_hammerton) ||
(config.decoder_in_use == 1 << decoder_apple_alac)) {
abuf->data = malloc(conn->frames_per_packet * conn->input_bytes_per_frame);
if (abuf->data != NULL) {
unencrypted_packet_decode(conn, data_to_use, len, abuf->data);
input_packets_used = conn->frames_per_packet; // return this to the caller
abuf->length = conn->frames_per_packet; // these decoders don't transcode
} else {
debug(1, "audio block not allocated!");
}
} else if (config.decoder_in_use == 1 << decoder_ffmpeg_alac) {
#ifdef CONFIG_FFMPEG
prepare_decoding_chain(conn, ALAC_44100_S16_2);
if (len > 8) {
abuf->avframe = block_to_avframe(conn, data_to_use, len);
abuf->ssrc = ALAC_44100_S16_2;
if (abuf->avframe) {
input_packets_used = abuf->avframe->nb_samples;
}
if (mute) {
// it's important to have already run it through the decoder before dropping it
// especially if it an AAC decoder
debug(2, "ap1 muting frame %u.", actual_timestamp);
abuf->length = abuf->avframe->nb_samples;
av_frame_free(&abuf->avframe);
abuf->avframe = NULL;
}
} else {
debug(1,
"Unrecognised audio packet of length %u -- replacing with %u frames of silence.",
len, conn->frames_per_packet);
abuf->length = conn->frames_per_packet;
abuf->avframe = NULL;
}
#else
debug(1, "FFMPEG support has not been built into this version Shairport Sync!");
#endif
} else {
debug(1, "Unknown decoder!");
}
// may be used during decryption
if (intermediate_buffer != NULL) {
free(intermediate_buffer);
intermediate_buffer = NULL;
}
abuf->ready = 1;
abuf->status = 0; // signifying that it was received
abuf->timestamp = actual_timestamp;
abuf->timestamp_gap = timestamp_gap; // needed to decide if a resync is needed
abuf->sequence_number = seqno;
} else {
// This is AirPlay 2 -- always use FFmpeg
#ifdef CONFIG_FFMPEG
// Use the appropriate FFMPEG decoder
// decoding is done now, transcoding to S32 and resampling is
// deferred to the player thread, to be sure all the blocks
// of data are present
prepare_decoding_chain(conn, ssrc); // dynamically set the decoding environment
if (len > 8) {
abuf->avframe = block_to_avframe(conn, data, len);
abuf->ssrc = ssrc; // tag the avframe with its specific SSRC
if (abuf->avframe) {
input_packets_used = abuf->avframe->nb_samples;
}
if (mute) {
// it's important to have already run it through the decoder before dropping it
debug(2, "ap2 muting frame %u.", actual_timestamp);
abuf->length = abuf->avframe->nb_samples;
av_frame_free(&abuf->avframe);
abuf->avframe = NULL;
}
} else {
debug(1,
"Unrecognised audio packet %u, rtptime %u, of length %u. Contents follow:", seqno,
actual_timestamp, len);
debug_print_buffer(1, data, len);
abuf->length = 0;
abuf->avframe = NULL;
}
abuf->ready = 1;
abuf->status = 0; // signifying that it was received
abuf->timestamp = actual_timestamp;
abuf->timestamp_gap = timestamp_gap;
abuf->sequence_number = seqno;
#else
debug(1, "FFMPEG support has not been included, so the packet is discarded.");
abuf->ready = 0;
abuf->status = 1 << 1; // bad packet, discarded
abuf->resend_request_number = 0;
abuf->timestamp = 0;
abuf->timestamp_gap = 0;
abuf->sequence_number = 0;
#endif
}
}
/*
{
uint64_t the_time_this_frame_should_be_played;
frame_to_local_time(abuf->timestamp,
&the_time_this_frame_should_be_played, conn);
int64_t lead_time = the_time_this_frame_should_be_played - get_absolute_time_in_ns();
debug(1, "put_packet %u, lead time is %.3f ms.", abuf->timestamp, lead_time * 0.000001);
}
*/
int rc = pthread_cond_signal(&conn->flowcontrol);
if (rc)
debug(1, "Error signalling flowcontrol.");
// resend checks
{
uint64_t minimum_wait_time =
(uint64_t)(config.resend_control_first_check_time * (uint64_t)1000000000);
uint64_t resend_repeat_interval =
(uint64_t)(config.resend_control_check_interval_time * (uint64_t)1000000000);
uint64_t minimum_remaining_time = (uint64_t)((config.resend_control_last_check_time +
config.audio_backend_buffer_desired_length) *
(uint64_t)1000000000);
uint64_t latency_time = (uint64_t)(conn->latency * (uint64_t)1000000000);
latency_time = latency_time / (uint64_t)conn->input_rate;
// find the first frame that is missing, if known
int x = conn->ab_read;
if (first_possibly_missing_frame >= 0) {
// if it's within the range
int16_t buffer_size = conn->ab_write - conn->ab_read; // must be positive
if (buffer_size >= 0) {
int16_t position_in_buffer = first_possibly_missing_frame - conn->ab_read;
if ((position_in_buffer >= 0) && (position_in_buffer < buffer_size))
x = first_possibly_missing_frame;
}
}
first_possibly_missing_frame = -1; // has not been set
int missing_frame_run_count = 0;
int start_of_missing_frame_run = -1;
int number_of_missing_frames = 0;
while (x != conn->ab_write) {
abuf_t *check_buf = conn->audio_buffer + BUFIDX(x);
if (!check_buf->ready) {
if (first_possibly_missing_frame < 0)
first_possibly_missing_frame = x;
number_of_missing_frames++;
// debug(1, "frame %u's initialisation_time is 0x%" PRIx64 ", latency_time is 0x%"
// PRIx64 ", time_now is 0x%" PRIx64 ", minimum_remaining_time is 0x%" PRIx64 ".", x,
// check_buf->initialisation_time, latency_time, time_now, minimum_remaining_time);
int too_late = ((check_buf->initialisation_time < (time_now - latency_time)) ||
((check_buf->initialisation_time - (time_now - latency_time)) <
minimum_remaining_time));
int too_early = ((time_now - check_buf->initialisation_time) < minimum_wait_time);
int too_soon_after_last_request =
((check_buf->resend_time != 0) &&
((time_now - check_buf->resend_time) <
resend_repeat_interval)); // time_now can never be less than the time_tag
if (too_late)
check_buf->status |= 1 << 2; // too late
else
check_buf->status &= 0xFF - (1 << 2); // not too late
if (too_early)
check_buf->status |= 1 << 3; // too early
else
check_buf->status &= 0xFF - (1 << 3); // not too early
if (too_soon_after_last_request)
check_buf->status |= 1 << 4; // too soon after last request
else
check_buf->status &= 0xFF - (1 << 4); // not too soon after last request
if ((!too_soon_after_last_request) && (!too_late) && (!too_early)) {
if (start_of_missing_frame_run == -1) {
start_of_missing_frame_run = x;
missing_frame_run_count = 1;
} else {
missing_frame_run_count++;
}
check_buf->resend_time = time_now; // setting the time to now because we are
// definitely going to take action
check_buf->resend_request_number++;
debug(3, "Frame %d is missing with ab_read of %u and ab_write of %u.", x, conn->ab_read,
conn->ab_write);
}
// if (too_late) {
// debug(1,"too late to get missing frame %u.", x);
// }
}
// if (number_of_missing_frames != 0)
// debug(1,"check with x = %u, ab_read = %u, ab_write = %u, first_possibly_missing_frame
// = %d.", x, conn->ab_read, conn->ab_write, first_possibly_missing_frame);
x = (x + 1) & 0xffff;
if (((check_buf->ready) || (x == conn->ab_write)) && (missing_frame_run_count > 0)) {
// send a resend request
if (missing_frame_run_count > 1)
debug(3, "request resend of %d packets starting at seqno %u.", missing_frame_run_count,
start_of_missing_frame_run);
if (config.disable_resend_requests == 0) {
debug_mutex_unlock(&conn->ab_mutex, 3);
rtp_request_resend(start_of_missing_frame_run, missing_frame_run_count, conn);
debug_mutex_lock(&conn->ab_mutex, 20000, 1);
conn->resend_requests++;
}
start_of_missing_frame_run = -1;
missing_frame_run_count = 0;
}
}
if (number_of_missing_frames == 0)
first_possibly_missing_frame = conn->ab_write;
}
}
debug_mutex_unlock(&conn->ab_mutex, 0);
return input_packets_used;
}
int32_t rand_in_range(int32_t exclusive_range_limit) {
static uint32_t lcg_prev = 12345;
// returns a pseudo random integer in the range 0 to (exclusive_range_limit-1) inclusive
int64_t sp = lcg_prev;
int64_t rl = exclusive_range_limit;
lcg_prev = lcg_prev * 69069 + 3; // crappy psrg
sp = sp * rl; // 64 bit calculation. Interesting part is above the 32 rightmost bits;
return sp >> 32;
}
static inline void process_sample(int32_t sample, char **outp, sps_format_t format, int volume,
int dither, rtsp_conn_info *conn) {
int64_t hyper_sample = sample;
int result = 0;
if ((config.loudness != 0) && (conn->input_rate == 44100)) {
hyper_sample <<=
32; // Do not apply volume as it has already been done with the Loudness DSP filter
} else {
int64_t hyper_volume = (int64_t)volume << 16;
hyper_sample = hyper_sample * hyper_volume; // this is 64 bit bit multiplication -- we may need
// to dither it down to its target resolution
}
// next, do dither, if necessary
if (dither) {
// Add a TPDF dither -- see
// http://educypedia.karadimov.info/library/DitherExplained.pdf
// and the discussion around https://www.hydrogenaud.io/forums/index.php?showtopic=16963&st=25
// I think, for a 32 --> 16 bits, the range of
// random numbers needs to be from -2^16 to 2^16, i.e. from -65536 to 65536 inclusive, not from
// -32768 to +32767
// Actually, what would be generated here is from -65535 to 65535, i.e. one less on the limits.
// See the original paper at
// http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf
// by Lipshitz, Wannamaker and Vanderkooy, 1992.
int64_t dither_mask = 0;
switch (format) {
case SPS_FORMAT_S32:
case SPS_FORMAT_S32_LE:
case SPS_FORMAT_S32_BE:
dither_mask = (int64_t)1 << (64 - 32);
break;
case SPS_FORMAT_S24:
case SPS_FORMAT_S24_LE:
case SPS_FORMAT_S24_BE:
case SPS_FORMAT_S24_3LE:
case SPS_FORMAT_S24_3BE:
dither_mask = (int64_t)1 << (64 - 24);
break;
case SPS_FORMAT_S16:
case SPS_FORMAT_S16_LE:
case SPS_FORMAT_S16_BE:
dither_mask = (int64_t)1 << (64 - 16);
break;
case SPS_FORMAT_S8:
case SPS_FORMAT_U8:
dither_mask = (int64_t)1 << (64 - 8);
break;
case SPS_FORMAT_UNKNOWN:
die("Unexpected SPS_FORMAT_UNKNOWN while calculating dither mask.");
break;
case SPS_FORMAT_AUTO:
die("Unexpected SPS_FORMAT_AUTO while calculating dither mask.");
break;
case SPS_FORMAT_INVALID:
die("Unexpected SPS_FORMAT_INVALID while calculating dither mask.");
break;
}
dither_mask -= 1;
int64_t r = r64i();
int64_t tpdf = (r & dither_mask) - (conn->previous_random_number & dither_mask);
conn->previous_random_number = r;
// add dither, allowing for clipping
if (tpdf >= 0) {
if (INT64_MAX - tpdf >= hyper_sample)
hyper_sample += tpdf;
else
hyper_sample = INT64_MAX;
} else {
if (INT64_MIN - tpdf <= hyper_sample)
hyper_sample += tpdf;
else
hyper_sample = INT64_MIN;
}
// dither is complete here
}
// move the result to the desired position in the int64_t
char *op = *outp;
uint8_t byt;
switch (format) {
case SPS_FORMAT_S32_LE:
hyper_sample >>= (64 - 32);
byt = (uint8_t)hyper_sample;
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 8);
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 16);
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 24);
*op++ = byt;
result = 4;
break;
case SPS_FORMAT_S32_BE:
hyper_sample >>= (64 - 32);
byt = (uint8_t)(hyper_sample >> 24);
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 16);
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 8);
*op++ = byt;
byt = (uint8_t)hyper_sample;
*op++ = byt;
result = 4;
break;
case SPS_FORMAT_S32:
hyper_sample >>= (64 - 32);
*(int32_t *)op = hyper_sample;
result = 4;
break;
case SPS_FORMAT_S24_3LE:
hyper_sample >>= (64 - 24);
byt = (uint8_t)hyper_sample;
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 8);
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 16);
*op++ = byt;
result = 3;
break;
case SPS_FORMAT_S24_3BE:
hyper_sample >>= (64 - 24);
byt = (uint8_t)(hyper_sample >> 16);
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 8);
*op++ = byt;
byt = (uint8_t)hyper_sample;
*op++ = byt;
result = 3;
break;
case SPS_FORMAT_S24_LE:
hyper_sample >>= (64 - 24);
byt = (uint8_t)hyper_sample;
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 8);
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 16);
*op++ = byt;
*op++ = 0;
result = 4;
break;
case SPS_FORMAT_S24_BE:
hyper_sample >>= (64 - 24);
*op++ = 0;
byt = (uint8_t)(hyper_sample >> 16);
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 8);
*op++ = byt;
byt = (uint8_t)hyper_sample;
*op++ = byt;
result = 4;
break;
case SPS_FORMAT_S24:
hyper_sample >>= (64 - 24);
*(int32_t *)op = hyper_sample;
result = 4;
break;
case SPS_FORMAT_S16_LE:
hyper_sample >>= (64 - 16);
byt = (uint8_t)hyper_sample;
*op++ = byt;
byt = (uint8_t)(hyper_sample >> 8);
*op++ = byt;
result = 2;
break;
case SPS_FORMAT_S16_BE:
hyper_sample >>= (64 - 16);
byt = (uint8_t)(hyper_sample >> 8);
*op++ = byt;
byt = (uint8_t)hyper_sample;
*op++ = byt;
result = 2;
break;
case SPS_FORMAT_S16:
hyper_sample >>= (64 - 16);
*(int16_t *)op = (int16_t)hyper_sample;
result = 2;
break;
case SPS_FORMAT_S8:
hyper_sample >>= (int8_t)(64 - 8);
*op = hyper_sample;
result = 1;
break;
case SPS_FORMAT_U8:
hyper_sample >>= (uint8_t)(64 - 8);
hyper_sample += 128;
*op = hyper_sample;
result = 1;
break;
case SPS_FORMAT_UNKNOWN:
die("Unexpected SPS_FORMAT_UNKNOWN while outputting samples");
break;
case SPS_FORMAT_AUTO:
die("Unexpected SPS_FORMAT_AUTO while outputting samples");
break;
case SPS_FORMAT_INVALID:
die("Unexpected SPS_FORMAT_INVALID while outputting samples");
break;
}
*outp += result;
}
void buffer_get_frame_cleanup_handler(void *arg) {
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
debug_mutex_unlock(&conn->ab_mutex, 0);
}
// get the next frame, when available. return 0 if underrun/stream reset.
static abuf_t *buffer_get_frame(rtsp_conn_info *conn, int resync_requested) {
// int16_t buf_fill;
// struct timespec tn;
/*
{
abuf_t *curframe = conn->audio_buffer + BUFIDX(conn->ab_read);
if (curframe != NULL) {
debug(1, "get seqno %u with ready: %u.", curframe->sequence_number, curframe->ready);
}
}
*/
abuf_t *curframe = NULL;
int notified_buffer_empty = 0; // diagnostic only
debug_mutex_lock(&conn->ab_mutex, 30000, 0);
int wait;
long dac_delay = 0; // long because alsa returns a long
int output_device_has_been_primed =
0; // set to true when we have sent at least one silent frame to the DAC
pthread_cleanup_push(buffer_get_frame_cleanup_handler,
(void *)conn); // undo what's been done so far
do {
// debug(3, "buffer_get_frame is iterating");
// we must have timing information before we can do anything here
if (have_timestamp_timing_information(conn)) {
int rco = get_requested_connection_state_to_output();
if (conn->connection_state_to_output != rco) {
conn->connection_state_to_output = rco;
// change happening
if (conn->connection_state_to_output == 0) { // going off
debug(2, "request flush because connection_state_to_output is off");
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
conn->flush_requested = 1;
conn->flush_rtp_timestamp = 0;
debug_mutex_unlock(&conn->flush_mutex, 3);
}
}
if (config.output->is_running)
if (config.output->is_running() != 0) { // if the back end isn't running for any reason
debug(2, "request flush because back end is not running");
debug_mutex_lock(&conn->flush_mutex, 1000, 0);
conn->flush_requested = 1;
conn->flush_rtp_timestamp = 0;
debug_mutex_unlock(&conn->flush_mutex, 0);
}
pthread_cleanup_debug_mutex_lock(&conn->flush_mutex, 1000, 0);
if (conn->flush_requested == 1) {
if (conn->flush_output_flushed == 0) {
#if CONFIG_FFMPEG
avflush(conn);
#endif
if (config.output->flush) {
config.output->flush(); // no cancellation points
debug(2, "flush request: flush output device.");
}
}
conn->flush_output_flushed = 1;
}
// now check to see it the flush request is for frames in the buffer or not
// if the first_packet_timestamp is zero, don't check
int flush_needed = 0;
int drop_request = 0;
if (conn->flush_requested == 1) {
if (conn->flush_rtp_timestamp == 0) {
debug(1, "flush request: flush frame 0 -- flush assumed to be needed.");
flush_needed = 1;
drop_request = 1;
} else {
if ((conn->ab_synced) && ((conn->ab_write - conn->ab_read) > 0)) {
abuf_t *firstPacket = conn->audio_buffer + BUFIDX(conn->ab_read);
abuf_t *lastPacket = conn->audio_buffer + BUFIDX(conn->ab_write - 1);
if ((firstPacket != NULL) && (firstPacket->ready)) {
uint32_t first_frame_in_buffer = firstPacket->timestamp;
int32_t offset_from_first_frame = conn->flush_rtp_timestamp - first_frame_in_buffer;
if ((lastPacket != NULL) && (lastPacket->ready)) {
// we have enough information to check if the flush is needed or can be discarded
uint32_t last_frame_in_buffer = lastPacket->timestamp + lastPacket->length - 1;
// clang-format off
// Now we have to work out if the flush frame is in the buffer.
// If it is later than the end of the buffer, flush everything and keep the
// request active.
// If it is in the buffer, we need to flush part of the buffer.
// (Actually we flush the entire buffer and drop the request.)
// If it is before the buffer, no flush is needed. Drop the request.
// clang-format on
if (offset_from_first_frame > 0) {
int32_t offset_to_last_frame = last_frame_in_buffer - conn->flush_rtp_timestamp;
if (offset_to_last_frame >= 0) {
debug(2,
"flush request: flush frame %u active -- buffer contains %u frames, from "
"%u to %u.",
conn->flush_rtp_timestamp,
last_frame_in_buffer - first_frame_in_buffer + 1, first_frame_in_buffer,
last_frame_in_buffer);
// We need to drop all complete frames leading up to the frame containing
// the flush request frame.
int32_t offset_to_flush_frame = 0;
abuf_t *current_packet = NULL;
do {
current_packet = conn->audio_buffer + BUFIDX(conn->ab_read);
if (current_packet != NULL) {
uint32_t last_frame_in_current_packet =
current_packet->timestamp + current_packet->length - 1;
offset_to_flush_frame =
conn->flush_rtp_timestamp - last_frame_in_current_packet;
if (offset_to_flush_frame > 0) {
debug(2,
"flush to %u request: flush buffer %u, from "
"%u to %u. ab_write is: %u.",
conn->flush_rtp_timestamp, conn->ab_read, current_packet->timestamp,
current_packet->timestamp + current_packet->length - 1,
conn->ab_write);
conn->ab_read++;
}
} else {
debug(1, "NULL current_packet");
}
pthread_testcancel(); // even if no packets are coming in...
} while ((current_packet == NULL) || (offset_to_flush_frame > 0));
// now remove any frames from the buffer that are before the flush frame itself.
int32_t frames_to_remove =
conn->flush_rtp_timestamp - current_packet->timestamp;
if (frames_to_remove > 0) {
debug(2, "%u frames to remove from current buffer", frames_to_remove);
void *dest = (void *)current_packet->data;
void *source = dest + conn->input_bytes_per_frame * frames_to_remove;
size_t frames_remaining = (current_packet->length - frames_to_remove);
memmove(dest, source, frames_remaining * conn->input_bytes_per_frame);
current_packet->timestamp = conn->flush_rtp_timestamp;
current_packet->length = frames_remaining;
}
debug(
2,
"flush request: flush frame %u complete -- buffer contains %u frames, from "
"%u to %u -- flushed to %u in buffer %u, with %u frames remaining.",
conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1,
first_frame_in_buffer, last_frame_in_buffer, current_packet->timestamp,
conn->ab_read, last_frame_in_buffer - current_packet->timestamp + 1);
drop_request = 1;
} else {
if (conn->flush_rtp_timestamp == last_frame_in_buffer + 1) {
debug(
2,
"flush request: flush frame %u completed -- buffer contained %u frames, "
"from "
"%u to %u",
conn->flush_rtp_timestamp,
last_frame_in_buffer - first_frame_in_buffer + 1, first_frame_in_buffer,
last_frame_in_buffer);
drop_request = 1;
} else {
debug(2,
"flush request: flush frame %u pending -- buffer contains %u frames, "
"from "
"%u to %u",
conn->flush_rtp_timestamp,
last_frame_in_buffer - first_frame_in_buffer + 1, first_frame_in_buffer,
last_frame_in_buffer);
}
flush_needed = 1;
}
} else {
debug(2,
"flush request: flush frame %u expired -- buffer contains %u frames, "
"from %u "
"to %u",
conn->flush_rtp_timestamp, last_frame_in_buffer - first_frame_in_buffer + 1,
first_frame_in_buffer, last_frame_in_buffer);
drop_request = 1;
}
}
}
} else {
debug(3,
"flush request: flush frame %u -- buffer not synced or empty: synced: %d, "
"ab_read: "
"%u, ab_write: %u",
conn->flush_rtp_timestamp, conn->ab_synced, conn->ab_read, conn->ab_write);
conn->flush_requested = 0; // remove the request
// leave flush request pending and don't do a buffer flush, because there isn't one
}
}
}
if (flush_needed) {
debug(2, "flush request: flush done.");
ab_resync(conn); // no cancellation points
conn->first_packet_timestamp = 0;
conn->first_packet_time_to_play = 0;
conn->time_since_play_started = 0;
output_device_has_been_primed = 0;
dac_delay = 0;
}
if (drop_request) {
conn->flush_requested = 0;
conn->flush_rtp_timestamp = 0;
conn->flush_output_flushed = 0;
}
pthread_cleanup_pop(1); // unlock the conn->flush_mutex
// skip out-of-date frames, and even more if we haven't seen the first frame
int out_of_date = 1;
uint32_t should_be_frame;
uint64_t time_to_aim_for = get_absolute_time_in_ns();
uint64_t desired_lead_time = 0;
if (conn->first_packet_timestamp == 0)
time_to_aim_for = time_to_aim_for + desired_lead_time;
while ((conn->ab_synced) && ((conn->ab_write - conn->ab_read) > 0) && (out_of_date != 0)) {
abuf_t *thePacket = conn->audio_buffer + BUFIDX(conn->ab_read);
if ((thePacket != NULL) && (thePacket->ready)) {
local_time_to_frame(time_to_aim_for, &should_be_frame, conn);
// debug(1,"should_be frame is %u.",should_be_frame);
int32_t frame_difference = thePacket->timestamp - should_be_frame;
if (frame_difference < 0) {
debug(3,
"Connection %d: dropping-out-of-date packet %u with timestamp %u. Lead time is "
"%f seconds.",
conn->connection_number, conn->ab_read, thePacket->timestamp,
frame_difference * 1.0 / conn->input_rate + desired_lead_time * 0.000000001);
free_audio_buffer_payload(thePacket);
conn->last_seqno_read = conn->ab_read;
conn->ab_read++;
} else {
if (conn->first_packet_timestamp == 0)
debug(3,
"Connection %d: accepting packet sequence number %u, ab_read: %u with "
"timestamp %u. Lead time is %f seconds.",
conn->connection_number, thePacket->sequence_number, conn->ab_read,
thePacket->timestamp,
frame_difference * 1.0 / conn->input_rate + desired_lead_time * 0.000000001);
out_of_date = 0;
}
} else {
if (thePacket == NULL)
debug(2, "Connection %d: packet %u is empty.", conn->connection_number, conn->ab_read);
else
debug(2, "Connection %d: packet %u not ready.", conn->connection_number, conn->ab_read);
conn->ab_read++;
conn->last_seqno_read++; // don' let it trigger the missing packet warning...
}
pthread_testcancel(); // even if no packets are coming in...
}
int16_t buffers_available = conn->ab_write - conn->ab_read;
if ((conn->ab_synced) && (buffers_available > 0)) {
curframe = conn->audio_buffer + BUFIDX(conn->ab_read);
if (resync_requested != 0) {
/*
if (((curframe != NULL) && ((conn->first_packet_timestamp != curframe->timestamp) &&
(curframe->timestamp_gap < 0))) ||
(resync_requested != 0)) {
// ignore a timestamp gap that occurs before the first_packet_timestamp
if (curframe == NULL)
debug(1, "Connection %d: reset first_packet_timestamp because curframe is NULL.",
conn->connection_number);
if (curframe->timestamp_gap != 0)
debug(1,
"Connection %d: reset first_packet_timestamp because curframe %u's timestamp_gap
is negative: "
"%d.",
conn->connection_number, curframe->timestamp, curframe->timestamp_gap);
if (resync_requested != 0)
*/
debug(2, "Connection %d: reset first_packet_timestamp resync_requested.",
conn->connection_number);
conn->ab_buffering = 1;
conn->first_packet_timestamp = 0;
conn->first_packet_time_to_play = 0;
output_device_has_been_primed = 1; // so that it can rely on the delay provided by it
}
if (conn->ab_synced) {
if (curframe != NULL) {
uint64_t should_be_time;
frame_to_local_time(curframe->timestamp, &should_be_time, conn);
int64_t time_difference = should_be_time - get_absolute_time_in_ns();
debug(3, "Check packet from buffer %u, timestamp %u, %f seconds ahead.", conn->ab_read,
curframe->timestamp, 0.000000001 * time_difference);
} else {
debug(3, "Check packet from buffer %u, empty.", conn->ab_read);
}
if ((conn->ab_read != conn->ab_write) &&
(curframe->ready)) { // it could be synced and empty, under
// exceptional circumstances, with the
// frame unused, thus apparently ready
if (curframe->sequence_number != conn->ab_read) {
// some kind of sync problem has occurred.
if (BUFIDX(curframe->sequence_number) == BUFIDX(conn->ab_read)) {
// it looks like aliasing has happened
// jump to the new incoming stuff...
conn->ab_read = curframe->sequence_number;
debug(1, "Connection %d: aliasing of buffer index -- reset.",
conn->connection_number);
} else {
debug(1, "Connection %d: inconsistent sequence numbers detected",
conn->connection_number);
}
}
}
if ((curframe) && (curframe->ready)) {
notified_buffer_empty = 0; // at least one buffer now -- diagnostic only.
if (conn->ab_buffering) { // if we are getting packets but not yet forwarding them to
// the player
if (conn->first_packet_timestamp == 0) { // if this is the very first packet
conn->first_packet_timestamp =
curframe->timestamp; // we will keep buffering until we are
// supposed to start playing this
debug(2, "Connection %d: first packet timestamp is %u.", conn->connection_number,
conn->first_packet_timestamp);
// Even though it'll be some time before the first frame will be output
// (and thus some time before the resampling chain is needed),
// we need to set up the output device to correspond to
// the input format w.r.t. rate, depth and channels
// because we'll be sending silence before the first real frame.
#ifdef CONFIG_FFMPEG
// Set up the output chain, including the software resampler.
debug(2, "set up the output chain to %s for FFmpeg.",
get_ssrc_name(curframe->ssrc));
setup_software_resampler(conn, curframe->ssrc);
conn->output_sample_ratio = 1; // it's always 1 if we're using FFmpeg
#else
// here, in the non-FFmpeg decoder case, we have the first frame, so
// we should set up the output device now.
debug(3,
"set up the output chain for the non-FFmpeg case with incoming audio at %u "
"FPS.",
conn->input_rate);
// ask the backend if it can give us its best choice for a non-ffmpeg configuration:
if (config.output->get_configuration) {
config.current_output_configuration = config.output->get_configuration(
2, conn->input_rate, (unsigned int)(SPS_FORMAT_S16));
} else {
// otherwise, use the standard 44100/S16_LE/2 for non-ffmpeg operation
config.current_output_configuration = CHANNELS_TO_ENCODED_FORMAT(2) |
RATE_TO_ENCODED_FORMAT(44100) |
FORMAT_TO_ENCODED_FORMAT(SPS_FORMAT_S16_LE);
}
// tell the output device, if possible
if (config.output->configure) {
config.output->configure(config.current_output_configuration, NULL);
}
if (conn->input_rate == 0)
debug(1, "input rate not set!");
else
conn->output_sample_ratio =
RATE_FROM_ENCODED_FORMAT(config.current_output_configuration) /
conn->input_rate;
#endif
// calculate the output bit depth
conn->output_bit_depth = 16; // default;
switch (FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration)) {
case SPS_FORMAT_S8:
case SPS_FORMAT_U8:
conn->output_bit_depth = 8;
break;
case SPS_FORMAT_S16:
case SPS_FORMAT_S16_LE:
case SPS_FORMAT_S16_BE:
conn->output_bit_depth = 16;
break;
case SPS_FORMAT_S24:
case SPS_FORMAT_S24_LE:
case SPS_FORMAT_S24_BE:
case SPS_FORMAT_S24_3LE:
case SPS_FORMAT_S24_3BE:
conn->output_bit_depth = 24;
break;
case SPS_FORMAT_S32:
case SPS_FORMAT_S32_LE:
case SPS_FORMAT_S32_BE:
conn->output_bit_depth = 32;
break;
case SPS_FORMAT_UNKNOWN:
die("An unknown format was encountered while choosing output bit depth. Please "
"check your configuration and settings.");
break;
case SPS_FORMAT_AUTO:
die("Invalid format -- SPS_FORMAT_AUTO -- choosing output bit depth. Please "
"check your configuration and settings.");
break;
case SPS_FORMAT_INVALID:
die("Invalid format -- SPS_FORMAT_INVALID -- choosing output bit depth. Please "
"check your configuration and settings.");
break;
}
debug(3, "output bit depth is %u.", conn->output_bit_depth);
uint64_t should_be_time;
frame_to_local_time(conn->first_packet_timestamp, // this will go modulo 2^32
&should_be_time, conn);
conn->first_packet_time_to_play = should_be_time;
int64_t lt = conn->first_packet_time_to_play - get_absolute_time_in_ns();
// can't be too late because we skipped late packets already, FLW.
debug(2, "Connection %d: lead time for first frame %u: %f seconds.",
conn->connection_number, conn->first_packet_timestamp, lt * 0.000000001);
}
if (conn->first_packet_time_to_play != 0) {
// Now that we know the timing of the first packet...
if (config.output->delay) {
// and that the output device is capable of synchronization...
// We may send packets of
// silence from now until the time the first audio packet should be sent
// and then we will send the first packet, which will be followed by
// the subsequent packets.
// here, we figure out whether and what silence to send.
uint64_t should_be_time;
// readjust first packet time to play
frame_to_local_time(conn->first_packet_timestamp, &should_be_time, conn);
int64_t change_in_should_be_time =
(int64_t)(should_be_time - conn->first_packet_time_to_play);
if (fabs(0.000001 * change_in_should_be_time) >
0.001) // ignore this unless if's more than a microsecond
debug(
2,
"Change in estimated first_packet_time: %f milliseconds for first_packet.",
0.000001 * change_in_should_be_time);
conn->first_packet_time_to_play = should_be_time;
int64_t lead_time = conn->first_packet_time_to_play -
get_absolute_time_in_ns(); // negative means late
if (lead_time < 0) {
debug(2, "Gone past starting time for %u by %" PRId64 " nanoseconds.",
conn->first_packet_timestamp, -lead_time);
conn->ab_buffering = 0;
} else {
// do some calculations
if ((config.audio_backend_silent_lead_in_time_auto == 1) ||
(lead_time <= (int64_t)(config.audio_backend_silent_lead_in_time *
(int64_t)1000000000))) {
debug(3, "Lead time: %" PRId64 " nanoseconds.", lead_time);
int resp = 0;
dac_delay = 0;
if (output_device_has_been_primed != 0)
resp = config.output->delay(
&dac_delay); // we know the output device must have a delay function
if (resp == 0) {
int64_t gross_frame_gap =
((conn->first_packet_time_to_play - get_absolute_time_in_ns()) *
RATE_FROM_ENCODED_FORMAT(config.current_output_configuration)) /
1000000000;
int64_t exact_frame_gap = gross_frame_gap - dac_delay;
debug(3,
"Exact frame gap: %" PRId64
". DAC delay: %ld. First packet timestamp: %u.",
exact_frame_gap, dac_delay, conn->first_packet_timestamp);
// int64_t frames_needed_to_maintain_desired_buffer =
// (int64_t)(config.audio_backend_buffer_desired_length *
// config.current_output_configuration->rate) -
// dac_delay;
// below, remember that exact_frame_gap and
// frames_needed_to_maintain_desired_buffer could both be negative
int64_t fs =
(RATE_FROM_ENCODED_FORMAT(config.current_output_configuration) * 100) /
1000; // 100 milliseconds
// if there isn't enough time to have the desired buffer size
// if (exact_frame_gap <= fs) {
// fs = conn->frames_per_packet * 2;
// }
// if we are close to the end of buffering,
// just add the remaining silence needed and end buffering
if (exact_frame_gap < fs) {
debug(3, "exact frame below fs of %" PRId64 " frames.", fs);
fs = exact_frame_gap;
conn->ab_buffering = 0;
}
void *silence;
if (fs > 0) {
silence = malloc(
sps_format_sample_size(
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration)) *
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) *
fs);
if (silence == NULL)
debug(1, "Failed to allocate %d byte silence buffer.", fs);
else {
// generate frames of silence with dither if necessary
pthread_cleanup_push(malloc_cleanup, &silence);
conn->previous_random_number = generate_zero_frames(
silence, fs, conn->enable_dither, conn->previous_random_number,
config.current_output_configuration);
debug(3, "Send %" PRId64 " frames of silence.", fs);
config.output->play(silence, fs, play_samples_are_untimed, 0, 0);
debug(3, "Sent %" PRId64 " frames of silence.", fs);
pthread_cleanup_pop(1); // deallocate silence
output_device_has_been_primed = 1;
}
}
} else {
if ((resp == -EAGAIN) || (resp == -EIO) || (resp == -ENODEV)) {
debug(2, "delay() information not (yet, hopefully!) available.");
} else {
debug(1, "delay() error %d: \"%s\".", -resp, strerror(-resp));
}
if (resp == sps_extra_code_output_stalled) {
if (config.unfixable_error_reported == 0) {
config.unfixable_error_reported = 1;
if (config.cmd_unfixable) {
command_execute(config.cmd_unfixable, "output_device_stalled", 1);
} else {
die("an unrecoverable error, \"output_device_stalled\", has been "
"detected.");
}
}
} else {
debug(3, "Unexpected response to getting dac delay: %d.", resp);
}
}
}
}
} else {
// if the output device doesn't have a delay, we simply send the lead-in
int64_t lead_time = conn->first_packet_time_to_play -
get_absolute_time_in_ns(); // negative if we are late
void *silence;
int64_t frame_gap =
(lead_time * RATE_FROM_ENCODED_FORMAT(config.current_output_configuration)) /
1000000000;
// debug(1,"%d frames needed.",frame_gap);
while (frame_gap > 0) {
ssize_t fs = RATE_FROM_ENCODED_FORMAT(config.current_output_configuration) / 10;
if (fs > frame_gap)
fs = frame_gap;
silence = malloc(
sps_format_sample_size(
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration)) *
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) * fs);
if (silence == NULL)
debug(1, "Failed to allocate %d frame silence buffer.", fs);
else {
// debug(1, "No delay function -- outputting %d frames of silence.", fs);
pthread_cleanup_push(malloc_cleanup, &silence);
conn->previous_random_number = generate_zero_frames(
silence, fs, conn->enable_dither, conn->previous_random_number,
config.current_output_configuration);
config.output->play(silence, fs, play_samples_are_untimed, 0, 0);
pthread_cleanup_pop(1); // deallocate silence
}
frame_gap -= fs;
}
conn->ab_buffering = 0;
}
}
#ifdef CONFIG_METADATA
if (conn->ab_buffering == 0) {
if ((curframe) && (curframe->ready) && (curframe->timestamp))
debug(3, "Current frame at \"resume\" is %u.", curframe->timestamp);
else
debug(1, "Current frame at \"resume\" is not known.", curframe->timestamp);
send_ssnc_metadata('prsm', NULL, 0,
0); // "resume", but don't wait if the queue is locked
}
#endif
}
}
}
} else {
// if (conn->ab_synced)
// debug(1, "no buffers available at seqno %u.", conn->ab_read);
}
// Here, we work out whether to release a packet or wait
// We release a packet when the time is right.
// To work out when the time is right, we need to take account of (1) the actual time the
// packet should be released, (2) the latency requested, (3) the audio backend latency offset
// and (4) the desired length of the audio backend's buffer
// The time is right if the current time is later or the same as
// The packet time + (latency + latency offset - backend_buffer_length).
// Note: the last three items are expressed in frames and must be converted to time.
int do_wait = 0; // don't wait unless we can really prove we must
if ((conn->ab_synced) && (curframe) && (curframe->ready) && (curframe->timestamp)) {
do_wait = 1; // if the current frame exists and is ready, then wait unless it's time to let
// it go...
// here, get the time to play the current frame.
if (have_timestamp_timing_information(conn)) { // if we have a reference time
uint64_t time_to_play;
// we must enable packets to be released early enough for the
// audio buffer to be filled to the desired length
uint32_t desired_buffer_latency =
(uint32_t)(config.audio_backend_buffer_desired_length * conn->input_rate);
frame_to_local_time(curframe->timestamp - desired_buffer_latency, &time_to_play, conn);
uint64_t current_buffer_delay = 0;
int resp = -1;
if (config.output->delay) {
long l_delay;
resp = config.output->delay(&l_delay);
if (resp == 0) { // no error
if (l_delay >= 0)
current_buffer_delay = l_delay;
else {
debug(2, "Underrun of %ld frames reported, but ignored.", l_delay);
current_buffer_delay =
0; // could get a negative value if there was underrun, but ignore it.
}
}
}
// If it's the first packet, or we don't have a working delay() function in the backend,
// then wait until it's time to play it
if ((((conn->first_packet_timestamp == curframe->timestamp) || (resp != 0)) &&
(get_absolute_time_in_ns() >= time_to_play)) ||
// Otherwise, if it isn't the first packet and we have a valid delay from the backend,
// ensure the buffer stays nearly full
((conn->first_packet_timestamp != curframe->timestamp) && (resp == 0) &&
(current_buffer_delay < desired_buffer_latency))) {
do_wait = 0;
}
// here, do a sanity check. if the time_to_play is not within a few seconds of the
// time now, the frame is probably not meant to be there, so let it go.
if (do_wait != 0) {
// this is a hack.
// we subtract two 2^n unsigned numbers and get a signed 2^n result.
// If we think of the calculation as occurring in modulo 2^n arithmetic
// then the signed result's magnitude represents the shorter distance around
// the modulo wheel of values from one number to the other.
// The sign indicates the direction: positive means clockwise (upwards) from the
// second number to the first (i.e. the first number comes "after" the second).
int64_t time_difference = get_absolute_time_in_ns() - time_to_play;
if ((time_difference > 10000000000) || (time_difference < -10000000000)) {
debug(2,
"crazy time interval of %f seconds between time now: 0x%" PRIx64
" and time of packet: %" PRIx64 ".",
0.000000001 * time_difference, get_absolute_time_in_ns(), time_to_play);
debug(2, "packet rtptime: %u, reference_timestamp: %u", curframe->timestamp,
conn->anchor_rtptime);
do_wait = 0; // let it go
}
}
}
}
if (do_wait == 0)
// wait if the buffer is empty
if ((conn->ab_synced != 0) && (conn->ab_read == conn->ab_write)) { // the buffer is empty!
if (notified_buffer_empty == 0) {
debug(2, "Connection %d: Buffer Empty", conn->connection_number);
notified_buffer_empty = 1;
// reset_input_flow_metrics(conn); // don't do a full flush parameters reset
// conn->initial_reference_time = 0;
// conn->initial_reference_timestamp = 0;
// conn->first_packet_timestamp = 0; // make sure the first packet isn't late
}
do_wait = 1;
}
wait = (conn->ab_buffering || (do_wait != 0) || (!conn->ab_synced));
} else {
wait = 1; // keep waiting until the timing information becomes available
}
if (wait) {
if (conn->frames_per_packet == 0)
debug(1, "frames_per_packet is zero!");
uint64_t time_to_wait_for_wakeup_ns = 20000000; // default if no input rate is set
if (conn->input_rate != 0) {
time_to_wait_for_wakeup_ns =
1000000000 / conn->input_rate; // this is time period of one frame
time_to_wait_for_wakeup_ns *= 4 * conn->frames_per_packet;
}
#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD
uint64_t time_of_wakeup_ns = get_realtime_in_ns() + time_to_wait_for_wakeup_ns;
uint64_t sec = time_of_wakeup_ns / 1000000000;
uint64_t nsec = time_of_wakeup_ns % 1000000000;
struct timespec time_of_wakeup;
time_of_wakeup.tv_sec = sec;
time_of_wakeup.tv_nsec = nsec;
int rc = pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex,
&time_of_wakeup); // this is a pthread cancellation point
if ((rc != 0) && (rc != ETIMEDOUT))
// if (rc)
debug(3, "pthread_cond_timedwait returned error code %d.", rc);
#endif
#ifdef COMPILE_FOR_OSX
uint64_t sec = time_to_wait_for_wakeup_ns / 1000000000;
uint64_t nsec = time_to_wait_for_wakeup_ns % 1000000000;
struct timespec time_to_wait;
time_to_wait.tv_sec = sec;
time_to_wait.tv_nsec = nsec;
pthread_cond_timedwait_relative_np(&conn->flowcontrol, &conn->ab_mutex, &time_to_wait);
#endif
}
} while (wait);
// seq_t read = conn->ab_read;
if (curframe) {
if (!curframe->ready) {
// debug(1, "Supplying a silent frame for frame %u", read);
conn->missing_packets++;
curframe->timestamp = 0; // indicate a silent frame should be substituted
}
curframe->ready = 0;
}
conn->ab_read++;
pthread_cleanup_pop(1); // buffer_get_frame_cleanup_handler
// debug(1, "Release frame %u.", curframe->timestamp);
#ifdef CONFIG_FFMPEG
#ifndef CONFIG_AIRPLAY_2
if (config.decoder_in_use == 1 << decoder_ffmpeg_alac) {
#endif
// clang-format off
// If we're using the Hammerton or ALAC decoder, then curframe->data will
// point to a malloced buffer of the stereo interleaved LPCM/44100/S16/2 audio
// But here, we must be using the FFMPEG decoder.
// With the FFmpeg decoder we have an AVFrame in curframe->avframe.
// The format could be anything -- it'll be transcoded here and placed in
// malloc memory pointed to by curframe->data and the AVFrame will be freed.
// If the avframe is NULL, then the length will be the number of frames of silence
// to be inserted into the audio stream to replace an AVFrame of the same length
// that is to be muted. Phew.
// clang-format on
if (curframe) {
if (conn->resampler_ssrc != curframe->ssrc) {
if (conn->resampler_ssrc == SSRC_NONE) {
debug(2, "setting up software resampler for %s for the first time.",
get_ssrc_name(curframe->ssrc));
} else {
debug(2, "SSRC has changed from %s to %s.", get_ssrc_name(conn->resampler_ssrc),
get_ssrc_name(curframe->ssrc));
clear_software_resampler(conn);
// ask the backend if it can give us its best choice for an ffmpeg configuration:
}
debug(3, "setup software resampler for %s", get_ssrc_name(curframe->ssrc));
if (curframe->ssrc != SSRC_NONE) {
setup_software_resampler(conn, curframe->ssrc);
} else {
debug(1, "attempt to setup_software_resampler for SSRC_NONE");
}
}
size_t number_of_output_frames;
uint8_t *pp;
size_t pl;
if (curframe->avframe) {
conn->frames_retained_in_the_resampler =
avframe_to_audio(conn, curframe->avframe, &pp, &pl, &number_of_output_frames);
curframe->data = (short *)pp;
curframe->length = number_of_output_frames;
av_frame_free(&curframe->avframe);
curframe->avframe = NULL;
} else if (curframe->length != 0) {
// if there's no data and no avframe, then the length is
// the number of frames of silence requested.
int ret = swr_inject_silence(conn->swr, curframe->length); // hardwired, ugh!
if (ret)
debug(1, "error %d", ret);
// We need to get those frames of silence out of the resampler
// so we'll pass in an empty AVFrame to flush them through
AVFrame *avf = av_frame_alloc(); // empty frame
conn->frames_retained_in_the_resampler =
avframe_to_audio(conn, avf, &pp, &pl, &number_of_output_frames);
curframe->data = (short *)pp;
curframe->length = number_of_output_frames;
av_frame_free(&avf);
}
}
#ifndef CONFIG_AIRPLAY_2
}
#endif
#endif
#ifdef CONFIG_METADATA
if ((curframe != NULL) && (conn->first_packet_timestamp) &&
(conn->first_packet_timestamp == curframe->timestamp)) {
char buffer[32];
memset(buffer, 0, sizeof(buffer));
// if this is not a resumption after a discontinuity,
// say we have started receiving frames here
if (curframe->timestamp_gap == 0) {
snprintf(buffer, sizeof(buffer), "%" PRIu32 "/%" PRIu64 "", curframe->timestamp,
conn->first_packet_time_to_play);
send_ssnc_metadata('pffr', buffer, strlen(buffer),
0); // "first frame received", but don't wait if the queue is locked
debug(3, "pffr: \"%s\"", buffer);
} else {
// otherwise, say a discontinuity occurred
snprintf(buffer, sizeof(buffer), "%" PRIu32 "/%" PRId32 "", curframe->timestamp,
curframe->timestamp_gap);
send_ssnc_metadata(
'pdis', buffer, strlen(buffer),
0); // "a discontinuity of this many frames", but don't wait if the queue is locked
debug(3, "pdis: \"%s\"", buffer);
}
}
#endif
if (curframe) {
// check sequencing
if (conn->last_seqno_valid == 0) {
conn->last_seqno_valid = 1;
conn->last_seqno_read = curframe->sequence_number;
} else {
conn->last_seqno_read++;
if (curframe->sequence_number != conn->last_seqno_read) {
debug(1,
"Player: packets out of sequence: expected: %u, got: %u, with ab_read: %u "
"and ab_write: %u.",
conn->last_seqno_read, curframe->sequence_number, conn->ab_read, conn->ab_write);
conn->last_seqno_read = curframe->sequence_number; // reset warning...
}
}
}
return curframe;
}
static inline int32_t mean_32(int32_t a, int32_t b) {
int64_t al = a;
int64_t bl = b;
int64_t mean = (al + bl) / 2;
int32_t r = (int32_t)mean;
if (r != mean)
debug(1, "Error calculating average of two int32_t values: %d, %d.", a, b);
return r;
}
// this takes an array of channels of signed 32-bit integers and
// (a) removes or inserts a frame as specified in "stuff",
// (b) multiplies each sample by the fixedvolume (a 16-bit quantity)
// (c) dithers the result to the output size 32/24/16/8 bits
// (d) outputs the result in the approprate format
// formats accepted include U8, S8, S16, S24, S24_3LE, S24_3BE and S32
// can only accept a plus or minus 1
// stuff: 1 means add 1; 0 means do nothing; -1 means remove 1
static int stuff_buffer_basic_32(int32_t *inptr, int length, sps_format_t l_output_format,
char *outptr, int stuff, int dither, rtsp_conn_info *conn) {
int tstuff = 0;
if (length >= 3) {
tstuff = stuff;
if (tstuff)
debug(3, "stuff_buffer_basic_32 %+d.", tstuff);
char *l_outptr = outptr;
if (stuff > 1)
stuff = 1;
if (stuff < -1)
stuff = -1;
if ((stuff > 1) || (stuff < -1) || (length < 100)) {
// debug(1, "Stuff argument to stuff_buffer must be from -1 to +1 and length >100.");
tstuff = 0; // if any of these conditions hold, don't stuff anything/
}
int i;
int stuffsamp = length;
if (tstuff)
// stuffsamp = rand() % (length - 1);
stuffsamp =
(rand() % (length - 2)) + 1; // ensure there's always a sample before and after the item
for (i = 0; i < stuffsamp; i++) { // the whole frame, if no stuffing
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++)
process_sample(*inptr++, &l_outptr, l_output_format, conn->fix_volume, dither, conn);
};
if (tstuff) {
if (tstuff == 1) {
// debug(3, "+++++++++");
// interpolate one sample
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++)
process_sample(mean_32(inptr[-2], inptr[0]), &l_outptr, l_output_format, conn->fix_volume,
dither, conn);
} else if (stuff == -1) {
// debug(3, "---------");
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++)
inptr++;
}
// if you're removing, i.e. stuff < 0, copy that much less over. If you're adding, do all the
// rest.
int remainder = length;
if (tstuff < 0)
remainder = remainder + tstuff; // don't run over the correct end of the output buffer
for (i = stuffsamp; i < remainder; i++) {
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++)
process_sample(*inptr++, &l_outptr, l_output_format, conn->fix_volume, dither, conn);
}
}
}
return length + tstuff;
}
// this takes an array of channels of n signed 32-bit integers and
// (a) replaces all of them with channels of n+stuff (+/-1) signed 32-bit integers,
// by first order interpolation.
// (b) multiplies each sample by the fixedvolume (a 16-bit quantity)
// (c) dithers the result to the output size 32/24/16/8 bits
// (d) outputs the result in the approprate format
// formats accepted include U8, S8, S16, S24, S24_3LE, S24_3BE and S32
// stuff: 1 means add 1; 0 means do nothing; -1 means remove 1
static int stuff_buffer_vernier(int32_t *inptr, int length, sps_format_t l_output_format,
char *outptr, int stuff, int dither, rtsp_conn_info *conn) {
int tstuff = 0;
if (length >= 3) {
tstuff = stuff;
if ((stuff > INTERPOLATION_LIMIT) || (stuff < -INTERPOLATION_LIMIT) || (length < 100)) {
debug(2,
"Stuff argument %d to stuff_buffer_vernier of length %d must be from -%d to +%d and "
"length > 100.",
stuff, length, INTERPOLATION_LIMIT, INTERPOLATION_LIMIT);
tstuff = 0; // if any of these conditions hold, don't stuff anything/
}
char *l_outptr = outptr;
int i;
if (tstuff == 0) {
for (i = 0; i < length; i++) { // the whole frame, if no stuffing
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++)
process_sample(*inptr++, &l_outptr, l_output_format, conn->fix_volume, dither, conn);
}
} else {
// we are using 64 bit integers to represent fixed point numbers
// the high 32 bits are the integer value and the low 32 bits are the fraction.
int64_t one_fp = 0x100000000L;
// this result will always be less than or equal to the exact true value.
int64_t step_size_fp = one_fp * (length - 1);
step_size_fp = step_size_fp / (length + tstuff - 1);
// the interpolation is done between the previous sample, starting
// with the zeroth sample, and the next one.
// the very first and very last sample of the stuffed frame should
// correspond 100% to the first and last samples of the original frame.
// the first sample will be calculated as 100% of the first sample and 0% of the next sample
// however, the last sample can not be calculated as 100% of the last sample and
// 0% of the next one, because there isn't a "next" sample after the last one, duh.
// however, rather than add extra code to deal with the last sample,
// simply use a copy of the last sample as the "next" one, and the maths will work out.
int64_t current_input_sample_index_fp = 0;
for (i = 0; i < length + tstuff; i++) {
int64_t current_input_sample_floor_index =
current_input_sample_index_fp >> 32; // this is the (integer) index of the sample before
// where the new sample will be interpolated
if (current_input_sample_floor_index == length) {
// generate the whole and fractional parts of current_input_sample_index_fp for printing
// without converting to floating point, which may do rounding.
int64_t current_input_sample_index_int = current_input_sample_index_fp >> 32;
int64_t current_input_sample_index_low = current_input_sample_index_fp & 0xFFFFFFFF;
current_input_sample_index_low =
current_input_sample_index_low * 100000; // 100000 for 5 decimal places
current_input_sample_index_low = current_input_sample_index_low >> 32;
debug(1,
"Can't see how this could ever happen, but "
"current_input_sample_floor_index %" PRId64
" has just stepped outside the frame of %" PRId64
"samples, with stuff %d and current_input_sample_index_fp at %" PRId64 ".%05" PRId64
".",
current_input_sample_floor_index, length, stuff, current_input_sample_index_int,
current_input_sample_index_low);
current_input_sample_floor_index = length - 1; // hack
}
// increment the ceiling index, but ensure it stays within the frame
int64_t current_input_sample_ceil_index = current_input_sample_floor_index + 1;
if (current_input_sample_ceil_index == length) {
if (current_input_sample_floor_index == length - 1) {
current_input_sample_ceil_index = length - 1;
} else {
// generate the whole and fractional parts of current_input_sample_index_fp for printing
// without converting to floating point, which may do rounding.
int64_t current_input_sample_index_int = current_input_sample_index_fp >> 32;
int64_t current_input_sample_index_low = current_input_sample_index_fp & 0xFFFFFFFF;
current_input_sample_index_low =
current_input_sample_index_low * 100000; // 100000 for 5 decimal places
current_input_sample_index_low = current_input_sample_index_low >> 32;
debug(1,
"Can't see how this could ever happen, but "
"current_input_sample_ceil_index %" PRId64
" has just stepped outside the frame of %" PRId64
"samples, with stuff %d and current_input_sample_index_fp at %" PRId64
".%05" PRId64 ".",
current_input_sample_floor_index, length, stuff, current_input_sample_index_int,
current_input_sample_index_low);
}
}
/*
{
// generate the whole and fractional parts of current_input_sample_index_fp for printing
// without converting to floating point, which may do rounding.
int64_t current_input_sample_index_int = current_input_sample_index_fp >> 32;
int64_t current_input_sample_index_low = current_input_sample_index_fp & 0xFFFFFFFF;
current_input_sample_index_low =
current_input_sample_index_low * 100000; // 100000 for 5 decimal places
current_input_sample_index_low = current_input_sample_index_low >> 32;
debug(1,
"samples: %u, stuff: %d, output_sample: %d, current_input_sample_index_fp: %" PRId64
".%05" PRId64 ", floor: %" PRId64 ", ceil: %" PRId64 ".",
length, stuff, i, current_input_sample_index_int, current_input_sample_index_low,
current_input_sample_floor_index, current_input_sample_ceil_index);
}
*/
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++) {
int32_t current_sample =
inptr[current_input_sample_floor_index * conn->input_num_channels + channel];
int32_t next_sample =
inptr[current_input_sample_ceil_index * conn->input_num_channels + channel];
int64_t current_sample_fp = current_sample;
// current_sample_fp = current_sample_fp << 32;
int64_t next_sample_fp = next_sample;
// next_sample_fp = next_sample_fp << 32;
int64_t offset_from_floor_fp = current_input_sample_index_fp & 0xffffffff;
int64_t offset_to_ceil_fp = one_fp - offset_from_floor_fp;
int64_t interpolated_sample_value_fp =
current_sample_fp * offset_to_ceil_fp + next_sample_fp * offset_from_floor_fp;
interpolated_sample_value_fp =
interpolated_sample_value_fp / one_fp; // back to a 32-bit samplle
int32_t interpolated_sample_value = interpolated_sample_value_fp;
process_sample(interpolated_sample_value, &l_outptr, l_output_format, conn->fix_volume,
dither, conn);
}
current_input_sample_index_fp = current_input_sample_index_fp + step_size_fp;
}
}
}
return length + tstuff;
}
#ifdef CONFIG_SOXR
// this takes an array of signed 32-bit integers and
// (a) uses libsoxr to
// resample the array to have one more or one less frame, as specified in
// stuff,
// (b) multiplies each sample by the fixedvolume (a 16-bit quantity)
// (c) dithers the result to the output size 32/24/16/8 bits
// (d) outputs the result in the approprate format
// formats accepted include U8, S8, S16, S24, S24_3LE, S24_3BE and S32
int32_t stat_n = 0;
double stat_mean = 0.0;
double stat_M2 = 0.0;
double longest_soxr_execution_time = 0.0;
int64_t packets_processed = 0;
int stuff_buffer_soxr_32(int32_t *inptr, int length, sps_format_t l_output_format, char *outptr,
int stuff, int dither, rtsp_conn_info *conn) {
// if (scratchBuffer == NULL) {
// die("soxr scratchBuffer not initialised.");
//}
packets_processed++;
int tstuff = stuff;
if ((stuff > INTERPOLATION_LIMIT) || (stuff < -INTERPOLATION_LIMIT) || (length < 100)) {
debug(2,
"Stuff argument %d to stuff_buffer_soxr_32 of length %d must be from -%d to +%d and "
"length > 100.",
stuff, length, INTERPOLATION_LIMIT, INTERPOLATION_LIMIT);
tstuff = 0; // if any of these conditions hold, don't stuff anything/
}
if (tstuff) {
// debug(1, "stuff_buffer_soxr_32 %+d.",stuff);
int32_t *scratchBuffer =
malloc(sizeof(int32_t) * CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) *
(length + tstuff));
if (scratchBuffer != NULL) {
soxr_io_spec_t io_spec;
io_spec.itype = SOXR_INT32_I;
io_spec.otype = SOXR_INT32_I;
io_spec.scale = 1.0; // this seems to crash if not = 1.0
io_spec.e = NULL;
io_spec.flags = 0;
size_t odone;
uint64_t soxr_start_time = get_absolute_time_in_ns();
soxr_error_t error =
soxr_oneshot(length, length + tstuff, conn->input_num_channels, // Rates and # of chans.
inptr, length, NULL, // Input.
scratchBuffer, length + tstuff, &odone, // Output.
&io_spec, // Input, output and transfer spec.
NULL, NULL); // Default configuration.
if (error)
die("soxr error: %s\n", "error: %s\n", soxr_strerror(error));
if (odone > (size_t)(length + INTERPOLATION_LIMIT))
die("odone = %u!\n", odone);
// mean and variance calculations from "online_variance" algorithm at
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm
double soxr_execution_time = (get_absolute_time_in_ns() - soxr_start_time) * 0.000000001;
// debug(1,"soxr_execution_time_us: %10.1f",soxr_execution_time_us);
if (soxr_execution_time > longest_soxr_execution_time)
longest_soxr_execution_time = soxr_execution_time;
stat_n += 1;
double stat_delta = soxr_execution_time - stat_mean;
if (stat_n != 0)
stat_mean += stat_delta / stat_n;
else
warn("calculation error for stat_n");
stat_M2 += stat_delta * (soxr_execution_time - stat_mean);
int i;
int32_t *ip, *op;
ip = inptr;
op = scratchBuffer;
const int gpm = 5;
// keep the first (dpm) samples, to mitigate the Gibbs phenomenon
for (i = 0; i < gpm; i++) {
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++)
*op++ = *ip++;
}
// keep the last (dpm) samples, to mitigate the Gibbs phenomenon
// pointer arithmetic, baby -- it's da bomb.
op = scratchBuffer + (length + tstuff - gpm) * conn->input_num_channels;
ip = inptr + (length - gpm) * conn->input_num_channels;
for (i = 0; i < gpm; i++) {
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++)
*op++ = *ip++;
}
// now, do the volume, dither and formatting processing
ip = scratchBuffer;
char *l_outptr = outptr;
for (i = 0; i < length + tstuff; i++) {
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++)
process_sample(*ip++, &l_outptr, l_output_format, conn->fix_volume, dither, conn);
};
free(scratchBuffer);
} else {
debug(1, "Cannot allocate scratchbuffer");
}
} else { // the whole frame, if no stuffing
// now, do the volume, dither and formatting processing
int32_t *ip = inptr;
char *l_outptr = outptr;
int i;
for (i = 0; i < length; i++) {
unsigned int channel;
for (channel = 0; channel < conn->input_num_channels; channel++)
process_sample(*ip++, &l_outptr, l_output_format, conn->fix_volume, dither, conn);
};
}
if (packets_processed % 1250 == 0) {
debug(3,
"soxr_oneshot execution time in nanoseconds: mean, standard deviation and max "
"for %" PRId32 " interpolations in the last "
"1250 packets. %10.6f, %10.6f, %10.6f.",
stat_n, stat_mean, stat_n <= 1 ? 0.0 : sqrtf(stat_M2 / (stat_n - 1)),
longest_soxr_execution_time);
stat_n = 0;
stat_mean = 0.0;
stat_M2 = 0.0;
longest_soxr_execution_time = 0.0;
}
return length + tstuff;
}
#endif
void player_thread_initial_cleanup_handler(__attribute__((unused)) void *arg) {
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
debug(3, "Connection %d: player thread main loop exit via player_thread_initial_cleanup_handler.",
conn->connection_number);
}
char line_of_stats[1024];
int statistics_row; // statistics_line 0 means print the headings; anything else 1 means print the
// values. Set to 0 the first time out.
int statistics_column; // used to index through the statistics_print_profile array to check if it
// should be printed
int was_a_previous_column;
int *statistics_print_profile;
// these arrays specify which of the statistics specified by the statistics_item calls will actually
// be printed -- 2 means print, 1 means print only in a debug mode, 0 means skip
// clang-format off
int ap1_synced_statistics_print_profile[] = {2, 1, 2, 2, 0, 2, 1, 1, 2, 1, 1, 1, 0, 1, 1, 2, 2};
int ap1_nosync_statistics_print_profile[] = {2, 0, 0, 0, 0, 2, 1, 1, 2, 1, 1, 1, 0, 1, 1, 0, 0};
int ap1_nodelay_statistics_print_profile[] = {0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 1, 1, 0, 1, 1, 0, 0};
int ap2_realtime_synced_stream_statistics_print_profile[] = {2, 1, 2, 2, 0, 2, 1, 1, 2, 1, 1, 1, 0, 0, 1, 2, 2};
int ap2_realtime_nosync_stream_statistics_print_profile[] = {2, 0, 0, 0, 0, 2, 1, 1, 2, 1, 1, 1, 0, 0, 1, 0, 0};
int ap2_realtime_nodelay_stream_statistics_print_profile[] = {0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 1, 1, 0, 0, 1, 0, 0};
int ap2_buffered_synced_stream_statistics_print_profile[] = {2, 2, 2, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 2, 2};
int ap2_buffered_nosync_stream_statistics_print_profile[] = {2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0};
int ap2_buffered_nodelay_stream_statistics_print_profile[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0};
// clang-format on
void statistics_item(const char *heading, const char *format, ...) {
if (((statistics_print_profile[statistics_column] == 1) && (debuglev != 0)) ||
(statistics_print_profile[statistics_column] == 2)) { // include this column?
if (was_a_previous_column != 0) {
if (statistics_row == 0)
strcat(line_of_stats, " | ");
else
strcat(line_of_stats, " ");
}
if (statistics_row == 0) {
strcat(line_of_stats, heading);
} else {
char b[1024];
b[0] = 0;
va_list args;
va_start(args, format);
vsnprintf(b, sizeof(b), format, args);
va_end(args);
strcat(line_of_stats, b);
}
was_a_previous_column = 1;
}
statistics_column++;
}
double suggested_volume(rtsp_conn_info *conn) {
double response = config.airplay_volume;
if ((conn != NULL) && (conn->own_airplay_volume_set != 0)) {
response = conn->own_airplay_volume;
}
return response;
}
#ifdef CONFIG_METADATA
void send_ssnc_stream_description(const char *type, const char *description) {
send_ssnc_metadata('styp', type, strlen(type), 1);
send_ssnc_metadata('sdsc', description, strlen(description), 1);
}
#endif
void player_thread_cleanup_handler(void *arg) {
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
// debug(1, "Connection %d: player_thread_cleanup_handler start.", conn->connection_number);
#ifdef CONFIG_FFMPEG
// debug(1, "FFmpeg clearup");
clear_software_resampler(conn);
clear_decoding_chain(conn);
// debug(1, "FFmpeg clearup done");
#endif
if (config.output->stop) {
#ifdef CONFIG_FFMPEG
if (avflush(conn) > 1)
debug(3, "ffmpeg flush at stop!");
#endif
debug(2, "Connection %d: player: stop the output backend.", conn->connection_number);
config.output->stop();
}
int oldState;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState);
debug(3, "Connection %d: player thread main loop exit via player_thread_cleanup_handler.",
conn->connection_number);
if ((conn->at_least_one_frame_seen_this_session != 0) && (config.statistics_requested)) {
int64_t time_playing = get_absolute_time_in_ns() - conn->playstart;
time_playing = time_playing / 1000000000;
int64_t elapsedHours = time_playing / 3600;
int64_t elapsedMin = (time_playing / 60) % 60;
int64_t elapsedSec = time_playing % 60;
if (conn->frame_rate_valid)
inform("Connection %d: Playback stopped. Total playing time %02" PRId64 ":%02" PRId64
":%02" PRId64 ". "
"Output: %0.2f (raw), %0.2f (corrected) "
"frames per second.",
conn->connection_number, elapsedHours, elapsedMin, elapsedSec, conn->raw_frame_rate,
conn->corrected_frame_rate);
else
inform("Connection %d: Playback stopped. Total playing time %02" PRId64 ":%02" PRId64
":%02" PRId64 ".",
conn->connection_number, elapsedHours, elapsedMin, elapsedSec);
}
#ifdef CONFIG_DACP_CLIENT
relinquish_dacp_server_information(
conn); // say it doesn't belong to this conversation thread any more...
#else
mdns_dacp_monitor_set_id(NULL); // say we're not interested in following that DACP id any more
#endif
// four possibilities
// 1 -- Classic Airplay -- "AirPlay 1"
// 2 -- AirPlay 2 in Classic Airplay mode
// 3 -- AirPlay 2 in Buffered Audio Mode
// 4 -- AirPlay 3 in Realtime Audio Mode.
#ifdef CONFIG_AIRPLAY_2
if (conn->airplay_type == ap_2) {
debug(2, "Cancelling AP2 timing, control and audio threads...");
if (conn->airplay_stream_type == realtime_stream) {
debug(2, "Connection %d: Delete Realtime Audio Stream thread", conn->connection_number);
pthread_cancel(conn->rtp_realtime_audio_thread);
pthread_join(conn->rtp_realtime_audio_thread, NULL);
} else if (conn->airplay_stream_type == buffered_stream) {
debug(2,
"Connection %d: Delete Buffered Audio Stream thread by player_thread_cleanup_handler",
conn->connection_number);
pthread_cancel(conn->rtp_buffered_audio_thread);
pthread_join(conn->rtp_buffered_audio_thread, NULL);
} else {
die("Unrecognised Stream Type");
}
debug(2, "Connection %d: Delete AirPlay 2 Control thread", conn->connection_number);
pthread_cancel(conn->rtp_ap2_control_thread);
pthread_join(conn->rtp_ap2_control_thread, NULL);
} else {
debug(2, "Cancelling AP1-compatible timing, control and audio threads...");
#else
debug(2, "Cancelling AP1 timing, control and audio threads...");
#endif
debug(3, "Cancel timing thread.");
pthread_cancel(conn->rtp_timing_thread);
debug(3, "Join timing thread.");
pthread_join(conn->rtp_timing_thread, NULL);
debug(3, "Timing thread terminated.");
debug(3, "Cancel control thread.");
pthread_cancel(conn->rtp_control_thread);
debug(3, "Join control thread.");
pthread_join(conn->rtp_control_thread, NULL);
debug(3, "Control thread terminated.");
debug(3, "Cancel audio thread.");
pthread_cancel(conn->rtp_audio_thread);
debug(3, "Join audio thread.");
pthread_join(conn->rtp_audio_thread, NULL);
debug(3, "Audio thread terminated.");
#ifdef CONFIG_AIRPLAY_2
}
// ptp_send_control_message_string("T"); // remove all timing peers to force the master to 0
// reset_anchor_info(conn);
#endif
if (conn->outbuf) {
free(conn->outbuf);
conn->outbuf = NULL;
}
if (conn->tbuf) {
free(conn->tbuf);
conn->tbuf = NULL;
}
// if (conn->statistics) {
// free(conn->statistics);
// conn->statistics = NULL;
// }
free_audio_buffers(conn);
if (conn->stream.type == ast_apple_lossless) {
#ifdef CONFIG_APPLE_ALAC
if (config.decoder_in_use == 1 << decoder_apple_alac) {
apple_alac_terminate();
}
#endif
#ifdef CONFIG_HAMMERTON
if (config.decoder_in_use == 1 << decoder_hammerton) {
alac_free(conn->decoder_info);
}
#endif
}
// no need to flush the FFMPEG decoder...
conn->rtp_running = 0;
pthread_setcancelstate(oldState, NULL);
debug(2, "Connection %d: player terminated.", conn->connection_number);
}
void *player_thread_func(void *arg) {
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
// if (config.output->prepare)
// config.output->prepare(); // give the backend its first chance to prepare itself, knowing it
// has access to the output device (i.e. knowing that it should not be in use by another program
// at this time).
#ifdef CONFIG_METADATA
uint64_t time_of_last_metadata_progress_update =
0; // the assignment is to stop a compiler warning...
#endif
uint64_t previous_frames_played = 0; // initialised to avoid a "possibly uninitialised" warning
uint64_t previous_raw_measurement_time =
0; // initialised to avoid a "possibly uninitialised" warning
uint64_t previous_corrected_measurement_time =
0; // initialised to avoid a "possibly uninitialised" warning
int previous_frames_played_valid = 0;
// pthread_cleanup_push(player_thread_initial_cleanup_handler, arg);
conn->latency_warning_issued =
0; // be permitted to generate a warning each time a play is attempted
conn->packet_count = 0;
conn->packet_count_since_flush = 0;
conn->previous_random_number = 0;
conn->decoder_in_use = 0;
conn->ab_buffering = 1;
conn->ab_synced = 0;
conn->first_packet_timestamp = 0;
conn->flush_requested = 0;
conn->flush_output_flushed = 0; // only send a flush command to the output device once
conn->flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to
// be used as a null operand, so we'll use it like that too
conn->fix_volume = 0x10000;
conn->frames_per_packet = 352; // for ALAC -- will be changed if necessary
#ifdef CONFIG_AIRPLAY_2
conn->ap2_flush_requested = 0;
conn->ap2_flush_from_valid = 0;
conn->ap2_rate = 0;
conn->ap2_play_enabled = 0;
#endif
const unsigned int sync_history_length = 40;
int64_t sync_samples[sync_history_length];
int64_t sync_samples_highest_error = 0;
int64_t sync_samples_lowest_error = 0;
int64_t sync_samples_second_highest_error;
int64_t sync_samples_second_lowest_error;
conn->sync_samples_index = 0;
conn->sync_samples_count = 0;
if (conn->stream.type == ast_apple_lossless) {
#ifdef CONFIG_HAMMERTON
if (config.decoder_in_use == 1 << decoder_hammerton) {
init_alac_decoder((int32_t *)&conn->stream.fmtp,
conn); // this sets up incoming rate, bit depth, channels.
// No pthread cancellation point in here
}
#endif
#ifdef CONFIG_APPLE_ALAC
if (config.decoder_in_use == 1 << decoder_apple_alac) {
apple_alac_init(conn->stream.fmtp); // no pthread cancellation point in here
}
#endif
}
// This must be after init_alac_decoder
init_buffer(conn); // will need a corresponding deallocation. No cancellation points in here
ab_resync(conn);
if (conn->stream.encrypted) {
#ifdef CONFIG_MBEDTLS
memset(&conn->dctx, 0, sizeof(mbedtls_aes_context));
mbedtls_aes_setkey_dec(&conn->dctx, conn->stream.aeskey, 128);
#endif
#ifdef CONFIG_POLARSSL
memset(&conn->dctx, 0, sizeof(aes_context));
aes_setkey_dec(&conn->dctx, conn->stream.aeskey, 128);
#endif
}
conn->session_corrections = 0;
conn->connection_state_to_output = get_requested_connection_state_to_output();
int number_of_statistics, oldest_statistic, newest_statistic;
uint32_t frames_since_last_stats_logged = 0;
int at_least_one_frame_seen = 0;
int64_t tsum_of_sync_errors, tsum_of_corrections, tsum_of_insertions_and_deletions;
size_t tsum_of_frames;
minimum_dac_queue_size = UINT64_MAX;
int64_t tsum_of_gaps;
int32_t minimum_buffer_occupancy = INT32_MAX;
int32_t maximum_buffer_occupancy = INT32_MIN;
#ifdef CONFIG_AIRPLAY_2
conn->ap2_audio_buffer_minimum_size = -1;
#endif
conn->at_least_one_frame_seen_this_session = 0;
conn->raw_frame_rate = 0.0;
conn->corrected_frame_rate = 0.0;
conn->frame_rate_valid = 0;
conn->input_frame_rate = 0.0;
conn->input_frame_rate_starting_point_is_valid = 0;
conn->buffer_occupancy = 0;
int play_samples = 0;
uint64_t current_delay;
int play_number = 0;
conn->play_number_after_flush = 0;
conn->time_of_last_audio_packet = 0;
// conn->shutdown_requested = 0;
number_of_statistics = oldest_statistic = newest_statistic = 0;
tsum_of_sync_errors = tsum_of_corrections = tsum_of_insertions_and_deletions = 0;
tsum_of_frames = 0;
tsum_of_gaps = 0;
// I think it's useful to keep this prime to prevent it from falling into a pattern with some
// other process.
static char rnstate[256];
initstate(time(NULL), rnstate, 256);
// signed short *inbuf;
int inbuflength;
// remember, the output device may never have been initialised prior to this call
#ifdef CONFIG_FFMPEG
if (avflush(conn) > 1)
debug(1, "ffmpeg flush at start!");
#endif
// leave this relic -- jack and soundio still use it
if (config.output->start != NULL)
config.output->start(44100, SPS_FORMAT_S16_LE);
conn->first_packet_timestamp = 0;
conn->missing_packets = conn->late_packets = conn->too_late_packets = conn->resend_requests = 0;
int sync_error_out_of_bounds =
0; // number of times in a row that there's been a serious sync error
// conn->statistics = malloc(sizeof(stats_t) * trend_samples);
// if (conn->statistics == NULL)
// die("Failed to allocate a statistics buffer");
conn->framesProcessedInThisEpoch = 0;
conn->framesGeneratedInThisEpoch = 0;
conn->correctionsRequestedInThisEpoch = 0;
statistics_row = 0; // statistics_line 0 means print the headings; anything else 1 means print the
// values. Set to 0 the first time out.
// decide on what statistics profile to use, if requested
#ifdef CONFIG_AIRPLAY_2
if (conn->airplay_type == ap_2) {
if (conn->airplay_stream_type == realtime_stream) {
if (config.output->delay) {
// if (config.no_sync == 0)
statistics_print_profile = ap2_realtime_synced_stream_statistics_print_profile;
// else
// statistics_print_profile = ap2_realtime_nosync_stream_statistics_print_profile;
} else {
statistics_print_profile = ap2_realtime_nodelay_stream_statistics_print_profile;
}
} else {
if (config.output->delay) {
// if (config.no_sync == 0)
statistics_print_profile = ap2_buffered_synced_stream_statistics_print_profile;
// else
// statistics_print_profile = ap2_buffered_nosync_stream_statistics_print_profile;
} else {
statistics_print_profile = ap2_buffered_nodelay_stream_statistics_print_profile;
}
}
} else {
#endif
if (config.output->delay) {
// if (config.no_sync == 0)
statistics_print_profile = ap1_synced_statistics_print_profile;
// else
// statistics_print_profile = ap1_nosync_statistics_print_profile;
} else {
statistics_print_profile = ap1_nodelay_statistics_print_profile;
}
// airplay 1 stuff here
#ifdef CONFIG_AIRPLAY_2
}
#endif
#ifdef CONFIG_AIRPLAY_2
if (conn->timing_type == ts_ntp) {
#endif
// create and start the timing, control and audio receiver threads
named_pthread_create(&conn->rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)conn,
"ap1_audio_%d", conn->connection_number);
named_pthread_create(&conn->rtp_control_thread, NULL, &rtp_control_receiver, (void *)conn,
"ap1_control_%d", conn->connection_number);
named_pthread_create(&conn->rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)conn,
"ap1_tim_rcv_%d", conn->connection_number);
#ifdef CONFIG_AIRPLAY_2
}
#endif
pthread_cleanup_push(player_thread_cleanup_handler, arg); // undo what's been done so far
// stop looking elsewhere for DACP stuff
int oldState;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState);
#ifdef CONFIG_DACP_CLIENT
set_dacp_server_information(conn);
#else
mdns_dacp_monitor_set_id(conn->dacp_id);
#endif
pthread_setcancelstate(oldState, NULL);
// if not already set, set the volume to the pending_airplay_volume, if any, or otherwise to the
// suggested volume.
double initial_volume = suggested_volume(conn);
debug(2, "Set initial volume to %.6f.", initial_volume);
player_volume(initial_volume, conn); // will contain a cancellation point if asked to wait
debug(2, "Play begin");
#ifdef CONFIG_FFMPEG
int64_t frames_previously_retained_in_the_resampler = 0;
#endif
// uint32_t flush_to_frame;
// int enable_flush_to_frame = 0;
int request_resync = 0; // will be set if a big discontinuity is detected
uint32_t frames_to_skip = 0; // when a discontinuity is registered
int skipping_frames_at_start_of_play = 0;
// debug(1, "player begin processing packets");
while (1) {
#ifdef CONFIG_METADATA
int this_is_the_first_frame = 0; // will be set if it is
#endif
pthread_testcancel(); // allow a pthread_cancel request to take effect.
// if we are using the software attenuator or downsampling or mixing to mono, enable dithering
if ((conn->fix_volume != 0x10000) || // if not 0x10000, it is attenuating...
((conn->output_bit_depth > 0) &&
(conn->input_effective_bit_depth > conn->output_bit_depth)) ||
(config.playback_mode == ST_mono)) {
if (conn->enable_dither == 0)
debug(2, "enabling dither", conn->fix_volume);
conn->enable_dither = 1;
} else {
if (conn->enable_dither != 0)
debug(2, "disabling dither");
conn->enable_dither = 0;
}
abuf_t *inframe = buffer_get_frame(
conn, request_resync); // this has a guaranteed [and needed!] cancellation point
request_resync = 0;
if (inframe) {
if (inframe->data != NULL) {
/*
{
uint64_t the_time_this_frame_should_be_played;
frame_to_local_time(inframe->timestamp,
&the_time_this_frame_should_be_played, conn);
int64_t lead_time = the_time_this_frame_should_be_played - get_absolute_time_in_ns();
debug(1, "get_packet %u, lead time is %3.f ms.", inframe->timestamp, lead_time *
0.000001);
}
*/
unsigned int last_sample_index;
int frames_played = 0;
int64_t sync_error = 0;
int amount_to_stuff = 0;
if (inframe->data) {
if (play_number == 0)
conn->playstart = get_absolute_time_in_ns();
play_number++;
// if (play_number % 100 == 0)
// debug(3, "Play frame %d.", play_number);
conn->play_number_after_flush++;
if (inframe->timestamp == 0) {
debug(2,
"Player has supplied a silent frame, (possibly frame %u) for play number %d, "
"status 0x%X after %u resend requests.",
conn->last_seqno_read + 1, play_number, inframe->status,
inframe->resend_request_number);
conn->last_seqno_read++; // manage the packet out of sequence minder
void *silence =
malloc(sps_format_sample_size(
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration)) *
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) *
conn->frames_per_packet);
if (silence == NULL) {
debug(1, "Failed to allocate memory for a silent frame silence buffer.");
} else {
// the player may change the contents of the buffer, so it has to be zeroed each
// time; might as well malloc and free it locally
conn->previous_random_number = generate_zero_frames(
silence, conn->frames_per_packet, conn->enable_dither,
conn->previous_random_number, config.current_output_configuration);
config.output->play(silence, conn->frames_per_packet, play_samples_are_untimed, 0, 0);
free(silence);
frames_played += conn->frames_per_packet;
}
} else {
// process the frame
// here, let's transform the frame of data, if necessary
// we need an intermediate "transition" buffer
if (conn->tbuf != NULL) {
debug(1, "conn->tbuf not free'd");
free(conn->tbuf);
}
conn->tbuf =
malloc(sizeof(int32_t) *
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) *
((inframe->length) * conn->output_sample_ratio + INTERPOLATION_LIMIT));
if (conn->tbuf == NULL)
die("Failed to allocate memory for the transition buffer.");
// size change
conn->outbuf =
malloc(sps_format_sample_size(
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration)) *
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) *
((inframe->length) * conn->output_sample_ratio + +INTERPOLATION_LIMIT));
if (conn->outbuf == NULL)
die("Failed to allocate memory for an output buffer.");
if (conn->input_num_channels == 2) {
// if (0) {
switch (conn->input_bit_depth) {
case 16: {
unsigned int i, j;
int16_t ls, rs;
int32_t ll = 0, rl = 0;
int16_t *inps = inframe->data;
// int16_t *outps = tbuf;
int32_t *outpl = (int32_t *)conn->tbuf;
for (i = 0; i < (inframe->length); i++) {
ls = *inps++;
rs = *inps++;
// here, do the mode stuff -- mono / reverse stereo / leftonly / rightonly
// also, raise the 16-bit samples to 32 bits.
switch (config.playback_mode) {
case ST_mono: {
int32_t lsl = ls;
int32_t rsl = rs;
int32_t both = lsl + rsl;
both =
both
<< (16 -
1); // keep all 17 bits of the sum of the 16 bit left and right channels
// -- the 17th bit will influence dithering later
ll = both;
rl = both;
} break;
case ST_reverse_stereo: {
ll = rs;
rl = ls;
ll = ll << 16;
rl = rl << 16;
} break;
case ST_left_only:
rl = ls;
ll = ls;
ll = ll << 16;
rl = rl << 16;
break;
case ST_right_only:
ll = rs;
rl = rs;
ll = ll << 16;
rl = rl << 16;
break;
case ST_stereo:
ll = ls;
rl = rs;
ll = ll << 16;
rl = rl << 16;
break; // nothing extra to do
}
// here, replicate the samples if you're upsampling
for (j = 0; j < conn->output_sample_ratio; j++) {
*outpl++ = ll;
*outpl++ = rl;
}
}
} break;
case 32: {
unsigned int i, j;
int32_t ls, rs;
int32_t ll = 0, rl = 0;
int32_t *inps = (int32_t *)inframe->data;
int32_t *outpl = (int32_t *)conn->tbuf;
for (i = 0; i < (inframe->length); i++) {
ls = *inps++;
rs = *inps++;
// here, do the mode stuff -- mono / reverse stereo / leftonly / rightonly
switch (config.playback_mode) {
case ST_mono: {
int64_t lsl = ls;
int64_t rsl = rs;
int64_t both = lsl + rsl;
both = both >> 1;
uint32_t both32 = both;
ll = both32;
rl = both32;
} break;
case ST_reverse_stereo: {
ll = rs;
rl = ls;
} break;
case ST_left_only:
rl = ls;
ll = ls;
break;
case ST_right_only:
ll = rs;
rl = rs;
break;
case ST_stereo:
ll = ls;
rl = rs;
break; // nothing extra to do
}
// here, replicate the samples if you're upsampling
for (j = 0; j < conn->output_sample_ratio; j++) {
*outpl++ = ll;
*outpl++ = rl;
}
}
} break;
default:
die("Shairport Sync only supports 16 or 32 bit input (stereo)");
}
} else {
// multichannel -- don't do anything odd here
if (conn->input_bit_depth == 16) {
unsigned int i;
int16_t ss;
int32_t sl;
int16_t *inps = inframe->data;
int32_t *outpl = (int32_t *)conn->tbuf;
for (i = 0; i < (inframe->length) * conn->input_num_channels; i++) {
ss = *inps++;
sl = ss;
sl = sl << 16;
unsigned int j;
for (j = 0; j < conn->output_sample_ratio; j++) {
*outpl++ = sl;
}
}
} else if (conn->input_bit_depth == 32) {
unsigned int i;
int32_t *inpl = (int32_t *)inframe->data;
int32_t *outpl = (int32_t *)conn->tbuf;
for (i = 0; i < (inframe->length) * conn->input_num_channels; i++) {
int32_t sl = *inpl++;
unsigned int j;
for (j = 0; j < conn->output_sample_ratio; j++) {
*outpl++ = sl;
}
}
} else {
die("Shairport Sync only supports 16 or 32 bit input (multichannel)");
}
}
inbuflength = (inframe->length) * conn->output_sample_ratio;
// We have a frame of data. We need to see if we want to add or remove a frame from
// it to keep in sync. So we calculate the timing error for the first frame in the
// DAC. If it's ahead of time, we add one audio frame to this frame to delay a
// subsequent frame If it's late, we remove an audio frame from this frame to bring
// a subsequent frame forward in time
// now, go back as far as the total latency less, say, 100 ms, and check the
// presence of frames from then onwards
at_least_one_frame_seen = 1;
int16_t bo = conn->ab_write - conn->ab_read; // do this in 16 bits
conn->buffer_occupancy = bo; // 32 bits
if (conn->buffer_occupancy < minimum_buffer_occupancy)
minimum_buffer_occupancy = conn->buffer_occupancy;
if (conn->buffer_occupancy > maximum_buffer_occupancy)
maximum_buffer_occupancy = conn->buffer_occupancy;
// now, before outputting anything to the output device, check the stats
uint32_t stats_logging_interval_in_frames = 8 * RATE_FROM_ENCODED_FORMAT(config.current_output_configuration);
if ((stats_logging_interval_in_frames != 0) && (frames_since_last_stats_logged > stats_logging_interval_in_frames)) {
// here, calculate the input and output frame rates, where possible, even if
// statistics have not been requested this is to calculate them in case they are
// needed by the D-Bus interface or elsewhere.
if (conn->input_frame_rate_starting_point_is_valid) {
uint64_t elapsed_reception_time, frames_received;
elapsed_reception_time = conn->frames_inward_measurement_time -
conn->frames_inward_measurement_start_time;
frames_received = conn->frames_inward_frames_received_at_measurement_time -
conn->frames_inward_frames_received_at_measurement_start_time;
conn->input_frame_rate = (1.0E9 * frames_received) /
elapsed_reception_time; // an IEEE double calculation
// with two 64-bit integers
} else {
conn->input_frame_rate = 0.0;
}
int stats_status = 0;
if ((config.output->delay) && (config.output->stats)) {
uint64_t frames_sent_for_play;
uint64_t raw_measurement_time;
uint64_t corrected_measurement_time;
uint64_t actual_delay;
stats_status =
config.output->stats(&raw_measurement_time, &corrected_measurement_time,
&actual_delay, &frames_sent_for_play);
// debug(1,"status: %d, actual_delay: %" PRIu64 ", frames_sent_for_play: %"
// PRIu64
// ", frames_played: %" PRIu64 ".", stats_status, actual_delay,
// frames_sent_for_play, frames_sent_for_play - actual_delay);
uint64_t frames_played_by_output_device = frames_sent_for_play - actual_delay;
// If the status is zero, it means that there were no output problems since the
// last time the stats call was made. Thus, the frame rate should be valid.
if ((stats_status == 0) && (previous_frames_played_valid != 0)) {
uint64_t frames_played_in_this_interval =
frames_played_by_output_device - previous_frames_played;
int64_t raw_interval = raw_measurement_time - previous_raw_measurement_time;
int64_t corrected_interval =
corrected_measurement_time - previous_corrected_measurement_time;
if (raw_interval != 0) {
conn->raw_frame_rate = (1e9 * frames_played_in_this_interval) / raw_interval;
conn->corrected_frame_rate =
(1e9 * frames_played_in_this_interval) / corrected_interval;
conn->frame_rate_valid = 1;
// debug(1,"frames_played_in_this_interval: %" PRIu64 ", interval: %" PRId64
// ", rate: %f.",
// frames_played_in_this_interval, interval, conn->frame_rate);
}
}
// uncomment the if statement if your want to get as long a period for
// calculating the frame rate as possible without an output break or error
if ((stats_status != 0) || (previous_frames_played_valid == 0)) {
// if we have just detected an outputting error, or if we have no
// starting information
if (stats_status != 0)
conn->frame_rate_valid = 0;
previous_frames_played = frames_played_by_output_device;
previous_raw_measurement_time = raw_measurement_time;
previous_corrected_measurement_time = corrected_measurement_time;
previous_frames_played_valid = 1;
}
}
// we can now calculate running averages for sync error (frames), corrections
// (ppm), insertions plus deletions (ppm)
double average_sync_error = 0.0;
double average_gap_ms = 0.0;
double corrections_ppm = 0.0;
double insertions_plus_deletions_ppm = 0.0;
if (number_of_statistics == 0) {
debug(1, "number_of_statistics is zero!");
} else {
average_sync_error =
(1000.0 * tsum_of_sync_errors) /
(number_of_statistics *
RATE_FROM_ENCODED_FORMAT(config.current_output_configuration));
average_gap_ms = ((1.0 * tsum_of_gaps) / number_of_statistics) * 0.000001;
if (tsum_of_frames != 0) {
corrections_ppm = (1000000.0 * tsum_of_corrections) / tsum_of_frames;
insertions_plus_deletions_ppm =
(1000000.0 * tsum_of_insertions_and_deletions) / tsum_of_frames;
} else {
debug(3, "tsum_of_frames: %u.", tsum_of_frames);
}
}
if (config.statistics_requested) {
if (at_least_one_frame_seen) {
do {
line_of_stats[0] = '\0';
statistics_column = 0;
was_a_previous_column = 0;
statistics_item("Av Sync Error (ms)", "%*.2f", 18, average_sync_error);
statistics_item("Net Sync PPM", "%*.1f", 12, corrections_ppm);
statistics_item("All Sync PPM", "%*.1f", 12, insertions_plus_deletions_ppm);
statistics_item("Av Sync Window (ms)", "%*.2f", 19, average_gap_ms);
statistics_item(" Packets", "%*d", 11, play_number);
statistics_item("Missing", "%*" PRIu64 "", 7, conn->missing_packets);
statistics_item(" Late", "%*" PRIu64 "", 6, conn->late_packets);
statistics_item("Too Late", "%*" PRIu64 "", 8, conn->too_late_packets);
statistics_item("Resend Reqs", "%*" PRIu64 "", 11, conn->resend_requests);
statistics_item("Min DAC Queue", "%*" PRIu64 "", 13, minimum_dac_queue_size);
statistics_item("Min Buffers", "%*" PRIu32 "", 11, minimum_buffer_occupancy);
statistics_item("Max Buffers", "%*" PRIu32 "", 11, maximum_buffer_occupancy);
#ifdef CONFIG_AIRPLAY_2
if (conn->ap2_audio_buffer_minimum_size > 10 * 1024)
statistics_item("Min Buffer Size", "%*" PRIu32 "k", 14,
conn->ap2_audio_buffer_minimum_size / 1024);
else
statistics_item("Min Buffer Size", "%*" PRIu32 "", 15,
conn->ap2_audio_buffer_minimum_size);
#else
statistics_item("N/A", " "); // dummy -- should never be visible
#endif
statistics_item("Nominal FPS", "%*.2f", 11, conn->remote_frame_rate);
statistics_item("Received FPS", "%*.2f", 12, conn->input_frame_rate);
// only make the next two columns appear if we are getting stats information
// from the back end
if (config.output->stats) {
if (conn->frame_rate_valid) {
statistics_item("Output FPS (r)", "%*.2f", 14, conn->raw_frame_rate);
statistics_item("Output FPS (c)", "%*.2f", 14, conn->corrected_frame_rate);
} else {
statistics_item("Output FPS (r)", " N/A");
statistics_item("Output FPS (c)", " N/A");
}
} else {
statistics_column = statistics_column + 2;
}
statistics_row++;
inform(line_of_stats);
} while (statistics_row < 2);
} else {
inform("No frames received in the last sampling interval.");
}
}
tsum_of_sync_errors = 0;
tsum_of_corrections = 0;
tsum_of_insertions_and_deletions = 0;
number_of_statistics = 0;
tsum_of_frames = 0;
tsum_of_gaps = 0;
minimum_dac_queue_size = UINT64_MAX; // hack reset
maximum_buffer_occupancy = INT32_MIN; // can't be less than this
minimum_buffer_occupancy = INT32_MAX; // can't be more than this
#ifdef CONFIG_AIRPLAY_2
conn->ap2_audio_buffer_minimum_size = -1;
#endif
at_least_one_frame_seen = 0;
frames_since_last_stats_logged = 0;
}
if (conn->at_least_one_frame_seen_this_session == 0) {
conn->at_least_one_frame_seen_this_session = 1;
#ifdef CONFIG_METADATA
this_is_the_first_frame = 1;
#endif
char short_description[256];
snprintf(short_description, sizeof(short_description), "%u/%s/%u",
RATE_FROM_ENCODED_FORMAT(config.current_output_configuration),
sps_format_description_string(
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration)),
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration));
// since this is the first frame of audio, inform the user if requested...
#ifdef CONFIG_AIRPLAY_2
if (conn->airplay_stream_type == realtime_stream) {
if (conn->airplay_type == ap_1) {
#ifdef CONFIG_METADATA
send_ssnc_stream_description("Classic", get_ssrc_name(conn->incoming_ssrc));
#endif
if (config.statistics_requested)
inform("Connection %d: Classic AirPlay (\"AirPlay 1\") Compatible playback. "
"Input format: %s. Output format: %s.",
conn->connection_number, get_ssrc_name(conn->incoming_ssrc),
short_description);
} else {
#ifdef CONFIG_METADATA
send_ssnc_stream_description("Realtime", get_ssrc_name(conn->incoming_ssrc));
#endif
if (config.statistics_requested) {
if (conn->ap2_client_name == NULL)
inform("Connection %d: AirPlay 2 Realtime playback. "
"Input format: %s. Output format: %s.",
conn->connection_number, get_ssrc_name(conn->incoming_ssrc), "");
else
inform("Connection %d: AirPlay 2 Realtime playback. "
"Source: \"%s\". Input format: %s. Output format: %s.",
conn->connection_number, conn->ap2_client_name,
get_ssrc_name(conn->incoming_ssrc), short_description);
}
}
} else {
#ifdef CONFIG_METADATA
send_ssnc_stream_description("Buffered", get_ssrc_name(conn->incoming_ssrc));
#endif
if (config.statistics_requested) {
if (conn->ap2_client_name == NULL)
inform("Connection %d: AirPlay 2 Buffered playback. "
"Input format: %s. Output format: %s.",
conn->connection_number, get_ssrc_name(conn->incoming_ssrc),
short_description);
else
inform("Connection %d: AirPlay 2 Buffered playback. "
"Source: \"%s\". Input format: %s. Output format: %s.",
conn->connection_number, conn->ap2_client_name,
get_ssrc_name(conn->incoming_ssrc), short_description);
}
}
#else
#ifdef CONFIG_METADATA
send_ssnc_stream_description("AirPlay", "ALAC/44100/S16/2");
#endif
if (config.statistics_requested)
inform("Connection %d: Classic AirPlay (\"AirPlay 1\") playback. "
"Input format: ALAC/44100/S16/2. Output format: %s.",
conn->connection_number, short_description);
#endif
#ifdef CONFIG_METADATA
send_ssnc_metadata('odsc', short_description, strlen(short_description), 1);
#endif
}
// here, we want to check (a) if we are meant to do synchronisation,
// (b) if we have a delay procedure, (c) if we can get the delay.
// If any of these are false, we don't do any synchronisation stuff
int resp = -1; // use this as a flag -- if negative, we can't rely on a real known delay
current_delay = -1; // use this as a failure flag
// if making the measurements takes too long (e.g. due to scheduling) , don't use
// it.
uint64_t mst = get_absolute_time_in_ns(); // measurement start time
uint64_t delay_measurement_time = 0;
if (config.output->delay) {
long l_delay;
resp = config.output->delay(&l_delay);
delay_measurement_time =
get_absolute_time_in_ns(); // put this after delay() returns, as it may take an
// appreciable amount of time to run
if (resp == 0) { // no error
current_delay = l_delay;
if (l_delay >= 0)
current_delay = l_delay;
else {
debug(2, "Underrun of %ld frames reported, but ignored.", l_delay);
current_delay =
0; // could get a negative value if there was underrun, but ignore it.
}
if (current_delay < minimum_dac_queue_size) {
minimum_dac_queue_size = current_delay; // update for display later
}
} else {
current_delay = 0;
if ((resp == sps_extra_code_output_stalled) &&
(config.unfixable_error_reported == 0)) {
config.unfixable_error_reported = 1;
if (config.cmd_unfixable) {
warn("Connection %d: An unfixable error has been detected -- output device "
"is "
"stalled. Executing the "
"\"run_this_if_an_unfixable_error_is_detected\" command.",
conn->connection_number);
command_execute(config.cmd_unfixable, "output_device_stalled", 1);
} else {
warn("Connection %d: An unfixable error has been detected -- output device "
"is "
"stalled. \"No "
"run_this_if_an_unfixable_error_is_detected\" command provided -- "
"nothing "
"done.",
conn->connection_number);
}
} else {
if ((resp != -EBUSY) &&
(resp != -ENODEV)) // delay and not-there errors can be reported if the
// device is (hopefully temporarily) busy or unavailable
// Note: ENODATA (a better fit) is not availabe in FreeBSD.
debug(1, "Delay error %d when checking running latency.", resp);
}
}
// debug(1, "resp is %d, delay is %ld.", resp, l_delay);
}
if (resp == 0) {
uint64_t the_time_this_frame_should_be_played;
frame_to_local_time(inframe->timestamp, &the_time_this_frame_should_be_played, conn);
uint64_t output_buffer_delay_time = current_delay;
#ifdef CONFIG_FFMPEG
// the current delay should also include the frames that were kept in swr
// before the current block was requested
output_buffer_delay_time =
output_buffer_delay_time + frames_previously_retained_in_the_resampler;
// debug(1,"Allowing for %" PRId64 " frames previously held in the resampler.",
// frames_previously_retained_in_the_resampler);
// now we'll update frames_previously_retained_in_the_resampler
// to the figure after the current block
frames_previously_retained_in_the_resampler = conn->frames_retained_in_the_resampler;
#endif
output_buffer_delay_time =
output_buffer_delay_time *
1000000000; // there should be plenty of space in a uint64_t for any
// conceivable current_delay value
output_buffer_delay_time =
output_buffer_delay_time /
RATE_FROM_ENCODED_FORMAT(config.current_output_configuration);
debug(3,
"current_delay: %" PRId64 ", output_buffer_delay_time: %.3f, output rate: %u.",
current_delay, output_buffer_delay_time * 0.000000001,
RATE_FROM_ENCODED_FORMAT(config.current_output_configuration));
uint64_t the_time_this_frame_will_be_played =
delay_measurement_time + output_buffer_delay_time;
double centered_sync_error_time = 0.0;
int64_t sync_error_ns = 0;
int64_t measurement_time = get_absolute_time_in_ns() - mst;
// debug(1, "measurement time: %" PRId64 " ns.", measurement_time);
if (measurement_time < 2000000) {
sync_error_ns =
the_time_this_frame_will_be_played - the_time_this_frame_should_be_played;
sync_error = (sync_error_ns *
RATE_FROM_ENCODED_FORMAT(config.current_output_configuration)) /
1000000000;
// debug(1, "measurement time: %" PRId64 " ns. Sync error: %" PRId64 " ns, %" PRId64
// " frames, skipping_frames_at_start_of_play is %d.", measurement_time,
// sync_error_ns, sync_error, skipping_frames_at_start_of_play);
// A timestamp gap is when the timstamp of the next packet of frames is not equal to
// the previous packet's timstamp + number o frames therein.
// But wait! If there is a timestamp gap, this isn't really an error.
// Also, if it's a sync error at the start of a play sequence, then
// it can be dealt with by inserting a silence or skipping frames.
// So, here we have enough information to decide what to do with the "frame" of
// audio.
// If we are already skipping frames because of a prior first frame,
// we might need to adjust the skipping count due to a better time estimate
if (skipping_frames_at_start_of_play != 0) {
if (sync_error <= 0) {
debug(3,
"cancel skipping at start of play -- skip estimate was: %" PRId64
", but sync_error is now: %" PRId64 ".",
frames_to_skip, sync_error);
frames_to_skip = 0;
skipping_frames_at_start_of_play = 0;
} else if (frames_to_skip != sync_error) {
debug(3,
"updating skipping at start of play count from: %" PRId64 " to: %" PRId64
".",
frames_to_skip, sync_error);
frames_to_skip = sync_error;
}
}
// If it's the first frame or if it's at a timestamp discontinuity, then we can
// deal with it straight away.
if ((inframe != NULL) && ((conn->first_packet_timestamp == inframe->timestamp) ||
(inframe->timestamp_gap != 0))) {
// By default, when there is a sync error and some kind of discontinuity,
// e.g. a gap between timestamps of adjacent packets or a first packet,
// then we try to fix the sync error, either by skipping frames or by inserting a
// silence. However, if it's a negative timestamp gap between packets, only try to
// fix the timestamp_gap. The reason for this is that we don't know the purpose of
// the negative gaps. For all we know, it may be that the audio frames before and
// after the gap are meant to be contiguous.
int64_t gap_to_fix = sync_error; // this is what we look at normally
if (conn->first_packet_timestamp == inframe->timestamp) {
debug(3, "first frame: %u, sync_error %" PRId64 " frames.", inframe->timestamp,
sync_error);
skipping_frames_at_start_of_play = 1;
} else {
debug(3, "timestamp_gap: %d on frame %u, sync_error %" PRId64 " frames.",
inframe->timestamp_gap, inframe->timestamp, sync_error);
if (inframe->timestamp_gap < 0) {
gap_to_fix = -inframe->timestamp_gap; // this is frames at the input rate
int64_t gap_to_fix_ns = (gap_to_fix * 1000000000) / conn->input_rate;
gap_to_fix = (gap_to_fix_ns *
RATE_FROM_ENCODED_FORMAT(config.current_output_configuration)) /
1000000000; // this is frames at the output rate
// debug(3, "due to timstamp gap of %d frames, skip %" PRId64 " output frames.", inframe->timestamp_gap, gap_to_fix);
}
}
if (gap_to_fix > 0) {
// debug(1, "drop %u frames, timestamp: %u, skipping_frames_at_start_of_play is
// %d.", gap_to_fix, inframe->timestamp, skipping_frames_at_start_of_play);
frames_to_skip += gap_to_fix;
sync_error_ns = 0; // don't invoke any sync checking
} else if (gap_to_fix < 0) { // this packet is early, so insert the right number
// of frames to zero the error
frames_to_skip = 0;
skipping_frames_at_start_of_play = 0;
int64_t gap = -gap_to_fix;
void *silence = malloc(
sps_format_sample_size(
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration)) *
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) * gap);
if (silence == NULL) {
debug(1, "Failed to allocate memory for a silent gap.");
} else {
// the player may change the contents of the buffer, so it has to be zeroed
// each time; might as well malloc and free it locally
conn->previous_random_number = generate_zero_frames(
silence, gap, conn->enable_dither, conn->previous_random_number,
config.current_output_configuration);
config.output->play(silence, gap, play_samples_are_untimed, 0, 0);
free(silence);
frames_played += gap;
// debug(1,"sent %d frames of silence.", gap);
sync_error_ns = 0; // don't invoke any sync checking
sync_error = 0;
}
}
}
// debug(1, "frames_to_skip: %u.", frames_to_skip);
// don't do any sync error calculations if you're skipping frames
if (frames_to_skip == 0) {
// first, make room in the array if it's full
if (conn->sync_samples_count == sync_history_length) {
conn->sync_samples_count--;
}
last_sample_index = conn->sync_samples_index;
sync_samples[conn->sync_samples_index] = sync_error_ns;
conn->sync_samples_count++;
conn->sync_samples_index = (conn->sync_samples_index + 1) % sync_history_length;
// now find the lowest and highest errors
sync_samples_highest_error = sync_samples[0];
sync_samples_lowest_error = sync_samples[0];
sync_samples_second_highest_error = sync_samples[0];
sync_samples_second_lowest_error = sync_samples[0];
unsigned int s;
int64_t mean = 0;
for (s = 0; s < conn->sync_samples_count; s++) {
mean += sync_samples[s];
if (sync_samples[s] > sync_samples_highest_error) {
sync_samples_second_highest_error = sync_samples_highest_error;
sync_samples_highest_error = sync_samples[s];
} else if (sync_samples[s] > sync_samples_second_highest_error) {
sync_samples_second_highest_error = sync_samples[s];
} else if (sync_samples[s] < sync_samples_lowest_error) {
sync_samples_second_lowest_error = sync_samples_lowest_error;
sync_samples_lowest_error = sync_samples[s];
} else if (sync_samples[s] < sync_samples_second_lowest_error) {
sync_samples_second_lowest_error = sync_samples[s];
}
}
if (conn->sync_samples_count != 0)
mean = mean / conn->sync_samples_count;
tsum_of_gaps = tsum_of_gaps + sync_samples_second_highest_error -
sync_samples_second_lowest_error;
int64_t centered_sync_error_ns =
(sync_samples_second_highest_error + sync_samples_second_lowest_error) / 2;
centered_sync_error_time = centered_sync_error_ns * 0.000000001;
// debug(1, "centered_sync_error_ns: %" PRId64 ", %.3f sec.",
// centered_sync_error_ns, centered_sync_error_time);
// int64_t centered_sync_error =
// (centered_sync_error_ns * config.current_output_configuration->rate) /
// 1000000000;
// decide whether to do a stuff
/*
// calculate the standard deviation
double sd = 0.0;
for (s = 0; s < conn->sync_samples_count; s++) {
sd += pow(sync_samples[s] - mean, 2);
}
if (conn->sync_samples_count != 0)
sd = sqrt(sd / conn->sync_samples_count);
// debug(1, "samples: %u, mean: %" PRId64 ", standard deviation: %f.",
// conn->sync_samples_count, mean, sd);
*/
// it seems (?) that the standard deviation settles down markedly after 10 samples
// == 1024 * 10 frames in AAC
if (play_number * inbuflength >= 10 * 1024) {
// the tolerance is on either side of the correct, thus it contributes twice
// to the overall gap
int64_t tolerance_ns = (int64_t)(config.tolerance * 1000000000L);
// int64_t gap = 2 * tolerance_ns + sync_samples_second_highest_error -
// sync_samples_second_lowest_error;
// int64_t gap = 2 * tolerance_ns;
// since the gap should be symmetrical about 0, stuff accordingly
if (centered_sync_error_ns > tolerance_ns) {
amount_to_stuff = -1 * (inbuflength / 350);
if (amount_to_stuff == 0)
amount_to_stuff = -1;
debug(3, "drop a frame, inbuflength is %d, amount_to_stuff is %d.",
inbuflength, amount_to_stuff);
} else if (centered_sync_error_ns < (-tolerance_ns)) {
amount_to_stuff = +1 * (inbuflength / 350);
if (amount_to_stuff == 0)
amount_to_stuff = 1;
debug(3, "add a frame, inbuflength is %d, amount_to_stuff is %d.",
inbuflength, amount_to_stuff);
} else {
debug(3,
"error is within tolerance: centered_sync_error_ns: %" PRId64
", tolerance_ns: %" PRId64 " ns.",
centered_sync_error_ns, tolerance_ns);
}
}
}
}
if (amount_to_stuff)
debug(3,
// "stuff: %+d, sync_error: %+5.3f milliseconds.",
// amount_to_stuff, sync_error * 1000);
"stuff: %+d, sync_errors actual: %+5.3f milliseconds, bufferlength: %d, "
"sync window : %+5.3f "
"milliseconds, prior second highest: %+5.3f milliseconds, prior second "
"lowest: %+5.3f "
"milliseconds.",
amount_to_stuff, sync_error_ns * 0.000001, inbuflength,
(sync_samples_second_highest_error - sync_samples_second_lowest_error) *
0.000001,
sync_samples_second_highest_error * 0.000001,
sync_samples_second_lowest_error * 0.000001);
// now, deal with sync errors and anomalies
if ((config.no_sync == 0) && (inframe->timestamp != 0) &&
(config.resync_threshold > 0.0) &&
// (fabs(sync_error) > config.resync_threshold)) {
(fabs(centered_sync_error_time) > config.resync_threshold) &&
// don't count it if the error max and min values bracket (i.e. are on either
// size of) zero
!((sync_samples_highest_error >= 0) && ((sync_samples_lowest_error <= 0))) &&
(conn->sync_samples_count == sync_history_length)) {
sync_error_out_of_bounds++;
} else {
sync_error_out_of_bounds = 0;
}
if (sync_error_out_of_bounds != 0) {
debug(2,
"sync error for frame %" PRIu32
" out of bounds on %d successive occasions. Error is %.3f milliseconds -- "
"resync requested (%u, %" PRId64 ", %" PRId64 ").",
inframe->timestamp, sync_error_out_of_bounds, centered_sync_error_time * 1000,
conn->sync_samples_count, sync_samples_highest_error,
sync_samples_lowest_error);
if (centered_sync_error_time < 0) {
request_resync = 1; // ask for a resync
} else {
int16_t occ = conn->ab_write - conn->ab_read;
debug(2,
"drop late packet, timestamp: %u, late by: %.3f ms, packets remaining in "
"the buffer: %u.",
inframe->timestamp, centered_sync_error_time * 1000, occ);
unsigned int s;
for (s = 0; s < conn->sync_samples_count; s++) {
debug(2, "sample: %u, value: %.3f ms", s, sync_samples[s] * 0.000001);
}
debug(2, "sync_history_length: %u, samples_count: %u, sample_index: %u",
sync_history_length, conn->sync_samples_count, last_sample_index);
}
sync_error_out_of_bounds = 0;
// conn->sync_samples_index = 0;
// conn->sync_samples_count = 0;
} else {
if (config.no_sync != 0)
amount_to_stuff = 0; // no stuffing if it's been disabled
// Apply DSP here
// check the state of loudness and convolution flags here and don't change them
// for the frame
int do_loudness = ((config.loudness != 0) && (conn->input_rate == 44100));
#ifdef CONFIG_CONVOLUTION
int do_convolution = 0;
if ((config.convolution) && (config.convolver_valid) && (conn->input_rate == 44100))
do_convolution = 1;
// we will apply the convolution gain if convolution is enabled, even if there
// is no valid convolution happening
int convolution_is_enabled = 0;
if (config.convolution)
convolution_is_enabled = 1;
#endif
if (do_loudness
#ifdef CONFIG_CONVOLUTION
|| convolution_is_enabled
#endif
) {
int32_t *tbuf32 = (int32_t *)conn->tbuf;
float fbuf_l[inbuflength];
float fbuf_r[inbuflength];
// Deinterleave, and convert to float
int i;
for (i = 0; i < inbuflength; ++i) {
fbuf_l[i] = tbuf32[2 * i];
fbuf_r[i] = tbuf32[2 * i + 1];
}
#ifdef CONFIG_CONVOLUTION
// Apply convolution
if (do_convolution) {
convolver_process_l(fbuf_l, inbuflength);
convolver_process_r(fbuf_r, inbuflength);
}
if (convolution_is_enabled) {
float gain = pow(10.0, config.convolution_gain / 20.0);
for (i = 0; i < inbuflength; ++i) {
fbuf_l[i] *= gain;
fbuf_r[i] *= gain;
}
}
#endif
if (do_loudness) {
// Apply volume and loudness
// Volume must be applied here because the loudness filter will increase the
// signal level and it would saturate the int32_t otherwise
float gain = conn->fix_volume / 65536.0f;
// float gain_db = 20 * log10(gain);
// debug(1, "Applying soft volume dB: %f k: %f", gain_db, gain);
for (i = 0; i < inbuflength; ++i) {
fbuf_l[i] = loudness_process(&loudness_l, fbuf_l[i] * gain);
fbuf_r[i] = loudness_process(&loudness_r, fbuf_r[i] * gain);
}
}
// Interleave and convert back to int32_t
for (i = 0; i < inbuflength; ++i) {
tbuf32[2 * i] = fbuf_l[i];
tbuf32[2 * i + 1] = fbuf_r[i];
}
}
#ifdef CONFIG_SOXR
double t = config.audio_backend_buffer_interpolation_threshold_in_seconds *
RATE_FROM_ENCODED_FORMAT(config.current_output_configuration);
// figure out if we're going for soxr or something else
if ((current_delay < t) || // delay is too small we definitely won't do soxr
(config.packet_stuffing == ST_basic) ||
(config.packet_stuffing == ST_vernier) ||
((config.packet_stuffing == ST_auto) &&
((config.soxr_delay_index == 0) || // soxr processing time unknown
(config.soxr_delay_index > config.soxr_delay_threshold) // too slow
))) {
debug(3, "current_delay: %" PRIu64 ", dac buffer queue minimum length: %f.",
current_delay, t);
#endif
if (config.packet_stuffing == ST_basic)
play_samples = stuff_buffer_basic_32(
(int32_t *)conn->tbuf, inbuflength,
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration),
conn->outbuf, amount_to_stuff, conn->enable_dither, conn);
else
play_samples = stuff_buffer_vernier(
(int32_t *)conn->tbuf, inbuflength,
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration),
conn->outbuf, amount_to_stuff, conn->enable_dither, conn);
#ifdef CONFIG_SOXR
} else { // soxr requested or auto requested with the index less or equal to the
// threshold
play_samples = stuff_buffer_soxr_32(
(int32_t *)conn->tbuf, inbuflength,
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration), conn->outbuf,
amount_to_stuff, conn->enable_dither, conn);
}
#endif
if (conn->outbuf == NULL)
debug(1, "NULL outbuf to play -- skipping it.");
else {
if (play_samples == 0)
debug(2, "nothing to play.");
else {
if (conn->software_mute_enabled) {
generate_zero_frames(conn->outbuf, play_samples, conn->enable_dither,
conn->previous_random_number,
config.current_output_configuration);
}
uint64_t should_be_time;
frame_to_local_time(inframe->timestamp, &should_be_time, conn);
// debug(1, "play frame %u.", inframe->timestamp);
// now, see if we are skipping some or all of these frames
if (frames_to_skip == 0) {
config.output->play(conn->outbuf, play_samples, play_samples_are_timed,
inframe->timestamp, should_be_time);
frames_played += play_samples;
} else {
if (frames_to_skip > (unsigned int)play_samples) {
debug(3, "skipping a packet of %u frames.", play_samples);
debug_print_buffer(
3, conn->outbuf,
play_samples *
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) *
sps_format_sample_size(FORMAT_FROM_ENCODED_FORMAT(
config.current_output_configuration)));
frames_to_skip -= play_samples;
} else {
char *offset = conn->outbuf;
offset +=
frames_to_skip *
CHANNELS_FROM_ENCODED_FORMAT(config.current_output_configuration) *
sps_format_sample_size(
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration));
config.output->play(offset, play_samples - frames_to_skip,
play_samples_are_timed, inframe->timestamp,
should_be_time);
debug(3, "skipping the first %u frames in a packet of %u frames.",
frames_to_skip, play_samples);
debug_print_buffer(3, conn->outbuf, offset - conn->outbuf);
frames_played += play_samples - frames_to_skip;
frames_to_skip = 0;
skipping_frames_at_start_of_play = 0;
}
}
#ifdef CONFIG_METADATA
// debug(1,"config.metadata_progress_interval is %f.",
// config.metadata_progress_interval);
if (config.metadata_progress_interval != 0.0) {
char hb[128];
if (this_is_the_first_frame != 0) {
memset(hb, 0, 128);
snprintf(hb, 127, "%" PRIu32 "/%" PRId64 "", inframe->timestamp,
should_be_time);
send_ssnc_metadata('phb0', hb, strlen(hb), 1);
send_ssnc_metadata('phbt', hb, strlen(hb), 1);
time_of_last_metadata_progress_update = get_absolute_time_in_ns();
} else {
uint64_t mx = 1000000000;
uint64_t iv = config.metadata_progress_interval * mx;
iv = iv + time_of_last_metadata_progress_update;
int64_t delta = iv - get_absolute_time_in_ns();
if (delta <= 0) {
memset(hb, 0, 128);
snprintf(hb, 127, "%" PRIu32 "/%" PRId64 "", inframe->timestamp,
should_be_time);
send_ssnc_metadata('phbt', hb, strlen(hb), 1);
time_of_last_metadata_progress_update = get_absolute_time_in_ns();
}
}
}
#endif
}
}
}
} else {
// if this is the first frame, see if it's close to when it's supposed to be
// released, which will be its time plus latency and any offset_time
if (config.packet_stuffing == ST_basic)
play_samples = stuff_buffer_basic_32(
(int32_t *)conn->tbuf, inbuflength,
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration), conn->outbuf,
0, conn->enable_dither, conn);
else
play_samples = stuff_buffer_vernier(
(int32_t *)conn->tbuf, inbuflength,
FORMAT_FROM_ENCODED_FORMAT(config.current_output_configuration), conn->outbuf,
0, conn->enable_dither, conn);
if (conn->outbuf == NULL)
debug(1, "NULL outbuf to play -- skipping it.");
else {
if (conn->software_mute_enabled) {
generate_zero_frames(conn->outbuf, play_samples, conn->enable_dither,
conn->previous_random_number,
config.current_output_configuration);
}
uint64_t should_be_time;
frame_to_local_time(inframe->timestamp, &should_be_time, conn);
debug(3, "play frame %u.", inframe->timestamp);
config.output->play(conn->outbuf, play_samples, play_samples_are_timed,
inframe->timestamp, should_be_time);
frames_played += play_samples;
#ifdef CONFIG_METADATA
// debug(1,"config.metadata_progress_interval is %f.",
// config.metadata_progress_interval);
if (config.metadata_progress_interval != 0.0) {
char hb[128];
if (this_is_the_first_frame != 0) {
memset(hb, 0, 128);
snprintf(hb, 127, "%" PRIu32 "/%" PRId64 "", inframe->timestamp,
should_be_time);
send_ssnc_metadata('phb0', hb, strlen(hb), 1);
send_ssnc_metadata('phbt', hb, strlen(hb), 1);
time_of_last_metadata_progress_update = get_absolute_time_in_ns();
} else {
uint64_t mx = 1000000000;
uint64_t iv = config.metadata_progress_interval * mx;
iv = iv + time_of_last_metadata_progress_update;
int64_t delta = iv - get_absolute_time_in_ns();
if (delta <= 0) {
memset(hb, 0, 128);
snprintf(hb, 127, "%" PRIu32 "/%" PRId64 "", inframe->timestamp,
should_be_time);
send_ssnc_metadata('phbt', hb, strlen(hb), 1);
time_of_last_metadata_progress_update = get_absolute_time_in_ns();
}
}
}
#endif
}
}
if (conn->tbuf) {
free(conn->tbuf);
conn->tbuf = NULL;
}
if (conn->outbuf) {
free(conn->outbuf);
conn->outbuf = NULL;
}
}
tsum_of_frames = tsum_of_frames + frames_played;
if (frames_played) {
number_of_statistics++;
frames_since_last_stats_logged += frames_played;
// stats accumulation. We want an average of sync error, drift, adjustment,
// number of additions+subtractions
tsum_of_sync_errors = tsum_of_sync_errors + sync_error;
tsum_of_corrections = tsum_of_corrections + amount_to_stuff;
tsum_of_insertions_and_deletions =
tsum_of_insertions_and_deletions + abs(amount_to_stuff);
}
}
// free buffers and mark the frame as finished
#ifdef CONFIG_FFMPEG
if (inframe->avframe != NULL) {
av_frame_free(&inframe->avframe);
inframe->avframe = NULL;
}
#endif
inframe->timestamp = 0;
inframe->sequence_number = 0;
inframe->resend_time = 0;
inframe->initialisation_time = 0;
inframe->timestamp_gap = 0;
} else {
debug(1, "audio block sequence number %u, ready status: %u with no data!",
inframe->sequence_number, inframe->ready);
}
free_audio_buffer_payload(inframe);
}
}
debug(1, "This should never be called.");
pthread_cleanup_pop(1); // pop the cleanup handler
// debug(1, "This should never be called either.");
// pthread_cleanup_pop(1); // pop the initial cleanup handler
pthread_exit(NULL);
}
static void player_send_volume_metadata(uint8_t vol_mode_both, double airplay_volume,
double scaled_attenuation, int32_t max_db, int32_t min_db,
int32_t hw_max_db) {
#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 (config.ignore_volume_control == 0) {
if (vol_mode_both == 1) {
// 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);
}
} else {
snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, 0.0, 0.0, 0.0);
}
send_ssnc_metadata('pvol', dv, strlen(dv), 1);
#else
(void)vol_mode_both;
(void)airplay_volume;
(void)scaled_attenuation;
(void)max_db;
(void)min_db;
(void)hw_max_db;
#endif
}
void player_volume_without_notification(double airplay_volume, rtsp_conn_info *conn) {
debug_mutex_lock(&conn->volume_control_mutex, 5000, 1);
// first, see if we are hw only, sw only, both with hw attenuation on the top or both with sw
// attenuation on top
enum volume_mode_type { vol_sw_only, vol_hw_only, vol_both } volume_mode;
// take account of whether there is a hardware mixer, if a max volume has been specified and if a
// range has been specified
// the range might imply that both hw and software mixers are needed, so calculate this
int32_t hw_max_db = 0, hw_min_db = 0; // zeroed to quieten an incorrect uninitialised warning
int32_t sw_max_db = 0, sw_min_db = -9630;
// if the device is giving us a decibel-denominated volume range
if ((config.output->parameters != NULL) && (config.output->parameters()->volume_range != NULL)) {
volume_mode = vol_hw_only;
hw_max_db = config.output->parameters()->volume_range->maximum_volume_dB;
hw_min_db = config.output->parameters()->volume_range->minimum_volume_dB;
if (config.volume_max_db_set) {
if (((config.volume_max_db * 100) <= hw_max_db) &&
((config.volume_max_db * 100) >= hw_min_db))
hw_max_db = (int32_t)config.volume_max_db * 100;
else if (config.volume_range_db) {
hw_max_db = hw_min_db;
sw_max_db = (config.volume_max_db * 100) - hw_min_db;
} else {
warn("The maximum output level is outside the range of the hardware mixer -- ignored");
}
}
// here, we have set limits on the hw_max_db and the sw_max_db
// but we haven't actually decided whether we need both hw and software attenuation
// only if a range is specified could we need both
if (config.volume_range_db) {
// see if the range requested exceeds the hardware range available
int32_t desired_range_db = (int32_t)trunc(config.volume_range_db * 100);
if ((desired_range_db) > (hw_max_db - hw_min_db)) {
volume_mode = vol_both;
int32_t desired_sw_range = desired_range_db - (hw_max_db - hw_min_db);
if ((sw_max_db - desired_sw_range) < sw_min_db)
warn("The range requested is too large to accommodate -- ignored.");
else
sw_min_db = (sw_max_db - desired_sw_range);
} else {
hw_min_db = hw_max_db - desired_range_db;
}
}
} else {
// debug(1,"has no hardware mixer");
volume_mode = vol_sw_only;
if (config.volume_max_db_set) {
if (((config.volume_max_db * 100) <= sw_max_db) &&
((config.volume_max_db * 100) >= sw_min_db))
sw_max_db = (int32_t)config.volume_max_db * 100;
}
if (config.volume_range_db) {
// see if the range requested exceeds the software range available
int32_t desired_range_db = (int32_t)trunc(config.volume_range_db * 100);
if ((desired_range_db) > (sw_max_db - sw_min_db))
warn("The range requested is too large to accommodate -- ignored.");
else
sw_min_db = (sw_max_db - desired_range_db);
}
}
// here, we know whether it's hw volume control only, sw only or both, and we have the hw and sw
// limits.
// 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 (airplay_volume == -144.0) {
// only mute if you're not ignoring the volume control
if (config.ignore_volume_control == 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);
}
}
uint8_t vol_mode_both = (volume_mode == vol_both) ? 1 : 0;
player_send_volume_metadata(vol_mode_both, airplay_volume, 0, 0, 0, 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 = max_db;
if (config.ignore_volume_control == 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)
scaled_attenuation =
flat_vol2attn(airplay_volume, max_db, min_db); // no cancellation points
else if (config.volume_control_profile == VCP_dasl_tapered)
scaled_attenuation =
dasl_tapered_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;
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);
}
} 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;
}
if ((volume_mode == vol_sw_only) || (volume_mode == vol_both)) {
double temp_fix_volume = 65536.0 * pow(10, software_attenuation / 2000);
if (config.ignore_volume_control == 0)
debug(3, "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(3, "Software attenuation set to %f, i.e %f out of 65,536. Volume control is ignored.",
software_attenuation, temp_fix_volume);
conn->fix_volume = temp_fix_volume;
// if (config.loudness)
loudness_set_volume(software_attenuation / 100);
}
if (conn != NULL)
debug(3, "Connection %d: AirPlay Volume set to %.3f, Output Level set to: %.2f dB.",
conn->connection_number, airplay_volume, scaled_attenuation / 100.0);
else
debug(3, "AirPlay Volume set to %.3f, Output Level set to: %.2f dB. NULL conn.",
airplay_volume, scaled_attenuation / 100.0);
if (config.logOutputLevel) {
inform("Output Level set to: %.2f dB.", scaled_attenuation / 100.0);
}
uint8_t vol_mode_both = (volume_mode == vol_both) ? 1 : 0;
player_send_volume_metadata(vol_mode_both, airplay_volume, scaled_attenuation, max_db, min_db,
hw_max_db);
if (config.output->mute)
config.output->mute(0);
conn->software_mute_enabled = 0;
debug(3,
"player_volume_without_notification: volume mode is %d, airplay volume is %.2f, "
"software_attenuation dB: %.2f, hardware_attenuation dB: %.2f, muting "
"is disabled.",
volume_mode, airplay_volume, software_attenuation / 100.0, hardware_attenuation / 100.0);
}
// here, store the volume for possible use in the future
config.airplay_volume = airplay_volume;
conn->own_airplay_volume = airplay_volume;
debug_mutex_unlock(&conn->volume_control_mutex, 3);
}
void player_volume(double airplay_volume, rtsp_conn_info *conn) {
command_set_volume(airplay_volume);
player_volume_without_notification(airplay_volume, conn);
}
void do_flush(uint32_t timestamp, rtsp_conn_info *conn) {
debug(3, "do_flush: flush to %u.", timestamp);
debug_mutex_lock(&conn->flush_mutex, 1000, 1);
conn->flush_requested = 1;
conn->flush_rtp_timestamp = timestamp; // flush all packets up to, but not including, this one.
reset_input_flow_metrics(conn);
debug_mutex_unlock(&conn->flush_mutex, 3);
}
void player_flush(uint32_t timestamp, rtsp_conn_info *conn) {
debug(3, "player_flush");
do_flush(timestamp, conn);
#ifdef CONFIG_METADATA
// only send a flush metadata message if the first packet has been seen -- it's a bogus message
// otherwise
if (conn->first_packet_timestamp) {
char numbuf[32];
snprintf(numbuf, sizeof(numbuf), "%u", timestamp);
send_ssnc_metadata('pfls', numbuf, strlen(numbuf), 1); // contains cancellation points
}
#endif
}
int player_play(rtsp_conn_info *conn) {
debug(2, "Connection %d: player_play.", conn->connection_number);
command_start(); // before startup, and before the prepare() method runs
// give the output device as much advance warning as possible to get ready
// and make sure it's done before launching the player thread
if (config.output->prepare)
config.output->prepare(); // give the backend its first chance to prepare itself, knowing it has
// access to the output device (i.e. knowing that it should not be in
// use by another program at this time).
pthread_cleanup_debug_mutex_lock(&conn->player_create_delete_mutex, 5000, 1);
if (conn->player_thread == NULL) {
pthread_t *pt = malloc(sizeof(pthread_t));
if (pt == NULL)
die("Couldn't allocate space for pthread_t");
int rc = named_pthread_create_with_priority(pt, 3, player_thread_func, (void *)conn,
"player_%d", conn->connection_number);
if (rc)
debug(1, "Connection %d: error creating player_thread: %s", conn->connection_number,
strerror(errno));
conn->player_thread = pt; // set _after_ creation of thread
} else {
debug(1, "Connection %d: player thread already exists.", conn->connection_number);
}
pthread_cleanup_pop(1); // release the player_create_delete_mutex
#ifdef CONFIG_METADATA
send_ssnc_metadata('pbeg', NULL, 0, 1); // contains cancellation points
#endif
conn->is_playing = 1;
return 0;
}
int player_stop(rtsp_conn_info *conn) {
// note -- this may be called from another connection thread.
debug(2, "Connection %d: player_stop.", conn->connection_number);
int response = 0; // okay
pthread_cleanup_debug_mutex_lock(&conn->player_create_delete_mutex, 5000, 1);
pthread_t *pt = conn->player_thread;
if (pt) {
debug(3, "player_thread cancel...");
conn->player_thread = NULL; // cleared _before_ cancelling of thread
pthread_cancel(*pt);
debug(3, "player_thread join...");
if (pthread_join(*pt, NULL) == -1) {
char errorstring[1024];
strerror_r(errno, (char *)errorstring, sizeof(errorstring));
debug(1, "Connection %d: error %d joining player thread: \"%s\".", conn->connection_number,
errno, (char *)errorstring);
} else {
debug(2, "Connection %d: player_stop successful.", conn->connection_number);
}
free(pt);
// reset_anchor_info(conn); // say the clock is no longer valid
response = 0; // deleted
} else {
debug(2, "Connection %d: no player thread.", conn->connection_number);
response = -1; // already deleted or never created...
}
pthread_cleanup_pop(1); // release the player_create_delete_mutex
if (response == 0) { // if the thread was just stopped and deleted...
conn->is_playing = 0;
#ifdef CONFIG_AIRPLAY_2
ptp_send_control_message_string("E"); // signify play is "E"nding
#endif
#ifdef CONFIG_METADATA
send_ssnc_metadata('pend', NULL, 0, 1); // contains cancellation points
#endif
command_stop();
}
return response;
}