Загрузка данных
static bool prepare_transfer(const struct device *i2s_dev_tx)
{
int ret;
for (int i = 0; i < ZEPHYR_AUDIO_INITIAL_BLOCKS; ++i)
{
void *mem_block;
ret = k_mem_slab_alloc(&mem_slab_tx, &mem_block, K_NO_WAIT);
if (ret < 0) {
printf("Failed to allocate TX block %d: %d\n", i, ret);
return false;
}
memset(mem_block, 0, current_audio_block_size);
ret = i2s_write(i2s_dev_tx, mem_block, current_audio_block_size);
if (ret < 0) {
printf("Failed to write block %d: %d\n", i, ret);
return false;
}
}
return true;
}
static bool trigger_command(const struct device *i2s_dev_rx,
const struct device *i2s_dev_tx,
enum i2s_trigger_cmd cmd)
{
int ret;
if (i2s_dev_rx == i2s_dev_tx) {
ret = i2s_trigger(i2s_dev_rx, I2S_DIR_BOTH, cmd);
if (ret == 0) return true;
if (ret != -ENOSYS) {
printf("Failed to trigger command %d: %d\n", cmd, ret);
return false;
}
}
ret = i2s_trigger(i2s_dev_rx, I2S_DIR_RX, cmd);
if (ret < 0) {
printf("Failed to trigger command %d on RX: %d\n", cmd, ret);
return false;
}
ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, cmd);
if (ret < 0) {
printf("Failed to trigger command %d on TX: %d\n", cmd, ret);
return false;
}
return true;
}
int zephyr_i2s_start(uint8_t audio_in)
{
printf("%s(%d) audio_in=%d\n",__FUNCTION__,__LINE__, audio_in);
if (start_stream) {
return 0;
}
if (!prepare_transfer(i2s_dev_tx)) {
return -1;
}
if (!trigger_command(i2s_dev_rx, i2s_dev_tx, I2S_TRIGGER_START)) {
return -1;
}
start_stream = 1;
return 0;
}
int zephyr_i2s_stop(uint8_t audio_in)
{
printf("%s(%d) start_stream=%d\n",__FUNCTION__,__LINE__, start_stream);
if(start_stream) {
start_stream = 0;
if (!trigger_command(i2s_dev_rx, i2s_dev_tx, I2S_TRIGGER_DROP)) {
return -1;
}
}
return 0;
}
int zephyr_i2s_open_stream(I2S_Stream **stream, uint8_t *buf, uint8_t audio_in)
{
struct i2s_strm *i2s_stream;
struct i2s_config config;
struct audio_codec_cfg audio_cfg;
int ret = 0;
uint32_t dynamic_block_size = ((current_sample_rate / ZEPHYR_AUDIO_DIV_SIZE) * NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE);
current_audio_block_size = dynamic_block_size;
printf("%s(%d) Set sample_rate=%u block_size=%u\n",__FUNCTION__,__LINE__,current_sample_rate,dynamic_block_size);
audio_cfg.dai_route = AUDIO_ROUTE_PLAYBACK_CAPTURE;
audio_cfg.dai_type = AUDIO_DAI_TYPE_I2S;
audio_cfg.dai_cfg.i2s.word_size = SAMPLE_BIT_WIDTH;
audio_cfg.dai_cfg.i2s.channels = NUMBER_OF_CHANNELS;
audio_cfg.dai_cfg.i2s.format = I2S_FMT_DATA_FORMAT_I2S;
if(codec_is_slave)
audio_cfg.dai_cfg.i2s.options = I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE;
else
audio_cfg.dai_cfg.i2s.options = I2S_OPT_FRAME_CLK_MASTER;
audio_cfg.dai_cfg.i2s.frame_clk_freq = current_sample_rate;
audio_cfg.dai_cfg.i2s.mem_slab = &mem_slab_tx;
audio_cfg.dai_cfg.i2s.block_size = dynamic_block_size;
audio_cfg.mclk_freq = AUDIO_MCLK_FREQ;
audio_codec_configure(codec_dev, &audio_cfg);
config.word_size = SAMPLE_BIT_WIDTH;
config.channels = NUMBER_OF_CHANNELS;
config.format = I2S_FMT_DATA_FORMAT_I2S;
if(rx_tx_is_slave)
config.options = I2S_OPT_BIT_CLK_SLAVE | I2S_OPT_FRAME_CLK_SLAVE;
else
config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER;
config.frame_clk_freq = current_sample_rate;
config.block_size = dynamic_block_size;
config.timeout = TIMEOUT;
if (!configure_streams(i2s_dev_rx, i2s_dev_tx, &config)) {
printf("Failed to reconfigure streams for %u Hz\n", current_sample_rate);
return -1;
}
audio_property_value_t vol_val = { .vol = 100 };
audio_codec_set_property(codec_dev, AUDIO_PROPERTY_OUTPUT_VOLUME, AUDIO_CHANNEL_ALL, vol_val);
vol_val.vol = 0;
audio_codec_set_property(codec_dev, AUDIO_PROPERTY_INPUT_VOLUME, AUDIO_CHANNEL_ALL, vol_val);
audio_property_value_t mute_val = { .mute = false };
audio_codec_set_property(codec_dev, AUDIO_PROPERTY_OUTPUT_MUTE, AUDIO_CHANNEL_ALL, mute_val);
audio_codec_set_property(codec_dev, AUDIO_PROPERTY_INPUT_MUTE, AUDIO_CHANNEL_ALL, mute_val);
audio_codec_start_output(codec_dev);
/* 2. Стандартная аллокация потока */
i2s_stream = i2s_str_alloc();
if (!i2s_stream) {
printf("Cannot allocate i2s_strm\n");
return -1;
}
close_stream = 0;
i2s_stream->devid = (audio_in) ? 1 : 2;
i2s_stream->i2s_buf = buf;
i2s_stream->state = I2S_STREAM_RUNNING;
i2s_stream->block_size = dynamic_block_size;
*stream = i2s_stream;
pthread_attr_init(&i2s_stream->threadAttr);
pthread_attr_setstacksize(&i2s_stream->threadAttr, 1024);
ret = pthread_create(&i2s_stream->i2s_thread, &i2s_stream->threadAttr,
audio_in ? i2s_thread_in : i2s_thread_out, i2s_stream);
if (ret != 0) {
printf("i2s pthread_create failed ret=%d\n", ret);
return -1;
}
pthread_setschedprio(i2s_stream->i2s_thread, I2S_THREAD_PRIORITY);
if(audio_in)
pthread_setname_np(i2s_stream->i2s_thread, "i2s_thread_in");
else
pthread_setname_np(i2s_stream->i2s_thread, "i2s_thread_out");
return 0;
}
int zephyr_i2s_close_stream(I2S_Stream *stream)
{
struct i2s_strm *i2s_stream = (struct i2s_strm *)stream;
i2s_thread_wakeup(i2s_stream, I2S_STREAM_CLOSED);
pthread_join(i2s_stream->i2s_thread, NULL);
pthread_attr_destroy(&i2s_stream->threadAttr);
i2s_str_free(i2s_stream);
close_stream = 1;
return 0; // paNoError
}
int zephyr_i2s_audio_init(void)
{
update_device_pointers(0);
if (!device_is_ready(i2s_dev_rx)) {
printf("%s is not ready\n", i2s_dev_rx->name);
return -1;
}
if (i2s_dev_rx != i2s_dev_tx && !device_is_ready(i2s_dev_tx)) {
printf("%s is not ready\n", i2s_dev_tx->name);
return -1;
}
if (!device_is_ready(codec_dev)) {
printf("Audio codec device not ready\n");
return -1;
}
return 0;
}
int zephyr_i2s_get_rate()
{
return current_sample_rate;
}
int zephyr_i2s_get_close_stream()
{
return close_stream;
}
int zephyr_i2s_set_rate(uint32_t sample_rate)
{
int ret = 0;
if(sample_rate == 8000 || sample_rate == 16000)
current_sample_rate = sample_rate;
else
{
printf("Don't support %u sample_rate\n",sample_rate);
ret = -1;
}
return ret;
}
int zephyr_i2s_get_block_size()
{
return current_audio_block_size;
}