From 0ee2783b49f6d3841e8afdeaea7186bc156192d4 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Wed, 21 Aug 2019 23:47:44 -0700 Subject: [PATCH] Continue to tweak AirPlay to SPDIF (still drifting) --- components/squeezelite/decode_external.c | 13 +++++---- components/squeezelite/output_i2s.c | 35 +++++++++++++++++------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/components/squeezelite/decode_external.c b/components/squeezelite/decode_external.c index 5d5a52c6..f2abb73d 100644 --- a/components/squeezelite/decode_external.c +++ b/components/squeezelite/decode_external.c @@ -61,8 +61,9 @@ static void sink_data_handler(const uint8_t *data, uint32_t len) // there will always be room at some point while (len) { LOCK_O; - - bytes = min(len, _buf_cont_write(outputbuf)); + + bytes = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)); + bytes = min(len, bytes); #if BYTES_PER_FRAME == 4 memcpy(outputbuf->writep, data, bytes); #else @@ -127,7 +128,7 @@ static void bt_sink_cmd_handler(bt_sink_cmd_t cmd, ...) LOG_INFO("BT sink stopped"); break; case BT_SINK_RATE: - output.next_sample_rate = va_arg(args, u32_t); + output.next_sample_rate = output.current_sample_rate = va_arg(args, u32_t); LOG_INFO("Setting BT sample rate %u", output.next_sample_rate); break; case BT_SINK_VOLUME: { @@ -151,7 +152,7 @@ static void raop_sink_data_handler(const uint8_t *data, uint32_t len, u32_t play raop_sync.playtime = playtime; raop_sync.len = len; - + sink_data_handler(data, len); } @@ -186,7 +187,7 @@ void raop_sink_cmd_handler(raop_event_t event, void *param) LOG_INFO("backend played %u, desired %u, (delta:%d)", ms, now - raop_sync.start_time, error); if (abs(error) < 10 && abs(raop_sync.error) < 10) raop_sync.start = false; } else { - // in how many ms will the most recent block play (there is one extra block of FRAME_BLOCK == MAX_SILENCE_FRAMES which is not in queue and not in outputbuf) + // in how many ms will the most recent block play ms = ((u64_t) ((_buf_used(outputbuf) - raop_sync.len) / BYTES_PER_FRAME + output.device_frames + output.frames_in_process) * 1000) / RAOP_SAMPLE_RATE - (now - output.updated); error = (raop_sync.playtime - now) - ms; LOG_INFO("head local:%u, remote:%u (delta:%d)", ms, raop_sync.playtime - now, error); @@ -219,7 +220,7 @@ void raop_sink_cmd_handler(raop_event_t event, void *param) raop_sync.start = true; raop_sync.enabled = !strcasestr(output.device, "BT"); output.external = true; - output.next_sample_rate = RAOP_SAMPLE_RATE; + output.next_sample_rate = output.current_sample_rate = RAOP_SAMPLE_RATE; output.state = OUTPUT_STOPPED; break; case RAOP_STOP: diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index e3b85867..90c884a4 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -84,7 +84,7 @@ sure that using rate_delay would fix that typedef enum { DAC_ON = 0, DAC_OFF, DAC_POWERDOWN, DAC_VOLUME } dac_cmd_e; -// must have an integer ratio with FRAME_BLOCK +// must have an integer ratio with FRAME_BLOCK (see spdif comment) #define DMA_BUF_LEN 512 #define DMA_BUF_COUNT 12 @@ -116,6 +116,7 @@ static int bytes_per_frame; static thread_type thread, stats_thread; static u8_t *obuf; static bool spdif; +static size_t dma_buf_frames; DECLARE_ALL_MIN_MAX; @@ -268,27 +269,37 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch }; i2s_config.sample_rate = output.current_sample_rate * 2; i2s_config.bits_per_sample = 32; + // Normally counted in frames, but 16 sample are transformed into 32 bits in spdif + i2s_config.dma_buf_len = DMA_BUF_LEN / 2; + i2s_config.dma_buf_count = DMA_BUF_COUNT * 2; + /* + In DMA, we have room for (LEN * COUNT) frames of 32 bits samples that + we push at sample_rate * 2. Each of these peuso-frames is a single true + audio frame. So the real depth is true frames is (LEN * COUNT / 2) + */ + dma_buf_frames = DMA_BUF_COUNT * DMA_BUF_LEN / 2; } else { pin_config = (i2s_pin_config_t) { .bck_io_num = CONFIG_I2S_BCK_IO, .ws_io_num = CONFIG_I2S_WS_IO, .data_out_num = CONFIG_I2S_DO_IO, .data_in_num = -1 //Not used }; i2s_config.sample_rate = output.current_sample_rate; i2s_config.bits_per_sample = bytes_per_frame * 8 / 2; + // Counted in frames (but i2s allocates a buffer <= 4092 bytes) + i2s_config.dma_buf_len = DMA_BUF_LEN; + i2s_config.dma_buf_count = DMA_BUF_COUNT; + dma_buf_frames = DMA_BUF_COUNT * DMA_BUF_LEN; #ifdef TAS575x gpio_pad_select_gpio(CONFIG_SPDIF_DO_IO); gpio_set_direction(CONFIG_SPDIF_DO_IO, GPIO_MODE_OUTPUT); gpio_set_level(CONFIG_SPDIF_DO_IO, 0); #endif } - + i2s_config.mode = I2S_MODE_MASTER | I2S_MODE_TX; i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; i2s_config.communication_format = I2S_COMM_FORMAT_I2S| I2S_COMM_FORMAT_I2S_MSB; // in case of overflow, do not replay old buffer i2s_config.tx_desc_auto_clear = true; - i2s_config.dma_buf_count = DMA_BUF_COUNT; - // Counted in frames (but i2s allocates a buffer <= 4092 bytes) - i2s_config.dma_buf_len = DMA_BUF_LEN; i2s_config.use_apll = true; i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; //Interrupt level 1 @@ -391,7 +402,6 @@ static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32 return out_frames; } - /**************************************************************************************** * Main output thread */ @@ -415,7 +425,7 @@ static void *output_thread_i2s() { TIME_MEASUREMENT_START(timer_start); LOCK; - + // manage led display if (state != output.state) { LOG_INFO("Output state is %d", output.state); @@ -441,11 +451,11 @@ static void *output_thread_i2s() { output.updated = gettime_ms(); output.frames_played_dmp = output.frames_played; - // try to estimate how much we have consumed from the DMA buffer - output.device_frames = DMA_BUF_COUNT * DMA_BUF_LEN - ((output.updated - fullness) * output.current_sample_rate) / 1000; + // try to estimate how much we have consumed from the DMA buffer (calculation is incorrect at the very beginning ...) + output.device_frames = dma_buf_frames - ((output.updated - fullness) * output.current_sample_rate) / 1000; oframes = _output_frames( iframes ); output.frames_in_process = oframes; - + SET_MIN_MAX_SIZED(oframes,rec,iframes); SET_MIN_MAX_SIZED(_buf_used(outputbuf),o,outputbuf->size); SET_MIN_MAX_SIZED(_buf_used(streambuf),s,streambuf->size); @@ -547,6 +557,11 @@ static void *output_thread_i2s_stats() { LOG_INFO(" ----------+----------+-----------+-----------+"); RESET_ALL_MIN_MAX; } + LOG_INFO("Heap internal:%zu (min:%zu) external:%zu (min:%zu)", + heap_caps_get_free_size(MALLOC_CAP_INTERNAL), + heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL), + heap_caps_get_free_size(MALLOC_CAP_SPIRAM), + heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); usleep(STATS_PERIOD_MS *1000); } return NULL;