#if os(macOS) import CoreAudio import LiveKitWebRTC import XCTest @testable import CallsKit /// Paul's first-launch report, reproduced without a Scarlett: a public /// aggregate device stands in for an interface that is connected but is /// not the system default, and is remembered as the microphone. Opt-in /// (CALLS_AUDIO_REPRO=1) because it adds a device to the Mac for the /// length of the test. final class ScarlettReproTests: XCTestCase { @MainActor func testARememberedNonDefaultInterfaceIsUsedAtFirstLaunch() throws { guard ProcessInfo.processInfo.environment["CALLS_AUDIO_REPRO"] == "1" else { throw XCTSkip("set CALLS_AUDIO_REPRO=1 to add a stand-in interface to this Mac") } let inventory = CoreAudioDevices.inventory() guard let mic = inventory.defaultInput, let speaker = inventory.defaultOutput else { throw XCTSkip("no default devices") } let uid = "net.amadan.oficina.calls.repro.\(UUID().uuidString)" let description: [String: Any] = [ kAudioAggregateDeviceNameKey: "Stand-in Scarlett", kAudioAggregateDeviceUIDKey: uid, kAudioAggregateDeviceMainSubDeviceKey: speaker, kAudioAggregateDeviceSubDeviceListKey: [ [kAudioSubDeviceUIDKey: mic, kAudioSubDeviceDriftCompensationKey: 1], [kAudioSubDeviceUIDKey: speaker], ], ] var device = AudioDeviceID(0) XCTAssertEqual(AudioHardwareCreateAggregateDevice(description as CFDictionary, &device), noErr) defer { AudioHardwareDestroyAggregateDevice(device) } RunLoop.main.run(until: Date().addingTimeInterval(0.5)) let suite = "calls-repro-\(UUID().uuidString)" let store = UserDefaults(suiteName: suite)! defer { store.removePersistentDomain(forName: suite) } store.set(uid, forKey: "audioInputUID") store.set("Stand-in Scarlett", forKey: "audioInputName") let routes = AudioRoutes(defaults: store) let audio = CallAudio(routes: routes, audioDevice: nil) print("REPRO at launch: input \(routes.currentInput ?? "nil"), note \"\(routes.routeNote)\"") XCTAssertEqual(routes.currentInput, uid, "the remembered interface at launch") XCTAssertEqual(routes.routeNote, "") let pc = audio.factory.peerConnection( with: RTCConfiguration(), constraints: RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil), delegate: nil) defer { pc?.close() } let listed = audio.factory.audioDeviceModule.inputDevices.map(\.deviceId) print("REPRO engine module inputs after the first connection: \(listed)") routes.refresh() XCTAssertEqual(routes.currentInput, uid, "and after the first connection") XCTAssertEqual(routes.routeNote, "") } } #endif