How to select bottom microphone for IOS video app? - ios

I found this sample code online: https://developer.apple.com/library/content/samplecode/AVCam/Introduction/Intro.html
I am trying to change the input microphone from the default microphone to the bottom microphone on an iPhone. Does anyone have any experience going about this in Swift? The only examples I've found were in Obj-C and caused errors when I implemented them. I'm using apple's AVCam sample app for reference, the audio part is included below.
// Add audio input.
do {
let audioDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice)
if session.canAddInput(audioDeviceInput) {
session.addInput(audioDeviceInput)
}
else {
print("Could not add audio device input to the session")
}
}
catch {
print("Could not create audio device input: \(error)")
}

You should try settings the category of the session using:
session.setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: AVAudioSessionCategoryOptions.DefaultToSpeaker, error: nil)
this should make use the bottom microphone by default

If you only need audio you should use AVAudioSession - https://developer.apple.com/reference/avfoundation/avaudiosession
Not tested Sample code you could play around with:
import AVFoundation
.
.
private var session: AVAudioSession!
private var input: AVAudioSessionPortDescription!
.
.
.
session = AVAudioSession.sharedInstance()
do {
try session.setCategory(AVAudioSessionCategoryRecord)
// Fetch Built in Mic
if let availableInputs = session.availableInputs {
for inputSource in availableInputs {
if inputSource.portType == AVAudioSessionPortBuiltInMic {
input = inputSource
break
}
}
// Set preferred data source by location
if let dataSources = input.dataSources {
for dataSource in dataSources {
if dataSource.location == AVAudioSessionLocationLower {
input.setPreferredDataSource(dataSource)
break
}
}
}
session.setPreferredInput(input)
.
.
} catch {
....
}

Related

Switch Audio Between Speaker, Built in mic, Bluetooth or No Audio

I am working on a Video/Audio Call App where i need to provide four options related to the Audio Output:
Speaker, Built in mic, Any BLE Device supporting audio, No Audio output
Below functions i have used:
static func setBuiltInMic() {
let outputs = audioSession.availableInputs
for output in outputs! {
if output.portType.rawValue == AVAudioSession.Port.builtInMic.rawValue {
do {
try audioSession.setPreferredInput(output)
} catch let error {
print("Setting Built in Mic Port: \(error.localizedDescription)")
}
}
}
}
static func setAndCheckBLEAudioPort() -> Bool {
let outputs = audioSession.availableInputs
for output in outputs! {
if output.portType.rawValue == AVAudioSession.Port.bluetoothHFP.rawValue {
do {
try audioSession.setPreferredInput(output)
return true
} catch let error {
print("Setting BLE Port: \(error.localizedDescription)")
return false
}
}
}
return false
}
static func setupAudioSession(isSpeakerEnabled: Bool) {
do {
try audioSession.setCategory(.playAndRecord)
try audioSession.setMode(.voiceChat)
try audioSession.overrideOutputAudioPort(isSpeakerEnabled ? .speaker : .none)
try audioSession.setActive(true, options: [])
} catch let error as NSError {
print("Fail: \(error.localizedDescription)")
}
}
But this doesn't work Audio keeps coming from different source like speaker even if i try to mute it using setupAudioSession
Anyone has an idea or reference for me to look into it?
The code is working fine, it was an issue with a third party library used for audio and video calls prior to Twilio.

AVAudioSession and Haptic Feedback

The main issue here is, when the microphone input is added, the device loses any haptic system sounds.
I setup the audio session here:
let audioSession = AVAudioSession.sharedInstance()
do {
try self.audioSession.setCategory(.playAndRecord, options: .mixWithOthers)
try self.audioSession.setAllowHapticsAndSystemSoundsDuringRecording(true)
try self.audioSession.setActive(true)
} catch { }
I make sure I am using setAllowHapticsAndSystemSoundsDuringRecording.
Though out the app, I am adding the microphone and removing it on-demand:
do {
let microphonePermission = AVCaptureDevice.authorizationStatus(for: AVMediaType.audio)
if microphonePermission != .denied && microphonePermission != .restricted {
let audioDevice = AVCaptureDevice.default(for: AVMediaType.audio)
let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice!)
if self.session.canAddInput(audioDeviceInput) {
self.session.addInput(audioDeviceInput)
}
else { print("Could not add audio device input to the session.") }
} else {
}
}
catch { print("Could not create audio device input: \(error).") }
As soon as the microphone is added, it loses haptic feedback and system sounds.

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.

AVAudioSession does not recognise audio from bluetooth device

