欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何在IOS上使用ReplayKit與RTC

 更新時間:2021年04月13日 09:22:27   作者:聲網(wǎng)Agora  
這篇文章主要介紹了如何在IOS上使用ReplayKit 與 RTC,對IOS音視頻感興趣的同學,一定要看一下

在日益繁多的直播場景中,如果你也是某位游戲主播的粉絲的話,有一種直播方式是你一定不陌生的,那就是我們今天要聊的屏幕分享。

直播場景下的屏幕分享,不僅要將當前顯示器所展示的畫面分享給遠端,也要將聲音傳輸出去,包括應用的聲音,以及主播的聲音。鑒于這兩點需求,我們可以簡單分析出,進行一次屏幕分享的直播所需要的媒體流如下:

  1. 一條顯示器畫面的視頻流
  2. 一條應用聲音的音頻流
  3. 一條主播聲音的音頻流

ReplayKit 是蘋果提供的用于 iOS 系統(tǒng)進行屏幕錄制的框架。

首先我們來看看蘋果提供的用于屏幕錄制的 ReplayKit 的數(shù)據(jù)回調(diào)接口:

override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
        DispatchQueue.main.async {
            switch sampleBufferType {
            case .video:
                AgoraUploader.sendVideoBuffer(sampleBuffer)
            case .audioApp:
                AgoraUploader.sendAudioAppBuffer(sampleBuffer)
            case .audioMic:
                AgoraUploader.sendAudioMicBuffer(sampleBuffer)
            @unknown default:
                break
            }
        }
    }

從枚舉 sampleBufferType 上,我們不難看出,剛好能符合我們上述對媒體流的需求。

視頻格式

guard let videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer) else {
    return
}
        
let type = CVPixelBufferGetPixelFormatType(videoFrame)
type = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange

通過 CVPixelBufferGetPixelFormatType,我們可以獲取到每幀的視頻格式為 yuv420。

幀率

通過打印接口的回調(diào)次數(shù),可以知道每秒能夠獲取的視頻幀為30次,也就是幀率為 30。

格式與幀率都能符合 Agora RTC 所能接收的范圍,所以通過 Agora RTC 的 pushExternalVideoFrame 就可以將視頻分享到遠端了。

agoraKit.pushExternalVideoFrame(frame)

插入一個小知識

顯示器所顯示的幀來自于一個幀緩存區(qū),一般常見的為雙緩存或三緩存。當屏幕顯示完一幀后,發(fā)出一個垂直同步信號(V-Sync),告訴幀緩存區(qū)切換到下一幀的緩存上,然后顯示器開始讀取新的一幀數(shù)據(jù)做顯示。

這個幀緩存區(qū)是系統(tǒng)級別的,一般的開發(fā)者是無法讀取跟寫入的。但是如果是蘋果自身提供的錄制框架 ReplayKit 能夠直接讀取到已經(jīng)渲染好且將用于顯示器的幀,且這一過程不會影響渲染流程而造成掉幀,那就能減少一次用于提供給 ReplayKit 回調(diào)數(shù)據(jù)的渲染過程。

音頻

ReplayKit 能提供的音頻有兩種,分為麥克風錄制進來的音頻流,與當前響應的應用播放的音頻流。(下文將前者稱為 AudioMic,后者為 AudioApp)

可以通過下面的兩行代碼,來獲取音頻格式

CMAudioFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer);
const AudioStreamBasicDescription *description = CMAudioFormatDescriptionGetStreamBasicDescription(format);

AudioApp

AudioApp 會在不同的機型下有不一樣的聲道數(shù)。例如在 iPad 或 iPhone7 以下機型中,不具備雙聲道播放的設備,這時候 AudioApp 的數(shù)據(jù)就是單聲道,反之則是雙聲道。

采樣率在部分試過的機型里,都是 44100,但不排除在未測試過的機型會是其他的采樣率。

AudioMic

AudioMic 在測試過的機型里,采樣率為 32000,聲道數(shù)為單聲道。

音頻前處理

