[audio] AudioTrack (七) 播放流程分析

app

java 复制代码
streamTrack.play()

base/media/java/android/media/AudioTrack.java play

java 复制代码
public void play()

    startImpl();

}


private void startImpl() {

    baseStart(new int[0]); // unknown device at this point

    native_start();

}

base/core/jni/android_media_AudioTrack.cpp native_start

cpp 复制代码
static void
android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
{
    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);


    lpTrack->start();
}

libaudioclient

av/media/libaudioclient/AudioTrack.cpp lpTrack->start

cpp 复制代码
status_t AudioTrack::start()
{
    
    status_t status = NO_ERROR; // logged: make sure to set this before returning.

    mAudioTrack->start(&status);

    return status;
}

audioflinger

av/services/audioflinger/Tracks.cpp TrackHandle::start

因为之前分析创建流程时知道,libaudioclientmAudioTrack 就是 TrackHandle ,所以这里调用的是 TrackHandle::start

cpp 复制代码
Status TrackHandle::start(int32_t* _aidl_return) {
    *_aidl_return = mTrack->start();
    return Status::ok();
}


status_t Track::start(AudioSystem::sync_event_t event __unused,
                                                    audio_session_t triggerSession __unused)
{

    status_t status = NO_ERROR;

    const sp<IAfThreadBase> thread = mThread.promote();
    
    auto* const playbackThread = thread->asIAfPlaybackThread().get();

    
    status = playbackThread->addTrack_l(this);

    return status;
}

av/services/audioflinger/Threads.cpp

将 track 加入到 mActiveTracks

cpp 复制代码
status_t PlaybackThread::addTrack_l(const sp<IAfTrack>& track)
{
    status_t status = ALREADY_EXISTS;

    // 不在mActiveTracks 中再加入 
    if (mActiveTracks.indexOf(track) < 0) {

        mActiveTracks.add(track);
    }
    
    onAddNewTrack_l();

    return status;
}


void PlaybackThread::onAddNewTrack_l()
{
    ALOGV("signal playback thread");
    broadcast_l();
}

void ThreadBase::broadcast_l()
{
    mSignalPending = true;
    mWaitWorkCV.notify_all();
}


threadLoop

av/services/audioflinger/Threads.cpp

processConfigEvents_l处理一些事件

prepareTracks_l

threadLoop_mix

threadLoop_write

cpp 复制代码
bool PlaybackThread::threadLoop()
{

    Vector<sp<IAfTrack>> tracksToRemove;


    for (int64_t loopCount = 0; !exitPending(); ++loopCount)
    {
        processConfigEvents_l();
        
        
        // 休眠逻辑
        if ((mActiveTracks.isEmpty() && systemTime() > mStandbyTimeNs) ||
                                   isSuspended()) {  
            // 进休眠
            threadLoop_standby();

            if (mActiveTracks.isEmpty() && mConfigEvents.isEmpty()) {

                // wait ...
                mWaitWorkCV.wait(_l);

                continue;
             }
        }
        
        // 返回一个状态 MIXER_TRACKS_READY
        mMixerStatus = prepareTracks_l(&tracksToRemove);

        // 满足播放要求 mix
        if (mMixerStatus == MIXER_TRACKS_READY) {
            
            threadLoop_mix();
        }

        
        if (!waitingAsyncCallback()) {

            // mSleepTimeUs == 0 means we must write to audio hardware

            if (mSleepTimeUs == 0) {


                if (mBytesRemaining) {
 
                    ret = threadLoop_write();
                }
            }
        }

    }

    return false;
}


prepareTracks_l

av/services/audioflinger/Threads.cpp prepareTracks_l

track 构造并添加到 mAudioMixer

mAudioMixer->create构造

track->framesReady

cpp 复制代码
PlaybackThread::mixer_state MixerThread::prepareTracks_l(
        Vector<sp<IAfTrack>>* tracksToRemove)
{
    mixer_state mixerStatus = MIXER_IDLE;

    size_t count = mActiveTracks.size();
    
    for (size_t i=0 ; i<count ; i++) {
        const sp<IAfTrack> t = mActiveTracks[i];

        IAfTrack* const track = t.get();
        
        // 获取 控制头
        audio_track_cblk_t* cblk = track->cblk();
        
        // 获取唯一id
        const int trackId = track->id();

        // 如果混音器中没有这个 id
        if (!mAudioMixer->exists(trackId)) {


            status_t status = mAudioMixer->create(
                    trackId,
                    track->channelMask(),
                    track->format(),
                    track->sessionId());


            size_t framesReady = track->framesReady();
            
            // 静音
            if (track->getInternalMute()) {
                vrf = 0.f;
                vlf = 0.f;
            }
            // 处理音量 设置音量
            track->setFinalVolume(vlf, vrf);
            
            // 设置参数
            mAudioMixer->enable(trackId);

            mAudioMixer->setParameter(trackId, param, AudioMixer::VOLUME0, &vlf);
            mAudioMixer->setParameter(trackId, param, AudioMixer::VOLUME1, &vrf);
            
            
        }
    }

    return mixerStatus;
}

// mixerStatus 参考 av/services/audioflinger/IAfThread.h

    enum mixer_state {
        MIXER_IDLE,            // no active tracks
        MIXER_TRACKS_ENABLED,  // at least one active track, but no track has any data ready
        MIXER_TRACKS_READY,    // at least one active track, and at least one track has data
        MIXER_DRAIN_TRACK,     // drain currently playing track
        MIXER_DRAIN_ALL,       // fully drain the hardware
    };

