Android14音频子系统-Framework分析

发布于:2025-06-28 ⋅ 阅读:(15) ⋅ 点赞:(0)

1、概述

1)应用怎么播放音频?

先来看看一个APP播放多媒体音频示例程序
import android.media.AudioFormat;
import android.media.AudioTrack;
import android.media.AudioAttributes;
import android.media.AudioManager;

public class AudioPlayer {
    private AudioTrack audioTrack;

    public void initAndPlay() {
        int sampleRateInHz = 44100; // 音频采样率
        int channelConfig = AudioFormat.CHANNEL_OUT_STEREO; // 音频通道配置
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 音频格式
        int minBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);

        // 创建 AudioTrack 对象
        AudioAttributes attributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build();

        audioTrack = new AudioTrack(
                attributes,
                sampleRateInHz,
                channelConfig,
                audioFormat,
                minBufferSize,
                AudioTrack.MODE_STREAM
        );

        // 生成示例音频数据(1秒 440Hz 的正弦波)
        int duration = 1; // 秒
        int numSamples = sampleRateInHz * duration;
        short[] audioData = new short[numSamples];
        double frequency = 440.0; // Hz
        double amplitude = 32767.0; // 最大振幅(16位PCM)

        for (int i = 0; i < numSamples; i++) {
            double angle = 2.0 * Math.PI * i * frequency / sampleRateInHz;
            audioData[i] = (short) (Math.sin(angle) * amplitude);
        }

        // 开始播放
        audioTrack.play();

        // 将音频数据写入 AudioTrack
        audioTrack.write(audioData, 0, audioData.length);

        // 停止播放并释放资源
        audioTrack.stop();
        audioTrack.release();
    }
}

APP播放音频流只需要简单的几个步骤
new AudioTrack()
AudioTrack.play()
AudioTrack.write()

2)Android Framework层音频框架

在这里插入图片描述

1、组件和术语

1、AudioTrack : 音轨
2、AudioRecord: 录音
3、AudioFlinger : native层server
4、stream type : 声音类型
5、policy :罗列各类条件 - 优先级、选择设备
6、headset/headphone(不带麦克风)
7、APM:audio policy management 音频策略管理

2、重点分析

1)AudioTrack / AuioRecord是Framework层给APP调用的最上层接口,接下来以AudioTrack作为线索往下研究分析
2)绝大部分核心实现都在native层,java层的Service只是对native层的进一步封装,接下来重点分析native层的AudioPolicyService/AudioFlinger
3)注意音频子系统中的数据结构庞大,更不好的是 各个层级的命名不统一(估计是Google不同工程师编写),令人混乱!

2、AudioService (AS) -java

1、AudioService
android\frameworks\base\services\core\java\com\android\server\audio\AudioService.java
AudioService用于管理音频设备路由策略,即java层对AudioPolicyService封装

3、Audioserver(as)-native

android\frameworks\av\media\audioserver\main_audioserver.cpp //注意audio/media是分开的
cc_binary {
    name: "audioserver",
    shared_libs: [
        "packagemanager_aidl-cpp",
        "libaaudioservice",
        "libaudioclient",
        "libaudioflinger",
        "libaudiopolicyservice",
        "libaudioprocessing",
}

4、AudioPolicyService(aps)-native

1、术语概念

深度分析:https://blog.csdn.net/yangwen123/article/details/39497375

术语
1、spatializer:空间音响
2、关键点:
1、android\frameworks\av\services\audiopolicy\service\AudioPolicyService.cpp
void AudioPolicyService::onFirstRef()  //指南指针的强引用机制
{}

AudioPolicyService继承RefBase(Android引用计数基类),当new sp<AudioPolicyService>时,引用计数从0变1,触发onFirstRef();

C++中,构造函数和onFirstRef,有什么不同,执行优先级?
1)构造函数在创建对象时触发;
2)OnFirstRef在引用对象时触发(传参也算引用),用于延迟初始化,这样可以节省资源;
相当于将构造函数分开两个地方放,看代码时都要看!

2、CPP11以后引入的显示底层类型枚举
enum enum_name1 : underlying_type {
}enum_name2

3、Vector / Collection机制
class HwAudioOutputCollection :
        public DefaultKeyedVector< audio_io_handle_t, sp<HwAudioOutputDescriptor> >
{}
DefaultKeyedVector是一个容器类,结合Vector和HashMap的特性


