shogo4405 / HaishinKit.swift

Camera and Microphone streaming library via RTMP and SRT for iOS, macOS, tvOS and visionOS.
BSD 3-Clause "New" or "Revised" License
2.78k stars 617 forks source link

Getting exception on AVCaptureSession.startRunning #177

Closed akolov closed 7 years ago

akolov commented 7 years ago

The following code

dispatchPrecondition(condition: .onQueue(.main))
let videoDevice = DeviceUtil.device(withPosition: .front)
let audioDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
rtmpStream.attachCamera(videoDevice!)
rtmpStream.attachAudio(audioDevice!, automaticallyConfiguresApplicationAudioSession: true)

crashes sometimes with the Exception while calling attachCamera method

2017-01-29 04:04:11.989799+0100 MyApplication[1533:507603] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** -[AVCaptureSession startRunning] startRunning may not be called between calls to beginConfiguration and commitConfiguration'
*** First throw call stack:
(0x184d13fac 0x18377853c 0x18cad4620 0x10186f200 0x10186ed0c 0x1045f1b1c 0x1045f1adc 0x1045f6c20 0x184cc2064 0x184cbfc80 0x184bef9bc 0x18665c074 0x18af9e984 0x10027bd48 0x183bfd59c)
libc++abi.dylib: terminating with uncaught exception of type NSException

Backtrace:

* thread #1: tid = 0x7bed3, 0x0000000183d0d014 libsystem_kernel.dylib`__pthread_kill + 8, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x0000000183d0d014 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x0000000183dd7334 libsystem_pthread.dylib`pthread_kill + 112
    frame #2: 0x0000000183c819ac libsystem_c.dylib`abort + 140
    frame #3: 0x0000000183750fb4 libc++abi.dylib`abort_message + 132
    frame #4: 0x000000018376ac10 libc++abi.dylib`default_terminate_handler() + 304
    frame #5: 0x0000000183778824 libobjc.A.dylib`_objc_terminate() + 124
    frame #6: 0x00000001837675e4 libc++abi.dylib`std::__terminate(void (*)()) + 16
    frame #7: 0x0000000183766f08 libc++abi.dylib`__cxa_throw + 136
    frame #8: 0x0000000183778670 libobjc.A.dylib`objc_exception_throw + 364
    frame #9: 0x000000018cad4620 AVFoundation`-[AVCaptureSession startRunning] + 284
  * frame #10: 0x000000010186f200 lf`specialized NetStream.(attachCamera(AVCaptureDevice?) -> ()).(closure #1) [inlined] lf.AVMixer.startRunning (self=0x000000017409c340) -> () + 260 at AVMixer.swift:96 [opt]
    frame #11: 0x000000010186f1cc lf`specialized NetStream.(self=<unavailable>, camera=0x000000010c907920) -> ()).(closure #1) + 208 at NetStream.swift:135 [opt]
    frame #12: 0x000000010186ed0c lf`partial apply for NetStream.(attachCamera(AVCaptureDevice?) -> ()).(closure #1) [inlined] lf.NetStream.(attachCamera (Swift.Optional<__ObjC.AVCaptureDevice>) -> ()).(closure #1) + 12 at NetStream.swift:0 [opt]
    frame #13: 0x000000010186ed00 lf`partial apply for NetStream.(attachCamera(AVCaptureDevice?) -> ()).(closure #1) + 48 at NetStream.swift:0 [opt]
    frame #14: 0x00000001045f1b1c libdispatch.dylib`_dispatch_call_block_and_release + 24
    frame #15: 0x00000001045f1adc libdispatch.dylib`_dispatch_client_callout + 16
    frame #16: 0x00000001045f6c20 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 1204
    frame #17: 0x0000000184cc2064 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
    frame #18: 0x0000000184cbfc80 CoreFoundation`__CFRunLoopRun + 1572
    frame #19: 0x0000000184bef9bc CoreFoundation`CFRunLoopRunSpecific + 424
    frame #20: 0x000000018665c074 GraphicsServices`GSEventRunModal + 100
    frame #21: 0x000000018af9e984 UIKit`UIApplicationMain + 208
    frame #22: 0x000000010027bd48 MyApplication`main + 140 at AppDelegate.swift:18
    frame #23: 0x0000000183bfd59c libdyld.dylib`start + 4