如果我們將 AudioApp 與 AudioMic 作為兩條音頻流去發(fā)送,那么流量肯定是大于一條音頻流的。我們?yōu)榱斯?jié)省一條音頻流的流量,就需要將這兩條音頻流做混音(融合)。

但是通過上述,我們不難看出,兩條音頻流的格式是不一樣的,而且不能保證隨著機型的不同,是不是會出現(xiàn)其他的格式。在測試的過程中還發(fā)現(xiàn) OS 版本的不同,每次回調(diào)給到的音頻數(shù)據(jù)長度也會出現(xiàn)變化。那么我們在對兩條音頻流做混音前,就需要進行格式統(tǒng)一,來應對 ReplayKit 給出的各種格式。所以我們采取了以下幾個重要的步驟:

if (channels == 1) {
    int16_t* intData = (int16_t*)dataPointer;
    int16_t newBuffer[totalSamples * 2];
            
    for (int i = 0; i < totalSamples; i++) {
        newBuffer[2 * i] = intData[i];
        newBuffer[2 * i + 1] = intData[i];
    }
    totalSamples *= 2;
    memcpy(dataPointer, newBuffer, sizeof(int16_t) * totalSamples);
    totalBytes *= 2;
    channels = 2;
}

無論是 AudioMic 還是 AudioApp,只要進來的流為單聲道,我們都將它轉(zhuǎn)化為雙聲道;

if (sampleRate != resampleRate) {
    int inDataSamplesPer10ms = sampleRate / 100;
    int outDataSamplesPer10ms = (int)resampleRate / 100;

    int16_t* intData = (int16_t*)dataPointer;

    switch (type) {
        case AudioTypeApp:
            totalSamples = resampleApp(intData, dataPointerSize, totalSamples,
                                       inDataSamplesPer10ms, outDataSamplesPer10ms, channels, sampleRate, (int)resampleRate);
            break;
        case AudioTypeMic:
            totalSamples = resampleMic(intData, dataPointerSize, totalSamples,
                                       inDataSamplesPer10ms, outDataSamplesPer10ms, channels, sampleRate, (int)resampleRate);
            break;
    }

    totalBytes = totalSamples * sizeof(int16_t);
}

無論是 AudioMic 還是 AudioApp,只要進來的流采樣率不為 48000,我們將它們重采樣為 48000;

memcpy(appAudio + appAudioIndex, dataPointer, totalBytes);
appAudioIndex += totalSamples;
memcpy(micAudio + micAudioIndex, dataPointer, totalBytes);
micAudioIndex += totalSamples;

通過第一步與第二步,我們保證了兩條音頻流都為同樣的音頻格式。但是由于 ReplayKit 是一次回調(diào)給到一種數(shù)據(jù)的,所以在混音前我們還得用兩個緩存區(qū)來存儲這兩條流數(shù)據(jù);

int64_t mixIndex = appAudioIndex > micAudioIndex ? micAudioIndex : appAudioIndex;
        
int16_t pushBuffer[appAudioIndex];
        
memcpy(pushBuffer, appAudio, appAudioIndex * sizeof(int16_t));
        
for (int i = 0; i < mixIndex; i ++) {
   pushBuffer[i] = (appAudio[i] + micAudio[i]) / 2;
}

ReplayKit 有選項是否開啟麥克風錄制,所以在關閉麥克風錄制的時候,我們就只有一條 AudioApp 音頻流。所以我們以這條流為主,去讀取 AudioMic 緩存區(qū)的數(shù)據(jù)長度,然后對比兩個緩存區(qū)的數(shù)據(jù)長度,以最小的數(shù)據(jù)長度為我們的混音長度。將混音長度的兩個緩存區(qū)里的數(shù)據(jù)做融合,得到混音后的數(shù)據(jù),寫入一個新的混音緩存區(qū)(或者直接寫入 AudioApp 緩存區(qū));

[AgoraAudioProcessing pushAudioFrame:(*unsigned* *char* *)pushBuffer
                                   withFrameSize:appAudioIndex * *sizeof*(int16_t)];

最后我們再將這段混音后的數(shù)據(jù)拷貝進 Agora RTC 的 C++ 錄制回調(diào)接口里,這時候就可以把麥克風錄制的聲音與應用播放的聲音傳輸?shù)竭h端了。