typedef Vector<sp<IOProfile> > OutputProfileCollection;

2、AudioPolicyService的作用及形式

1、路由作用
在这里插入图片描述

1)基本作用就是将上层抛下来的数据传给哪种设备播放,及路由作用;

2)为什么单独拎出来,用Switch不就完事了?原因是Android音频播放设计得比较复杂,有较多拓扑关系,单看Stream Type的类型就够多够复杂,这样可以实现多种表现满足用户要求

在这里插入图片描述

举个例子:

stream type为VOICE CALL时,没有接耳机时,从喇叭输出;接耳机时,从耳机和喇叭同时输出;

用户使用过程中有更复杂的组合场景,当然不同设备(手机/TV…)的复杂度也是不同;

2、AudioTrack、AudioPolicyService和AudioFlinger的层级关系
在这里插入图片描述

1)AudioPolicyService充当“switch”角色,将各种STREAM_TYPE 的Track数据分发给AudioFlinger层的PlaybackThread处理;

2)一种类型STREAM_TYPE对应一个PlaybackThread线程;

3、audio policy策略配置文件

1)配置文件类型
一般放置在device目录下,比如/android/device/mediatek/mt5862/common/audio_policy/
Android下的文件策略配置文件
1)低版本(<Android 7.0)的audio_policy.conf
对应的加载函数:loadAudioPolicyConfig
2)高版本的(>Android 7.0)audio_policy_configuration.xml
对应的加载函数:AudioPolicyConfig::loadFromXml
Android 7.0后推出,能描述复杂的音频拓扑,例如电视和汽车等行业

audio_policy.conf还有必要了解? 代码中还有保留这部分逻辑,需要了解识别!
2)audio_policy.conf
audio_policy.conf
一个简单的例子如下
a2dp {  //称为Module 或 HwModule 或interface
  outputs {
    a2dp {
      sampling_rates 44100|48000
      channel_masks AUDIO_CHANNEL_OUT_STEREO
      formats AUDIO_FORMAT_PCM_16_BIT
      devices AUDIO_DEVICE_OUT_ALL_A2DP
    }
  }
  # a2dp sink
  inputs {
    a2dp {
      sampling_rates 44100
      channel_masks AUDIO_CHANNEL_IN_STEREO
      formats AUDIO_FORMAT_PCM_16_BIT
      devices AUDIO_DEVICE_IN_BLUETOOTH_A2DP
    }
  }
}

1、module 一般指一个厂商提供的一个HAL库(可以理解为一个音频系统下的子系统!),AudiopolicyService会根据这个字段找到对应的库(格式audio."module".default.so,比如audio.a2dp.default.so,那还不如直接写库的名称更为直接!),module一般包含一个output和input,也就是这个库所驱动的外设,output/input设备就比较多种多样了。
2、一个简单的例子
1)output:包含一个speaker(device)和earphone(device),他们具备同样的profile,所以放在一起,从上层来看,他们没有区别,音频数据往这个output塞,因为上层知道他们都可以处理,至于最终走哪个device,由其它条件决定;
2)input:包含一个headset和bluetooth,同理
3、文件路径
1)在线路径(板卡):/vendor/etc/audio_policy.conf
2)离线路径(跟厂商):android/device/mediatek/audio_policy

为何这样分类设计?根据产品的设计和管理来进行理解
在这里插入图片描述

3)audio_policy_configuration.xml

1、拓扑关系
在这里插入图片描述

(1)理解并区分两个概念:policy (策略/路由) 、profile(配置/属性)

2、xml对应的类图

相当复杂,了解即可,工程应用上只需配置xml

1)基础类型
在这里插入图片描述

2)HwModule/AudioPolicyConfig
在这里插入图片描述

3)AudioOutputDescripter/AudioInputDescripter
在这里插入图片描述

4、APS启动代码时序图

1)重点数据结构和方法

Policy相关的类图
在这里插入图片描述

1、AudioPolicyService统一向上提供服务接口(binder接口)

2、AudioPolicyManger负责厂家策略服务,AudioPolicyClient则负责调用AudioFlinger接口

3、MAudioPolicyManager 来自厂家提供的libaudiopolicymanagercustom.so,主要作用是调用

4、AudioSystem封装AudioFlinger接口 提供给AudioPolicyClient

