andykent
We see occasional crashes in AudioHardware, I don' have a reliable way to reproduce them but here is an example. ``` Thread 12 Crashed: 0 My_App Beta 0x20382e9f8 [inlined] range 1 My_App Beta 0x20382e9f8 [inlined] Array._checkSubscript 2 My_App Beta 0x20382e9f8 [inlined] Array.subscript.getter 3 My_App Beta 0x20382e9f8 [inlined] Array.subscript.read 4 My_App Beta 0x20382e9f8 [inlined] [A] 5 My_App Beta 0x20382e9f8 MutableCollection._halfStablePartition 6 My_App Beta 0x203832160 [inlined] MutableCollection._halfStablePartition 7 My_App Beta 0x203832160 [inlined] AudioHardware.remove 8 My_App Beta 0x203832160 propertyListener (AudioHardware.swift:181) 9 CoreAudio 0x31397a9f0 HALObject::PropertiesChanged 10 CoreAudio 0x3137ff1e4 HALSystem::PropertiesChanged 11 CoreAudio 0x3137fefc0 HALSystem::ObjectsPublishedAndDied 12 CoreAudio 0x313803b04 HALSystem::AudioObjectsPublishedAndDied 13 CoreAudio 0x3138cec58 HALC_ShellPlugIn::ProxyObject_PropertiesChanged 14 CoreAudio 0x3139261b8 HALC_ProxyNotifications::CallListener_f 15 libdispatch.dylib 0x30f1d03fc _dispatch_client_callout 16 libdispatch.dylib 0x30f1d7a84 _dispatch_lane_serial_drain 17 libdispatch.dylib 0x30f1d8628 _dispatch_lane_invoke 18 libdispatch.dylib 0x30f1d98e4 _dispatch_workloop_invoke 19 libdispatch.dylib 0x30f1e3240 _dispatch_workloop_worker_thread 20 libsystem_pthread.dylib 0x30f529070 _pthread_wqthread ``` It seems like AudioHardware.remove, and probably other functions in AudioHardware too, are being called concurrently and access to `allKnownDevices` is not thread safe. I tried to investigate `AudioObjectAddPropertyListener` further but it's not really clear to me from the very limited docs what guarantees it gives around notifying on different threads or concurrency. Given `DispatchQueue.main.async` is already used in the propertyListener I have to assume that the listener calls back on different threads. One easy path might be extend the DispatchQueue block to enclose all of the propertyListener thus serialising these calls at least. I don't think this would fix the root issue though, for that I think `allKnownDevices` probably needs to have a thread safe implementation or locks around all accesses. I'm happy to take a stab at a PR here but I'm not entirely sure what the right or preferred solution is?