import SwiftUI // The device panel's two §15.20 rows, apart from DevicePanel so the panel // changes by a line each: what your microphone is sending, measured, and // on a Mac with an audio interface, which of its inputs. /// "Microphone level": the meter from your own tile, in the panel where a /// person looks when they are told they cannot be heard — which, before /// this, showed a microphone name and nothing measured at all. public struct MicLevelRow: View { @ObservedObject var mic: MicAudio public init(mic: MicAudio) { self.mic = mic } public var body: some View { VStack(alignment: .leading, spacing: 4) { HStack(spacing: 8) { Text("Microphone level").font(.subheadline) // The tiles' glow is for a call; setting up wants to see the // level itself, so the panel keeps a compact meter, borderless. AudioLevelBars(step: mic.muted ? 0 : mic.step, height: 14) Text(words).font(.footnote).foregroundStyle(.secondary) } if mic.silent { Label(AudioWords.micSilent, systemImage: "exclamationmark.triangle.fill") .font(.callout).foregroundStyle(.orange) .fixedSize(horizontal: false, vertical: true) .accessibilityIdentifier("micSilent") Text(AudioWords.micSilentDetail(source: mic.source, channels: mic.channels)) .font(.footnote).foregroundStyle(.secondary) .fixedSize(horizontal: false, vertical: true) } } .accessibilityElement(children: .combine) .accessibilityIdentifier("micLevel") } /// The meter in words, so it is never only a picture. private var words: String { if mic.muted { return "Muted" } if mic.silent { return "Silent" } return mic.step == 0 ? "Quiet" : mic.speaking ? "Hearing you" : "Picking up sound" } } #if os(macOS) /// "Input", for a microphone with more than one: an audio interface's /// inputs by number and, where the driver names them, by name. The call /// sends the chosen one, and the choice is remembered for the device. public struct InputChannelPicker: View { @ObservedObject var audio: AudioRoutes public init(audio: AudioRoutes) { self.audio = audio } public var body: some View { if audio.inputChannels.count > 1 { VStack(alignment: .leading, spacing: 4) { Picker( "Input", selection: Binding( get: { audio.inputChannel }, set: { audio.use(inputChannel: $0) }) ) { ForEach(Array(audio.inputChannels.enumerated()), id: \.offset) { index, label in Text(label).tag(index) } } .pickerStyle(.menu) .accessibilityIdentifier("inputChannelPicker") Text( "This microphone has \(audio.inputChannels.count) inputs, and the call sends one. Choose the one your microphone is plugged into; changing it restarts the microphone for a moment." ) .font(.footnote).foregroundStyle(.secondary) .fixedSize(horizontal: false, vertical: true) } } } } #endif