音频流格式启用数据流

音频流格式启用数据流

在单个样本帧级别处理音频数据时,就像使用音频单元一样,仅仅指定正确的数据类型来表示音频是不够的。单个音频样本值中的位布局是有意义的,因此像 Float32 或 UInt16 这样的数据类型不够有表现力。本节将介绍 Core Audio 解决这个问题的方法。

使用 AudioStreamBasicDescription 结构

在应用程序中以及应用程序和音频硬件之间移动音频值的媒介是 AudioStreamBasicDescription 结构:

struct AudioStreamBasicDescription {
    Float64 mSampleRate;
    UInt32  mFormatID;
    UInt32  mFormatFlags;
    UInt32  mBytesPerPacket;
    UInt32  mFramesPerPacket;
    UInt32  mBytesPerFrame;
    UInt32  mChannelsPerFrame;
    UInt32  mBitsPerChannel;
    UInt32  mReserved;
};
typedef struct AudioStreamBasicDescription  AudioStreamBasicDescription;

由于 AudioStreamBasicDescription 这个名字很长,以下缩写为 ASBD。要定义 ASBD 字段的值,请编写类似于下面的代码:

size_t bytesPerSample = sizeof (AudioUnitSampleType);
AudioStreamBasicDescription stereoStreamFormat = {0};
 
stereoStreamFormat.mFormatID          = kAudioFormatLinearPCM;
stereoStreamFormat.mFormatFlags       = kAudioFormatFlagsAudioUnitCanonical;
stereoStreamFormat.mBytesPerPacket    = bytesPerSample;
stereoStreamFormat.mBytesPerFrame     = bytesPerSample;
stereoStreamFormat.mFramesPerPacket   = 1;
stereoStreamFormat.mBitsPerChannel    = 8 * bytesPerSample;
stereoStreamFormat.mChannelsPerFrame  = 2;           // 2 indicates stereo
stereoStreamFormat.mSampleRate        = graphSampleRate;

首先,应该确定采样值的数据类型。此示例使用 AudioUnitSampleType 定义类型,这是大多数音频单元的推荐数据类型。在 iOS 中,AudioUnitSampleType 被定义为 8.24 固定点整数。接下来定义 ASBD 类型变量,初始化为 0 代表不包含任何数据(注意不能跳过该步,否则可能产生一些想不到的问题)。然后就是对变量赋值:

  • mFormatID:格式标识符。例如 kAudioFormatLinearPCM 表示音频单元使用未压缩的音频数据。
  • mFormatFlags:某些 audio unit 使用不规则的音频数据格式即不同的音频数据类型,则该字段需要不同的标志集。例如 3D Mixer unit 需要 UInt16 类型数据作为采样值且 mFormatFlags 需要设置为 kAudioFormatFlagsCanonical。
  • mBytesPerPacket:每个音频包中有多少字节数。
  • mBytesPerFrame:每一帧中有多少字节。
  • mFramesPerPacket:每个包中有多少帧。
  • mFramesPerPacket:每个包中有多少帧。
  • mBitsPerChannel:每个声道有多少位。
  • mChannelsPerFrame:每一帧中有多少声道。
  • mSampleRate:采样率。

在哪里以及如何设置流格式

必须为 audio processing graph 中的关键点设置音频数据流格式。在其他点,系统会设置格式。在其他点上,音频单元连接将流格式从一个音频单元传播到另一个音频单元。

iOS 设备上的音频输入和输出硬件具有系统确定的音频流格式。这些格式总是未压缩的、交错的线性 PCM 格式。该系统在 audio processing graph 中将这些格式强加到 I/O 单元的外向两侧,如图 1-8 所示。

在这里插入图片描述

在图中,麦克风代表输入音频硬件。系统确定输入硬件的音频流格式,并将其强加到远程 I/O 单元输入元素的输入范围内。同样,图中的扬声器代表输出音频硬件。系统确定输出硬件的流格式,并将其强加到远程 I/O 单元输出元素的输出范围上。

