Repository: HaishinKit/HaishinKit.swift

Issue #429: Random "dispatch_sync called on queue already owned by current thread" crash
Created: 2018-06-22T07:19:19Z
My app randomly crashes when using HaishinKit, here is the stack:
Application Specific Information:
BUG IN CLIENT OF LIBDISPATCH: dispatch_sync called on queue already owned by current thread
...
Thread 11 name:  Dispatch queue: com.haishinkit.HaishinKit.NetStream.lock
Thread 11 Crashed:
0   libdispatch.dylib             	0x0000000186a430d0 _dispatch_sync_wait + 600
1   HaishinKit                    	0x0000000100f2c6f8 _T010HaishinKit9NetStreamC13audioSettingss10DictionaryVySSypGvgTm + 156
2   HaishinKit                    	0x0000000100f2c6f8 _T010HaishinKit9NetStreamC13audioSettingss10DictionaryVySSypGvgTm + 156
3   Seize                         	0x00000001008cdb38 specialized SZBroadcastView.observeValue(forKeyPath:of:change:context:) + 56120 (SZBroadcastView.swift:108)
4   Seize                         	0x00000001008c8850 @objc SZBroadcastView.observeValue(forKeyPath:of:change:context:) + 34896 (SZBroadcastView.swift:0)
5   Foundation                    	0x00000001879ab9f0 NSKeyValueNotifyObserver + 304
6   Foundation                    	0x00000001879ab518 NSKeyValueDidChange + 404
7   Foundation                    	0x0000000187a65324 -[NSObject+ 865060 (NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:usingBlock:] + 668
8   Foundation                    	0x00000001879aa9b4 -[NSObject+ 100788 (NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 60
9   Foundation                    	0x0000000187a62b40 _NSSetUnsignedShortValueAndNotify + 272
10  HaishinKit                    	0x0000000100f546cc _T010HaishinKit10RTMPStreamC10readyStateAC05ReadyE0OvW + 542412 (RTMPStream.swift:258)
11  HaishinKit                    	0x0000000100f56880 closure #1 in RTMPStream.publish(_:type:) + 551040 (RTMPStream.swift:422)
12  HaishinKit                    	0x0000000100efff8c _T0Ieg_IeyB_TR + 196492 (SoundSpliter.swift:0)
13  libdispatch.dylib             	0x0000000186a35088 _dispatch_call_block_and_release + 24
14  libdispatch.dylib             	0x0000000186a35048 _dispatch_client_callout + 16
15  libdispatch.dylib             	0x0000000186a3ee48 _dispatch_queue_serial_drain$VARIANT$mp + 528
16  libdispatch.dylib             	0x0000000186a3f7d8 _dispatch_queue_invoke$VARIANT$mp + 340
17  libdispatch.dylib             	0x0000000186a40200 _dispatch_root_queue_drain_deferred_wlh$VARIANT$mp + 400
18  libdispatch.dylib             	0x0000000186a484a0 _dispatch_workloop_worker_thread$VARIANT$mp + 644
19  libsystem_pthread.dylib       	0x0000000186cdafe0 _pthread_wqthread + 932
20  libsystem_pthread.dylib       	0x0000000186cdac30 start_wqthread + 4

It seems to be caused by my adaptive bitrate algorithm based on rtmpStream.currentFPS observer. Here is my code of the observer:
  override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
    let stream = (object as! RTMPStream)
    let currentBitrate = stream.videoSettings["bitrate"] as! Int
    if (stream.currentFPS < 25) {
      let newBitrate = stream.currentFPS > 20 ? Int(Double(currentBitrate) * 0.9) : stream.currentFPS > 10 ? Int(Double(currentBitrate) * 0.75) :  Int(Double(currentBitrate) * 0.5)
      stream.videoSettings["bitrate"] = newBitrate
    }
    if (stream.currentFPS > 29 && currentBitrate != SZBroadcastView.initialVideoBitRate!) {
      let newBitrate = Int(Double(currentBitrate) * 1.1)
      stream.videoSettings["bitrate"] = newBitrate > SZBroadcastView.initialVideoBitRate! ? SZBroadcastView.initialVideoBitRate! : newBitrate
    }
  }

Should I check something about the thread I'm running on before modifying rtmpStream.videoSettings?

Duplicate issue #404: UI hangs videoSettings
Created: 2018-04-03T16:41:26Z
From #400
I have modified the example iOS app to reproduce this issue. The changes are at ronhuang/HaishinKit.swift@fdc563b.
Steps to reproduce:

Build example iOS app with the above modifications
Launch app (in simulator will be sufficient)
Switch to Second tab
Update any text field to change Preference.defaultInstance.bitrate
Switch back and forth between First and Second tabs until UI hangs
Once UI hangs, click "Pause program execution" in Xcode
Exam the call stack and see thread is stuck at __ulock_wait (as illustrated in the following screenshot)

Closing comment (2018-06-27T12:55:55Z): It may be related to #429 since changing videoSettings can cause deadlocks, my app just crashes when it happens but maybe sometimes the system can recover from the deadlock after a little while, it would explain this issue.
It's likely that #432 would solve this problem too.