7、Engine - 负责路由的选择,比如决出最适合的output

1)Engine.cpp(在高Android版本才有此模块,抽离出来 让厂商来制定路由)
2)低版本函数getDeviceForStrategy() 对应Engine模块的getOutputDevicesForAttributes()

3)几个重要函数

mEngine->getOutputDevicesForAttributes()
mEngine->getAllAttributesForProductStrategy()
mEngine->getOrderedProductStrategies()

8、小结几个重点类的关系:AudioPolicyService<–>AudioPolicyManager<–>Engine

2)初始化逻辑在这里插入图片描述

5、关键点代码分析

1、
AudioPolicyClient 是 AudioFliger 的客户端

2、AudioPolicyService访问AudioFlinger需要跨进程? >> 需要,属于两个服务(但属于Binder同进程通讯,注意区分),在main_audioserver.cpp中启动
sp<IServiceManager> sm = defaultServiceManager();
sm->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME), afAdapter,
false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
sm->addService(String16(AudioPolicyService::getServiceName()), aps,
false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);


3、audio_policy_configuration.xml 对应的数据结构在哪里解析?
android\frameworks\av\services\audiopolicy\common\managerdefinitions\src  //每一项都有对应的类
xml是什么?audio_policy_configuration.xml
/vendor/etc/audio_policy_configuration.xml


4、AudioSystem.cpp均是静态方法,不需要new 即可调用
status_t AudioPolicyService::AudioPolicyClient::getAudioPolicyConfig(
        media::AudioPolicyConfig *config)
{
    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
    return af->getAudioPolicyConfig(config);
}

5、AudioPolicyService中的Command
Status AudioPolicyService::onNewAudioModulesAvailable()
{
    mOutputCommandThread->audioModulesUpdateCommand();
    return Status::ok();
}

6、MAudioPolicyManager 厂商部分代码的嵌入设计
1)厂家部分 封装成一个库 
1、一部分是class内容(继承AudioPolicyManager);
2、另一部分是: extern "c" function (dlopen,主要负责初始化);>> 这样设计的好处?

5、AudioFlinger(af) - native启动过程分析

1、delegate : 授权
2、

如何打开devices?
AUDIO_DEVICE_OUT_SPEAKER //枚举变量

为什么用线程来接收track?

1、CPP中的命名空间和前向声明
namespace android {
class StreamInHalInterface;
class StreamOutHalInterface;

class DeviceHalInterface : public virtual RefBase
{}
//前向声明(Forward Declaration),仅使用此类的指针或引用,无需知道类的具体结构,前向声明即可满足;解决头文件依赖(会触发对应源文件的编译)和循环依赖;

2、android\frameworks\av\services\audioflinger\AudioFlinger.cpp
mDevicesFactoryHal = DevicesFactoryHalInterface::create(); //打开hal库,获取hal接口
mEffectsFactoryHal = audioflinger::EffectConfiguration::getEffectsFactoryHal(); //音频效果


3、AudioFlingerService 优先于 AudioPolicyService启动;后者需要调用前者


4、AudioFlingerClientAdapter?
//用于封装处理Binder IPC(aidl) 通信异常情况- AudioFlinger
static inline ::android::status_t statusTFromBinderStatus(const ::android::binder::Status &status) {
    return status.isOk() ? ::android::OK // check ::android::OK,
        : status.serviceSpecificErrorCode() // service-side error, not standard Java exception
                                            // (fromServiceSpecificError)
        ?: status.transactionError() // a native binder transaction error (fromStatusT)
        ?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a
                                                    // standard Java exception (fromExceptionCode)
}

5、Delagate代理模式-与继承功能相反
1)适合基类会变化,而子类不会变化的情况
class AudioFlingerServerAdapter : public media::BnAudioFLingerService {
public:
    using Status = binder::Status;
    class Delegate : public IAudioFling {
        friend class AudioFlingerServerAdapter;
    }
    explicit AudioFlingerServerAdapter(const sp<AudioFlingerServerAdapter::Delegate>& delegate)
private:
    sp<AudioFlingerServerAdapter::Delegate> mDelegate;
}


