Android 音频源码分析——Thread Track分析

Posted VNanyesheshou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 音频源码分析——Thread Track分析相关的知识,希望对你有一定的参考价值。

基于Andorid9.0源码

分析下AudioRecord、AudioTrack对应 audioserver中的关键类。

一.ThreadBase

ThreadBase,线程类对音频数据处理(混音、音效),从Hal层读数据、写数据

分析AudioRecord和AudioTrack源码,发现有多种Thread,都继承ThreadBase。其结构如下图

  • RecordThread:录音线程

  • PlaybackThread:播放线程,包括多个子类,对应不同的播放模式;

    MixerThread:混音线程

    DuplicatingThread:混音线程子类,特殊在于音频数据复制成两份分别输出

    DirectOutputThread:直接输出,软件层不需要mixer混音,直接交给hal层数据

    OffloadThread:压缩的音频数据,直接输出到hal层,由音频DSP进行解码处理;

  • MmapThread:映射线程,AAudio使用,后续研究。。。

MixerThread

以MixerThread为例分析下其内部使用

MixerThread由AudioFlinger openOutput创建,其父类PlaybackThread重写了Thread的threadLoop,onFirstRef方法,MixerThread没有重写.

void AudioFlinger::PlaybackThread::onFirstRef()

    run(mThreadName, android_PRIORITY_URGENT_AUDIO);

MixerThread对象创建时会调用onFirstRef函数,run 方法启动线程循环体threadLoop

bool AudioFlinger::PlaybackThread::threadLoop()
	while (!exitPending())
    	//....
    	processConfigEvents_l();
    	
    	mMixerStatus = prepareTracks_l(&tracksToRemove);
    	
    	if (mMixerStatus == MIXER_TRACKS_READY) 
        	threadLoop_mix();
         else if ((mMixerStatus != MIXER_DRAIN_TRACK)
                        && (mMixerStatus != MIXER_DRAIN_ALL)) 
        	threadLoop_sleepTime();
        
            
        for (size_t i = 0; i < effectChains.size(); i ++) 
        	effectChains[i]->process_l();
        
        
        ret = threadLoop_write();

  • processConfigEvents_l处理event,包括:PRIO、IO、set_parameter、CREATE_AUDIO_PATCH、RELEASE_AUDIO_PATCH
  • prepareTracks_l 准备工作,管理Track状态,添加、删除,设置参数到AudioMixer
  • threadLoop_mix调用mAudioMixer->process()进行混音处理
  • threadLoop_write输出音频数据
ssize_t AudioFlinger::MixerThread::threadLoop_write()

    if (mFastMixer != 0) 
    
    return PlaybackThread::threadLoop_write();


// shared by MIXER and DIRECT, overridden by DUPLICATING
ssize_t AudioFlinger::PlaybackThread::threadLoop_write()

    // If an NBAIO sink is present, use it to write the normal mixer's submix
    if (mNormalSink != 0) 

    // otherwise use the HAL / AudioStreamOut directly
     else 
        // Direct output and offload threads
        
        // FIXME We should have an implementation of timestamps for direct output threads.
        // They are used e.g for multichannel PCM playback over HDMI.
        bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining);
    

    mNumWrites++;
    mInWrite = false;
    mStandby = false;
    return bytesWritten;

MixerThread threadLoop_write函数调用PlaybackThread write函数,mOutput->write 将音频数据写到hal层

二.TrackBase

音频管理类,创建共享内存,控制音频流状态。TrackBase继承关系如下图所示:

  • RecordTrack:录音track
  • Track:播放track
    OutputTrack:播放Track子类,对应Duplicat 音频模式
    PatchTrack:未知。。。
  • MmapTrack:映射模式,对应MMapThread

应用创建一个录音实列(AudioRecord、MediaRecorder),AudioFlinger中对应创建RecordTrack;

应用创建一个播放实列(AudioTrack、MediaPlayer、SoundPool等),AudioFlinger中对应创建播放Track;

AudioFlinger::ThreadBase::TrackBase::TrackBase()

    if (client != 0) 
        mCblkMemory = client->heap()->allocate(size);
        if (mCblkMemory == 0 ||
                (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())) == NULL) 
            ALOGE("not enough memory for AudioTrack size=%zu", size);
            client->heap()->dump("AudioTrack");
            mCblkMemory.clear();
            return;
        
     else 
        mCblk = (audio_track_cblk_t *) malloc(size);
        if (mCblk == NULL) 
            ALOGE("not enough memory for AudioTrack size=%zu", size);
            return;
        
    
	//......

TrackBase初始化会创建共享内存mCblkMemory,与app交互音频数据。

以上是关于Android 音频源码分析——Thread Track分析的主要内容,如果未能解决你的问题,请参考以下文章

Android 音频源码分析——AudioFlinger

Android 音频源码分析——AudioFlinger

Android 音频源码分析——AudioTrack设备选择

Android 音频源码分析——AudioTrack设备选择

Android 音频源码分析——audioserver启动

Android 音频源码分析——音频设备切换(插入耳机)