Skip to content

Commit

Permalink
Provide default device api (aws#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
hokyungh authored Nov 5, 2020
1 parent 1d8688d commit 5d8d0fc
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 5 deletions.
1 change: 1 addition & 0 deletions AmazonChimeSDK/.swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
excluded:
- MockingbirdMocks
- MockingbirdSupport
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,8 @@ import Foundation
}

public func hasBandwidthPriorityCallback(hasBandwidthPriority: Bool) {}

public func getActiveAudioDevice() -> MediaDevice? {
return deviceController.getActiveAudioDevice()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import AVFoundation

public func listAudioDevices() -> [MediaDevice] {
var inputDevices: [MediaDevice] = []
let loudSpeaker = MediaDevice(label: "Built-in Speaker", type: MediaDeviceType.audioBuiltInSpeaker)
let loudSpeaker = getSpeakerMediaDevice()
if let availablePort = audioSession.availableInputs {
inputDevices = availablePort.map { port in MediaDevice.fromAVSessionPort(port: port) }
}
Expand Down Expand Up @@ -122,4 +122,24 @@ import AVFoundation
public func listSupportedVideoCaptureFormats(mediaDevice: MediaDevice) -> [VideoCaptureFormat] {
return MediaDevice.listSupportedVideoCaptureFormats(mediaDevice: mediaDevice)
}

public func getActiveAudioDevice() -> MediaDevice? {
// Check for speaker case
if audioSession.currentRoute.outputs.count > 0 {
let currentOutput = audioSession.currentRoute.outputs[0]

if currentOutput.portType == .builtInSpeaker {
return getSpeakerMediaDevice()
}
}
if audioSession.currentRoute.inputs.count > 0 {
return MediaDevice.fromAVSessionPort(port: audioSession.currentRoute.inputs[0])
} else {
return nil
}
}

private func getSpeakerMediaDevice() -> MediaDevice {
return MediaDevice(label: "Built-in Speaker", type: MediaDeviceType.audioBuiltInSpeaker)
}
}
4 changes: 4 additions & 0 deletions AmazonChimeSDK/AmazonChimeSDK/device/DeviceController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,8 @@ import Foundation
/// e.g. one passed in via `AudioVideoControllerFacade.startLocalVideo`
/// - Returns: a media device or nil if no device is present
func getActiveCamera() -> MediaDevice?

/// Get currently used audio device
/// - Returns: a media device or nil if no device is present
func getActiveAudioDevice() -> MediaDevice?
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// swiftlint:disable identifier_name function_parameter_count

import AmazonChimeSDKMedia
import Foundation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Foundation
var availableInputs: [AVAudioSessionPortDescription]? { get }
func setPreferredInput(_ inPort: AVAudioSessionPortDescription?) throws
func overrideOutputAudioPort(_ portOverride: AVAudioSession.PortOverride) throws
var currentRoute: AVAudioSessionRouteDescription { get }
}

extension AVAudioSession: AudioSession {}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ class DefaultDeviceControllerTests: XCTestCase {
override func setUp() {
videoClientControllerMock = mock(VideoClientController.self)
loggerMock = mock(Logger.self)
let route = AVAudioSession.sharedInstance().currentRoute
audioSessionMock = mock(AudioSession.self)
given(audioSessionMock.getCurrentRoute()).willReturn(route)
defaultDeviceController = DefaultDeviceController(audioSession: audioSessionMock,
videoClientController: videoClientControllerMock,
logger: loggerMock)
Expand Down Expand Up @@ -57,4 +59,22 @@ class DefaultDeviceControllerTests: XCTestCase {

verify(videoClientControllerMock.switchCamera()).wasCalled()
}

func testGetCurrentAudioDevice() {
let currentDevice = defaultDeviceController.getActiveAudioDevice()
let route = AVAudioSession.sharedInstance().currentRoute
var expected: MediaDevice?
if route.outputs.count > 0 {
if route.outputs[0].portType == .builtInSpeaker {
expected = MediaDevice(label: "Built-in Speaker", type: MediaDeviceType.audioBuiltInSpeaker)
} else if route.inputs.count > 0 {
expected = MediaDevice.fromAVSessionPort(port: route.inputs[0])
}
}

verify(audioSessionMock.getCurrentRoute()).wasCalled(2)
XCTAssertEqual(currentDevice?.label, expected?.label)
XCTAssertEqual(currentDevice?.type, expected?.type)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class ConcurrentMutableSetTests: XCTestCase {
mainThreadEndedExpectation.fulfill()
}

wait(for: [backgroundThreadEndedExpectation, mainThreadEndedExpectation], timeout: 5)
wait(for: [backgroundThreadEndedExpectation, mainThreadEndedExpectation], timeout: 7)
XCTAssertEqual(count, 1)
XCTAssertEqual(sum, 1)
XCTAssertEqual(normalSet.count, 1)
Expand Down
4 changes: 4 additions & 0 deletions AmazonChimeSDKDemo/AmazonChimeSDKDemo/MeetingModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ class MeetingModel: NSObject {
return currentMeetingSession.audioVideo.listAudioDevices()
}

var currentAudioDevice: MediaDevice? {
return currentMeetingSession.audioVideo.getActiveAudioDevice()
}

var isLocalVideoActive = false {
didSet {
if isLocalVideoActive {
Expand Down
13 changes: 10 additions & 3 deletions AmazonChimeSDKDemo/AmazonChimeSDKDemo/MeetingViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -335,13 +335,20 @@ class MeetingViewController: UIViewController {
guard let meetingModel = meetingModel else {
return
}
let optionMenu = UIAlertController(title: nil, message: "Choose Audio Device", preferredStyle: .actionSheet)

let optionMenu = UIAlertController(title: nil, message: "Choose Audio Device", preferredStyle: .actionSheet)
let currentAudioDevice = meetingModel.currentAudioDevice
for inputDevice in meetingModel.audioDevices {
let deviceAction = UIAlertAction(title: inputDevice.label,
var label = inputDevice.label
if let selectedAudioDevice = currentAudioDevice {
if selectedAudioDevice.label == inputDevice.label {
label = "\(label) ✔︎"
}
}
let deviceAction = UIAlertAction(title: label,
style: .default,
handler: { _ in meetingModel.chooseAudioDevice(inputDevice)
})
})
optionMenu.addAction(deviceAction)
}

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Added new APIs in `RealtimeControllerFacade` to enable/disable Voice Focus (ML-based noise suppression) and get the on/off status of Voice Focus.
* Added Voice Focus feature in Swift demo app.
* Added more verbose logging from media layer to SDK layer for builders to control log level. Set `LogLevel` to `INFO` or above for production application to not be bombarded with logs.
* Added `getActiveAudioDevice` API in `DefaultDeviceController`.

### Fixed
* Fixed `DefaultDeviceController` not removing itself as observer from `NotificationCenter` after deallocation and causes crash in Swift demo app.
Expand Down

0 comments on commit 5d8d0fc

Please sign in to comment.