6、通过aidl访问hal层
android\frameworks\av\media\libaudiohal\impl\DevicesFactoryHalAidl.cpp
if (std::find(deviceNames.begin(), deviceNames.end(), name) != deviceNames.end()) {
        if (strcmp(name, "primary") == 0) name = "default";
        auto serviceName = std::string(IModule::descriptor) + "/" + name;
        service = IModule::fromBinder(
                ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str()))); //获取aidl服务
        ALOGE_IF(service == nullptr, "%s fromBinder %s failed", __func__, serviceName.c_str());
}

7、hal
1)android\frameworks\av\media\libaudiohal\impl
2)android\frameworks\av\media\libaudiohal\include\media\audiohal
充斥着大量的跨进程封装(parcel/错误处理/返回值处理等等),使用factory模式 兼容hidl和aidl

1、术语概念

2、AudioFlingerService的作用

3、数据结构及代码时序图

1)数据结构 - HAL层的类图

在这里插入图片描述

1、为什么如此复杂?为了适应不同系统版本共存的HAL/HIDL/AIDL方式

2、以AIDL为例:DevicesFactoryHalAidl包含DeviceHalAidl (hal接口)

2)数据结构 - AudioFlinger层 与 hal层的对接关系类图

在这里插入图片描述

1)AudioHwDevice对应的是audio policy策略文件中的module,在AudioPolicyService中又被称为HwModule!

4)AudioFlinger初始化代码流程图

在这里插入图片描述

1、PlaybackTread是AudioFlinger模块中的组成,在初始化时创建,循环地将音频从共享内存中稍加处理后送到硬件中;

2、创建MixerThread(由audio_policy_configuration.xml决定创建哪种类型的Thread)后,上层即可从mPlaybackTrreads选择对应的Thread丢数据;

3、应用给底层丢数据的过程如下:
在这里插入图片描述

一种类型STREAM_TYPE对应一个PlaybackThread线程;

4、audio_io_handle_t

audio_io_handle_t是一个全局唯一的整形值,作为键值对的索引值key,在output中对应PlaybackThread
/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */
typedef int audio_io_handle_t;

audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
        audio_io_handle_t output2)
{
...
    mPlaybackThreads.add(id, thread);
    // notify client processes of the new output creation
    thread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
    return id;
}

6、AudioTrack创建过程

1、playback: 重放
2、offload : 音频数据不解码,即软件不解码,硬件负责解码
3、time-stretch : 时间拉伸,对应音频的加速
4、fallback : 回放
5、MSD :multi-Stream Decoder
6、underrun : 生产速度 赶不上 消费速度


10、一个音轨Track对应一个共享内存,一个APP只能对应一个Track;
AudioFlinger会轮训多个Track,送进mixer,混合后给到output->device;

1、
android\frameworks\av\media\libaudioclient\AudioSystem.cpp

2、
android\frameworks\av\media\libaudioclient\AudioTrack.cpp
const sp<media::IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); //获取AudioFliger接口

1、AudioTrack创建过程

先来看从java层如何使用AudioTrack

1、播放音频流几个步骤
new AudioTrack
AudioTrack.set()
AudioTrack.start()

2、调用native方法创建Track
android\frameworks\base\media\java\android\media\AudioTrack.java
int initResult = native_setup();

3、写共享内存
public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
 return write(audioData, offsetInBytes, sizeInBytes, WRITE_BLOCKING);
}

final int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat,
                writeMode == WRITE_BLOCKING);

2、选择一个output

1、基础数据结构
在这里插入图片描述

1、audio_flags_mask_t
typedef enum {
    AUDIO_FLAG_NONE                       = 0x0,
    AUDIO_FLAG_AUDIBILITY_ENFORCED        = 0x1,  //不能被静音,比如防止偷拍
    AUDIO_FLAG_SECURE                     = 0x2,  //音频加密类型,受数字版权管理(DRM)
    AUDIO_FLAG_SCO                        = 0x4,  //SCO Synchronous Connection-Oriented 蓝牙
    AUDIO_FLAG_BEACON                     = 0x8,
}

2、
enum legacy_strategy {
    STRATEGY_NONE = -1,
    STRATEGY_MEDIA,  //媒体播放的音频策略
    STRATEGY_PHONE, //通话的音频策略
    STRATEGY_SONIFICATION,  //系统提示音
    STRATEGY_SONIFICATION_RESPECTFUL, //尊重用户环境的系统提示音
    STRATEGY_DTMF, //双音多频(DTML), 蓝牙设备
    STRATEGY_ENFORCED_AUDIBLE, //强制可听
    STRATEGY_TRANSMITTED_THROUGH_SPEAKER, //通过speaker
    STRATEGY_ACCESSIBILITY, //辅助功能
    STRATEGY_REROUTING, //音频重路由
    STRATEGY_CALL_ASSISTANT, //通话辅助
};

