国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

AudioTrack的聲音輸出流程

這篇具有很好參考價值的文章主要介紹了AudioTrack的聲音輸出流程。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

通過普通AudioTrack的流程追蹤數(shù)據(jù)流。分析一下聲音模塊的具體流程。這里比較復雜的是binder以及共享內(nèi)存。這里不做詳細介紹。只介紹原理

正文

java層的AudioTrack主要是通過jni調(diào)用到cpp層的AudioTrack。我們只介紹cpp層相關。

初始化

初始化只核心是通過set函數(shù)實現(xiàn)的。主要包括三步。

1. 客戶端準備數(shù)據(jù),
status_t AudioTrack::set(
        audio_stream_type_t streamType,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t frameCount,
        audio_output_flags_t flags,
        callback_t cbf,
        void* user,
        int32_t notificationFrames,
        const sp<IMemory>& sharedBuffer,
        bool threadCanCallJava,
        audio_session_t sessionId,
        transfer_type transferType,
        const audio_offload_info_t *offloadInfo,
        uid_t uid,
        pid_t pid,
        const audio_attributes_t* pAttributes,
        bool doNotReconnect,
        float maxRequiredSpeed,
        audio_port_handle_t selectedDeviceId)
{
   //如果構造audioTrack時時傳入AudioTrack.MODE_STREAM。則sharedBuffer為空
    mSharedBuffer = sharedBuffer;

    if (cbf != NULL) {
        mAudioTrackThread = new AudioTrackThread(*this);
        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
        // thread begins in paused state, and will not reference us until start()
    }

    // create the IAudioTrack
    {
        AutoMutex lock(mLock);
        //這是核心,通過audiofligure 創(chuàng)建服務端數(shù)據(jù),以及拿到共享內(nèi)存。
        status = createTrack_l();
    }
    mVolumeHandler = new media::VolumeHandler();
}


status_t AudioTrack::createTrack_l()
{
    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger()
    IAudioFlinger::CreateTrackInput inpu
    IAudioFlinger::CreateTrackOutput output;
//關鍵部分
    sp<IAudioTrack> track = audioFlinger->createTrack(input,output,&status);

    sp<IMemory> iMem = track->getCblk();

    void *iMemPointer = iMem->pointer();

    mAudioTrack = track;
    mCblkMemory = iMem;

    audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
    mCblk = cblk;

    void* buffers;
        buffers = cblk + 1;

    mAudioTrack->attachAuxEffect(mAuxEffectId);

    if (mFrameCount > mReqFrameCount) {
        mReqFrameCount = mFrameCount;
    }

    // update proxy
    if (mSharedBuffer == 0) {
        mStaticProxy.clear();
        mProxy = new AudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize);
    }
    
    mProxy->setPlaybackRate(playbackRateTemp);
    mProxy->setMinimum(mNotificationFramesAct);
    }
}

核心是createTrack,之后拿到關鍵的共享內(nèi)存消息,然后寫入內(nèi)容

2. Audiofligure創(chuàng)建遠端track。

sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
                                          CreateTrackOutput& output,
                                          status_t *status)
{
    sp<PlaybackThread::Track> track;
    sp<TrackHandle> trackHandle;
    sp<Client> client;
    
    pid_t clientPid = input.clientInfo.clientPid;
    const pid_t callingPid = IPCThreadState::self()->getCallingPid();
    


    {
        Mutex::Autolock _l(mLock);
        PlaybackThread *thread = checkPlaybackThread_l(output.outputId);


        client = registerPid(clientPid);

        PlaybackThread *effectThread = NULL;

        track = thread->createTrack_l(client, streamType, localAttr, &output.sampleRate,
                                      input.config.format, input.config.channel_mask,
                                      &output.frameCount, &output.notificationFrameCount,
                                      input.notificationsPerBuffer, input.speed,
                                      input.sharedBuffer, sessionId, &output.flags,
                                      callingPid, input.clientInfo.clientTid, clientUid,
                                      &lStatus, portId);
        
    trackHandle = new TrackHandle(track);

    return trackHandle;
}

核心是createTrack_l,在混音線程中加入新建一個服務端的Track。新建共享內(nèi)存,返還給客戶端的Track,最終可以共享數(shù)據(jù)。代碼如下:


// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
        const sp<AudioFlinger::Client>& client,
        const sp<IMemory>& sharedBuffer,)
{
    sp<Track> track;

        track = new Track(this, client, streamType, attr, sampleRate, format,
                          channelMask, frameCount,
                          nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
                          sessionId, creatorPid, uid, *flags, TrackBase::TYPE_DEFAULT, portId);
			//這個不太重要,后面調(diào)用start后,track會進入mActiveTracks列表,最終會在Threadloop中讀取數(shù)據(jù),經(jīng)過處理寫入out中
        mTracks.add(track);
        
    return track;
}