I suspect some race condition in AVMixer? I'm using lf.swift version 0.5.8

brycesteve commented 7 years ago

I'm having this exact same problem. The stack trace starts around NetStream.attachCamera, and the final breakpoint is shown as session.startRunning() in AVMixer:Runnable extension. I have tried to figure this out myself, but Xcode's "Uncaught exception of type NSException" isn't exactly helpful ;)

I also have a problem, that when I use LFView as a preview, then close the view controller. If I open another view controller and try to use LFView again, the preview is just a black view. Although this doesn't generally throw an exception, and the rtmp stream does in fact broadcast (just with a blank preview).

With both of these facts in mind, I have been looking for leaks (i.e. I assume that the first LFView isn't getting deallocated before the new one is initialised), but looking at your latest commits it seems you have made changes to address this, yet the problem still exists.

The two problems may be unrelated, just that I have them occurring in the same view and both are somewhat intermittent, makes me suspect that they are connected.

akolov commented 7 years ago

@brycesteve yes, I'm getting black screen sometimes as well, especially right after camera/microphone permission requests.

shogo4405 commented 7 years ago

Yes. I'm trying to fix this issue and #175, #131.

shogo4405 commented 7 years ago

@shogo4405

shogo4405 commented 7 years ago

fixed this issue :) I will release 0.5.11 in a few days.

Please call RTMPStream.dispose() method at "viewWillDisappear" RTMPStream#dispose method can destroy an AVCaptureSession safety :)

import lf
import UIKit
import XCGLogger
import AVFoundation

let sampleRate:Double = 44_100

final class LiveViewController: UIViewController {
    var rtmpConnection:RTMPConnection = RTMPConnection()
    var rtmpStream:RTMPStream!

    @IBOutlet var lfView:GLLFView?

    var currentPosition:AVCaptureDevicePosition = AVCaptureDevicePosition.back

    override func viewDidLoad() {
        super.viewDidLoad()

        rtmpStream = RTMPStream(connection: rtmpConnection)
        rtmpStream.syncOrientation = true
        rtmpStream.captureSettings = [
            "sessionPreset": AVCaptureSessionPreset1280x720,
            "continuousAutofocus": true,
            "continuousExposure": true,
        ]
        rtmpStream.videoSettings = [
            "width": 1280,
            "height": 720,
        ]
        rtmpStream.audioSettings = [
            "sampleRate": sampleRate
        ]
    }

    override func viewWillAppear(_ animated: Bool) {
        logger.info("viewWillAppear")
        super.viewWillAppear(animated)
        rtmpStream.attachAudio(AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio), automaticallyConfiguresApplicationAudioSession: false)
        rtmpStream.attachCamera(DeviceUtil.device(withPosition: currentPosition))
        lfView?.attachStream(rtmpStream)
    }

    override func viewWillDisappear(_ animated: Bool) {
        logger.info("viewWillDisappear")
        super.viewWillDisappear(animated)
        rtmpStream.close()
        rtmpStream.dispose()
    }
}
shogo4405 commented 7 years ago

Released 0.5.11

M-I-N commented 1 year ago

Experiencing the similar crash. Stack trace from firebase crashlytics:

Fatal Exception: NSGenericException
0  CoreFoundation                 0xa248 __exceptionPreprocess
1  libobjc.A.dylib                0x17a68 objc_exception_throw
2  AVFCapture                     0x2a1f8 -[AVCaptureSession startRunning]
3  HaishinKit                     0x1ad7c thunk for @escaping @callee_guaranteed () -> () (<compiler-generated>)
4  libdispatch.dylib              0x24b4 _dispatch_call_block_and_release
5  libdispatch.dylib              0x3fdc _dispatch_client_callout
6  libdispatch.dylib              0x15b8c _dispatch_root_queue_drain
7  libdispatch.dylib              0x16284 _dispatch_worker_thread2
8  libsystem_pthread.dylib        0xdbc _pthread_wqthread
9  libsystem_pthread.dylib        0xb98 start_wqthread