应用程序负责在 I/O 单元元素的内侧建立音频流格式。I/O 单元在您的应用程序格式和硬件格式之间执行任何必要的转换。应用程序还负责在 graph 中需要的任何地方设置流格式。在某些情况下,例如在上图的多通道混合器单元的输出中,只需设置部分格式,特别是采样率。

如图 1-8 所示,音频单元连接的一个关键特征是,连接将音频数据流格式从源音频单元的输出传播到目标音频单元的输入。这是一个关键点,因此需要强调:流格式传播通过音频单元连接进行,并且只在一个方向上——从源音频单元的输出到目标音频单元的输入。

流格式传播发生在音频处理图形生命周期的一个特定点,即初始化时。利用格式传播的优势可以显著减少需要编写的代码量。例如,当将多通道混音器单元的输出连接到远程 I/O 单元进行播放时,无需为 I/O 单元设置流格式。

虽然我们可以通过 ASBD 灵活的设置音频数据流的属性,但是建议还是使用当前设备硬件默认使用值。当这样做时,I/O 单元不需要执行采样率转换,这将最大限度地减少功耗,并最大限度地提高了音频质量。

### 关于音频流数据转储的技术方法 #### 使用 ALSA 实现音频流数据的捕获与保存 在嵌入式 Linux 下,alsa-lib 是一种常用的工具来实现音频流的数据捕获和保存功能。通过配置合适的参数,可以将实时采集到的声音数据存储为指定格式的文件[^1]。 以下是基于 ALSA 的简单录音程序示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <alsa/asoundlib.h> #define BUFFER_SIZE 4096 int main() { int err; snd_pcm_t *capture_handle; // PCM handle for capture snd_pcm_hw_params_t *hw_params; unsigned int rate = 44100; // Sample rate (Hz) unsigned int channels = 2; // Number of channels snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; // Audio sample format FILE *output_file = fopen("captured_audio.raw", "wb"); if ((err = snd_pcm_open(&capture_handle, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0) { fprintf(stderr, "Cannot open audio device (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { fprintf(stderr, "Cannot allocate hardware parameter structure (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) { fprintf(stderr, "Cannot initialize hardware parameter structure (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf(stderr, "Cannot set access type (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, format)) < 0) { fprintf(stderr, "Cannot set sample format (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &rate, NULL)) < 0) { fprintf(stderr, "Cannot set sample rate (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, channels)) < 0) { fprintf(stderr, "Cannot set channel count (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) { fprintf(stderr, "Cannot set parameters (%s)\n", snd_strerror(err)); exit(1); } free(hw_params); char buffer[BUFFER_SIZE]; while (1) { err = snd_pcm_readi(capture_handle, buffer, BUFFER_SIZE / sizeof(short)); if (err < 0){ fprintf(stderr,"Read from audio interface failed (%s)\n",snd_strerror(err)); break; } fwrite(buffer,sizeof(char),BUFFER_SIZE,output_file); } fclose(output_file); snd_pcm_close(capture_handle); } ``` 此代码片段展示了如何利用 ALSA 进行简单的音频录制,并将其写入原始二进制文件 `captured_audio.raw` 中。 --- #### FFmpeg 处理 RTSP 流中的音频数据 FFmpeg 提供了一个强大的框架用于处理音视频流,包括从网络协议(如 RTSP)获取音频数据并保存为标准格式文件的功能。如果遇到无法正确保存音频的情况,通常是因为编译时未启用必要的解码器支持。重新编译 FFmpeg 并确保启用了相关选项即可解决问题[^2]。 下面是一个命令行例子,展示如何使用 FFmpeg 将来自 RTSP 流的音频提取出来并保存成 WAV 文件: ```bash ffmpeg -i rtsp://your_rtsp_stream_url -vn -acodec pcm_s16le output.wav ``` 该命令会忽略视频部分 (`-vn`) 只保留音频轨道,并采用无压缩编码方式(`pcm_s16le`) 输出至目标文件 `output.wav`。 --- #### 其他可能涉及的方法和技术 除了上述两种主流技术外,在某些特定场景下还可以考虑其他方案比如 PulseAudio 或 PortAudio 等跨平台库来进行更灵活的操作;或者借助 GStreamer 构建复杂的多媒体流水线完成同样的任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值