stream_type(music-细分) -> strategy(media-粗分)

audio_stream_type_t、audio_attributes_t、Strategy、Device的关联关系
在这里插入图片描述

2、决出一个output,选择大致过程简述:

1)stream type->attribute(属性)->stratege(根据属性分组/类别)->device(此类别所对应的设备)->output(支持此设备的output,有一定的优先级)

2)AudioPolicyManager根据stream type获取合适的output(由Engine模块来负责决策)
audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream)
{
    DeviceVector devices = mEngine->getOutputDevicesForStream(stream, false /*fromCache*/);
    SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
    const audio_io_handle_t output = selectOutput(outputs);
    ALOGV("getOutput() stream %d selected devices %s, output %d", stream,
          devices.toString().c_str(), output);
    return output;
}

3、创建Track代码流程图

在这里插入图片描述

4、共享内存机制

1)基本数据结构(无非就是将实体往上封装 加点管理接口)
在这里插入图片描述

2)共享内存(cbk : control block)示意图
在这里插入图片描述

3)重点部分

1、基本数据结构定义的头文件
android\frameworks\av\include\private\media\AudioTrackShared.h

2、通过共享内存提供音频数据的两种方式
1)一次性提供方式(MODE_STATIC,也称为静态模式),适合音频数据很小的场合,比如系统铃声,警告声;流式提供(MODE_STREAM,也称流模式),比如音乐;
2)MODE_STATIC、MODE_STREAM对应的共享内存创建者不同
android\frameworks\base\core\jni\android_media_AudioTrack.cpp
static jint android_media_AudioTrack_setup(...,jint memoryMode, ...)
switch (memoryMode) {
        case MODE_STREAM:  //APP层不创建内容,由AudioFlingerService负责创建,需要复杂的管理机制支持(环形buffer),底层控制实现
            status = lpTrack->set();
            break;
        case MODE_STATIC: //APP层创建共享内存,因为是一次性任务,不需要管理,直接APP层创建好传给底层即可
        {
            // AudioTrack is using shared memory
            const auto iMem = allocSharedMem(buffSizeInBytes);
            if (iMem == nullptr) {
                ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
                goto native_init_failure;
            }
            status = lpTrack->set(..,iMem,..);
            break;
        }
}
3)AudioFlingerService创建共享内存
1、共享内存相关的变量
android\frameworks\av\services\audioflinger\TrackBase.h
class TrackBase : public ExtendedAudioBufferProvider, public RefBase {
    sp<IMemory>         mCblkMemory;
    audio_track_cblk_t* mCblk;
    sp<IMemory>         mBufferMemory;  // currently non-0 for fast RecordTrack only
    void*               mBuffer;    // start of track buffer, typically in shared memory
                                    // except for OutputTrack when it is in local memory
    size_t              mBufferSize; // size of mBuffer in bytes
}

2、分配内存
android\frameworks\av\services\audioflinger\Tracks.cpp
AudioFlinger::ThreadBase::TrackBase::TrackBase(){
    if (client != 0) {
        mCblkMemory = client->allocator().allocate(mediautils::NamedAllocRequest{{size},
                std::string("Track ID: ").append(std::to_string(mId))});
    } else {
        mCblk = (audio_track_cblk_t *) malloc(size);
    }
}

3、Tracks.cpp : AudioTrackServerProxy和StaticAudioTrackServerProxy都是负责管理共享内存的类
AudioFlinger::PlaybackThread::Track::Track(){
    if (sharedBuffer == 0) {
            mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
                    mFrameSize, !isExternalTrack(), sampleRate); //对应MODE_STATIC
        } else {
            mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
                    mFrameSize, sampleRate); //对应MODE_STATIC
    }
}

4、
AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
         mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize,
}

4、共享内存采用的是Ashmem匿名共享机制
在这里插入图片描述

5、PlaybackThread

1)概述
疑问:
1、音频数据格式 谁来解析处理?编解码模块(Codec)负责处理
2、Mix 原理是什么?

