Closed BenReierson closed 6 years ago
@BenReierson Not aware of any specific conflict with that plugin, but it sounds a bit like this, albeit with slightly different symptoms. From the followup comments on that issue, it sounds like having other audio processes going on at the same time can cause issues. On iOS I'm stopping and disposing the InputAudioQueue
when recording stops and creating it anew when recording begins, so I don't think there's anything being held on to, etc.
@NateRickard thanks for the quick response. Yeah, I'm thinking it's likely more an issue with MediaManager than with your plugin, so I will post an issue there. I was just hoping you might have seen this happen, since that's a super popular playback library. I wouldn't even need it if I was just doing audio, but they make video playback a lot easier. I just can't seem to figure out whether they are properly disposing of their services, or how to trigger that.
SOLVED: The shared instance of AVAudioSession must be set to the PlayAndRecord category.
Currently, this plugin is not accessing AVAudioSession directly, but I believe the underlying shared session accessed by other libraries, like MediaManager, is still being used.
MediaManager explicitly does the following:
avSession.SetCategory(AVAudioSessionCategory.Playback);
Which seems to prevent subsequent audio recording. By adding
var audioSession = AVAudioSession.SharedInstance();
var err = audioSession.SetCategory(AVAudioSessionCategory.PlayAndRecord);
To initAudioQueue() in the ios AudioStream class, I was able to fix the issue. You may also want to set the session as active/inactive when recording starts/stops.
Let me know if you'd like me to do a pull request with what I've done, which probably needs more investigation to be sure it's correct.
@BenReierson Well, glad you tracked that down... I'm finding that AVAudioSessionCategory
is supposed to be set per app, and ideally, before the session starts. We can certainly set the category each time the audio queue is init'd to work around the issue here, but honestly it seems that it should be delegated to the app if we're doing things the 'correct' way.
Here's an example where another lib is checking the category and just raising an error if it's incorrectly configured. I'd prefer that approach but obviously since MM is setting the category each time they play audio I'm not sure that's feasible. Thoughts?
To me, it makes sense for an app to need to switch between categories while running. My app only needs the ability to record in a specific screen that is likely not going to be used nearly as much as the playback function in the gallery.
I think there's a couple of things you could do to help in your library:
I just discovered that my app is affected by this as well. My issue is caused by a different plugin, but the result is the same. I ended up getting around it by writing a platform-specific method which could be called by my shared library.
Just before I start recording, I call the method which sets the category to one which allows recording. Then just before playback, I call the method again and set it to the category I want for playback (it actually checks to see if a change is even necessary first). Since this is an iOS only issue, the platform-specific method for both Android and UWP is an empty block. Seems to work just fine.
I suppose you could simply pick PlayAndRecord and forego the multiple calls. I just wanted Ambient instead of Playback (or PlayAndRecord).
@FlammableFork, that solved it for me as well. Here's the functions I used in case someone is looking for similar. It's setup the same as FlammableFork said inside a Xamarin DependencyService and Android just does nothing for these.
public void PreparePlayback()
{
AVAudioSession.SharedInstance().SetCategory(AVAudioSessionCategory.Playback);
}
public void PrepareRecording()
{
AVAudioSession.SharedInstance().SetCategory(AVAudioSessionCategory.Record);
}
It would be nice if this plugin just kept track of the current category before playback, changed it for recording, and then set it back when it was complete before sending the complete callback. That way this plugin handles itself without worrying about other plugins.
Implemented this in v1.0.1. Can anyone verify it solves the issue? Seems to work for me in testing, but I didn't test alongside another plugin/library.
@NateRickard Found this post after I implemented the same thing myself ...
Anyway I tested your implementation and it's working, thanks.
The suggested solutions worked fine until last week. I did an iOS update and this error is back. Who has this same issue (again) and did they found a solution for it? I tried to back trace the issue but could not determine what is going on. The error is to general. Disabling Xamarin MediaManager 'fixes' the problem but then i cant play audio.
Same problem here with v1.1.0, solved as @quinnhoener says but using dependency service.
I'm building a Forms app that needs to record audio, but also playback audio/video. Your plugin is a great fit for the recording, but I've noticed that if I have the Xamarin MediaManager (https://github.com/martijn00/XamarinMediaManager) plugin active at all in a given instance of the app, audio recording will fail. Is there any known conflict with these libraries?
I get the following error when calling StartRecording(): audioQueue.Start() returned non-OK status: GeneralParamError
I have reproduced this by loading up the media manager sample, adding Plugin.AudioRecorder, and this error is immediately produced upon trying to record. If I remove the auto load of the media manager playback, the error is triggered after the first time I playback and then try to record again. I've also gone the other way and added mediamanager to the AudioRecorder sample with the same result.
Any help is very much appreciated.