aws / amazon-chime-sdk-ios

An iOS client library for integrating multi-party communications powered by the Amazon Chime service.
https://aws.amazon.com/chime/chime-sdk/
Apache License 2.0
144 stars 67 forks source link

[AVCaptureSession startRunning] startRunning may not be called between calls to beginConfiguration and commitConfiguration' was thrown while invoking switchCamera #619

Open haroldh17 opened 11 months ago

haroldh17 commented 11 months ago

Describe the bug I have a React Native App using AWS Chime SDK based on your demo code amazon-chime-react-native-demo

When I use the switchCamera function, it works but if I do it several times in a row, I eventually get the following native exception:

Exception '*** -[AVCaptureSession startRunning] startRunning may not be called between calls to beginConfiguration and commitConfiguration' was thrown while invoking switchCamera on target NativeMobileSDKBridge with params (
    45998,
    45999
)
callstack: (
    0   CoreFoundation                      0x0000000192ae25ec CEB74A0C-5EA4-3F5A-9DE8-73F0DAD2F4CB + 972268
    1   libobjc.A.dylib                     0x000000018adebc00 objc_exception_throw + 60
    2   AVFCapture                          0x00000001aed10254 38142193-EFCC-367A-91CC-27CEF8267E7B + 172628
    3   libRPAC.dylib                       0x0000000108ef4ff0 _replacement_AVCaptureSession_startRunning + 108
    4   AmazonChimeSDK                      0x000000010962edd8 _swift_stdlib_malloc_size + 6692
    5   AmazonChimeSDK                      0x000000010962e2d4 _swift_stdlib_malloc_size + 3872
    6   AmazonChimeSDK                      0x000000010962f1d4 _swift_stdlib_malloc_size + 7712
    7   AmazonChimeSDK                      0x0000000109600d00 __swift_memcpy48_8 + 17028
    8   AmazonChimeSDK                      0x0000000109600d2c __swift_memcpy48_8 + 17072
    9   ExpertSession                       0x0000000104d47a0c -[NativeMobileSDKBridge switchCamera:rejecter:] + 108
    10  CoreFoundation                      0x0000000192a27134 CEB74A0C-5EA4-3F5A-9DE8-73F0DAD2F4CB + 205108
    11  CoreFoundation                      0x0000000192a26bcc CEB74A0C-5EA4-3F5A-9DE8-73F0DAD2F4CB + 203724
    12  CoreFoundation                      0x0000000192a269f4 CEB74A0C-5EA4-3F5A-9DE8-73F0DAD2F4CB + 203252
    13  ExpertSession                       0x00000001052422bc -[RCTModuleMethod invokeWithBridge:module:arguments:] + 1808
    14  ExpertSession                       0x0000000105245c90 _ZN8facebook5reactL11invokeInnerEP9RCTBridgeP13RCTModuleDatajRKN5folly7dynamicEiN12_GLOBAL__N_117SchedulingContextE + 1160
    15  ExpertSession                       0x000000010524563c _ZZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEiENK3$_0clEv + 128
    16  ExpertSession                       0x00000001052455b0 ___ZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEi_block_invoke + 28
    17  libdispatch.dylib                   0x0000000109960f50 _dispatch_call_block_and_release + 32
    18  libdispatch.dylib                   0x0000000109962b34 _dispatch_client_callout + 20
    19  libdispatch.dylib                   0x000000010996a98c _dispatch_lane_serial_drain + 832
    20  libdispatch.dylib                   0x000000010996b728 _dispatch_lane_invoke + 408
    21  libdispatch.dylib                   0x00000001099785f8 _dispatch_root_queue_drain_deferred_wlh + 328
    22  libdispatch.dylib                   0x0000000109977c2c _dispatch_workloop_worker_thread + 444
    23  libsystem_pthread.dylib             0x00000001fbbde964 _pthread_wqthread + 288
    24  libsystem_pthread.dylib             0x00000001fbbdea04 start_wqthread + 8
)

It also happens when I toggle on and off the camera too many times. or when I start the session (or any native functions that I can call)

To Reproduce Steps to reproduce the behavior: Flip the local video from front camera to back camera multiple times on iOS.

Expected behavior No exception is thrown

Screenshots IMG_8131 IMG_8132 IMG_8133

Test environment Info (please complete the following information):

Let me know if you need more information

davidsiemers commented 11 months ago

I'm experiencing this issue as well, would love some feedback here from the team.

iPhone 15 iOS 17 AmazonChimeSDK Version: 023.3 AmazonChimeSDKMedia Version: 0.18.3

haroldh17 commented 11 months ago

I too have iOS 17 and it also happens with the react native demo! Just run the demo and toggle the camera on and off a few times, you will see it.

dylonChime commented 11 months ago

We are actively investigating this issue and will update here as soon as we have more information to provide. Thank you for your patience.