1、PlaybackThread的作用及整体的处理音频数据流程
1)PlaybackTread是AudioFlinger模块中的组成,在初始化时创建,循环地将音频从共享内存中稍加处理后送到硬件中;
2)整理流程:轮询共享内存 -> 取出处理 -> 送到HAL层去 -> 硬件播放
2)数据结构 - playbackThread与Track类图

在这里插入图片描述

1、audio_track_cblk_t 是共享内存 控制块,用于音频流的传送

2、PlaybackThread中对Track的管理
在这里插入图片描述

3)关键代码分析
1、Threads.cpp
AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
                                             AudioStreamOut* output,
                                             audio_io_handle_t id,
                                             type_t type,
                                             bool systemReady,
                                             audio_config_base_t *mixerConfig)
    :   ThreadBase(audioFlinger, id, type, systemReady, true /* isOut */),
        mNormalFrameCount(0), mSinkBuffer(NULL),
{ }

2、整体流程
1)onFirstRef执行run
void AudioFlinger::PlaybackThread::onFirstRef()
{
    if (!isStreamInitialized()) {
        ALOGE("The stream is not open yet"); // This should not happen.
    }
    run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
    mThreadSnapshot.setTid(getTid());
}
2)进入子线程循环体
bool AudioFlinger::PlaybackThread::threadLoop()
{
    ....
    for (int64_t loopCount=0; !exitPending(); ++loopCount) {
        // mMixerStatusIgnoringFastTracks is also updated internally
        mMixerStatus = prepareTracks_l(&tracksToRemove); //取出Track音频数据
        ....
        if (mBytesRemaining == 0) {
            mCurrentWriteLength = 0;
            if (mMixerStatus == MIXER_TRACKS_READY) {
                // threadLoop_mix() sets mCurrentWriteLength
                threadLoop_mix(); //对音频数据进行mix
            }
        }
        ....
        if (!waitAsynCallback()) {
            ret = threadLoop_write(); //调用hal接口写入硬件
        }
    }
    ....
    threadLoop_exit();
}

3)threadLoop_write()
ssize_t AudioFlinger::MixerThread::threadLoop_write() {
    return PlaybackThread::threadLoop_write();
}

ssize_t AudioFlinger::PlaybackThread::threadLoop_write()
{
    if(mNormalSink != 0) {
        //采用NBAIO(Non-blocking Audio I/O),即先将数据送进缓冲区,让软件进一步处理(比如mix混音),再通过非阻塞方式将数据传输到音频硬件
        ssize_t frameWritten = mNormalSink->write((char *)mSinkBuffer + offset, count); 
    }else{
        //Direct output and offload, 即不进行音频处理,直接调用hal接口写入,比如HDMI设备
        bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining);
    }
}

6、AudioMix处理流程

1)概述

每一个MixerThread都有一个唯一对应的AudioMixer,接口如下
在这里插入图片描述

2)关键代码分析
1、调用处
android\frameworks\av\services\audioflinger\Threads.cpp
void AudioFlinger::MixerThread::threadLoop_mix()
{
    //mix buffers..
    mAudioMixer->process();
}

2、Mixer的内部实现
android\frameworks\av\media\libaudioprocessing\include\media\AudioMixerBase.h
class AudioMixer : public AudioMixerBase
{
    //process的实现如下,调用mHook,mHooK会根据不同场景赋值,指向不同的函数
    void        process() {
        preProcess();
        (this->*mHook)();
        postProcess();
    }
    
    // process hook functionality - 函数指针,指向AudioMixerBase的函数
    using process_hook_t = void(AudioMixerBase::*)();
    process_hook_t mHook = &AudioMixerBase::process__nop;   // one of process__*, never nullptr
    //函数指针,指向TrackBase的函数
    using hook_t = void(TrackBase::*)(int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);
    hook_t      hook;
    
    void process__validate();
    void process__nop();
    void process__genericNoResampling(); //两路以上Track,不重采样
    void process__genericResampling(); //两路以上Track,重采样
    void process__oneTrack16BitsStereoNoResampling();//只有一路Track,16bit 立体声,不重采样
}

注意AudioMixer和TrackBase是共用音频数据缓冲区的

mHook的变化图
在这里插入图片描述

