swift 3 using speech recognition and AVFoundation together - ios

I am successfully able to use Speech (speech recognition) and I can use AVFoundation to play wav files in Xcode 8/IOS 10. I just can't use them both together. I have working speech recognition code where I import Speech. When I import AVFoundation into the same app and use the following code, there is no sound and no errors are generated:
var audioPlayer: AVAudioPlayer!
func playAudio() {
let path = Bundle.main.path(forResource: "file.wav", ofType: nil)!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
audioPlayer = sound
sound.play()
} catch {
//handle error
}
}
I assume it is because both use audio. Can anyone suggest how to use both in the same app? I also find that I cannot use speech recognition and text-to-speech together in the same app.

I just bumped into the same problem, and here is how I solved,
add the following line when Speech Recognition is done. What it does is basically setting the audio session back to AVAudioSessionCategoryPlayback category.
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSessionCategoryPlayback)
try audioSession.setActive(false, with: .notifyOthersOnDeactivation)
} catch {
// handle errors
}
hope it helps.

You should change this line:
try audioSession.setCategory(AVAudioSessionCategoryPlayback)
on to:
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
This should work ;-)

It seems that AVAudioPlayer stops playing the sample if you're using AVAudioSession to record the microphone as in Apple's speech recognition example.
However, I've managed to circumvent this by using AVCaptureSession to capture audio as described in this answer.

Related

Use AudioKit Node to AVCaptureSession as audio inputs

I'm developing app for sound effects. I use AudioKit and I got a needed result for recoding voice. Now I want to add sound effect to voice while video is recording. I can record video with default voice, but I don't know how I can add effect to voice from video.
I use AVCaptureSession for video recording and I get audio stream like this:
self.audioDevice = AVCaptureDevice.default(for: AVMediaType.audio)
if let audioDevice = self.audioDevice {
self.audioInput = try AVCaptureDeviceInput(device: audioDevice)
if captureSession.canAddInput(self.audioInput!) {
captureSession.addInput(self.audioInput!)
} else {
throw CameraControllerError.inputsAreInvalid
}
}
But I want to set to captureSession input AVAudioNode, because AudioKit works with it.
I will be glad for any help. Thanks

How to switch to earSpeaker programmatically in iOS?

I am currently playing an audio file with "MobileVlcKit" and I need to switch to earSpeaker (top speaker for phone calls) in the middle of playing audio file.
Currently I am using this code:
AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
But it keep playing from main speaker.
Do anyone knows what is my problem?
I just checked my 2 years old objective-c code, not sure will it work for you, but worth to try. here is its swift version:
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setActive(false)
try audioSession.setCategory(.playAndRecord, options: .defaultToSpeaker)
try audioSession.overrideOutputAudioPort(.none)
try audioSession.setActive(true)
} catch {
// handle error
print(error)
}

Play dialler tone on ear-speaker

I'm currently working on a VOIP based application. In which when a user calls another person I need to play a dialler tone on the ear-speaker. I've searched a lot, but couldn't find any solution yet. I've used the following code to play the dialler tone:
// This method plays the ringtone for incoming call
func playRingtone()
{
let path = Bundle.main.path(forResource: "ringing.mp3", ofType:nil)!
let url = URL(fileURLWithPath: path)
do
{
ringtonePlayer = try AVAudioPlayer(contentsOf: url)
ringtonePlayer?.numberOfLoops = 5
ringtonePlayer?.play()
}
catch let error
{
print(error.localizedDescription)
}
}
But it's playing on the loud speaker, not on the ear-speaker.
Additional Info: I'm using TokBox SDK
Can anyone please help me to solve this issue? Thanks in advance.

AVAudioPlayer sound not playing