I am using AVAudioSession to listen to voice input. it works fine for wired headphones but it is not working for connected bluetooth device. Following is the code I am using to set input to bluetooth mic
func setupSessionForRecording() {
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, with: [.allowBluetooth])
} catch let error as NSError {
debugPrint("Error in listening "+error.localizedDescription)
}
var inputsPriority: [(type: String, input: AVAudioSessionPortDescription?)] = [
(AVAudioSessionPortLineIn, nil),
(AVAudioSessionPortHeadsetMic, nil),
(AVAudioSessionPortBluetoothHFP, nil),
(AVAudioSessionPortUSBAudio, nil),
(AVAudioSessionPortCarAudio, nil),
(AVAudioSessionPortBuiltInMic, nil),
]
for availableInput in audioSession.availableInputs! {
guard let index = inputsPriority.index(where: { $0.type == availableInput.portType }) else { continue }
inputsPriority[index].input = availableInput
}
guard let input = inputsPriority.filter({ $0.input != nil }).first?.input else {
fatalError("No Available Ports For Recording")
}
do {
try audioSession.setPreferredInput(input)
try audioSession.setMode(AVAudioSessionModeMeasurement)
try audioSession.setActive(true, with: .notifyOthersOnDeactivation)
try audioSession.setPreferredIOBufferDuration(10)
} catch {
fatalError("Error Setting Up Audio Session")
}
}
This code stops taking input from device mic and I also get sound in bluetooth headset that it is ready to listen but it doesn't pick any input from device.
Also,
When I am trying to play any audio into bluetooth headset It doesn't work. Here is the code to play audio
do {
let output = AVAudioSession.sharedInstance().currentRoute.outputs[0].portType
if output == "Receiver" || output == "Speaker"{
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
}
else{
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
}
print("Voice Out \(output)" )
} catch let error as NSError {
print("audioSession error: \(error.localizedDescription)")
os_log("Error during changing the current audio route: %#" , log: PollyVoiceViewController.log, type: .error, error)
} catch {
os_log("Unknown error during changing the current audio route", log: PollyVoiceViewController.log, type: .error)
}
do {
let soundData = try Data(contentsOf: url as URL)
self.audioPlayer = try AVAudioPlayer(data: soundData)
self.audioPlayer?.prepareToPlay()
self.audioPlayer?.volume = 3.0
self.audioPlayer?.delegate = self
self.audioPlayer?.play()
} catch let error as NSError {
print("Error getting the audio file"+error.description)
}
The reason is: BluetoothHFP is not available in AVAudioSessionModeMeasurement mode
AVAudioSessionModeMeasurement
After you set try audioSession.setMode(AVAudioSessionModeMeasurement), the audioSession.availableInputs is not contain the BluetoothHFP.
This mode is intended for apps that need to minimize the amount of system-supplied signal processing to input and output signals. If recording on devices with more than one built-in microphone, the primary microphone is used.
And in the document of setPreferredInput(_:)
The AVAudioSessionPortDescription must be in the availableInputs array.
The value of the inPort parameter must be one of the AVAudioSessionPortDescription objects in the availableInputs array. If this parameter specifies a port that is not already part of the current audio route and the app’s session controls audio routing, this method initiates a route change to use the preferred port.
And it must set up after setting the mode.
You must set a preferred input port only after setting the audio session’s category and mode and activating the session.

MPMoviePlayerViewController only display video but not playing the audio iOS 8

Forgive me if this question has been asked already, but I've looked everywhere and all I can find is old questions from iOS 5.0 and people have the opposite problem.
My problem is I have created a video I would like to use in my application, and I recently added audio to it. The video plays fine with no problems, but the audio does not play. If I play the video in any video player in my computer, the sound is there so I cant figure out what the problem is.
Here is my code:
var movieViewController: MPMoviePlayerViewController?
func playVideoUsingViewController() {
if let
path = NSBundle.mainBundle().pathForResource("wakyIntro", ofType: "mp4"),
url = NSURL(fileURLWithPath: path),
movieViewController = MPMoviePlayerViewController(contentURL: url) {
self.movieViewController = movieViewController
movieViewController.moviePlayer.fullscreen = true
movieViewController.moviePlayer.controlStyle = .None
movieViewController.moviePlayer.scalingMode = .AspectFill
movieViewController.view.userInteractionEnabled = false
self.showViewController(movieViewController, sender: self)
println("Movie loaded")
} else {
println("Video failed")
}
}
Then I just call it from my ViewController:
func mainMenuViewControllerDidPressPlay(mainMenuViewController: MainMenuViewController) {
game?.runAction(pressButton)
if !videoPlayed{
playVideoUsingViewController()
} else if !gameStarted {
gameStarted = true
game?.bird.startAnimation(game!)
game?.bird.startPhysics()
}
self.hideViewController(mainMenuViewController)
}
Any ideas or suggestions would be greatly appreciated!
This is a solution in swift based on #user2709666's response
var session: AVAudioSession = AVAudioSession.sharedInstance()
session.setCategory("AVAudioSessionCategoryPlayback", withOptions: AVAudioSessionCategoryOptions.DefaultToSpeaker, error: nil)
Call this before playing the video.
Edit for Swift 2.2 :
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
} catch let error as NSError {
print(error)
}
Make a session of AVAudioSession.
Following is the code:
var session = AVAudioSession.SharedInstance();
session.SetCategory(new NSString("AVAudioSessionCategoryPlayback"), AVAudioSessionCategoryOptions.DefaultToSpeaker, out error);
if (error != null)
{
Console.WriteLine(error);
}
and add this before your video player. I am sure this will work for you, I got the same issue before.

Resources