I am trying to create a few instances of ClipRecorder
s in order to later in my app just trigger cliprecorder.start(...)
to record a clip. I have one instance of AKMicrophone
which I provide to the ClipRecorder
. To create the clip recorders I use the next setup:
for _ in 0 ... 4 {
let t = Track(microphone: microphone)
tracks.append(t)
}
Track:
init(microphone: Microphone) {
self.microphone = microphone
clipRecorder = AKClipRecorder(node: microphone.node)
}
Microphone:
class Microphone {
private var microphone: AKMicrophone = AKMicrophone()
private var micMixer: AKMixer!
private var micBooster: AKBooster!
var node: AKNode {
return micBooster
}
init(){
micMixer = AKMixer(microphone)
micBooster = AKBooster(micMixer)
micBooster.gain = 0.5
}
}
The first clip recorder is indeed initialised but on the second one (in the for loop) the application crashes (checked it with only one append and worked), here is the log:
2018-10-03 18:10:59.455441+0300 BeatmanApp[56475:2289336] [avae] AVAEInternal.h:70:_AVAE_Check: required condition is false: [AVAEGraphNode.mm:851:CreateRecordingTap: (nullptr == Tap())]
2018-10-03 18:10:59.467667+0300 BeatmanApp[56475:2289336] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: nullptr == Tap()'
*** First throw call stack:
(
0 CoreFoundation 0x000000010953629b __exceptionPreprocess + 331
1 libobjc.A.dylib 0x0000000108373735 objc_exception_throw + 48
2 CoreFoundation 0x0000000109536022 +[NSException raise:format:arguments:] + 98
3 AVFAudio 0x000000010b44889c _Z19AVAE_RaiseExceptionP8NSStringz + 156
4 AVFAudio 0x000000010b48595b _Z11_AVAE_CheckPKciS0_S0_b + 323
5 AVFAudio 0x000000010b47e63c _ZN17AUGraphNodeBaseV318CreateRecordingTapEmjP13AVAudioFormatU13block_pointerFvP16AVAudioPCMBufferP11AVAudioTimeE + 116
6 AVFAudio 0x000000010b45c1be _ZN18AVAudioEngineGraph16InstallTapOnNodeEP11AVAudioNodemjP13AVAudioFormatU13block_pointerFvP16AVAudioPCMBufferP11AVAudioTimeE + 218
7 AVFAudio 0x000000010b4cd423 _ZN17AVAudioEngineImpl16InstallTapOnNodeEP11AVAudioNodemjP13AVAudioFormatU13block_pointerFvP16AVAudioPCMBufferP11AVAudioTimeE + 13
8 AVFAudio 0x000000010b4bd48c -[AVAudioNode installTapOnBus:bufferSize:format:block:] + 208
9 BeatmanApp 0x00000001068d47db $S8AudioKit14AKClipRecorderC4nodeAcA8AKOutput_p_tcfcTf4gn_n + 363
10 BeatmanApp 0x00000001068d0299 $S8AudioKit14AKClipRecorderC4nodeAcA8AKOutput_p_tcfC + 73
11 BeatmanApp 0x00000001066752b4 $S10BeatmanApp5TrackC10microphoneAcA10MicrophoneC_tcfc + 724
12 BeatmanApp 0x0000000106674f83 $S10BeatmanApp5TrackC10microphoneAcA10MicrophoneC_tcfC + 67
13 BeatmanApp 0x000000010667bbd1 $S10BeatmanApp4LoopC05setupC033_AA3A7D0867ACF3D9219815B736BA3641LLyyF + 385
14 BeatmanApp 0x000000010667b93c $S10BeatmanApp4LoopC9metronome10microphoneAcA9MetronomeC_AA10MicrophoneCtcfc + 1164
15 BeatmanApp 0x000000010667b44f $S10BeatmanApp4LoopC9metronome10microphoneAcA9MetronomeC_AA10MicrophoneCtcfC + 79
16 BeatmanApp 0x000000010666ece5 $S10BeatmanApp11CoordinatorCyACSo22UINavigationControllerCcfc + 325
17 BeatmanApp 0x000000010666eb43 $S10BeatmanApp11CoordinatorCyACSo22UINavigationControllerCcfC + 67
18 BeatmanApp 0x000000010665952e $S10BeatmanApp0B8DelegateC11application_29didFinishLaunchingWithOptionsSbSo13UIApplicationC_SDySo0j6LaunchI3KeyaypGSgtF + 686
19 BeatmanApp 0x0000000106659854 $S10BeatmanApp0B8DelegateC11application_29didFinishLaunchingWithOptionsSbSo13UIApplicationC_SDySo0j6LaunchI3KeyaypGSgtFTo + 228
20 UIKitCore 0x000000011338b4d7 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 280
21 UIKitCore 0x000000011338cec4 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 3979
22 UIKitCore 0x0000000113392527 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1623
23 UIKitCore 0x0000000113c34e3e __111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 866
24 UIKitCore 0x0000000113c31403 +[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 153
25 UIKitCore 0x0000000113c34a7b -[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:] + 233
26 UIKitCore 0x0000000113c35435 -[__UICanvasLifecycleMonitor_Compatability activateEventsOnly:withContext:completion:] + 1085
27 UIKitCore 0x0000000113bf2b31 __82-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:]_block_invoke + 795
28 UIKitCore 0x0000000113bf27db -[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:] + 435
29 UIKitCore 0x0000000113c3792c __125-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke + 584
30 UIKitCore 0x0000000113c38256 _performActionsWithDelayForTransitionContext + 100
31 UIKitCore 0x0000000113c3768b -[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] + 221
32 UIKitCore 0x0000000113c30aa1 -[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] + 392
33 UIKitCore 0x0000000113390d46 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 515
34 UIKitCore 0x00000001133c2856 -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 357
35 FrontBoardServices 0x0000000112b2adda -[FBSSceneImpl _didCreateWithTransitionContext:completion:] + 448
36 FrontBoardServices 0x0000000112b35f43 __56-[FBSWorkspace client:handleCreateScene:withCompletion:]_block_invoke_2 + 271
37 FrontBoardServices 0x0000000112b3563a __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 53
38 libdispatch.dylib 0x000000010b02863e _dispatch_client_callout + 8
39 libdispatch.dylib 0x000000010b02bbb4 _dispatch_block_invoke_direct + 301
40 FrontBoardServices 0x0000000112b6a3c8 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30
41 FrontBoardServices 0x0000000112b6a080 -[FBSSerialQueue _performNext] + 457
42 FrontBoardServices 0x0000000112b6a660 -[FBSSerialQueue _performNextFromRunLoopSource] + 45
43 CoreFoundation 0x0000000109499b31 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
44 CoreFoundation 0x00000001094993a3 __CFRunLoopDoSources0 + 243
45 CoreFoundation 0x0000000109493a4f __CFRunLoopRun + 1263
46 CoreFoundation 0x0000000109493221 CFRunLoopRunSpecific + 625
47 GraphicsServices 0x000000010d8101dd GSEventRunModal + 62
48 UIKitCore 0x0000000113394115 UIApplicationMain + 140
49 BeatmanApp 0x000000010665a007 main + 71
50 libdyld.dylib 0x000000010b09e551 start + 1
51 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
this looks as the microphone node could not be shared with pre initialised clip recorders, what am I doing wrong? The other possibility that I can think of is to create a cliprecorder no demand (because I am obviously not recording simultaneously) then after the recording finished and the call back closure is called I will discard the recorder and move the clip into a player (or clip player), is this the right direction?
Thanks a lot.
Ok after few hours of debugging, searching the source code of AudioKit and SO, the fix for the problem was only few lines of code which I needed change/add in Track
.
init(microphone: Microphone) {
self.microphone = microphone
}
func record(){
microphone.node.outputNode.removeTap(onBus: 0)
clipRecorder = AKClipRecorder(node: microphone.node)
}
The removeTap
function is called only in the deinit
of the AKClipRecorder
so until you not de-initialize the instance the tap is assigned to the microphone bus which suppose to have only one tap assigned (reference here). What I had to do is to call this method manually to clear the tap on microphone bus before I start the recording with my clip recorder. This SO thread which is closely related question about other class in AudioKit, helped me a lot.