Track的構造函數(shù)是關鍵,主要是拿到共享內(nèi)存。交給binder服務端的TrackHandle對象。大概代碼如下:

AudioFlinger::ThreadBase::TrackBase::TrackBase(
            ThreadBase *thread,
            const sp<Client>& client
            void *buffer,)
    :   RefBase(),
{
   //client是audiofligure中維護的一個變量,主要持有MemoryDealer。用于管理共享內(nèi)存。
    if (client != 0) {
        mCblkMemory = client->heap()->allocate(size);
        
    }
}

然后把tracxk對象封裝成TrackHandle這個binder對象,傳給AudioTrack,通過TrackHandle實現(xiàn)數(shù)據(jù)傳輸。他主要實現(xiàn)了start和stop。以及獲取共享內(nèi)存的接口如下


class IAudioTrack : public IInterface
{
public:
    DECLARE_META_INTERFACE(AudioTrack);

    /* Get this track's control block */
    virtual sp<IMemory> getCblk() const = 0;

    /* After it's created the track is not active. Call start() to
     * make it active.
     */
    virtual status_t    start() = 0;

    /* Stop a track. If set, the callback will cease being called and
     * obtainBuffer will return an error. Buffers that are already released
     * will continue to be processed, unless/until flush() is called.
     */
    virtual void        stop() = 0;

    /* Flush a stopped or paused track. All pending/released buffers are discarded.
     * This function has no effect if the track is not stopped or paused.
     */
    virtual void        flush() = 0;

    /* Pause a track. If set, the callback will cease being called and
     * obtainBuffer will return an error. Buffers that are already released
     * will continue to be processed, unless/until flush() is called.
     */
    virtual void        pause() = 0;

    /* Attach track auxiliary output to specified effect. Use effectId = 0
     * to detach track from effect.
     */
    virtual status_t    attachAuxEffect(int effectId) = 0;

    /* Send parameters to the audio hardware */
    virtual status_t    setParameters(const String8& keyValuePairs) = 0;

    /* Selects the presentation (if available) */
    virtual status_t    selectPresentation(int presentationId, int programId) = 0;

    /* Return NO_ERROR if timestamp is valid.  timestamp is undefined otherwise. */
    virtual status_t    getTimestamp(AudioTimestamp& timestamp) = 0;

    /* Signal the playback thread for a change in control block */
    virtual void        signal() = 0;

    /* Sets the volume shaper */
    virtual media::VolumeShaper::Status applyVolumeShaper(
            const sp<media::VolumeShaper::Configuration>& configuration,
            const sp<media::VolumeShaper::Operation>& operation) = 0;

    /* gets the volume shaper state */
    virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) = 0;
};

下面大概介紹一下寫入數(shù)據(jù)的過程,因為這個算法比較復雜,主要是通過共享內(nèi)存,通過共享內(nèi)存中的結構體,控制共享內(nèi)存中后半部分的數(shù)據(jù)寫入寫出。就不在詳細介紹。這里只簡要介紹大概流程:
首先是Audiotrack的write方法:

ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)

//申請空間,
        status_t err = obtainBuffer(&audioBuffer,
                blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking)
         //寫入內(nèi)容       
        memcpy(audioBuffer.i8, buffer, toWrite);
//寫入結尾,通知共享內(nèi)存結構體,已經(jīng)寫入,防止讀取錯誤數(shù)據(jù)。
        releaseBuffer(&audioBuffer);
    }

