工具/软件:
我遇到了本帖子中描述的问题
在那篇文章中、提到 TI 计划在后续 SDK 版本中修复它。 我们目前使用的是 SDK 的08.06.00.42版本。 在切换到更新的 SDK 之前、我们想知道此问题是否已修复。 我通读了发行说明、但没有看到明确提及。
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
工具/软件:
我遇到了本帖子中描述的问题
在那篇文章中、提到 TI 计划在后续 SDK 版本中修复它。 我们目前使用的是 SDK 的08.06.00.42版本。 在切换到更新的 SDK 之前、我们想知道此问题是否已修复。 我通读了发行说明、但没有看到明确提及。
我正在回答我自己的问题。 即使在08.06.00.42 SDK 中使用的5.10.X 内核上、也可以修复该问题。 此补丁为我解决了问题
https://github.com/varigit/ti-linux-kernel/commit/85a4b70c0bbddff31c7a075cf985008f30955f1f
下面是一个简单的 c 程序,它使用 mmap 来录制32位音频(如果您使用的是 EVK 则更改为16位)。 它可以运行多次
// mmap-record.c - Records audio using ALSA mmap and writes to S32_LE WAV file
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <alsa/asoundlib.h>
#define SAMPLE_RATE 48000
#define CHANNELS 2
#define FORMAT SND_PCM_FORMAT_S32_LE
#define BUFFER_TIME 500000 // us
#define PERIOD_TIME 100000 // us
#define DURATION 5 // seconds
#define FILENAME "record_mmap.wav"
#define PCM_DEVICE "hw:0,0"
#define WAV_HEADER_SIZE 44
#define kAudioFrameSamples 256 // This is the audio driver callback rate. Should not be too huge as it consumes coherent kernel memory.
#define kNumAlsaBuffers 4
snd_pcm_uframes_t periodSize = kAudioFrameSamples;
snd_pcm_uframes_t bufferSize = kAudioFrameSamples * kNumAlsaBuffers; // adjusted in initPcmHandle
void write_wav_header(FILE *f, int data_bytes) {
int32_t sample_rate = SAMPLE_RATE;
int16_t bits_per_sample = 32;
int16_t channels = CHANNELS;
int32_t byte_rate = sample_rate * channels * bits_per_sample / 8;
int16_t block_align = channels * bits_per_sample / 8;
int32_t chunk_size = 36 + data_bytes;
uint8_t header[WAV_HEADER_SIZE] = {
'R','I','F','F',
chunk_size & 0xFF, (chunk_size >> 8) & 0xFF, (chunk_size >> 16) & 0xFF, (chunk_size >> 24) & 0xFF,
'W','A','V','E','f','m','t',' ',
16,0,0,0, // Subchunk1Size
1,0, // PCM
channels,0,
sample_rate & 0xFF, (sample_rate >> 8) & 0xFF, (sample_rate >> 16) & 0xFF, (sample_rate >> 24) & 0xFF,
byte_rate & 0xFF, (byte_rate >> 8) & 0xFF, (byte_rate >> 16) & 0xFF, (byte_rate >> 24) & 0xFF,
block_align,0,
bits_per_sample,0,
'd','a','t','a',
data_bytes & 0xFF, (data_bytes >> 8) & 0xFF, (data_bytes >> 16) & 0xFF, (data_bytes >> 24) & 0xFF
};
fwrite(header, 1, WAV_HEADER_SIZE, f);
}
const char *snd_pcm_state_name(snd_pcm_state_t state)
{
switch (state)
{
case SND_PCM_STATE_OPEN:
return "SND_PCM_STATE_OPEN";
case SND_PCM_STATE_SETUP:
return "SND_PCM_STATE_SETUP";
case SND_PCM_STATE_PREPARED:
return "SND_PCM_STATE_PREPARED";
case SND_PCM_STATE_RUNNING:
return "SND_PCM_STATE_RUNNING";
case SND_PCM_STATE_XRUN:
return "SND_PCM_STATE_XRUN";
case SND_PCM_STATE_DRAINING:
return "SND_PCM_STATE_DRAINING";
case SND_PCM_STATE_PAUSED:
return "SND_PCM_STATE_PAUSED";
case SND_PCM_STATE_SUSPENDED:
return "SND_PCM_STATE_SUSPENDED";
case SND_PCM_STATE_DISCONNECTED:
return "SND_PCM_STATE_DISCONNECTED";
default:
return "Unknown state";
}
}
const char *snd_pcm_stream_name_zz(snd_pcm_t *pcmHandle)
{
snd_pcm_stream_t stream = snd_pcm_stream(pcmHandle);
switch (stream)
{
case SND_PCM_STREAM_PLAYBACK:
return "SND_PCM_STREAM_PLAYBACK";
case SND_PCM_STREAM_CAPTURE:
return "SND_PCM_STREAM_CAPTURE";
default:
return "Unknown stream";
}
}
int handlePcmOverOrUnderRun(snd_pcm_t *pcmHandle, int dbgCauseSource)
{
// handle overrun or underrun.
snd_pcm_drop(pcmHandle);
snd_pcm_recover(pcmHandle, -EPIPE, 0);
snd_pcm_prepare(pcmHandle);
usleep(3000);
snd_pcm_state_t state = snd_pcm_state(pcmHandle);
printf("Stream %s: state = %s after recovery, source = %d\n",
snd_pcm_stream_name_zz(pcmHandle), snd_pcm_state_name(state), dbgCauseSource);
state = snd_pcm_state(pcmHandle);
printf("Stream %s: state = %s after start, source = %d\n",
snd_pcm_stream_name_zz(pcmHandle), snd_pcm_state_name(state), dbgCauseSource);
usleep(3000);
return 0;
}
void hw_init(snd_pcm_t *handle)
{
snd_pcm_hw_params_t *hwparams;
int err;
snd_pcm_hw_params_malloc(&hwparams);
snd_pcm_hw_params_any(handle, hwparams);
snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, hwparams, FORMAT);
snd_pcm_hw_params_set_rate(handle, hwparams, SAMPLE_RATE, 0);
snd_pcm_hw_params_set_channels(handle, hwparams, CHANNELS);
err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &periodSize, 0);
if (err < 0) printf("Error %d with snd_pcm_hw_params_set_period_size_near\n", err);
bufferSize = periodSize * kNumAlsaBuffers; // e.g., 4 audio frames in the entire alsa buffer
err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &bufferSize);
if (err < 0) printf("Error %d with snd_pcm_hw_params_set_buffer_size_near\n", err);
printf("Using period (audio frame) size: %lu and buffer size %lu\n", periodSize, bufferSize);
snd_pcm_hw_params(handle, hwparams);
snd_pcm_hw_params_free(hwparams);
}
void sw_init(snd_pcm_t *handle,const int audio_frame_size)
{
snd_pcm_sw_params_t *swparams;
snd_pcm_sw_params_malloc(&swparams);
snd_pcm_sw_params_current(handle, swparams);
snd_pcm_sw_params_set_avail_min(handle, swparams, audio_frame_size);
snd_pcm_sw_params_set_start_threshold(handle, swparams, 0);
snd_pcm_sw_params_set_stop_threshold(handle, swparams, 65536);
snd_pcm_sw_params(handle, swparams);
snd_pcm_sw_params_free(swparams);
}
void do_capture_samples(snd_pcm_t *handle,const int audio_frame_size, FILE *fout)
{
int dir, err;
int total_frames = SAMPLE_RATE * DURATION;
int frame_size = CHANNELS * sizeof(int32_t);
int recorded_frames = 0;
int attempts = 0;
const snd_pcm_channel_area_t *areas;
snd_pcm_uframes_t offset, frames;
while (recorded_frames < total_frames)
{
frames = audio_frame_size;
err = snd_pcm_mmap_begin(handle, &areas, &offset, &frames);
if (err < 0) {
fprintf(stderr, "mmap_begin error: %s\n", snd_strerror(err));
break;
}
snd_pcm_state_t state = snd_pcm_state(handle);
if (frames == 0)
{
err = snd_pcm_mmap_commit(handle, offset, frames);
// printf ("commit 0 frames err = %d, state = %s)\n", err,
// snd_pcm_state_name(state));
if (attempts > 500)
{
printf ("Not getting audio frames\n");
attempts = 0;
}
if (attempts > 0)
++attempts;
if (state == SND_PCM_STATE_PREPARED)
{
printf("Starting pcm capture stream after %d attempts\n", attempts);
snd_pcm_start(handle);
}
else if (state == SND_PCM_STATE_XRUN)
{
printf("XRUN detected, attempting recovery\n");
handlePcmOverOrUnderRun(handle, 1);
continue;
}
usleep(4000);
continue;
}
if ((recorded_frames & 0x3FF) == 0)
printf ("%d frames\n", recorded_frames);
if (frames > audio_frame_size)
frames = audio_frame_size;
if (frames < audio_frame_size)
{
printf ("Short: %d\n", frames);
}
// else
{
int32_t *samples = (int32_t *)((uint8_t *)areas[0].addr + (offset * (areas[0].step / 8)));
size_t bytes = frames * frame_size;
fwrite(samples, 1, bytes, fout);
recorded_frames += frames;
err = snd_pcm_mmap_commit(handle, offset, frames);
if (err < 0) {
fprintf(stderr, "mmap_commit error: %s\n", snd_strerror(err));
break;
}
usleep(5000);
}
attempts = -1;
}
}
int main()
{
snd_pcm_t *handle;
const snd_pcm_channel_area_t *areas;
snd_pcm_uframes_t offset, frames;
int dir, err;
const int audio_frame_size = 256;
int frame_size = CHANNELS * sizeof(int32_t);
int total_frames = SAMPLE_RATE * DURATION;
int recorded_frames = 0;
err = snd_pcm_open(&handle, PCM_DEVICE, SND_PCM_STREAM_CAPTURE, 0);
if (err < 0) {
fprintf(stderr, "Error opening PCM device: %s\n", snd_strerror(err));
return 1;
}
hw_init(handle);
sw_init(handle, audio_frame_size);
FILE *fout = fopen(FILENAME, "wb");
if (!fout) {
perror("fopen");
return 1;
}
write_wav_header(fout, total_frames * frame_size);
snd_pcm_prepare(handle);
do_capture_samples(handle, audio_frame_size, fout);
snd_pcm_pause(handle, 1);
fclose(fout);
snd_pcm_pause(handle, 1);
snd_pcm_close(handle);
printf("Wrote %s\n", FILENAME);
return 0;
}
进行编译、方法是为 SDK 的环境设置脚本提供源代码、然后运行
${CC}McASP-alsa-recor记录-map-main.c -lasound -lm -o McASP-alsa-mmap-record
您好、Chris、
https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/commit/?h=ti-linux-6.6.y&id=e0a0ce8c2684c13fab0e65be767d036dfa592ee1
https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/commit/?h=ti-linux-6.6.y&id=343c3e2d9d0b49905aac24f9795cb2de5ef0cdaf
上述三项内容对于音频功能在 AM62x 上正常工作至关重要。
如果迁移到最新的 SDK 是一项挑战、请查看您是否可以使用最新的(这些已集成在最新的 SDK 中)进行验证、或将其重新移植。
希望这些帮助。
此致、
Suren