工具/软件:
我遇到了本帖子中描述的问题
在那篇文章中、提到 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