obtainBuffer主要是通過AudioTrackClientProxy這個客戶端共享內(nèi)存控制的,
大概代碼如下:

status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested,
        struct timespec *elapsed)
{

//核心是這里,方便循環(huán)數(shù)組的下標的變化。是把長的坐標去掉頭部。
rear &= mFrameCountP2 - 1;

//這是取的是AudioTrack,所以需要在結尾添加數(shù)據(jù),所以是rear。
            buffer->mRaw = part1 > 0 ?
                    &((char *) mBuffers)[(rear) * mFrameSize] : NULL;

關于releaseBuffer這里就不在詳細介紹,因為主要是加鎖,然后通知數(shù)組下標變化的,具體邏輯這里不詳細介紹。

關于循環(huán)讀取的過程,本篇文章不再詳細介紹,主要是通過track類中的getNextBuffer實現(xiàn)的,他主要是audiomixer中被調(diào)用,本質(zhì)上都是通過audiomixerthread這個線程實現(xiàn)的,audiomix通過職責鏈模式,對聲音進行處理,最終寫入到hal層。

后記

這篇文章,這篇文章雖說不夠完善,但是基本上解釋了聲音的大概流向,但是framew層用到比較多的系統(tǒng)組件,還有更底層的鎖與同步機制,完全詳細介紹清楚,還是分困難了,這里暫時就這樣,以后如果有空,進一步補充。文章來源地址http://www.zghlxwxcb.cn/news/detail-541693.html

到了這里,關于AudioTrack的聲音輸出流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【音視頻原理】音視頻 “ 采樣 - 編碼 - 封裝 過程 “ 和 “ 解封裝 - 解碼 - 播放 過程 “ 分析 ( 視頻采集處理流程 | 音頻采集處理流程 | 音視頻文件解封裝播放流程 )

    【音視頻原理】音視頻 “ 采樣 - 編碼 - 封裝 過程 “ 和 “ 解封裝 - 解碼 - 播放 過程 “ 分析 ( 視頻采集處理流程 | 音頻采集處理流程 | 音視頻文件解封裝播放流程 )

    本篇文件主要分析 音視頻文件 是怎么產(chǎn)生的 , 以及 音視頻文件是如何播放的 ; 視頻文件從錄像到生成文件的全過程 : 采集圖像幀 : 攝像頭 硬件 負責 采集畫面 , 采集的 初始畫面 稱為 \\\" 圖像幀 \\\" , 一秒鐘 采集 的 圖像幀 數(shù)量 稱為 \\\" 幀率 \\\" , 如 : 60 幀 就是 一秒鐘采集 60 個畫

    2024年02月11日
    瀏覽(104)
  • WebRTC音視頻通話-WebRTC推拉流過程中日志log輸出

    WebRTC音視頻通話-WebRTC推拉流過程中日志log輸出

    WebRTC音視頻通話-WebRTC推拉流過程中日志log輸出 之前實現(xiàn)iOS端調(diào)用ossrs服務實現(xiàn)推拉流流程。 推流:https://blog.csdn.net/gloryFlow/article/details/132262724 拉流:https://blog.csdn.net/gloryFlow/article/details/132417602 在推拉流過程中的WebRTC的相關日志log輸出可以看到一些相關描述信息。在WebRTC日志

    2024年02月10日
    瀏覽(32)
  • 精選58道——Android 音視頻面試題_安卓音視頻面試題(3)

    精選58道——Android 音視頻面試題_安卓音視頻面試題(3)

    先自我介紹一下,小編浙江大學畢業(yè),去過華為、字節(jié)跳動等大廠,目前阿里P7 深知大多數(shù)程序員,想要提升技能,往往是自己摸索成長,但自己不成體系的自學效果低效又漫長,而且極易碰到天花板技術停滯不前! 因此收集整理了一份《2024年最新Android移動開發(fā)全套學習資

    2024年04月28日
    瀏覽(35)
  • 5G時代下,Android音視頻強勢崛起,我們該如何快速入門音視頻技術?

    5G時代下,Android音視頻強勢崛起,我們該如何快速入門音視頻技術?

