Skip to content

Commit

Permalink
rebase on main
Browse files Browse the repository at this point in the history
  • Loading branch information
lovettchris committed Dec 6, 2023
1 parent 3b3950d commit 4e2c8c0
Show file tree
Hide file tree
Showing 10 changed files with 390 additions and 28 deletions.
1 change: 1 addition & 0 deletions applications/nrf5340_audio/src/audio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ target_sources(app PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/audio_datapath.c
${CMAKE_CURRENT_SOURCE_DIR}/sw_codec_select.c
${CMAKE_CURRENT_SOURCE_DIR}/le_audio_rx.c
${CMAKE_CURRENT_SOURCE_DIR}/wav_file.c
)

if (CONFIG_BT_BAP_BROADCAST_SINK)
Expand Down
10 changes: 10 additions & 0 deletions applications/nrf5340_audio/src/audio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ config AUDIO_MUTE
Use button 5 to mute audio instead of
doing a user defined action.

config AUDIO_SAVE_WAV
bool "Save a 10 second wav file instead of mute"
default n
help
Use button 5 to save a wav file.

if AUDIO_HEADSET_CHANNEL_COMPILE_TIME

config AUDIO_HEADSET_CHANNEL
Expand Down Expand Up @@ -297,6 +303,10 @@ module = LE_AUDIO_RX
module-str = le-audio-rx
source "subsys/logging/Kconfig.template.log_config"

module = WAV_FILE
module-str = audio-system
source "subsys/logging/Kconfig.template.log_config"

endmenu # Log levels

#----------------------------------------------------------------------------#
Expand Down
143 changes: 141 additions & 2 deletions applications/nrf5340_audio/src/audio/audio_datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <zephyr/kernel.h>
#include <zephyr/shell/shell.h>
#include <nrfx_clock.h>
#include <contin_array.h>
#include <pcm_mix.h>

#include "nrf5340_audio_common.h"
#include "macros_common.h"
Expand All @@ -21,9 +23,9 @@
#include "sw_codec_select.h"
#include "audio_system.h"
#include "tone.h"
#include "contin_array.h"
#include "pcm_mix.h"
#include "streamctrl.h"
#include "sd_card.h"
#include "wav_file.h"
#include "audio_sync_timer.h"
#include "sd_card_playback.h"

Expand Down Expand Up @@ -857,6 +859,139 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us)
*delay_us = ctrl_blk.pres_comp.pres_delay_us;
}

static char pcm_data1[CONFIG_AUDIO_SAMPLE_RATE_HZ *
CONFIG_AUDIO_BIT_DEPTH_OCTETS]; // 96kb can hold one second.
static char pcm_data2[CONFIG_AUDIO_SAMPLE_RATE_HZ *
CONFIG_AUDIO_BIT_DEPTH_OCTETS]; // 96kb can hold one second.
static char *pcm_data = NULL;
static size_t pcm_data_used = 0;
static size_t pcm_data_duration = 0;
static size_t wav_file_bytes = 0;
static struct fs_file_t wav_file;
static bool wav_file_open = false;
static bool save_busy = false;

struct save_wave_msg {
const char *buffer;
uint32_t size;
};

ZBUS_CHAN_DEFINE(save_wav_channel, /* Name */
struct save_wave_msg, /* Message type */
NULL, /* Validator */
NULL, /* User data */
ZBUS_OBSERVERS(save_wav_sub), /* observers */
ZBUS_MSG_INIT(0)); /* Initial value */

ZBUS_SUBSCRIBER_DEFINE(save_wav_sub, 1);

static void save_wav_task(void)
{
const struct zbus_channel *chan;
struct save_wave_msg msg;

while (!zbus_sub_wait(&save_wav_sub, &chan, K_FOREVER)) {
if (&save_wav_channel == chan) {
zbus_chan_read(&save_wav_channel, &msg, K_MSEC(500));
if (wav_file_open) {
save_busy = true;
int ret = write_wav_data(&wav_file, msg.buffer, msg.size);
save_busy = false;
if (ret != 0) {
LOG_ERR("Failed to write to file, rc=%d", ret);
return;
}

if (pcm_data_duration == 0) {
// close the file!
// bugbug: I would prefer to do this to fix up the wav
// header now that we know the size of the file but seek is
// not working. write_wav_header(wav_file_bytes);
sd_card_close(&wav_file);
wav_file_open = false;
LOG_INF("Saved %d bytes to wav file.", wav_file_bytes);
}
}
}
}
}

