取消分配RTCMediaStream会阻止主线程

时间:2015-03-02 14:04:49

标签: ios objective-c multithreading webrtc

我正在构建一个应该使用WebRTC实施形式webrtc.org的iOS应用。我创建了演示应用程序,一切正常。在将框架集成到我自己的应用程序后,我遇到了有关解除资源分配的问题。

作为第一步,我想创建一个本地媒体流,并为其添加音频和视频轨道。在我的测试中,我意识到,解除分配RTCMediaStream(和VideoTrackProxy)对象会阻塞主线程大约10秒钟。

为了重现这一点,我创建了一个单独的测试,它创建了一个媒体流,为它添加了一个视频轨道并在之后解除分配(在范围的末尾释放对象)。

@interface RTCTests : XCTestCase
@property (nonatomic, strong) RTCPeerConnectionFactory *factory;
@end

@implementation RTCTests

- (void)setUp
{
    [super setUp];
    self.factory = [[RTCPeerConnectionFactory alloc] init];
}

- (void)tearDown
{
    self.factory = nil;
    [super tearDown];
}

- (void)testLocalMediaStream
{
    RTCMediaStream *mediaStream = [self.factory mediaStreamWithLabel:@"stream-a"];

    XCTestExpectation *expectation = [self expectationWithDescription:@"Create Media Stream"];

    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
                             completionHandler:^(BOOL granted){
                                 dispatch_async(dispatch_get_main_queue(), ^{

                                     if (granted == NO) {
                                         XCTFail(@"Access to camera not granted.");
                                         [expectation fulfill];
                                     } else {

                                         NSString *cameraID = nil;
                                         for (AVCaptureDevice *captureDevice in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
                                             if (captureDevice.position == AVCaptureDevicePositionFront) {
                                                 cameraID = [captureDevice localizedName];
                                                 break;
                                             }
                                         }

                                         if (cameraID) {
                                             RTCVideoCapturer *capturer = [RTCVideoCapturer capturerWithDeviceName:cameraID];
                                             RTCMediaConstraints *mediaConstraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:@[]
                                                                                                                           optionalConstraints:@[]];
                                             RTCVideoSource *videoSource = [self.factory videoSourceWithCapturer:capturer
                                                                                                     constraints:mediaConstraints];

                                             RTCVideoTrack *track = [self.factory  videoTrackWithID:@"stream-a-v" source:videoSource];
                                             if (track) {
                                                 [mediaStream addVideoTrack:track];
                                             }
                                         }

                                         [expectation fulfill];
                                     }
                                 });
                             }];

    [self waitForExpectationsWithTimeout:10.0 handler:^(NSError *error) {
        XCTAssertNil(error, @"Failed with error: %@", [error localizedDescription]);
    }];

    XCTAssertEqual([mediaStream.videoTracks count], 1);
    XCTAssertEqualObjects([[[mediaStream videoTracks] firstObject] label], @"stream-a-v");

    NSLog(@"Done! %@", [NSDate date]);
}

@end

测试本身按预期工作,它或多或少立即成功,如下面的日志中所示:

Test Case '-[RTCTests testLocalMediaStream]' started.
2015-03-02 14:51:36.458 App[9043:2810016] Begin! 2015-03-02 13:51:36 +0000
2015-03-02 14:51:36.643 App[9043:2810016] End! 2015-03-02 13:51:36 +0000
Test Case '-[RTCTests testLocalMediaStream]' passed (9.266 seconds).

但是需要另外9秒来释放资源(在这种情况下是VideoTrackProxy),它同步调用析构函数中另一个线程上的方法(如果我正确读取sources of the proxy)。不幸的是,这个线程接缝成为主线程,这会导致死锁并且我会猜到超时解决。

* thread #1: tid = 0x2ae4a8, 0x00000001978db078 libsystem_kernel.dylib`__psynch_cvwait + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00000001978db078 libsystem_kernel.dylib`__psynch_cvwait + 8
    frame #1: 0x0000000197976fe4 libsystem_pthread.dylib`_pthread_cond_wait + 624
    frame #2: 0x0000000100cbc2c0 RTCTests`rtc::Event::Wait(int) + 232
    frame #3: 0x0000000100b210cc RTCTests`webrtc::VideoTrackProxy::~VideoTrackProxy() + 120
    frame #4: 0x0000000100b206b0 RTCTests`rtc::RefCountedObject::~RefCountedObject() + 12
    frame #5: 0x0000000100b20690 RTCTests`rtc::RefCountedObject::Release() + 52
    frame #6: 0x0000000197152b1c libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 148
    frame #7: 0x000000019715ff38 libobjc.A.dylib`objc_destructInstance + 92
    frame #8: 0x000000019715ff90 libobjc.A.dylib`object_dispose + 28
    frame #9: 0x0000000100b58db4 RTCTests`-[RTCMediaStreamTrack(Internal) dealloc] + 92
    frame #10: 0x0000000100b5ef6c RTCTests`-[RTCVideoTrack dealloc] + 356
    frame #11: 0x000000018692d228 CoreFoundation`CFRelease + 524
    frame #12: 0x0000000186935308 CoreFoundation`-[__NSArrayI dealloc] + 88
    frame #13: 0x000000019716d724 libobjc.A.dylib`(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 564
    frame #14: 0x00000001011f1c54 XCTest`-[XCTestCase invokeTest] + 336
    ...

WebRTC框架是否可以配置为不将主线程用于其内部任务?或者我在这里错过了其他什么?

我很欣赏各种提示。

0 个答案:

没有答案