In iOS 8/Xcode 6 I had a function that included a sound effect. It no longer works in iOS 9 after changing the code multiple times. This is what I've tried:
Original:
let bangSoundEffect = SKAction.playSoundFileNamed("Bang.mp3", waitForCompletion: false)
runAction(bangSoundEffect)
Other attempt:
self.runAction(SKAction.playSoundFileNamed("Bang.mp3", waitForCompletion: false))
Also:
func playRocketExplosionSound(filename: String) {
let url = NSBundle.mainBundle().URLForResource(
filename, withExtension: nil)
if (url == nil) {
print("Could not find file: \(filename)")
return }
var error: NSError? = nil
do {
backgroundMusicPlayer =
try AVAudioPlayer(contentsOfURL: url!)
} catch let error1 as NSError {
error = error1
backgroundMusicPlayer = nil
}
if backgroundMusicPlayer == nil {
print("Could not create audio player: \(error!)")
return}
backgroundMusicPlayer.numberOfLoops = 1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play() }
playRocketExplosionSound("Bang.mp3")
I'm pulling my hair out. I'm using the same code in a different scene for another sound effect and it works fine!! What's going wrong?
I've noticed that the sound effect begins to play sometimes in the simulator, however it doesn't complete and throws this error:
2015-09-24 19:12:14.554 APPNAME[4982:270835] 19:12:14.553 ERROR: 177: timed out after 0.012s (735 736); mMajorChangePending=0
It doesn't work at all on actual devices.
What is the problem? :'(
Possible problem with MP3 file
The problem is most likely connected with the MP3 file you're using. The code works for other sounds, this suggests that the MP3 file might be corrupted and AVAudioPlayer fails with decoding it. You can try re-encode this file and see if the problem persists. Or, even better, converting it to WAV.
Using WAVs
General rule of the thumb when creating short sound effects for games, is to use WAV unless you really feel you need the trim the fat.
Top-notch games are going for top-of-the-line production quality, so they record and produce assets uncompressed 24bit/48kHz. Titles with slightly lesser ambitions might record and produce in 16/44.1, which is the official standard for CD quality audio.
This has at least two benefits. One is that the sound has a better quality. Second one, the CPU does not have to decode the file to play it.
Corrupt data file | AVAudioPlayer out of scope
1. Corrupt data file
This will ensure you have found the file:
var backgroundMusicPlayer: AVAudioPlayer? = nil
if let url = Bundle.main.url(
forResource: "Bang", withExtension: "mp3") {
do {
try backgroundMusicPlayer = AVAudioPlayer(contentsOf: url)
backgroundMusicPlayer!.play()
} catch {}
}
return nil
2. AVAudioPlayer out of scope
The variable retaining backgroundMusicPlayer must not go out of scope before play() has completed and returns. This is generally achieved by using a class variable:
var backgroundMusicPlayer: AVAudioPlayer? = nil
Don't do this: the following sound will play for, at best, outOfScopeDelay due to the local scope of var audioPlayer.
let outOfScopeDelay = 0.5
do {
var audioPlayer:AVAudioPlayer! // Incorrectly scoped variable
try audioPlayer = AVAudioPlayer(contentsOf: audioRecorder.url)
audioPlayer.play()
Thread.sleep(forTimeInterval: outOfScopeDelay)
} catch {}
► Find this solution on GitHub and additional details on Swift Recipes.
try this:
dispatch_async(dispatch_get_main_queue(), {
(self.playRocketExplosionSound("Bang.mp3")
})
it's no longer safe to play audio in child thread under iOS 9.

how do I set my Audio Session Default Behavior to Playback in swift?

My app has a "Click" sound functionality. I used the
import AVFoundation
then the following function to run the "Click" sound:
var audioPlayer = AVAudioPlayer()
func playSound() {
var soundPath = NSBundle.mainBundle().pathForResource("tick", ofType: "wav")
var soundURL = NSURL.fileURLWithPath(soundPath!)
self.audioPlayer = AVAudioPlayer(contentsOfURL: soundURL, error: nil)
self.audioPlayer.play()
}
Now if the user is running a music player, my app causes the music player to stop. I read about the Audio Session Default Behavior in the documentation, but I don't know how to apply it.
Can you please help?
Thank you!
If you are wondering the syntax for swift 2, here it is:
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: .DuckOthers)
} catch {
print("AVAudioSession cannot be set: \(error)")
}
Depending on what you want the app to behave, i.e, how your app's sound effect or music should interact with other app's background audio session, you might need to tweak both the audio session category and categoryOption.
If you just want to play the sound effect, like "tick" sound, then, AVAudioSessionCategoryAmbient and DuckOthers should be used respectively, for example:
let audioSession = AVAudioSession.sharedInstance()
var error: NSErrorPointer = nil
audioSession.setCategory(AVAudioSessionCategoryAmbient, withOptions: .DuckOthers, error: error)
However, I suppose you are actually trying to play a sound effect, in this case, the AudioServices API is a more suitable choice. You can check func AudioServicesPlaySystemSound(inSystemSoundID: SystemSoundID) in AudioToolbox framework for more details.
Another common scenario. If you want to have your app to play audio exclusively, even if there're other app's playing the music in the background, you need to set the category to AVAudioSessionCategorySoloAmbient, for example:
let audioSession = AVAudioSession.sharedInstance()
var error: NSErrorPointer = nil
audioSession.setCategory(AVAudioSessionCategorySoloAmbient, error: error)
I hope you've got what you're looking for.

Resources