Hello again! This library is really great and I will soon be able to provide you with some iOS examples for you to add to the collection (if you like them, obviously)! ๐
Now, I've started developing an app that requires the Audio background mode enabled for some of its features to work. In this app, I'm also using AudioKit to record audio for a few seconds, save it and then let the user play it back. This happens in different view controllers so bear with me.
The issue with this setup is that when I initialise an AKMicrophone, start AudioKit and exit that particular controller, the microphone stays active no matter what I've tried. Obviously AudioKit.stop() stops it but the issue doesn't stop there. Whenever AudioKit starts from that point forward, the red recording bar shows up when the app is in the background, even when the session is set to playback only.
Example scenario: push to view controller with mic and audiokit -> pop to empty controller without audiokit -> background (shows red bar).
However here's where it gets even weirder: when I call this line AudioKit.engine.outputNode.removeTap(onBus: 0) right before exiting the view controller, the red bar is gone if I go to the background but only to come back right after I switch into the app again. Timing is irrelevant, it only comes back when you switch back to the app and go into background mode for the 2nd time.
Where am I going with this? Well, this problem has been posted before in a similar fashion in google groups and in stackoverflow without a good answer on how to properly close an AKMicrophone. I'm guessing it hasn't been dealt with so far and that's why I'm opening an issue. There seems to be no way to stop the AKMicrophone once it has been initialised, unless AudioKit.stop() is called. Which isn't practical or solves anything. I think I'm not missing something here and I feel like this is something worth investigating as I don't think it's an implementation issue on my end (hopefully ๐).
If you know how you'd like ti to work, we're open to PRs for sure.
I've been trying to make it work without fiddling with AudioKit's files but so far had no luck. I know how it should be working but I have no idea how to fix this myself. The node is being attached to the engine and there's no proper way to deallocate it apparently.
Things I've tried:
All of the above work together in the correct order
Setting the engine to a new AVAudioEngine() -> crashes
These just seem to not solve the issue. Once the shared engine starts again, the red bar is back. Surely this is just a sub-problem of a bigger one: nodes stay in memory because they do no harm since their model is 'pull data from me'. I guess Apple wants to protect their users by telling them that there's a disconnected node in memory that used to be attached to the microphone, watch out! โ ๏ธ
If you have no further input on this issue and can't point me to the right direction (since I'm obviously lacking a lot of knowledge here) go ahead and close this!
I really would like to deal with this issue, but its going to be a lot of work to set up the testing scenario that you have. Is there any way you could post this as a StackOverflow question with a link to a sample project. You'll get a lot more eyeballs on the issue that way.
Oh, and reopen this issue as necessary with more information, just closing it for now.
Hey Aure,
I was the one that had posted in the google group and on stackoverflow about this in the past. The best way to get a good testing scenario is to just take the "Recorder" sample project and add this to the plist.
Required background modes
Item 0: App plays audio or streams audio/video using AirPlay
In this example it would be nice to disable recording after you have recorded and are simply playing back your track. Currently if the app is in the background the red bar will show up. For my app OffTop the only solution I could find was turning off Audiokit after exiting the studio (which, as you know, is just stopping the AVAudioEngine).
A few things I have discovered/tried:
I found that connecting the AVAudioEngine's inputNode (the last line of the AKMicrophone init method) triggers the red recording bar. It then seemed logical that disconnecting the inputNode in AKMicrophone's "stop" method ( Audiokit.engine.disconnectNodeInput(AudioKit.engine.inputNode) ) would make the recording bar go away because the mic hardware was no longer connected to anything. This doesn't work however.
I've also tried this in combination with changing the avaudiosession category to playBack, stopping and starting audiokit, setting inputEnabled=false, and a few variations of this with no luck.
There is an app called "RapChat" that is able to remove the red bar as soon as they are done recording so it is certainly possible, however I have no idea what their underlying setup is so it could be very different from the AVAudioEngine approach of Audiokit.
Audiokit has been awesome for me and I'm getting ready to push a great new update utilizing the new AKPlayer and offline rendering introduced with iOS 11. This is the last little thing that my app's studio could really use that I haven't been able to figure out.
Appreciate any help you can give, and if you find some good detailed documentation that might shed some light on how apple decides when the red bar should be presented please share it with me.
Let me know if there's anything I can do to help you out with this.
-Nathan
I took the time to upload 2 versions of the same implementation on github. One with AKMicrophone (from your Recorder sample app) and one that that uses the default AVFoundation microphone to test a few things.
https://github.com/nCr78/RecPlayer-iOS
So, in this project you can test the recorder app with the following steps:
The main project's microphone is properly deinitialised when the VC gets dismissed/popped and thus the red recording bar doesn't reappear when AudioKit starts again in a different VC (I think I don't show that in the implementation but I don't have to, there's no mic attached to AudioKit's engine anyway).
PS: My code may be a mess so feel free to correct me anywhere you see fit ๐
Can you reopen this issue so it gets some more eyes on it?
Unfortunately it looks like this may not be possible. I took a look at the documentation for the AVAudioEngine's inputNode property and it says "The audio engine creates a singleton on demand when inputNode is first accessed". Which made me think that the mic hardware is accessed, and red bar is triggered, simply during the creating of this singleton. So to confirm this I simply put the line "let input = Audiokit.engine.inputNode" and sure enough this is all it took to trigger the red recording bar. Since inputNode is a singleton and a read only property it looks like the only way to remove the red bar after inputNode has been accessed is to stop the associated AVAudioEngine.
So, there's nothing that can be done about this save for that. That doesn't sound unreasonable to me.
Unfortunately it looks like this may not be possible. I took a look at the documentation for the AVAudioEngine's inputNode property and it says "The audio engine creates a singleton on demand when inputNode is first accessed". Which made me think that the mic hardware is accessed, and red bar is triggered, simply during the creating of this singleton. So to confirm this I simply put the line "let input = Audiokit.engine.inputNode" and sure enough this is all it took to trigger the red recording bar. Since inputNode is a singleton and a read only property it looks like the only way to remove the red bar after inputNode has been accessed is to stop the associated AVAudioEngine.
Resolved my Red Status Bar issue by recreating AVAudioEngine instance after recording finishes.
Seems like you have a choice to have a separate AVAudioEngine just for recording. A couple of engines can co-exist, the first one is playing, the second one is recording. If you prepare both of them before usage โ you'll get a pretty nice sync. After recording is finished just stop and deinit your recording engine.
@nfaulkner9312 I was having trouble figuring out why my red bar would still show even though I executed AudioKit stop and shutdown. Come to find out what you said here was 100% correct.
So to confirm this I simply put the line "let input = Audiokit.engine.inputNode" and sure enough this is all it took to trigger the red recording bar. Since inputNode is a singleton and a read only property it looks like the only way to remove the red bar after inputNode has been accessed is to stop the associated AVAudioEngine.
With my application I have 2 different modes: record and playback. In my case I was setting AKSettings.audioInputEnabled = true within the record mode, but not setting it back when I stopped recording. So, when I stopped recording and then transitioned to playback I was building the audio nodes with audioInputEnabled set to true. As a result of not setting the audioInputEnabled to false, this code within AudioKit was always executing. ๐
https://github.com/AudioKit/AudioKit/blob/2fab72d4ed30a1a19ff9a964ef03c0945c56de66/AudioKit/Common/Internals/AudioKit.swift#L38-L40
My red bar icon was always getting displayed even though I never initialized an AKMicrophone instance.
So, thank you for pointing this out! ๐
Most helpful comment
Resolved my Red Status Bar issue by recreating
AVAudioEngineinstance after recording finishes.Seems like you have a choice to have a separate
AVAudioEnginejust for recording. A couple of engines can co-exist, the first one is playing, the second one is recording. If you prepare both of them before usage โ you'll get a pretty nice sync. After recording is finished just stop and deinit your recording engine.