3)如何实现混音?
1、以process__genericResampling为例
void AudioMixerBase::process__genericResampling()
{
    ALOGVV("process__genericResampling\n");
    int32_t * const outTemp = mOutputTemp.get(); // 临时buffer存放Track
    size_t numFrames = mFrameCount;

    for (const auto &pair : mGroups) {
        const auto &group = pair.second;
        const std::shared_ptr<TrackBase> &t1 = mTracks[group[0]]; //应用程序提供的Track数据

        // clear temp buffer
        memset(outTemp, 0, sizeof(*outTemp) * t1->mMixerChannelCount * mFrameCount);
        for (const int name : group) {
            const std::shared_ptr<TrackBase> &t = mTracks[name];
            int32_t *aux = NULL;
            if (CC_UNLIKELY(t->needs & NEEDS_AUX)) {
                aux = t->auxBuffer;
            }

            // this is a little goofy, on the resampling case we don't
            // acquire/release the buffers because it's done by
            // the resampler.
            if (t->needs & NEEDS_RESAMPLE) {
                (t.get()->*t->hook)(outTemp, numFrames, mResampleTemp.get() /* naked ptr */, aux);
            } else {

                size_t outFrames = 0;

                while (outFrames < numFrames) {
                    t->buffer.frameCount = numFrames - outFrames;
                    t->bufferProvider->getNextBuffer(&t->buffer);
                    t->mIn = t->buffer.raw;
                    // t->mIn == nullptr can happen if the track was flushed just after having
                    // been enabled for mixing.
                    if (t->mIn == nullptr) break;

                    (t.get()->*t->hook)(
                            outTemp + outFrames * t->mMixerChannelCount, t->buffer.frameCount,
                            mResampleTemp.get() /* naked ptr */,
                            aux != nullptr ? aux + outFrames : nullptr);
                    outFrames += t->buffer.frameCount;

                    t->bufferProvider->releaseBuffer(&t->buffer);
                }
            }
        }
        convertMixerFormat(t1->mainBuffer, t1->mMixerFormat,
                outTemp, t1->mMixerInFormat, numFrames * t1->mMixerChannelCount); //转换格式,最终数据存放在t1->mainBuffer中
    }
}
总的来说就是将各个Track音频数据叠加起来,实现混音

7、Playback音频数据的传递

AudioTrack或AudioFlingerService创建好共享内存,APP只需要将数据写进共享内存,并通知AudioFlingerService(主要是PLaybackThread和AudioMix)进行处理即可,我们从宏观上了解交互控制部分,其它细节比较晦涩(极端buffer大小等)不好记忆,这里不展开,需要了解时再去琢磨

1)Audio Playback数据流传递如下
在这里插入图片描述

2)AudioTrack(生产者-user) 与AudioFlinger(消费者-Server)的数据交互大致如下
在这里插入图片描述

3)环形缓冲区
在这里插入图片描述

4)AudioTrack与AudioFlinger都通过obtainBuffer和releaseBuffer来获取/释放同一块缓冲区,

如何实现互斥?这两个方法使用Mutex实现互斥功能

7、音量调节 - 综合应用

1)基本概念

master volume //Android框架中的主音量,决定全局的音量
stream volume //Android框架中的流类型音量,决定局部(比如铃声/电话/音乐)的音量
stream volume alias //Android框架中的流类型音量,即对stream volume二次分类
track volume //音频流中的音量( 附属在音频数据中 )
在这里插入图片描述

无论是AudioTrack volume、stream volume, 都是单独设置.
能否通过某个变量影响到所有stream、所有AudioTrack的音量?
有!这就是 master volume, 这个值是可以直接用来控制声卡的

音量处理公式:final volume = master volume * stream volume * stream volume alias * track volume

2)讨论两种线程对音量的设置

1)哪里决定使用哪种线程驱动声卡?

audio_policy_configuration.xml
flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ" maxOpenCount="2" maxActiveCount="1">

2)数据流简图
在这里插入图片描述

1、对于MixerThread

APP对音量的设置不会影响到声卡的硬件音量,而只会影响APP的音频数据的幅值(变小或放大),
这些音频数据最终被混合后传给声卡,多个APP本身的音量设置互不影响

对于混音的音量处理公式
app1: 
data1_mix = data1_in * master_volume * stream1_volume * AudioTrack1_volume