#ifdef CONFIG_AUDIO_SAVE_WAV
K_THREAD_DEFINE(subscriber_task_id, CONFIG_MAIN_STACK_SIZE, save_wav_task, NULL, NULL, NULL, 3, 0,
0);
#endif

void audio_datapath_pcm_save_data(const char *pcm_buffer, size_t size)
{
struct save_wave_msg msg;
const size_t pcm_data_size = sizeof(pcm_data1);
if (pcm_data_used + size > pcm_data_size) {
if (save_busy) {
LOG_ERR("sd save is not keeping up");
return;
}
msg.buffer = pcm_data;
msg.size = pcm_data_used;

// toggle buffers so sd card write can happen in parallel with collecting
// the next buffer.
if (pcm_data == pcm_data1) {
pcm_data = pcm_data2;
} else {
pcm_data = pcm_data1;
}

if (pcm_data_used >= pcm_data_duration) {
pcm_data_duration = 0; // done!
} else {
pcm_data_duration -= pcm_data_used;
}
wav_file_bytes += pcm_data_used;

// do the save on a separate thread so it doesn't block our PDM read thread.
int ret = zbus_chan_pub(&save_wav_channel, &msg, K_NO_WAIT);
if (ret) {
LOG_ERR("Failed to publish save wav msg, ret: %d", ret);
}

pcm_data_used = 0;
}
memcpy(&pcm_data[pcm_data_used], pcm_buffer, size);
pcm_data_used += size;
}

int audio_datapath_save_wav(const char *filename, uint32_t duration_seconds)
{
pcm_data_used = 0;
pcm_data = pcm_data1;
pcm_data_duration =
duration_seconds * CONFIG_AUDIO_SAMPLE_RATE_HZ * CONFIG_AUDIO_BIT_DEPTH_OCTETS;
wav_file_bytes = 0;

if (wav_file_open) {
sd_card_close(&wav_file);
wav_file_open = false;
}

int err = sd_card_open_for_write(filename, &wav_file);
if (err != 0) {
pcm_data_duration = 0;
LOG_ERR("Failed to open file, rc=%d", err);
return err;
} else {
wav_file_open = true;
write_wav_header(
&wav_file,
320000, // hard coded header because fs_seek doesn't seem to be working.
CONFIG_AUDIO_SAMPLE_RATE_HZ * 2, // bugbug: somehow the lc3 decoded data is
// returning twice as much data as expected...?
CONFIG_AUDIO_BIT_DEPTH_OCTETS,
1 // 1 channel
);
}
return 0;
}

void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
uint32_t recv_frame_ts_us)
{
Expand Down Expand Up @@ -938,6 +1073,10 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
return;
}

if (pcm_data_duration > 0) {
audio_datapath_pcm_save_data(ctrl_blk.decoded_data, pcm_size);
}

/*** Add audio data to FIFO buffer ***/

int32_t num_blks_in_fifo = ctrl_blk.out.prod_blk_idx - ctrl_blk.out.cons_blk_idx;
Expand Down
10 changes: 10 additions & 0 deletions applications/nrf5340_audio/src/audio/audio_datapath.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,14 @@ int audio_datapath_stop(void);
*/
int audio_datapath_init(void);

/**
* @brief Save received PCM audio to sd card.
*
* @param[in] filename Name of wav file to create on sd card.
* @param[in] duration_seconds Length of recording in seconds.
*
* @return 0 on success, error otherwise.
*/
int audio_datapath_save_wav(const char* filename, uint32_t duration_seconds);

#endif /* _AUDIO_DATAPATH_H_ */
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "button_assignments.h"
#include "macros_common.h"
#include "audio_system.h"
#include "audio_datapath.h"
#include "button_handler.h"
#include "le_audio.h"
#include "bt_mgmt.h"
Expand Down Expand Up @@ -179,7 +180,10 @@ static void button_msg_sub_thread(void)
break;

