Speaker/normal microphone during VOIP Call programatically iOS 10 swift - ios

I am designing an iOS application using PJSIP for VOIP Calling,
I start the call on speaker and on a button press i am able to make the call on normal microphone, but i am unable to make it on speaker again after pressing the speaker button.
I have used the following code to achieve that functionality :-
if sender.titleLabel?.text == "Speaker"{
do {
try audioSession.overrideOutputAudioPort(.none)
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try audioSession.setMode(AVAudioSessionModeVoiceChat)
try audioSession.setActive(true)
} catch {
print("AVAudioSession cannot be set: \(error)")
}
}else{
do {
try audioSession.overrideOutputAudioPort(.speaker)
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try audioSession.setMode(AVAudioSessionModeVoiceChat)
try audioSession.setActive(true)
} catch {
print("AVAudioSession cannot be set: \(error)")
}
}

Im not sure but I think your code will work while using NSNotificationCenter. Send notificaion for speaker in your if statement, and one notification for that else code.
var speaker = false
on press button action:
if speaker == false {
NSNotificationCenter.defaultCenter().postNotificationName("speakerON", object: nil)
} else {
NSNotificationCenter.defaultCenter().postNotificationName("speakerOFF", object: nil)
}
on viewDidLoad:
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"speakerON", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"speakerOFF", object: nil)
your functions:
func speakerON() {
try audioSession.overrideOutputAudioPort(.none)
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try audioSession.setMode(AVAudioSessionModeVoiceChat)
try audioSession.setActive(true)
}
func speakerOFF() {
try audioSession.overrideOutputAudioPort(.speaker)
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try audioSession.setMode(AVAudioSessionModeVoiceChat)
try audioSession.setActive(true)
}
Please see this link if you want to learn more about NSNotificationCenter:
https://stackoverflow.com/questions/24049020/nsnotificationcenter-addobserver-in-swift

Related

How to use main speaker programmatically in Swift

I'm implementing video chat using webrtc. In that I want use the main speaker when the other participant joins the session. For that, I wrote this code, but I'm getting a low voice volume (means voice coming from ear speaker)
func audioSetting() {
RTCAudioSession.sharedInstance().isAudioEnabled = true
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(AVAudioSession.Category.playAndRecord, mode: .videoChat, options: [])
if self.speakerOn {
try session.overrideOutputAudioPort(.none)
}
else {
try session.overrideOutputAudioPort(.speaker)
}
try session.setActive(true)
self.speakerOn = !self.speakerOn
}
catch let error {
print("Couldn't set audio to speaker: \(error)")
}
}
I am working on webRTC with socket.IO,
func setSpeakerStates(enabled: Bool)
{
let session = AVAudioSession.sharedInstance()
var _: Error?
try? session.setCategory(AVAudioSession.Category.playAndRecord)
try? session.setMode(AVAudioSession.Mode.voiceChat)
if enabled {
try? session.overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)
} else {
try? session.overrideOutputAudioPort(AVAudioSession.PortOverride.none)
}
try? session.setActive(true)
}
Please try this method at the end of the viewdidload after adding audio streaming and video streaming.

Audio controls in lock screen with AudioKit

I am using AudioKit to manage my sound engine in my app. I think AudioKit's settings are overriding something and I can't get lock screen audio controls. This is the code I have currently:
//Configure media control center
UIApplication.shared.beginReceivingRemoteControlEvents()
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.pauseCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
//Update your button here for the pause command
return .success
}
commandCenter.playCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
//Update your button here for the play command
return .success
}
I have this in a function which sets up all of my AudioKit settings but it doesn't work. Is there a special procedure for lock screen audio controls with AudioKit?
you have to write these code in appdelegate to implement :
do {
try AVAudioSession.sharedInstance().setActive(true)
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
}catch{
}
UIApplication.shared.beginReceivingRemoteControlEvents()
Keep in mind it's important to disable .mixWithOthers
You have to rewrite this methord:
//MARK:-音乐播放相应后台状态
override func remoteControlReceived(with event: UIEvent?) {
if (event?.type == .remoteControl) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: Configs.remotePlayCotrolNotificaation), object: nil, userInfo: ["event":event!])
}
}

App unable to find AVAudio BluetoothHFP Handsfree port Swift