    作為Android開發(fā)者的我們到底應不應該上音視頻這條船? 接下來一起分析下。 大趨勢 從未來的大趨勢來看,隨著5G時代的到來,音視頻慢慢變成人們?nèi)粘I钪械谋匦杵?。除了在線教育、音視頻會議、即時通訊這些必須使用音視頻技術的產(chǎn)品外,其它的產(chǎn)品也需要加入音頻、

    2024年04月15日
    瀏覽(28)
  • 音視頻八股文(11)-- ffmpeg avio 內(nèi)存輸入和內(nèi)存輸出。內(nèi)存輸出有完整代碼,網(wǎng)上很少有的。

    音視頻八股文(11)-- ffmpeg avio 內(nèi)存輸入和內(nèi)存輸出。內(nèi)存輸出有完整代碼,網(wǎng)上很少有的。

    avio是FFmpeg中的一個模塊,用于實現(xiàn)多種輸入輸出方式的封裝。 avio提供了一系列API,可以將數(shù)據(jù)從內(nèi)存讀取到緩沖區(qū)中,也可以將緩沖區(qū)中的數(shù)據(jù)寫入到內(nèi)存中。其實現(xiàn)依賴于IOContext結構體,該結構體定義了當前輸入/輸出事件的狀態(tài)、數(shù)據(jù)、回調(diào)函數(shù)等信息,并支持通過自定

    2024年02月03日
    瀏覽(30)
  • Android音視頻-MediaCodec

    Android音視頻-MediaCodec

    原文:https://mp.weixin.qq.com/s?__biz=MzU3NTA3MDU1OQ==mid=2247484865idx=1sn=174b8ca702466e83e72c7115d91b06eachksm=fd298df1ca5e04e7b2df9dc9f21e5cfe3e910204c905d8605f648ce6f6404432a83ae52a23a3scene=178cur_album_id=1638784435628064770#rd MediaCodec 支持處理三種數(shù)據(jù)類型,分別是壓縮數(shù)據(jù)(compressed data)、原始音頻數(shù)據(jù)(raw audio d

    2023年04月08日
    瀏覽(17)
  • Android音視頻編碼(2)

    Android音視頻編碼(2)

    Android本身提供了音視頻編解碼工具,很多時候是不需要第三方工具的,比如 ffmpeg , OpenCV 等,在android中引入第三庫比較復雜,在Android音視頻編碼中介紹了如何引入第三方庫libpng來進行進行圖片處理,同時引入這些第三方庫,是程序結構變得復雜。 本文介紹的音視頻編解碼利

    2024年01月17日
    瀏覽(23)
  • Android 音視頻開發(fā) - VideoView

    本篇文章主要介紹下Android 中的VideoView. VideoView是一個用于播放視頻的視圖組件,可以方便地在應用程序中播放本地或網(wǎng)絡上的視頻文件。 VideoView可以直接在布局文件中使用,也可以在代碼中動態(tài)創(chuàng)建。 它封裝了MediaPlayer和SurfaceView,提供了簡單的接口來控制視頻的播放和顯示

    2024年04月08日
    瀏覽(28)
  • Android之 集成音視頻通話

    Android之 集成音視頻通話

    一,背景 1.1 最近接收一個即時通訊二開項目,即時通訊部分用的XMPP協(xié)議,音視頻則是集成的國外的開源免費庫jitsi-meet-sdk-2.4.0-4.aar,是基于WebRTC的開源框架。但客戶想要微信那種頁面的排版,后來經(jīng)研究jitsi是不能修改UI的,UI部分是用混合框架ReactNative寫的,這樣難度就大了

    2024年02月12日
    瀏覽(32)
  • Android音視頻之協(xié)議介紹

    Android音視頻之協(xié)議介紹

    本文對音視頻的協(xié)議起源做詳細介紹,學習之后可以加深對音視頻知識的了解。 這里的音視頻不僅針對Android平臺,其他平臺也通用。 一般是指以某種格式封裝了音視頻數(shù)據(jù)的文件 常見的音頻格式:mp3、wma、avi、rm、rmvb、flv、mpg、mov、mkv等。 常見的視頻格式:rmvb、rm、wmv、

    2023年04月19日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包