通過對音視頻流的處理,結合 Agora RTC SDK,我們就完成了一個屏幕分享直播場景的實現(xiàn)了。

以上就是如何在IOS上使用ReplayKit與RTC的詳細內(nèi)容,更多關于IOS上使用ReplayKit與RTC的資料請關注腳本之家其它相關文章!

相關文章

  • ios原生二維碼掃描與生成的實現(xiàn)教程

    ios原生二維碼掃描與生成的實現(xiàn)教程

    這篇文章主要給大家介紹了關于ios原生二維碼掃描與生成的相關資料,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • 總結iOS開發(fā)中的斷點續(xù)傳與實踐

    總結iOS開發(fā)中的斷點續(xù)傳與實踐

    本文先從斷點續(xù)傳問題開始,介紹斷點續(xù)傳概述和原理。接著結合筆者調(diào)研中嘗試的 AFHTTPRequestOpeartion,簡單分析源碼。最后分別基于 NSURLConnection,NSURLSessionDataTask 和 NSURLSessionDownloadTask 去實現(xiàn)應用重啟情況下的斷點續(xù)傳。下面一起來看看。
    2016-07-07
  • iOS密碼在進入后臺1小時后重新設置

    iOS密碼在進入后臺1小時后重新設置

    這篇文章主要介紹了iOS密碼在進入后臺1小時后重新設置的相關資料,需要的朋友可以參考下
    2017-08-08
  • iOS中大尺寸圖片的旋轉(zhuǎn)與縮放實例詳解

    iOS中大尺寸圖片的旋轉(zhuǎn)與縮放實例詳解

    圖片縮小旋轉(zhuǎn)是我們在開發(fā)中經(jīng)常會遇到的一個功能,下面這篇文章主要給大家介紹了關于iOS中大尺寸圖片的旋轉(zhuǎn)與縮放的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧
    2018-09-09
  • iOS用兩行代碼完美解決數(shù)據(jù)持久化

    iOS用兩行代碼完美解決數(shù)據(jù)持久化

    所謂的持久化,就是將數(shù)據(jù)保存到硬盤中,使得在應用程序或機器重啟后可以繼續(xù)訪問之前保存的數(shù)據(jù)。在iOS開發(fā)中,有很多數(shù)據(jù)持久化的方案,接下來我將嘗試著介紹一種巧妙的方法,用兩行代碼解決這個問題,一起來學習下。
    2016-08-08
  • iOS購物分類模塊的實現(xiàn)方案

    iOS購物分類模塊的實現(xiàn)方案

    這篇文章主要為大家詳細介紹了iOS購物分類模塊的實現(xiàn)方案,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-02-02
  • 關于iOS中的各種顏色設置總結大全(推薦)

    關于iOS中的各種顏色設置總結大全(推薦)

    這篇文章主要給大家介紹了關于iOS中顏色設置的相關資料,其中包括導航欄、狀態(tài)欄、Tabbar、Button、TextField、AttributedString和通用部分的顏色設置方法示例,對大家具有一定的參考學習價值,需要的朋友們下面隨著小編來一起看看吧。
    2017-09-09
  • iOS 指紋解鎖驗證TouchID功能

    iOS 指紋解鎖驗證TouchID功能

    這篇文章主要介紹了iOS 指紋解鎖驗證TouchID功能,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • IOS開發(fā)自定義Button的外觀和交互行為示例詳解

    IOS開發(fā)自定義Button的外觀和交互行為示例詳解

    這篇文章主要為大家介紹了IOS開發(fā)自定義Button的外觀和交互行為示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • 如何在iphon IOS設備上使用二維碼

    如何在iphon IOS設備上使用二維碼

    深度解析iPhone ios設備上使用二維碼是本文要介紹的內(nèi)容,二維碼是用某種特定的幾何圖形按一定規(guī)律在平面(二維方向上)分布的黑白相間的圖形記錄數(shù)據(jù)符號信息的。不多說,我們直接來腳本之家學習內(nèi)容詳解,感興趣的朋友一起來關注吧
    2015-08-08

最新評論