Android Audio模块框架和基础属性概念讲解

在学习Android Audio模块之前,我们先了解整体的Audio模块框架和一些涉及到的基础属性概念。如下图是Android Audio模块整体框架图

以播放为例,使用AudioTrack播放会通过JNI在C++层也创建相应的AudioTrack类,这个相当于客户端,会通过binder最终在AudioFlinger中创建相应的Track类,播放的音频数据通过共享环形缓存区进行传递给AudioFlinger,AudioFlinger中创建了回放线程如MixerThread将多个track混音后传递给Hal层,hal使用tinyalsa库发送给内核驱动进行播放。这个链路中有三个进程,一个是App自己播放的进程,如在App创建AudioTrack播放PCM数据,AudioTrack 通过JNI创建对应的C++层AudioTrack.cpp 然后就是AudioFlinger 和AudioPolicy所在的进程即audio_server进程。audioFlinger发送音频数据给Hal,Hal层一般在高版本也是单独的进程。

java 复制代码
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;

public class AudioTrackPlayer {

    private static final int SAMPLE_RATE = 44100; // 采样率
    private AudioTrack mAudioTrack;
    private boolean isPlaying = false;

    public void startPlay() {
        // 1. 设置音频参数
        int channelConfig = AudioFormat.CHANNEL_OUT_STEREO; // 双声道
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;  // 16位PCM

        // 2. 计算系统要求的最小缓冲区大小
        int minBufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, channelConfig, audioFormat);

        // 3. 使用 Builder 模式构建实例
        mAudioTrack = new AudioTrack.Builder()
                .setAudioAttributes(new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_MEDIA)
                        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                        .build())
                .setAudioFormat(new AudioFormat.Builder()
                        .setEncoding(audioFormat)
                        .setSampleRate(SAMPLE_RATE)
                        .setChannelMask(channelConfig)
                        .build())
                .setBufferSizeInBytes(minBufferSize)
                // 设置为流模式 (MODE_STREAM)
                .setTransferMode(AudioTrack.MODE_STREAM) 
                .build();

        // 4. 开始播放状态(此时还没数据,是在等待 write)
        mAudioTrack.play();
        isPlaying = true;

        // 5. 在子线程中不断写入数据
        new Thread(() -> {
            // 生成一段简单的 440Hz 正弦波数据
            byte[] pcmData = generateSineWaveData(SAMPLE_RATE, 5); // 5秒长
            
            int offset = 0;
            while (isPlaying && offset < pcmData.length) {
                // 将数据写入 AudioTrack 的缓冲区
                int written = mAudioTrack.write(pcmData, offset, Math.min(minBufferSize, pcmData.length - offset));
                if (written > 0) {
                    offset += written;
                } else {
                    break; // 写入出错
                }
            }
            stopPlay();
        }).start();
    }

    public void stopPlay() {
        isPlaying = false;
        if (mAudioTrack != null) {
            mAudioTrack.stop();
            mAudioTrack.release();
            mAudioTrack = null;
        }
    }

    /**
     * 工具方法:生成一段正弦波 PCM 数据
     */
    private byte[] generateSineWaveData(int sampleRate, int durationSeconds) {
        int waveCount = sampleRate * durationSeconds;
        byte[] data = new byte[waveCount * 2 * 2]; // 16bit, 双声道
        double frequency = 440.0; // A4 键频率

        for (int i = 0; i < waveCount; i++) {
            // 生成正弦波采样点
            short sample = (short) (Math.sin(2 * Math.PI * i / (sampleRate / frequency)) * 0x7FFF);
            // 左声道
            data[i * 4] = (byte) (sample & 0xff);
            data[i * 4 + 1] = (byte) ((sample >> 8) & 0xff);
            // 右声道
            data[i * 4 + 2] = (byte) (sample & 0xff);
            data[i * 4 + 3] = (byte) ((sample >> 8) & 0xff);
        }
        return data;
    }
}

在上面播放demo中涉及2个重要的类

AudioFormat:描述采样率 采样格式 采样率

AudioAttributes:描述音频流信息,AudioFlinger和AudioPolicyService通过这个来选择哪个策略,选择哪个输出设备在哪个回放线程上播放,很重要。其中有几个属性

USAGE 音频流用途

ContentType 音频流内容

StreamType :使用哪个音频流如MUSIC,这个是兼容以前的

上面三个参数影响了AudioPolicyService使用哪个策略

mFlags 标志位如FLAG_HW_AV_SYNC FLAG_LOW_LATENCY 会影响选择使用哪个AudioFlinger使用哪个回放线程OutputThread

其他AudioFlinger AudioPolicyService中的概念参考https://blog.csdn.net/weixin_43013761/article/details/89418633

相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui