前言
本文主要是整理了使用WebRTC做音視頻通訊時的各知識點及問題點,有理解不足和不到位的地方也歡迎指正, 對于你感興趣的部分可以選擇性觀看,
WebRTC的初始化
在使用WebRTC的庫之前,需要對WebRTC進行初始化, 用到的代碼如下:
RTCInitializeSSL();
轉定義后可以看到方法的宣告:
/**
* Initialize and clean up the SSL library. Failure is fatal. These call the
* corresponding functions in webrtc/rtc_base/ssladapter.h.
*/
RTC_EXTERN BOOL RTCInitializeSSL(void);
RTC_EXTERN BOOL RTCCleanupSSL(void);
Initialize and clean up the SSL library. Failure is fatal. 初始化SSL庫,失敗是致命的,
函式回傳的是一個布爾型別
, 表示初始化的結果, 如果失敗,則不能繼續使用其他特性,這是使用WebRTC的前提
PeerConnection工廠的創建
在 WebRTC Native 層,factory 可以說是 “萬物的根源”,像 RTCVideoSource
、RTCVideoTrack
、RTCPeerConnection
這些型別的物件,都需要通過 factory 來創建
[RTCPeerConnectionFactory initialize];
//如果點對點工廠為空
if (!factory)
{
RTCDefaultVideoDecoderFactory* decoderFactory = [[RTCDefaultVideoDecoderFactory alloc] init];
RTCDefaultVideoEncoderFactory* encoderFactory = [[RTCDefaultVideoEncoderFactory alloc] init];
NSArray* codecs = [encoderFactory supportedCodecs];
[encoderFactory setPreferredCodec:codecs[2]];
factory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory: encoderFactory
decoderFactory: decoderFactory];
}
- 首先要呼叫
RTCPeerConnectionFactory
類的initialize
方法進行初始化;- 然后創建 factory 物件,需要注意的是,在創建 factory 物件時,傳入了兩個引數:一個是默認的
編碼器
;一個是默認的解碼器
,我們可以通過修改這兩個引數來達到使用不同編解碼器的目的,
獲取本地視頻流
在獲取視頻之前,我們首先要選擇使用哪個視頻設備采集資料,在WebRTC中,我們可以通過RTCCameraVideoCapture
類獲取所有的視頻設備,如下所示:
NSArray<AVCaptureDevice*>* devices = [RTCCameraVideoCapture captureDevices];
AVCaptureDevice* device = devices[0];
通過上面兩行代碼,我們就拿到了視頻設備中的第一個設備,當然,光有設備還不行,我們還要清楚從設備中采集的資料放到哪里了,這樣我們才能將其展示出來,WebRTC 為我們提供了一個專門的類,即 RTCVideoSource
, 它有兩層含義:
- 一是表明它是一個
視頻源
,當我們要展示視頻的時候,就從這里獲取資料; - 另一方面,它也是一個終點,即,當我們從視頻設備采集到視頻資料時,要交給它暫存起來,
RTCVideoSource* videoSource = [factory videoSource];
除此之外,為了能更方便的控制視頻設備,WebRTC 提供了一個專門用于操作設備的類,即 RTCCameraVideoCapture
,通過它,我們就可以自如的控制視頻設備
了,
RTCVideoSource* videoSource = [factory videoSource];
capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:videoSource];
[capture startCaptureWithDevice:device
format:format
fps:fps];
現在已經可以通過RTCCameraVideoCapture
類控制視頻設備來采集視頻了, 那如何獲取采集的視頻流呢 ? 上面的代碼我們已經將視頻采集到視頻源RTCVideoSource
了, 那RTCVideoSource
就是我們的視頻流
嗎 ?顯然不是, 這里要提到的是WebRTC三大物件中的其中一個物件RTCMediaStream
,它才是我們說的視頻流,那它和RTCVideoSource之間是什么關系呢,之間是如何建立關聯的呢?
//創建本地流
_localStream = [_factory mediaStreamWithStreamId:@"ARDAMS"];
//獲取資料源
_localVideoSource = [_factory videoSource];
//音頻
RTCAudioTrack * audioTrack = [_factory audioTrackWithTrackId:@"ARDAMSa0"];
//視頻
RTCVideoTrack *videoTrack = [_factory videoTrackWithSource:_localVideoSource trackId:@"ARDAMSv0"];
//將audioTrack、videoTrack添加到流
[_localStream addAudioTrack:audioTrack];
[_localStream addVideoTrack:videoTrack];
//拿到capture物件
RTCCameraVideoCapturer * capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:_localVideoSource];
原來是通過一個中間物件RTCVideoTrack
建立的關聯,
RTCCameraVideoCapturer
將采集的視頻資料
交給RTCVideoSource
- 通過
RTCVideoSource
創建RTCVideoTrack
RTCMediaStream
添加視頻軌 videoTrack,
獲取本地流完整的代碼如下:
if (!_localStream) {
NSArray<AVCaptureDevice *> *captureDevices = [RTCCameraVideoCapturer captureDevices];
AVCaptureDevice * device = captureDevices[0];
//檢測攝像頭權限
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)
{
NSLog(@"相機訪問受限");
//TODO:
if ([self.delegate respondsToSelector:@selector(webRTCClient:setLocalStream:)]) {
[self.delegate webRTCClient:self setLocalStream:nil];
}
} else {
if (device) {
//創建本地流
_localStream = [_factory mediaStreamWithStreamId:@"ARDAMS"];
//獲取資料源
_localVideoSource = [_factory videoSource];
//音頻
RTCAudioTrack * audioTrack = [_factory audioTrackWithTrackId:@"ARDAMSa0"];
//視頻
RTCVideoTrack *videoTrack = [_factory videoTrackWithSource:_localVideoSource trackId:@"ARDAMSv0"];
//將audioTrack、videoTrack添加到流
[_localStream addAudioTrack:audioTrack];
[_localStream addVideoTrack:videoTrack];
//拿到capture物件
RTCCameraVideoCapturer * capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:_localVideoSource];
//format , fps
AVCaptureDeviceFormat * format = [[RTCCameraVideoCapturer supportedFormatsForDevice:device] lastObject];
CGFloat fps = [[format videoSupportedFrameRateRanges] firstObject].maxFrameRate;
//開始采集
_videoCapture = capture;
[capture startCaptureWithDevice:device format:format fps:fps completionHandler:^(NSError * error) {
NSLog(@"startCaptureWithDevice---:%@",error);
dispatch_async(dispatch_get_main_queue(), ^{
//展示預覽
if ([self.delegate respondsToSelector:@selector(webRTCClient:setLocalStream:)]) {
[self.delegate webRTCClient:self setLocalStream:self.localStream];
}
});
}];
}
else
{
NSLog(@"該設備不能打開攝像頭");
if ([self.delegate respondsToSelector:@selector(webRTCClient:setLocalStream:)]) {
[self.delegate webRTCClient:self setLocalStream:nil];
}
} //end device
}//end auth
}
PeerConnection物件的創建
RTCPeerConnection
是WebRTC用于構建點對點之間穩定、高效的流傳輸
的組件,是WebRTC三大核心組件之一, 使用它我們可以建立一條與遠端通話的音視頻資料傳輸通道
,
上面提到了PeerConnection工廠 RTCPeerConnectionFactory
, RTCPeerConnection
的實體就是通過此工廠來創建.
if (!ICEServers) {
ICEServers = [NSMutableArray array];
[ICEServers addObject:[self defaultSTUNServer]];
}
RTCConfiguration* configuration = [[RTCConfiguration alloc] init];
[configuration setIceServers:ICEServers];
RTCPeerConnection* conn = [factory
peerConnectionWithConfiguration:configuration
constraints:[self defaultPeerConnContraints]
delegate:self];
- (RTCMediaConstraints *)defaultPeerConnContraints
{
RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:@{kRTCMediaConstraintsOfferToReceiveAudio:kRTCMediaConstraintsValueTrue,kRTCMediaConstraintsOfferToReceiveVideo:kRTCMediaConstraintsValueTrue} optionalConstraints:nil];
return constraints;
}
對于 iOS 的 RTCPeerConnection
物件有三個引數:
- 第一個,是
RTCConfiguration
型別的物件,該物件中最重要的一個欄位是iceservers
,它里邊存放了stun/turn
服務器地址,其主要作用是用于NAT穿越
, - 第二個引數,是
RTCMediaConstraints
型別物件,也就是對RTCPeerConnection
的限制
,如,是否接收視頻資料?是否接收音頻資料?如果要與瀏覽器互通還要開啟DtlsSrtpKeyAgreement
選項, - 第三個引數,是
委托
型別,相當于給RTCPeerConnection
設定一個觀察者
,這樣RTCPeerConnection
可以將一個狀態/資訊
通過它通知給觀察者,但它并不屬于觀察者模式,這一點大家一定要清楚,
更多內容
- PeerConnection物件添加媒體流
- PeerConnection物件的信令狀態
- PeerConnection物件獲取sdp并設定
- 獲取Candidate并添加到PeerConnection物件
- PeerConnection物件的幾種狀態
- 多點連接建立的流程
詳見: https://zhanglei.blog.csdn.net/article/details/122539459
本文來自博客園,作者:reyzhang,轉載請注明原文鏈接:https://www.cnblogs.com/reyzhang/p/16198230.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/469950.html
標籤:iOS