This commit is contained in:
Ali
2020-05-12 12:11:51 +04:00
parent b8bee2bd70
commit 8c9ecb800e
4 changed files with 386 additions and 201 deletions

View File

@@ -20,6 +20,7 @@ objc_library(
"-DWEBRTC_IOS",
"-DWEBRTC_MAC",
"-DWEBRTC_POSIX",
"-std=c++14",
],
includes = [
"PublicHeaders",

View File

@@ -25,6 +25,8 @@
#import "components/renderer/metal/RTCMTLVideoView.h"
#import "components/renderer/opengl/RTCEAGLVideoView.h"
#import "RtcConnection.h"
static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
static void voipLog(NSString* format, ...) {
@@ -38,82 +40,6 @@ static void voipLog(NSString* format, ...) {
}
}
@interface NativePeerConnectionDelegate : NSObject <RTCPeerConnectionDelegate> {
id<OngoingCallThreadLocalContextQueueWebrtcCustom> _queue;
void (^_didGenerateIceCandidate)(RTCIceCandidate *);
void (^_didChangeIceState)(OngoingCallStateWebrtcCustom);
}
@end
@implementation NativePeerConnectionDelegate
- (instancetype)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtcCustom>)queue didGenerateIceCandidate:(void (^)(RTCIceCandidate *))didGenerateIceCandidate didChangeIceState:(void (^)(OngoingCallStateWebrtcCustom))didChangeIceState {
self = [super init];
if (self != nil) {
_queue = queue;
_didGenerateIceCandidate = [didGenerateIceCandidate copy];
_didChangeIceState = [didChangeIceState copy];
}
return self;
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeSignalingState:(RTCSignalingState)stateChanged {
switch (stateChanged) {
case RTCSignalingStateStable:
_didChangeIceState(OngoingCallStateConnected);
break;
case RTCSignalingStateHaveLocalOffer:
_didChangeIceState(OngoingCallStateInitializing);
break;
case RTCSignalingStateHaveLocalPrAnswer:
_didChangeIceState(OngoingCallStateInitializing);
break;
case RTCSignalingStateHaveRemoteOffer:
_didChangeIceState(OngoingCallStateInitializing);
break;
case RTCSignalingStateHaveRemotePrAnswer:
_didChangeIceState(OngoingCallStateInitializing);
break;
default:
break;
}
voipLog(@"didChangeSignalingState: %d", stateChanged);
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didAddStream:(RTCMediaStream *)stream {
voipLog(@"Added stream: %@", stream.streamId);
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didRemoveStream:(RTCMediaStream *)stream {
}
- (void)peerConnectionShouldNegotiate:(RTCPeerConnection *)peerConnection {
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeIceConnectionState:(RTCIceConnectionState)newState {
voipLog(@"IceConnectionState: %d", newState);
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeIceGatheringState:(RTCIceGatheringState)newState {
voipLog(@"didChangeIceGatheringState: %d", newState);
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didGenerateIceCandidate:(RTCIceCandidate *)candidate {
[_queue dispatch:^{
_didGenerateIceCandidate(candidate);
}];
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didRemoveIceCandidates:(NSArray<RTCIceCandidate *> *)candidates {
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection
didOpenDataChannel:(RTCDataChannel *)dataChannel {
}
@end
@implementation OngoingCallConnectionDescriptionWebrtcCustom
- (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId ip:(NSString * _Nonnull)ip ipv6:(NSString * _Nonnull)ipv6 port:(int32_t)port peerTag:(NSData * _Nonnull)peerTag {
@@ -136,8 +62,6 @@ static void voipLog(NSString* format, ...) {
bool _isOutgoing;
void (^_sendSignalingData)(NSData * _Nonnull);
NativePeerConnectionDelegate *_peerConnectionDelegate;
OngoingCallNetworkTypeWebrtcCustom _networkType;
NSTimeInterval _callReceiveTimeout;
@@ -148,13 +72,11 @@ static void voipLog(NSString* format, ...) {
OngoingCallStateWebrtcCustom _state;
int32_t _signalBars;
RTCPeerConnectionFactory *_peerConnectionFactory;
RtcConnection *_connection;
RTCPeerConnection *_peerConnection;
RTCVideoCapturer *_videoCapturer;
RTCVideoTrack *_localVideoTrack;
RTCVideoTrack *_remoteVideoTrack;
//RTCVideoCapturer *_videoCapturer;
//RTCVideoTrack *_localVideoTrack;
//RTCVideoTrack *_remoteVideoTrack;
bool _receivedRemoteDescription;
@@ -222,54 +144,31 @@ static void voipLog(NSString* format, ...) {
[RTCAudioSession sharedInstance].useManualAudio = true;
[RTCAudioSession sharedInstance].isAudioEnabled = true;
RTCDefaultVideoDecoderFactory *decoderFactory = [[RTCDefaultVideoDecoderFactory alloc] init];
RTCDefaultVideoEncoderFactory *encoderFactory = [[RTCDefaultVideoEncoderFactory alloc] init];
_peerConnectionFactory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory:encoderFactory decoderFactory:decoderFactory];
NSArray<NSString *> *iceServers = @[
@"stun:stun.l.google.com:19302"
];
RTCConfiguration *config = [[RTCConfiguration alloc] init];
config.iceServers = @[
[[RTCIceServer alloc] initWithURLStrings:iceServers]
];
config.sdpSemantics = RTCSdpSemanticsUnifiedPlan;
config.continualGatheringPolicy = RTCContinualGatheringPolicyGatherContinually;
RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:nil optionalConstraints:@{ @"DtlsSrtpKeyAgreement": kRTCMediaConstraintsValueTrue }];
__weak OngoingCallThreadLocalContextWebrtcCustom *weakSelf = self;
_peerConnectionDelegate = [[NativePeerConnectionDelegate alloc] initWithQueue:_queue didGenerateIceCandidate:^(RTCIceCandidate *iceCandidate) {
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf sendCandidate:iceCandidate];
} didChangeIceState: ^(OngoingCallStateWebrtcCustom state) {
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
if (strongSelf.stateChanged) {
strongSelf.stateChanged(state);
}
_connection = [[RtcConnection alloc] initWithDiscoveredIceCandidate:^(NSString *sdp, int mLineIndex, NSString *sdpMid) {
[queue dispatch:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf sendCandidateWithSdp:sdp mLineIndex:mLineIndex sdpMid:sdpMid];
}];
} connectionStateChanged:^(bool isConnected) {
[queue dispatch:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
if (strongSelf.stateChanged) {
strongSelf.stateChanged(isConnected ? OngoingCallStateConnected : OngoingCallStateInitializing);
}
}];
}];
_peerConnection = [_peerConnectionFactory peerConnectionWithConfiguration:config constraints:constraints delegate:_peerConnectionDelegate];
//RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:nil optionalConstraints:@{ @"DtlsSrtpKeyAgreement": kRTCMediaConstraintsValueTrue }];
NSString *streamId = @"stream";
RTCMediaConstraints *audioConstrains = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:nil optionalConstraints:nil];
RTCAudioSource *audioSource = [_peerConnectionFactory audioSourceWithConstraints:audioConstrains];
RTCAudioTrack * _Nonnull audioTrack = [_peerConnectionFactory audioTrackWithSource:audioSource trackId:@"audio0"];
[_peerConnection addTrack:audioTrack streamIds:@[streamId]];
RTCVideoSource *videoSource = [_peerConnectionFactory videoSource];
/*RTCVideoSource *videoSource = [_peerConnectionFactory videoSource];
#if TARGET_OS_SIMULATOR
_videoCapturer = [[RTCFileVideoCapturer alloc] initWithDelegate:videoSource];
@@ -278,31 +177,25 @@ static void voipLog(NSString* format, ...) {
#endif
_localVideoTrack = [_peerConnectionFactory videoTrackWithSource:videoSource trackId:@"video0"];
[_peerConnection addTrack:_localVideoTrack streamIds:@[streamId]];
[_peerConnection addTrack:_localVideoTrack streamIds:@[streamId]];*/
if (isOutgoing) {
id<OngoingCallThreadLocalContextQueueWebrtcCustom> queue = _queue;
NSDictionary *mediaConstraints = @{
kRTCMediaConstraintsOfferToReceiveAudio: kRTCMediaConstraintsValueTrue,
kRTCMediaConstraintsOfferToReceiveVideo: kRTCMediaConstraintsValueTrue
};
RTCMediaConstraints *connectionConstraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mediaConstraints optionalConstraints:nil];
__weak OngoingCallThreadLocalContextWebrtcCustom *weakSelf = self;
[_peerConnection offerForConstraints:connectionConstraints completionHandler:^(RTCSessionDescription * _Nullable sdp, NSError * _Nullable error) {
[_connection getOffer:^(NSString *sdp, NSString *type) {
[queue dispatch:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf->_peerConnection setLocalDescription:sdp completionHandler:^(__unused NSError * _Nullable error) {
[strongSelf->_connection setLocalDescription:sdp type:type completion:^{
[queue dispatch:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf tryAdvertising:sdp];
[strongSelf tryAdvertising:sdp type:type];
}];
}];
}];
@@ -318,24 +211,24 @@ static void voipLog(NSString* format, ...) {
assert([_queue isCurrent]);
}
- (void)tryAdvertising:(RTCSessionDescription *)sessionDescription {
- (void)tryAdvertising:(NSString *)sdp type:(NSString *)type {
if (_receivedRemoteDescription) {
return;
}
[self sendSdp:sessionDescription];
[self sendSdp:sdp type:type];
__weak OngoingCallThreadLocalContextWebrtcCustom *weakSelf = self;
[_queue dispatchAfter:1.0 block:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf tryAdvertising:sessionDescription];
[strongSelf tryAdvertising:sdp type:type];
}];
}
- (void)startLocalVideo {
if (_videoCapturer == nil || ![_videoCapturer isKindOfClass:[RTCCameraVideoCapturer class]]) {
/*if (_videoCapturer == nil || ![_videoCapturer isKindOfClass:[RTCCameraVideoCapturer class]]) {
return;
}
RTCCameraVideoCapturer *cameraCapturer = (RTCCameraVideoCapturer *)_videoCapturer;
@@ -383,7 +276,7 @@ static void voipLog(NSString* format, ...) {
}
[cameraCapturer startCaptureWithDevice:frontCamera format:bestFormat fps:27 completionHandler:^(NSError * _Nonnull error) {
}];
}];*/
}
- (bool)needRate {
@@ -391,11 +284,11 @@ static void voipLog(NSString* format, ...) {
}
- (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
if ([_videoCapturer isKindOfClass:[RTCCameraVideoCapturer class]]) {
/*if ([_videoCapturer isKindOfClass:[RTCCameraVideoCapturer class]]) {
RTCCameraVideoCapturer *cameraCapturer = (RTCCameraVideoCapturer *)_videoCapturer;
[cameraCapturer stopCapture];
}
[_peerConnection close];
}*/
[_connection close];
if (completion) {
completion(@"", 0, 0, 0, 0);
}
@@ -414,30 +307,24 @@ static void voipLog(NSString* format, ...) {
return [NSData data];
}
- (void)sendSdp:(RTCSessionDescription *)rtcSdp {
- (void)sendSdp:(NSString *)sdp type:(NSString *)type {
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
json[@"messageType"] = @"sessionDescription";
json[@"sdp"] = rtcSdp.sdp;
if (rtcSdp.type == RTCSdpTypeOffer) {
json[@"type"] = @"offer";
} else if (rtcSdp.type == RTCSdpTypePrAnswer) {
json[@"type"] = @"prAnswer";
} else if (rtcSdp.type == RTCSdpTypeAnswer) {
json[@"type"] = @"answer";
}
json[@"sdp"] = sdp;
json[@"type"] = type;
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
if (data != nil) {
_sendSignalingData(data);
}
}
- (void)sendCandidate:(RTCIceCandidate *)rtcIceCandidate {
- (void)sendCandidateWithSdp:(NSString *)sdp mLineIndex:(int)mLineIndex sdpMid:(NSString *)sdpMid {
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
json[@"messageType"] = @"iceCandidate";
json[@"sdp"] = rtcIceCandidate.sdp;
json[@"mLineIndex"] = @(rtcIceCandidate.sdpMLineIndex);
if (rtcIceCandidate.sdpMid != nil) {
json[@"sdpMid"] = rtcIceCandidate.sdpMid;
json[@"sdp"] = sdp;
json[@"mLineIndex"] = @(mLineIndex);
if (sdpMid != nil) {
json[@"sdpMid"] = sdpMid;
}
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
if (data != nil) {
@@ -466,50 +353,31 @@ static void voipLog(NSString* format, ...) {
return;
}
RTCSdpType type;
if ([typeString isEqualToString:@"offer"]) {
type = RTCSdpTypeOffer;
} else if ([typeString isEqualToString:@"prAnswer"]) {
type = RTCSdpTypePrAnswer;
} else if ([typeString isEqualToString:@"answer"]) {
type = RTCSdpTypeAnswer;
} else {
return;
}
if (_receivedRemoteDescription) {
return;
}
_receivedRemoteDescription = true;
RTCSessionDescription *sessionDescription = [[RTCSessionDescription alloc] initWithType:type sdp:sdp];
NSDictionary *mediaConstraints = @{
kRTCMediaConstraintsOfferToReceiveAudio: kRTCMediaConstraintsValueTrue,
kRTCMediaConstraintsOfferToReceiveVideo: kRTCMediaConstraintsValueTrue
};
RTCMediaConstraints *connectionConstraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mediaConstraints optionalConstraints:nil];
[_peerConnection setRemoteDescription:sessionDescription completionHandler:^(__unused NSError * _Nullable error) {
[_connection setRemoteDescription:sdp type:typeString completion:^{
}];
if (!_isOutgoing) {
__weak OngoingCallThreadLocalContextWebrtcCustom *weakSelf = self;
[_peerConnection answerForConstraints:connectionConstraints completionHandler:^(RTCSessionDescription * _Nullable sdp, NSError * _Nullable error) {
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
id<OngoingCallThreadLocalContextQueueWebrtcCustom> queue = strongSelf->_queue;
[strongSelf->_peerConnection setLocalDescription:sdp completionHandler:^(__unused NSError * _Nullable error) {
[queue dispatch:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf sendSdp:sdp];
id<OngoingCallThreadLocalContextQueueWebrtcCustom> queue = _queue;
[_connection getAnswer:^(NSString *sdp, NSString *type) {
[queue dispatch:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf->_connection setLocalDescription:sdp type:type completion:^{
[queue dispatch:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf sendSdp:sdp type:type];
}];
}];
}];
}];
@@ -531,26 +399,24 @@ static void voipLog(NSString* format, ...) {
sdpMid = sdpMidString;
}
RTCIceCandidate *iceCandidate = [[RTCIceCandidate alloc] initWithSdp:sdp sdpMLineIndex:[mLineIndex intValue] sdpMid:sdpMid];
voipLog(@"didReceiveIceCandidate: %@", iceCandidate);
[_peerConnection addIceCandidate:iceCandidate];
[_connection addIceCandidateWithSdp:sdp sdpMLineIndex:[mLineIndex intValue] sdpMid:sdpMid];
}
}
- (void)setIsMuted:(bool)isMuted {
for (RTCRtpTransceiver *transceiver in _peerConnection.transceivers) {
/*for (RTCRtpTransceiver *transceiver in _peerConnection.transceivers) {
if ([transceiver isKindOfClass:[RTCAudioTrack class]]) {
RTCAudioTrack *audioTrack = (RTCAudioTrack *)transceiver;
[audioTrack setIsEnabled:!isMuted];
}
}
}*/
}
- (void)setNetworkType:(OngoingCallNetworkTypeWebrtcCustom)networkType {
}
- (void)getRemoteCameraView:(void (^_Nonnull)(UIView * _Nullable))completion {
if (_remoteVideoTrack == nil) {
/*if (_remoteVideoTrack == nil) {
for (RTCRtpTransceiver *transceiver in _peerConnection.transceivers) {
if (transceiver.mediaType == RTCRtpMediaTypeVideo && [transceiver.receiver.track isKindOfClass:[RTCVideoTrack class]]) {
_remoteVideoTrack = (RTCVideoTrack *)transceiver.receiver.track;
@@ -571,7 +437,7 @@ static void voipLog(NSString* format, ...) {
[remoteVideoTrack addRenderer:remoteRenderer];
completion(remoteRenderer);
#endif
});
});*/
}
@end

View File

@@ -0,0 +1,20 @@
#ifndef RTCCONNECTION_H
#define RTCCONNECTION_H
#import <Foundation/Foundation.h>
@interface RtcConnection : NSObject
- (instancetype)initWithDiscoveredIceCandidate:(void (^)(NSString *, int, NSString *))discoveredIceCandidate connectionStateChanged:(void (^)(bool))connectionStateChanged;
- (void)close;
- (void)getOffer:(void (^)(NSString *, NSString *))completion;
- (void)getAnswer:(void (^)(NSString *, NSString *))completion;
- (void)setLocalDescription:(NSString *)serializedDescription type:(NSString *)type completion:(void (^)())completion;
- (void)setRemoteDescription:(NSString *)serializedDescription type:(NSString *)type completion:(void (^)())completion;
- (void)addIceCandidateWithSdp:(NSString *)sdp sdpMLineIndex:(int)sdpMLineIndex sdpMid:(NSString *)sdpMid;
@end
#endif

View File

@@ -0,0 +1,298 @@
#import "RtcConnection.h"
#include <memory>
#include "api/scoped_refptr.h"
#include "rtc_base/thread.h"
#include "api/peer_connection_interface.h"
#include "api/task_queue/default_task_queue_factory.h"
#include "media/engine/webrtc_media_engine.h"
#include "sdk/objc/native/api/audio_device_module.h"
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "sdk/objc/components/video_codec/RTCVideoEncoderFactoryH264.h"
#include "sdk/objc/components/video_codec/RTCVideoDecoderFactoryH264.h"
#include "sdk/objc/native/api/video_encoder_factory.h"
#include "sdk/objc/native/api/video_decoder_factory.h"
#include "api/rtc_event_log/rtc_event_log_factory.h"
#include "sdk/media_constraints.h"
#include "api/peer_connection_interface.h"
class PeerConnectionObserverImpl : public webrtc::PeerConnectionObserver {
private:
void (^_discoveredIceCandidate)(NSString *, int, NSString *);
void (^_connectionStateChanged)(bool);
public:
PeerConnectionObserverImpl(void (^discoveredIceCandidate)(NSString *, int, NSString *), void (^connectionStateChanged)(bool)) {
_discoveredIceCandidate = [discoveredIceCandidate copy];
_connectionStateChanged = [connectionStateChanged copy];
}
virtual ~PeerConnectionObserverImpl() {
_discoveredIceCandidate = nil;
_connectionStateChanged = nil;
}
virtual void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) {
bool isConnected = false;
if (new_state == webrtc::PeerConnectionInterface::SignalingState::kStable) {
isConnected = true;
}
_connectionStateChanged(isConnected);
}
virtual void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
}
virtual void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
}
virtual void OnDataChannel(
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
}
virtual void OnRenegotiationNeeded() {
}
virtual void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) {
}
virtual void OnStandardizedIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) {
}
virtual void OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState new_state) {
}
virtual void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) {
}
virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) {
std::string sdp;
candidate->ToString(&sdp);
NSString *sdpString = [NSString stringWithUTF8String:sdp.c_str()];
NSString *sdpMidString = [NSString stringWithUTF8String:candidate->sdp_mid().c_str()];
_discoveredIceCandidate(sdpString, candidate->sdp_mline_index(), sdpMidString);
}
virtual void OnIceCandidateError(const std::string& host_candidate, const std::string& url, int error_code, const std::string& error_text) {
}
virtual void OnIceCandidateError(const std::string& address,
int port,
const std::string& url,
int error_code,
const std::string& error_text) {
}
virtual void OnIceCandidatesRemoved(const std::vector<cricket::Candidate>& candidates) {
}
virtual void OnIceConnectionReceivingChange(bool receiving) {
}
virtual void OnIceSelectedCandidatePairChanged(const cricket::CandidatePairChangeEvent& event) {
}
virtual void OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& streams) {
}
virtual void OnTrack(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) {
}
virtual void OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) {
}
virtual void OnInterestingUsage(int usage_pattern) {
}
};
class CreateSessionDescriptionObserverImpl : public webrtc::CreateSessionDescriptionObserver {
private:
void (^_completion)(NSString *, NSString *);
public:
CreateSessionDescriptionObserverImpl(void (^completion)(NSString *, NSString *)) {
_completion = [completion copy];
}
~CreateSessionDescriptionObserverImpl() override {
_completion = nil;
}
virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) override {
if (desc) {
NSString *typeString = [NSString stringWithUTF8String:desc->type().c_str()];
std::string sdp;
desc->ToString(&sdp);
NSString *serializedString = [NSString stringWithUTF8String:sdp.c_str()];
if (_completion && typeString && serializedString) {
_completion(serializedString, typeString);
}
}
_completion = nil;
}
virtual void OnFailure(webrtc::RTCError error) override {
_completion = nil;
}
};
class SetSessionDescriptionObserverImpl : public webrtc::SetSessionDescriptionObserver {
private:
void (^_completion)();
public:
SetSessionDescriptionObserverImpl(void (^completion)()) {
_completion = [completion copy];
}
~SetSessionDescriptionObserverImpl() override {
_completion = nil;
}
virtual void OnSuccess() override {
if (_completion) {
_completion();
}
_completion = nil;
}
virtual void OnFailure(webrtc::RTCError error) override {
_completion = nil;
}
};
@interface RtcConnection () {
void (^_discoveredIceCandidate)(NSString *, int, NSString *);
void (^_connectionStateChanged)(bool);
std::unique_ptr<rtc::Thread> _networkThread;
std::unique_ptr<rtc::Thread> _workerThread;
std::unique_ptr<rtc::Thread> _signalingThread;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> _nativeFactory;
std::unique_ptr<PeerConnectionObserverImpl> _observer;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
std::unique_ptr<webrtc::MediaConstraints> _nativeConstraints;
bool _hasStartedRtcEventLog;
}
@end
@implementation RtcConnection
- (instancetype)initWithDiscoveredIceCandidate:(void (^)(NSString *, int, NSString *))discoveredIceCandidate connectionStateChanged:(void (^)(bool))connectionStateChanged {
self = [super init];
if (self != nil) {
_discoveredIceCandidate = [discoveredIceCandidate copy];
_connectionStateChanged = [connectionStateChanged copy];
_networkThread = rtc::Thread::CreateWithSocketServer();
_networkThread->SetName("network_thread", _networkThread.get());
BOOL result = _networkThread->Start();
assert(result);
_workerThread = rtc::Thread::Create();
_workerThread->SetName("worker_thread", _workerThread.get());
result = _workerThread->Start();
assert(result);
_signalingThread = rtc::Thread::Create();
_signalingThread->SetName("signaling_thread", _signalingThread.get());
result = _signalingThread->Start();
assert(result);
webrtc::PeerConnectionFactoryDependencies dependencies;
dependencies.network_thread = _networkThread.get();
dependencies.worker_thread = _workerThread.get();
dependencies.signaling_thread = _signalingThread.get();
dependencies.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory();
cricket::MediaEngineDependencies media_deps;
media_deps.adm = webrtc::CreateAudioDeviceModule();
media_deps.task_queue_factory = dependencies.task_queue_factory.get();
media_deps.audio_encoder_factory = webrtc::CreateBuiltinAudioEncoderFactory();
media_deps.audio_decoder_factory = webrtc::CreateBuiltinAudioDecoderFactory();
media_deps.video_encoder_factory = webrtc::ObjCToNativeVideoEncoderFactory([[RTCVideoEncoderFactoryH264 alloc] init]);
media_deps.video_decoder_factory = webrtc::ObjCToNativeVideoDecoderFactory([[RTCVideoDecoderFactoryH264 alloc] init]);
media_deps.audio_processing = webrtc::AudioProcessingBuilder().Create();
dependencies.media_engine = cricket::CreateMediaEngine(std::move(media_deps));
dependencies.call_factory = webrtc::CreateCallFactory();
dependencies.event_log_factory =
std::make_unique<webrtc::RtcEventLogFactory>(dependencies.task_queue_factory.get());
dependencies.network_controller_factory = nil;
dependencies.media_transport_factory = nil;
_nativeFactory = webrtc::CreateModularPeerConnectionFactory(std::move(dependencies));
webrtc::PeerConnectionInterface::RTCConfiguration config;
config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
config.continual_gathering_policy = webrtc::PeerConnectionInterface::ContinualGatheringPolicy::GATHER_CONTINUALLY;
webrtc::PeerConnectionInterface::IceServer iceServer;
iceServer.uri = "stun:stun.l.google.com:19302";
config.servers.push_back(iceServer);
_observer.reset(new PeerConnectionObserverImpl(_discoveredIceCandidate, _connectionStateChanged));
_peerConnection = _nativeFactory->CreatePeerConnection(config, nullptr, nullptr, _observer.get());
cricket::AudioOptions options;
rtc::scoped_refptr<webrtc::AudioSourceInterface> audioSource = _nativeFactory->CreateAudioSource(options);
rtc::scoped_refptr<webrtc::AudioTrackInterface> track = _nativeFactory->CreateAudioTrack("audio0", audioSource);
std::vector<std::string> streamIds;
streamIds.push_back("stream");
_peerConnection->AddTrack(track, streamIds);
}
return self;
}
- (void)close {
_peerConnection->Close();
}
- (void)getOffer:(void (^)(NSString *, NSString *))completion {
webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
options.offer_to_receive_audio = 1;
options.offer_to_receive_video = 1;
rtc::scoped_refptr<CreateSessionDescriptionObserverImpl> observer(new rtc::RefCountedObject<CreateSessionDescriptionObserverImpl>(completion));
_peerConnection->CreateOffer(observer, options);
}
- (void)getAnswer:(void (^)(NSString *, NSString *))completion {
webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
options.offer_to_receive_audio = 1;
options.offer_to_receive_video = 1;
rtc::scoped_refptr<CreateSessionDescriptionObserverImpl> observer(new rtc::RefCountedObject<CreateSessionDescriptionObserverImpl>(completion));
_peerConnection->CreateAnswer(observer, options);
}
- (void)setLocalDescription:(NSString *)serializedDescription type:(NSString *)type completion:(void (^)())completion {
webrtc::SdpParseError error;
webrtc::SessionDescriptionInterface *sessionDescription = webrtc::CreateSessionDescription(type.UTF8String, serializedDescription.UTF8String, &error);
if (sessionDescription != nullptr) {
rtc::scoped_refptr<SetSessionDescriptionObserverImpl> observer(new rtc::RefCountedObject<SetSessionDescriptionObserverImpl>(completion));
_peerConnection->SetLocalDescription(observer, sessionDescription);
}
}
- (void)setRemoteDescription:(NSString *)serializedDescription type:(NSString *)type completion:(void (^)())completion {
webrtc::SdpParseError error;
webrtc::SessionDescriptionInterface *sessionDescription = webrtc::CreateSessionDescription(type.UTF8String, serializedDescription.UTF8String, &error);
if (sessionDescription != nullptr) {
rtc::scoped_refptr<SetSessionDescriptionObserverImpl> observer(new rtc::RefCountedObject<SetSessionDescriptionObserverImpl>(completion));
_peerConnection->SetRemoteDescription(observer, sessionDescription);
}
}
- (void)addIceCandidateWithSdp:(NSString *)sdp sdpMLineIndex:(int)sdpMLineIndex sdpMid:(NSString *)sdpMid {
webrtc::SdpParseError error;
webrtc::IceCandidateInterface *iceCandidate = webrtc::CreateIceCandidate(sdpMid == nil ? "" : sdpMid.UTF8String, sdpMLineIndex, sdp.UTF8String, &error);
if (iceCandidate != nullptr) {
std::unique_ptr<webrtc::IceCandidateInterface> nativeCandidate = std::unique_ptr<webrtc::IceCandidateInterface>(iceCandidate);
_peerConnection->AddIceCandidate(std::move(nativeCandidate), [](auto error) {
});
}
}
@end