dylonChime commented 10 months ago

Our RN demo does not have a switch camera button, but I am not able to reproduce the issue on iOS 17 by quickly toggling the video on/off button.

I am also unable to repro this on the iOS SDK demo app with iOS 17 either by quickly toggling the camera switch button or quickly toggling the video on/off button.

I used iPhone 12 with iOS 17 for both tests. For the RN Demo we only support up to 0.22.7 version of AmazonChimeSDK, so that is what I used to test. For iOS SDK Demo, I used AmazonChimeSDK version 0.23.3. I'll try to locate an iPhone 15 for testing.

Is the iPhone model the only difference in setup? Did I get the repo steps right?

Here is a similar issue that was resolved by using NSLock in start and stop functions: https://github.com/aws/amazon-chime-sdk-ios/issues/231

dylonChime commented 10 months ago

I was also unable to reproduce this issue on iPhone 15.

Are there any variations in your setup or environment that might allow us to reproduce this issue?

icloutier commented 10 months ago

We've been having the same issue and it seems to be happening more frequently since iOS 17. We can repro by toggling the camera on/off a few times in a row.

We have a serial dispatch queue on which we run all our interactions with the Chime SDK client. I believe this might not repro if functions like startLocalVideo are called directly from the main thread.

The issue is a race in DefaultCameraCaptureSource if start is called from a background thread:

  1. updateOrientation is called between commitConfiguration and startRunning (link)
  2. updateOrientation dispatches to the main thread and sets the video orientation. (link) Internally, setting the orientation on the connection also triggers begin/commitConfiguration events.
  3. This means that when start is called from a background thread, there's a risk that the update to the video orientation (on the main thread) happens in parallel to the call to startRunning (on the background thread), which will then trigger the exception.
ashirkhan94 commented 8 months ago

Hi team, Got the same issue in iOS version 16.6 when we toggled (ON/OFF) the camera multiple times. We are using:- AmazoneChimeSDK-0.22.3 AmazoneChimeSDKMedia-0.17.7 "react-native": "^0.71.11",

EDD8CED6-C905-4107-AD4E-F16A9168267A

setCameraOn--*** -[AVCaptureSession startRunning] startRunning may not be called between calls to beginConfiguration and commitConfiguration
ashirkhan94 commented 8 months ago

Hi team We face the same issue in Android sometimes.

aaronroggow commented 5 months ago

Adding that we're also seeing this inconsistently (maybe 1/3 of the time) if attempting to start local video on a background thread. Can be as simple as

DispatchQueue.global().async {
    do {
        try meetingSession.audioVideo.startLocalVideo()
    } catch {
        // the error is not actually caught
    }
}

Switching to main thread seems to mitigate the issue, we just get a runtime warning then that

-[AVCaptureSession startRunning] should be called from background thread. Calling it on the main thread can lead to UI unresponsiveness

which is expected, but not ideal

georgezy-amzn commented 5 months ago

DispatchQueue.global() is concurrent queue, please use serial queue, please also make sure always use the same serial queue.

aaronroggow commented 5 months ago

@georgezy-amzn thanks for the suggestion! Unfortunately I'm still seeing the issue. I implemented a serial queue, and am still seeing the same result:

private static var serialQueue = DispatchQueue(label: "chime.video.provider") // static class var to ensure that I'm not accidentally using multiple queues
 ...
func refreshVideo() {
  Self.serialQueue.async { in
    ...
    do {
      try meetingSession.audioVideo.startLocalVideo() // hits the exception
    } catch {
      // does not catch
    }
  }
}

We call startLocalVideo in our primary connection function, as well as in this "refreshVideo" function - our application has some scenarios where we have to pause a user's connection to a session and then refresh their connection. I'm seeing it sometimes crash on the first call in the connection function, but sometimes that succeeds, and it still fails then when we refresh the connection

I poked around Chime's DefaultCameraCaptureSource.start() source code, and it seems like all paths should be safe in terms of not being able to escape without committing the configuration, even if there were an error. FWIW, I have the ChimeLogger logging all errors and faults, and I'm not seeing any before we hit this crash.

I also took a look at the usage of startLocalVideo in the ViewModel in the demo code - it doesn't seem that any special thread configurations are being used around that function call. Is there somewhere this is configured that I'm missing?

It does seem like this is a thread configuration issue - it works when using DispatchQueue.main.async, and from what I understand, that's just a globally available serial queue, albeit with come special configurations I'm sure. Any ideas on what else I could try here? I'm not the most familiar with customizing serial queues, so I'm sure there's something here I just don't know to look for

georgezy-amzn commented 2 weeks ago

Hi, we will release the fix in next release. Meanwhile, you can create a custom source by duplicate the DefaultCameraCaptureSource from this commit, and inject it when start local video.