app2: 
data2_mix = data2_in * master_volume * stream2_volume * AudioTrack2_volume

混合在一起:
data_mix = data1_mix + data2_mix

2、对于DirectOutputThread
同一时间里只有一个APP、只有一个AudioTrack使用它,
所以该AudioTrack的音量可以被DirectOutputThread直接用来设置硬件音量

3)数据结构与重点方法

1、基本数据结构

1、android\frameworks\av\services\audioflinger\AudioFlinger.h
struct  stream_type_t {
        stream_type_t()
            :   volume(1.0f),
                mute(false)
        {
        }
        float       volume;
        bool        mute;
    };

2、android\frameworks\av\services\audioflinger\AudioFlinger.h
class AudioFlinger : public AudioFlingerServerAdapter::Delegate
{
                // member variables below are protected by mLock
                float                               mMasterVolume;
                bool                                mMasterMute;
                float                               mMasterBalance = 0.f;
                // end of variables protected by mLock
}

3、
void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
    Mutex::Autolock _l(mLock);
    mStreamTypes[stream].volume = value;
    broadcast_l();
}

4、
status_t AudioFlinger::setMasterVolume(float value)
{
    Mutex::Autolock _l(mLock);
    mMasterVolume = value;
    //设置设备的主音量
    AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
    dev->hwDevice()->setMasterVolume(value);
    //如果声卡不支持主音量设置,在每个PlaybackThreads中设置软件"主音量"
    mPlaybackThreads.valueAt(i)->setMasterVolume(value);

    return NO_ERROR;
}

2、Mixer中对音量的控制

android\frameworks\av\media\libaudioprocessing\include\media\AudioMixerBase.h
class AudioMixerBase
{
    struct TrackBase {
           // TODO: Eventually remove legacy integer volume settings
        union {
        int16_t     volume[MAX_NUM_VOLUMES]; // U4.12 fixed point (top bit should be zero)
        int32_t     volumeRL;
        };

        int32_t     prevVolume[MAX_NUM_VOLUMES];
        int32_t     volumeInc[MAX_NUM_VOLUMES];
        int32_t     auxInc;
        int32_t     prevAuxLevel;
        int16_t     auxLevel;       // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance
        
        float          mVolume[MAX_NUM_VOLUMES];     // floating point set volume
        float          mPrevVolume[MAX_NUM_VOLUMES]; // floating point previous volume
        float          mVolumeInc[MAX_NUM_VOLUMES];  // floating point volume increment

        float          mAuxLevel;                     // floating point set aux level
        float          mPrevAuxLevel;                 // floating point prev aux level
        float          mAuxInc;                       // floating point aux increment
    }
}
aux:指的是单声道设备

prevolume/inc/volume的关系,目的是为了平缓音量的变化,避免对用户产生不适
在这里插入图片描述

3、音量最终在哪里生效?

android\frameworks\av\services\audioflinger\Threads.cpp
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
        Vector< sp<Track> > *tracksToRemove)
{
// cache the combined master volume and stream type volume for fast mixer; this
                // lacks any synchronization or barrier so VolumeProvider may read a stale value
                const float vh = track->getVolumeHandler()->getVolume(
                    proxy->framesReleased()).first;
                volume *= vh;
                track->mCachedVolume = volume;
                gain_minifloat_packed_t vlr = proxy->getVolumeLR();
                float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
                float vrf = float_from_gain(gain_minifloat_unpack_right(vlr));

                vlf *= volume;  //volume left final
                vrf *= volume;  //volume right final

                track->setFinalVolume(vlf, vrf);
                ++fastTracks;
}

void AudioFlinger::PlaybackThread::Track::setFinalVolume(float volumeLeft, float volumeRight)
{
    mFinalVolumeLeft = volumeLeft;
    mFinalVolumeRight = volumeRight;
}

4)代码时序图

1、

在这里插入图片描述

2、用户按下音量键先进入输入子系统,再转到音频子系统处理

1、输入子系统入口
android\frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
            int policyFlags) {}

2、音频子系统入口
android\frameworks\base\services\core\java\com\android\server\audio\AudioService.java
public void handleVolumeKey(@NonNull KeyEvent event, boolean isOnTv,
            @NonNull String callingPackage, @NonNull String caller) {}

3、音量相关的keyevent
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE:

网站公告

今日签到

点亮在社区的每一天
去签到