av/media/libaudioprocessing/AudioMixerBase.cpp create

根据 cblk 的信息创建一个 AudioMixerBase

cpp 复制代码
status_t AudioMixerBase::create(
        int name, audio_channel_mask_t channelMask, audio_format_t format, int sessionId)
{

    auto t = preCreateTrack();
    
    mTracks[name] = t;
        return OK;
    }
}

std::shared_ptr<AudioMixerBase::TrackBase> AudioMixerBase::preCreateTrack()
{
    return std::make_shared<TrackBase>();
}

av/services/audioflinger/Tracks.cpp framesReady

cpp 复制代码
size_t Track::framesReady() const {

    return mAudioTrackServerProxy->framesReady();
}

av/media/libaudioclient/AudioTrackShared.cpp framesReady

rear - mFront返回填满的未读取的数据帧数

cpp 复制代码
__attribute__((no_sanitize("integer")))
size_t AudioTrackServerProxy::framesReady()
{

    audio_track_cblk_t* cblk = mCblk;

    const int32_t rear = getRear();

    ssize_t filled = audio_utils::safe_sub_overflow(rear, cblk->u.mStreaming.mFront);


    return filled;
}


threadLoop_mix

av/services/audioflinger/Threads.cpp threadLoop_mix

主要干的事就是混音重采样 最后将数据送到hal中

cpp 复制代码
void MixerThread::threadLoop_mix()
{
    // mix buffers...
    mAudioMixer->process();

    mSleepTimeUs = 0;

}

// 主要干的事就是混音重采样 最后将数据送到hal中
// av/media/libaudioprocessing/include/media/AudioMixerBase.h  process

void        process() {
    preProcess();
    (this->*mHook)();
    postProcess();
}


threadLoop_write

av/services/audioflinger/Threads.cpp

cpp 复制代码
ssize_t MixerThread::threadLoop_write()
{

    return PlaybackThread::threadLoop_write();
}

av/services/audioflinger/Threads.cpp threadLoop_write

AudioMixerBasemSinkBuffer 填充,将数据写入到 hal 中

cpp 复制代码
ssize_t PlaybackThread::threadLoop_write()
{

    ssize_t bytesWritten;

    const size_t offset = mCurrentWriteLength - mBytesRemaining;


    if (mNormalSink != 0) {

        const size_t count = mBytesRemaining / mFrameSize;


        ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);


    }
    return bytesWritten;
}



dumpsys media.audio_flinger

bash 复制代码
Notification Clients:
   pid    uid  name
  1448   1013  media
  1709   1000  android.uid.system
  2485  10157  android.uid.systemui
  2651   1001  android.uid.phone
  3976   1041  audioserver
  4385  10133  org.lineageos.glimpse
 10242  10187  com.example.myapplication
Global session refs:
  session  cnt     pid    uid  name
      641    1    1709   1000  android.uid.system
      857    1    2485  10157  android.uid.systemui
     1009    1   10242  10187  com.example.myapplication

Supported latency modes: { }
  Stream volumes in dB: 0:-inf, 1:-11, 2:-inf, 3:-inf, 4:-inf, 5:-8.7, 6:-inf, 7:-inf, 8:-inf, 9:0, 10:-inf, 11:-inf, 12:0, 13:0, 14:0
  Normal mixer raw underrun counters: partial=0 empty=0
  2 Tracks of which 0 are active
    Type     Id Active Client(pid/uid) Session Port Id S  Flags   Format Chn mask  SRate ST Usg CT  G db  L dB  R dB  VS dB  PortVol dB  PortMuted   Server FrmCnt  FrmRdy F Underruns  Flushed BitPerfect InternalMute   Latency
       S     56     no    1709/   1000     641      24 S  0x600 00000001 00000003  44100  1   d  4   -17    -6    -6     0          -11      false 0000612C   4146       0 f         0        0      false        false   61.79 k
       S     74     no    2485/  10157     857      42 S  0x600 00000001 00000003  44100  1   d  4   -17    -6    -6     0          -11      false 0000A2AD   8329       0 f         0        0      false        false   61.78 k
相关推荐
贾修行5 小时前
Kestrel:.NET 的高性能 Web 服务器探秘
服务器·前端·kestrel·.net·net core·web-server·asp.net-core
吃吃喝喝小朋友5 小时前
HTML DOM
前端·javascript·html
HWL56795 小时前
HTML中,<video> 和 <source> 标签
前端·javascript·html
球球不吃虾5 小时前
分享一个简单的交互式塔罗牌抽牌应用
前端·vue
2501_948120155 小时前
中职动漫设计与制作专业实训方案研究
前端·人工智能·语言模型·自然语言处理·架构
小小鸟0085 小时前
前端 RBAC基于角色的权限控制(按钮级别)
前端
学习java的小库里5 小时前
EasyExcel复杂导出
java·前端
muddjsv5 小时前
前端开发通用全流程:从需求到上线,步步拆解
前端
Mr Xu_5 小时前
从零实战!使用 Mars3D 快速构建水利监测 WebGIS 系统
前端·3d·webgis
wuhen_n5 小时前
类型断言:as vs <> vs ! 的使用边界与陷阱
前端·javascript·typescript