case BUTTON_5:
if (IS_ENABLED(CONFIG_AUDIO_MUTE)) {
if (IS_ENABLED(CONFIG_AUDIO_SAVE_WAV)) {
audio_datapath_save_wav("test.wav", 10);
}
else if (IS_ENABLED(CONFIG_AUDIO_MUTE)) {
ret = bt_rend_volume_mute(false);
if (ret) {
LOG_WRN("Failed to mute, ret: %d", ret);
Expand Down
77 changes: 77 additions & 0 deletions applications/nrf5340_audio/src/audio/wav_file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include "wav_file.h"

LOG_MODULE_REGISTER(audio_wavfile, CONFIG_WAV_FILE_LOG_LEVEL);

int write_wav_header(struct fs_file_t *wav_file, uint32_t size, uint16_t sample_rate,
uint16_t bytes_per_sample, uint16_t num_channels)
{
struct wav_header wav_file_header;
wav_file_header.riff_header[0] = 'R';
wav_file_header.riff_header[1] = 'I';
wav_file_header.riff_header[2] = 'F';
wav_file_header.riff_header[3] = 'F';
wav_file_header.wav_size = size + 0x24;
wav_file_header.wav_header[0] = 'W';
wav_file_header.wav_header[1] = 'A';
wav_file_header.wav_header[2] = 'V';
wav_file_header.wav_header[3] = 'E';
wav_file_header.fmt_header[0] = 'f';
wav_file_header.fmt_header[1] = 'm';
wav_file_header.fmt_header[2] = 't';
wav_file_header.fmt_header[3] = ' ';
wav_file_header.wav_chunk_size = 16;
wav_file_header.audio_format = WAV_FORMAT_PCM;
wav_file_header.num_channels = 1;
wav_file_header.sample_rate = sample_rate;
wav_file_header.byte_rate = sample_rate * bytes_per_sample * num_channels;
wav_file_header.block_alignment = bytes_per_sample * num_channels;
wav_file_header.bit_depth = bytes_per_sample * 8;
wav_file_header.data_header[0] = 'd';
wav_file_header.data_header[1] = 'a';
wav_file_header.data_header[2] = 't';
wav_file_header.data_header[3] = 'a';
wav_file_header.data_bytes = size;

off_t position = fs_tell(wav_file);

// seek back to the beginning to rewrite the header.
// BUGBUG: this seek doesn't seem to be working?
int ret = fs_seek(wav_file, 0, FS_SEEK_SET);
if (ret) {
LOG_ERR("Seek file pointer failed");
return ret;
}

ret = write_wav_data(wav_file, (char *)&wav_file_header, sizeof(wav_file_header));

// seek back to where we were.
fs_seek(wav_file, position, FS_SEEK_SET);
return ret;
}

int read_wav_header(struct fs_file_t *wav_file, struct wav_header *header)
{
int ret = fs_read(wav_file, header, sizeof(struct wav_header));
if (ret < 0) {
LOG_ERR("Read file failed: %d", ret);
}
return ret;
}

int write_wav_data(struct fs_file_t *wav_file, const char *buffer, uint32_t size)
{
int ret = fs_write(wav_file, buffer, size);
if (ret < 0) {
LOG_ERR("Write file failed: %d", ret);
return ret;
}
return 0;
}
44 changes: 44 additions & 0 deletions applications/nrf5340_audio/src/audio/wav_file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#ifndef _WAV_FILE_H_
#define _WAV_FILE_H_

#include <stdint.h>
#include <stddef.h>
#include <zephyr/fs/fs.h>

#define WAV_FORMAT_PCM 1

/* WAV header */
struct wav_header {
/* RIFF Header */
char riff_header[4];
uint32_t wav_size; /* File size excluding first eight bytes */
char wav_header[4]; /* Contains "WAVE" */
/* Format Header */
char fmt_header[4];
uint32_t wav_chunk_size; /* Should be 16 for PCM */
short audio_format; /* Should be 1 for PCM */
short num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
short block_alignment; /* num_channels * Bytes Per Sample */
short bit_depth;

/* Data */
char data_header[4];
uint32_t data_bytes; /* Number of bytes in data */
} __packed; // 44 bytes

int read_wav_header(struct fs_file_t *wav_file, struct wav_header *header);

int write_wav_header(struct fs_file_t *wav_file, uint32_t size, uint16_t sample_rate,
uint16_t bytes_per_sample, uint16_t num_channels);

int write_wav_data(struct fs_file_t *wav_file, const char *buffer, uint32_t size);

#endif
Loading

0 comments on commit 4e2c8c0

Please sign in to comment.