1*d9f75844SAndroid Build Coastguard Worker/* 2*d9f75844SAndroid Build Coastguard Worker * Copyright 2015 The WebRTC project authors. All Rights Reserved. 3*d9f75844SAndroid Build Coastguard Worker * 4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license 5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source 6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found 7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may 8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree. 9*d9f75844SAndroid Build Coastguard Worker */ 10*d9f75844SAndroid Build Coastguard Worker 11*d9f75844SAndroid Build Coastguard Worker#import "RTCVideoTrack+Private.h" 12*d9f75844SAndroid Build Coastguard Worker 13*d9f75844SAndroid Build Coastguard Worker#import "RTCMediaStreamTrack+Private.h" 14*d9f75844SAndroid Build Coastguard Worker#import "RTCPeerConnectionFactory+Private.h" 15*d9f75844SAndroid Build Coastguard Worker#import "RTCVideoSource+Private.h" 16*d9f75844SAndroid Build Coastguard Worker#import "api/RTCVideoRendererAdapter+Private.h" 17*d9f75844SAndroid Build Coastguard Worker#import "helpers/NSString+StdString.h" 18*d9f75844SAndroid Build Coastguard Worker 19*d9f75844SAndroid Build Coastguard Worker@implementation RTC_OBJC_TYPE (RTCVideoTrack) { 20*d9f75844SAndroid Build Coastguard Worker rtc::Thread *_workerThread; 21*d9f75844SAndroid Build Coastguard Worker NSMutableArray *_adapters /* accessed on _workerThread */; 22*d9f75844SAndroid Build Coastguard Worker} 23*d9f75844SAndroid Build Coastguard Worker 24*d9f75844SAndroid Build Coastguard Worker@synthesize source = _source; 25*d9f75844SAndroid Build Coastguard Worker 26*d9f75844SAndroid Build Coastguard Worker- (instancetype)initWithFactory:(RTC_OBJC_TYPE(RTCPeerConnectionFactory) *)factory 27*d9f75844SAndroid Build Coastguard Worker source:(RTC_OBJC_TYPE(RTCVideoSource) *)source 28*d9f75844SAndroid Build Coastguard Worker trackId:(NSString *)trackId { 29*d9f75844SAndroid Build Coastguard Worker NSParameterAssert(factory); 30*d9f75844SAndroid Build Coastguard Worker NSParameterAssert(source); 31*d9f75844SAndroid Build Coastguard Worker NSParameterAssert(trackId.length); 32*d9f75844SAndroid Build Coastguard Worker std::string nativeId = [NSString stdStringForString:trackId]; 33*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<webrtc::VideoTrackInterface> track = 34*d9f75844SAndroid Build Coastguard Worker factory.nativeFactory->CreateVideoTrack(nativeId, source.nativeVideoSource.get()); 35*d9f75844SAndroid Build Coastguard Worker if (self = [self initWithFactory:factory nativeTrack:track type:RTCMediaStreamTrackTypeVideo]) { 36*d9f75844SAndroid Build Coastguard Worker _source = source; 37*d9f75844SAndroid Build Coastguard Worker } 38*d9f75844SAndroid Build Coastguard Worker return self; 39*d9f75844SAndroid Build Coastguard Worker} 40*d9f75844SAndroid Build Coastguard Worker 41*d9f75844SAndroid Build Coastguard Worker- (instancetype)initWithFactory:(RTC_OBJC_TYPE(RTCPeerConnectionFactory) *)factory 42*d9f75844SAndroid Build Coastguard Worker nativeTrack: 43*d9f75844SAndroid Build Coastguard Worker (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeMediaTrack 44*d9f75844SAndroid Build Coastguard Worker type:(RTCMediaStreamTrackType)type { 45*d9f75844SAndroid Build Coastguard Worker NSParameterAssert(factory); 46*d9f75844SAndroid Build Coastguard Worker NSParameterAssert(nativeMediaTrack); 47*d9f75844SAndroid Build Coastguard Worker NSParameterAssert(type == RTCMediaStreamTrackTypeVideo); 48*d9f75844SAndroid Build Coastguard Worker if (self = [super initWithFactory:factory nativeTrack:nativeMediaTrack type:type]) { 49*d9f75844SAndroid Build Coastguard Worker _adapters = [NSMutableArray array]; 50*d9f75844SAndroid Build Coastguard Worker _workerThread = factory.workerThread; 51*d9f75844SAndroid Build Coastguard Worker } 52*d9f75844SAndroid Build Coastguard Worker return self; 53*d9f75844SAndroid Build Coastguard Worker} 54*d9f75844SAndroid Build Coastguard Worker 55*d9f75844SAndroid Build Coastguard Worker- (void)dealloc { 56*d9f75844SAndroid Build Coastguard Worker for (RTCVideoRendererAdapter *adapter in _adapters) { 57*d9f75844SAndroid Build Coastguard Worker self.nativeVideoTrack->RemoveSink(adapter.nativeVideoRenderer); 58*d9f75844SAndroid Build Coastguard Worker } 59*d9f75844SAndroid Build Coastguard Worker} 60*d9f75844SAndroid Build Coastguard Worker 61*d9f75844SAndroid Build Coastguard Worker- (RTC_OBJC_TYPE(RTCVideoSource) *)source { 62*d9f75844SAndroid Build Coastguard Worker if (!_source) { 63*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source( 64*d9f75844SAndroid Build Coastguard Worker self.nativeVideoTrack->GetSource()); 65*d9f75844SAndroid Build Coastguard Worker if (source) { 66*d9f75844SAndroid Build Coastguard Worker _source = [[RTC_OBJC_TYPE(RTCVideoSource) alloc] initWithFactory:self.factory 67*d9f75844SAndroid Build Coastguard Worker nativeVideoSource:source]; 68*d9f75844SAndroid Build Coastguard Worker } 69*d9f75844SAndroid Build Coastguard Worker } 70*d9f75844SAndroid Build Coastguard Worker return _source; 71*d9f75844SAndroid Build Coastguard Worker} 72*d9f75844SAndroid Build Coastguard Worker 73*d9f75844SAndroid Build Coastguard Worker- (void)addRenderer:(id<RTC_OBJC_TYPE(RTCVideoRenderer)>)renderer { 74*d9f75844SAndroid Build Coastguard Worker if (!_workerThread->IsCurrent()) { 75*d9f75844SAndroid Build Coastguard Worker _workerThread->BlockingCall([renderer, self] { [self addRenderer:renderer]; }); 76*d9f75844SAndroid Build Coastguard Worker return; 77*d9f75844SAndroid Build Coastguard Worker } 78*d9f75844SAndroid Build Coastguard Worker 79*d9f75844SAndroid Build Coastguard Worker // Make sure we don't have this renderer yet. 80*d9f75844SAndroid Build Coastguard Worker for (RTCVideoRendererAdapter *adapter in _adapters) { 81*d9f75844SAndroid Build Coastguard Worker if (adapter.videoRenderer == renderer) { 82*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << "|renderer| is already attached to this track"; 83*d9f75844SAndroid Build Coastguard Worker return; 84*d9f75844SAndroid Build Coastguard Worker } 85*d9f75844SAndroid Build Coastguard Worker } 86*d9f75844SAndroid Build Coastguard Worker // Create a wrapper that provides a native pointer for us. 87*d9f75844SAndroid Build Coastguard Worker RTCVideoRendererAdapter* adapter = 88*d9f75844SAndroid Build Coastguard Worker [[RTCVideoRendererAdapter alloc] initWithNativeRenderer:renderer]; 89*d9f75844SAndroid Build Coastguard Worker [_adapters addObject:adapter]; 90*d9f75844SAndroid Build Coastguard Worker self.nativeVideoTrack->AddOrUpdateSink(adapter.nativeVideoRenderer, 91*d9f75844SAndroid Build Coastguard Worker rtc::VideoSinkWants()); 92*d9f75844SAndroid Build Coastguard Worker} 93*d9f75844SAndroid Build Coastguard Worker 94*d9f75844SAndroid Build Coastguard Worker- (void)removeRenderer:(id<RTC_OBJC_TYPE(RTCVideoRenderer)>)renderer { 95*d9f75844SAndroid Build Coastguard Worker if (!_workerThread->IsCurrent()) { 96*d9f75844SAndroid Build Coastguard Worker _workerThread->BlockingCall([renderer, self] { [self removeRenderer:renderer]; }); 97*d9f75844SAndroid Build Coastguard Worker return; 98*d9f75844SAndroid Build Coastguard Worker } 99*d9f75844SAndroid Build Coastguard Worker __block NSUInteger indexToRemove = NSNotFound; 100*d9f75844SAndroid Build Coastguard Worker [_adapters enumerateObjectsUsingBlock:^(RTCVideoRendererAdapter *adapter, 101*d9f75844SAndroid Build Coastguard Worker NSUInteger idx, 102*d9f75844SAndroid Build Coastguard Worker BOOL *stop) { 103*d9f75844SAndroid Build Coastguard Worker if (adapter.videoRenderer == renderer) { 104*d9f75844SAndroid Build Coastguard Worker indexToRemove = idx; 105*d9f75844SAndroid Build Coastguard Worker *stop = YES; 106*d9f75844SAndroid Build Coastguard Worker } 107*d9f75844SAndroid Build Coastguard Worker }]; 108*d9f75844SAndroid Build Coastguard Worker if (indexToRemove == NSNotFound) { 109*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << "removeRenderer called with a renderer that has not been previously added"; 110*d9f75844SAndroid Build Coastguard Worker return; 111*d9f75844SAndroid Build Coastguard Worker } 112*d9f75844SAndroid Build Coastguard Worker RTCVideoRendererAdapter *adapterToRemove = 113*d9f75844SAndroid Build Coastguard Worker [_adapters objectAtIndex:indexToRemove]; 114*d9f75844SAndroid Build Coastguard Worker self.nativeVideoTrack->RemoveSink(adapterToRemove.nativeVideoRenderer); 115*d9f75844SAndroid Build Coastguard Worker [_adapters removeObjectAtIndex:indexToRemove]; 116*d9f75844SAndroid Build Coastguard Worker} 117*d9f75844SAndroid Build Coastguard Worker 118*d9f75844SAndroid Build Coastguard Worker#pragma mark - Private 119*d9f75844SAndroid Build Coastguard Worker 120*d9f75844SAndroid Build Coastguard Worker- (rtc::scoped_refptr<webrtc::VideoTrackInterface>)nativeVideoTrack { 121*d9f75844SAndroid Build Coastguard Worker return rtc::scoped_refptr<webrtc::VideoTrackInterface>( 122*d9f75844SAndroid Build Coastguard Worker static_cast<webrtc::VideoTrackInterface *>(self.nativeTrack.get())); 123*d9f75844SAndroid Build Coastguard Worker} 124*d9f75844SAndroid Build Coastguard Worker 125*d9f75844SAndroid Build Coastguard Worker@end 126