Skip to content

Commit 4edbdb3

Browse files
Merge pull request #204 from blackboxembedded/bt_mic
Add BT microphone support
2 parents 001207f + 3cd5b55 commit 4edbdb3

1 file changed

Lines changed: 78 additions & 22 deletions

File tree

WunderLINQ/TaskList/TasksCollectionViewController.swift

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class TasksCollectionViewController: UICollectionViewController, UICollectionVie
4141
var captureSession: AVCaptureSession?
4242
var cameraImage: UIImage?
4343

44+
private let audioSession = AVAudioSession.sharedInstance()
4445
var videoCaptureSession = AVCaptureSession()
4546
let movieOutput = AVCaptureMovieFileOutput()
4647
var activeInput: AVCaptureDeviceInput!
@@ -921,10 +922,64 @@ class TasksCollectionViewController: UICollectionViewController, UICollectionVie
921922
})
922923
}
923924

924-
//MARK:- Setup Camera
925+
//MARK: - Select Audio Source
926+
// Prefer BT HFP, else fall back to built-in mic
927+
private func configureAudioSessionForVideo() throws {
928+
// Let *you* control the audio session (not AVCaptureSession)
929+
videoCaptureSession.automaticallyConfiguresApplicationAudioSession = false
930+
931+
// Category/mode appropriate for video capture; allow BT HFP input
932+
try audioSession.setCategory(.playAndRecord,
933+
mode: .videoRecording,
934+
options: [.allowBluetooth, .defaultToSpeaker])
935+
936+
// HFP is typically 8–16 kHz mono; asking for 16 kHz reduces resampling
937+
try? audioSession.setPreferredSampleRate(16_000)
938+
939+
// Pick HFP if available; otherwise nil = system default (built-in mic)
940+
if let hfp = audioSession.availableInputs?.first(where: { $0.portType == .bluetoothHFP }) {
941+
try audioSession.setPreferredInput(hfp)
942+
} else {
943+
try audioSession.setPreferredInput(nil)
944+
}
945+
946+
try audioSession.setActive(true, options: [])
947+
948+
// (Optional) log the actual route you got
949+
let routeDesc = audioSession.currentRoute.inputs.map { "\($0.portType.rawValue) \($0.portName)" }.joined(separator: ", ")
950+
NSLog("Audio route inputs: \(routeDesc)")
951+
}
952+
953+
// Keep preferring HFP when the route changes (AirPods in/out, etc.)
954+
@objc private func handleRouteChange(_ note: Notification) {
955+
do {
956+
if let hfp = audioSession.availableInputs?.first(where: { $0.portType == .bluetoothHFP }) {
957+
try audioSession.setPreferredInput(hfp)
958+
} else {
959+
try audioSession.setPreferredInput(nil) // fallback (built-in)
960+
}
961+
} catch {
962+
NSLog("Audio route change handling failed: \(error)")
963+
}
964+
}
965+
966+
//MARK: - Setup Camera
925967
func setupSession(position: AVCaptureDevice.Position) -> Bool {
926-
videoCaptureSession.sessionPreset = AVCaptureSession.Preset(rawValue: convertFromAVCaptureSessionPreset(AVCaptureSession.Preset.high))
927-
// Setup Camera
968+
videoCaptureSession.sessionPreset = .high
969+
970+
// 1) Configure audio session first (prefer BT HFP, else builtin)
971+
do {
972+
try configureAudioSessionForVideo()
973+
NotificationCenter.default.addObserver(self,
974+
selector: #selector(handleRouteChange(_:)),
975+
name: AVAudioSession.routeChangeNotification,
976+
object: audioSession)
977+
} catch {
978+
NSLog("Audio session config failed: \(error)")
979+
// keep going; we'll still attempt builtin mic via default route
980+
}
981+
982+
// 2) Setup Camera
928983
if let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: position) {
929984
do {
930985
let input = try AVCaptureDeviceInput(device: camera)
@@ -933,36 +988,37 @@ class TasksCollectionViewController: UICollectionViewController, UICollectionVie
933988
activeInput = input
934989
}
935990
} catch {
936-
NSLog("TasksCollectionViewController: Error setting device video input: \(error)")
991+
NSLog("Error setting device video input: \(error)")
937992
return false
938993
}
994+
} else {
995+
NSLog("Front camera not available")
939996
}
940-
else {
941-
NSLog("TasksCollectionViewController: Front camera not available")
942-
}
943-
944-
// Setup Microphone
945-
let microphone = AVCaptureDevice.default(for: AVMediaType(rawValue: convertFromAVMediaType(AVMediaType.audio)))
946-
947-
do {
948-
let micInput = try AVCaptureDeviceInput(device: microphone!)
949-
if videoCaptureSession.canAddInput(micInput) {
950-
videoCaptureSession.addInput(micInput)
997+
998+
// 3) Setup Microphone (device is generic; AVAudioSession decides route)
999+
if let microphone = AVCaptureDevice.default(for: .audio) {
1000+
do {
1001+
let micInput = try AVCaptureDeviceInput(device: microphone)
1002+
if videoCaptureSession.canAddInput(micInput) {
1003+
videoCaptureSession.addInput(micInput)
1004+
}
1005+
} catch {
1006+
NSLog("Error setting device audio input: \(error)")
1007+
return false
9511008
}
952-
} catch {
953-
NSLog("TasksCollectionViewController: Error setting device audio input: \(error)")
954-
return false
1009+
} else {
1010+
NSLog("No audio capture device available")
9551011
}
956-
957-
// Movie output
1012+
1013+
// 4) Movie output
9581014
if videoCaptureSession.canAddOutput(movieOutput) {
9591015
videoCaptureSession.addOutput(movieOutput)
9601016
}
961-
1017+
9621018
return true
9631019
}
9641020

965-
//MARK:- Camera Session
1021+
//MARK: - Camera Session
9661022
func startSession(orientation: AVCaptureVideoOrientation) {
9671023
NSLog("TasksCollectionViewController: startSession()")
9681024
if !videoCaptureSession.isRunning {

0 commit comments

Comments
 (0)