In my app I want to check for the AVAudio portTypes already connected to the phone. The code below works for BluetoothA2DP and Headphones, but not BluetoothHFP when I connect the phone to my car handsfree. Can anyone help me?! I think have been through all the SO posts on Handsfree/AV/Bluetooth, and many others, but can't work out why it is not recognising the BluetoothHFP output portType.
import AVFoundation
func startCheckAVConnection() {
// set the AVAudioSession to allow bluetooth. This do/try/catch doesn't seem to make a difference if it is here or not.
do{
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: AVAudioSessionCategoryOptions.allowBluetooth)
} catch{
print(error)
}
// Check possible outputs for handsfree
let outputs = AVAudioSession.sharedInstance().currentRoute.outputs
if outputs.count != 0 {
for output in outputs {
if output.portType == AVAudioSessionPortBluetoothA2DP {
peripheralLabel.text = "connected to BluetoothA2DP"
} else if output.portType == AVAudioSessionPortBluetoothHFP { // NOT RECOGNISED
peripheralLabel.text = "connected to BluetoothHFP"
} else if output.portType == AVAudioSessionPortHeadphones {
peripheralLabel.text = "connected to Headphones"
}
}
} else {
peripheralLabel.text = "Please connect handsfree"
}
// Add observer for audioRouteChangeListener
NotificationCenter.default.addObserver(
self,
selector: #selector(TopVC.audioRouteChangeListener(_:)),
name: NSNotification.Name.AVAudioSessionRouteChange,
object: nil)
}
I needed to add setActive after setCategory.
do { try AVAudioSession.sharedInstance().setActive(true)
print("setActive")
} catch {
print(error)
}
Try changing your category setup to:
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: AVAudioSessionCategoryOptions.allowBluetooth)
HFP doesn't work with multi-route category AFAICT.

iOS stream Audio and record Audio

i have an app which should record audio when a button i pressed.
In my ViewDidLoad i preapare the recorder, the problem is that streaming audio interrupts when the line 'self.audioRecorder.prepareToRecord()' is called.
My setup :
do {
recordingSession = AVAudioSession.sharedInstance()
try recordingSession.setCategory(AVAudioSessionCategoryRecord, withOptions: [.DuckOthers, .AllowBluetooth, .MixWithOthers])
recordingSession.requestRecordPermission() { [unowned self] (allowed: Bool) -> Void in
dispatch_async(dispatch_get_main_queue()) {
do {
if allowed {
self.audioRecorder = try AVAudioRecorder(URL: self.tempAudioPath, settings: self.settings)
self.audioRecorder.delegate = self
self.audioRecorder.prepareToRecord()
//self.audioRecorder.record()
} else {
// failed to record!
print("No Access to Micro")
}
}catch{}
}
}
} catch {
print (error)
}
is there a way to preapare the audio recorder for record, and continue to play audio in background ? (duck it when recording the audio)
Per Apple's documentation for AVAudio​Session​Category​​Record, "this category silences playback audio". Have you tried setting the category to AVAudio​Session​Category​Play​And​Record?

Play Audio when device in silent mode - ios swift

I am creating an application using xcode 7.1, swift. I want to play an audio. Everything is fine. Now my problem I want to hear sound when the device in silent mode or muted. How can I do it?
I am using the following code to play audio
currentAudio!.stop()
currentAudio = try? AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("sample_audio", ofType: "mp3")!));
currentAudio!.currentTime = 0
currentAudio!.play();
Put this line before calling play() method of AVPlayer.
In Objective C
[[AVAudioSession sharedInstance]
setCategory: AVAudioSessionCategoryPlayback
error: nil];
In Swift
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch {
// report for an error
}
Swift 5
do {
try AVAudioSession.sharedInstance().setCategory(.playback)
} catch(let error) {
print(error.localizedDescription)
}
You can use AppDelegate class.
For enable sound (for audio or video) when device is in silent mode use AVAudioSessionCategoryPlayback:
func applicationDidBecomeActive(_ application: UIApplication) {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch {
print("AVAudioSessionCategoryPlayback not work")
}
}
For disable sound when device is in silent mode (for example when we answer the phone call) use AVAudioSessionCategorySoloAmbient:
func applicationWillResignActive(_ application: UIApplication) {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategorySoloAmbient)
} catch {
print("AVAudioSessionCategorySoloAmbient not work")
}
}
Swift 4
use this line before play video
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
Swift 3.0 and Xcode > 8
Play sound in Video when device is on RINGER mode and SLIENT mode
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
//print("AVAudioSession Category Playback OK")
do {
try AVAudioSession.sharedInstance().setActive(true)
//print("AVAudioSession is Active")
} catch _ as NSError {
//print(error.localizedDescription)
}
} catch _ as NSError {
//print(error.localizedDescription)
}
Swift 4.2
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
} catch let error {
print("Error in AVAudio Session\(error.localizedDescription)")
}
Swift 5.0.1
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
You can go through this, it will help you out
When you use following audio session categories, sounds will not be muted on iOS: AVAudioSessionCategoryPlayback,AVAudioSessionCategoryRecord,AVAudioSessionCategoryPlayAndRecord
Example
func playSound (Sound: String, Type: String) {
//Prepare the sound file name & extension
var alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(Sound, ofType: Type)!)
//Preparation to play
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
//Play audio
var error: NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: alertSound, error: &error)
audioPlayer.prepareToPlay()
audioPlayer.play()
}
import AVKit
And add this to your AppDelegate's applicationDidBecomeActive section
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
print("AVAudioSession Category Playback OK")
do {
try AVAudioSession.sharedInstance().setActive(true)
print("AVAudioSession is Active")
} catch {
print(error.localizedDescription)
}
} catch {
print(error.localizedDescription)
}
}

Resources