oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1import SwiftUI
2
3// The device panel's two §15.20 rows, apart from DevicePanel so the panel
4// changes by a line each: what your microphone is sending, measured, and
5// on a Mac with an audio interface, which of its inputs.
6
7/// "Microphone level": the meter from your own tile, in the panel where a
8/// person looks when they are told they cannot be heard — which, before
9/// this, showed a microphone name and nothing measured at all.
10public struct MicLevelRow: View {
11 @ObservedObject var mic: MicAudio
12 public init(mic: MicAudio) { self.mic = mic }
13 public var body: some View {
14 VStack(alignment: .leading, spacing: 4) {
15 HStack(spacing: 8) {
16 Text("Microphone level").font(.subheadline)
17 // The tiles' glow is for a call; setting up wants to see the
18 // level itself, so the panel keeps a compact meter, borderless.
19 AudioLevelBars(step: mic.muted ? 0 : mic.step, height: 14)
20 Text(words).font(.footnote).foregroundStyle(.secondary)
21 }
22 if mic.silent {
23 Label(AudioWords.micSilent, systemImage: "exclamationmark.triangle.fill")
24 .font(.callout).foregroundStyle(.orange)
25 .fixedSize(horizontal: false, vertical: true)
26 .accessibilityIdentifier("micSilent")
27 Text(AudioWords.micSilentDetail(source: mic.source, channels: mic.channels))
28 .font(.footnote).foregroundStyle(.secondary)
29 .fixedSize(horizontal: false, vertical: true)
30 }
31 }
32 .accessibilityElement(children: .combine)
33 .accessibilityIdentifier("micLevel")
34 }
35
36 /// The meter in words, so it is never only a picture.
37 private var words: String {
38 if mic.muted { return "Muted" }
39 if mic.silent { return "Silent" }
40 return mic.step == 0 ? "Quiet" : mic.speaking ? "Hearing you" : "Picking up sound"
41 }
42}
43
44#if os(macOS)
45 /// "Input", for a microphone with more than one: an audio interface's
46 /// inputs by number and, where the driver names them, by name. The call
47 /// sends the chosen one, and the choice is remembered for the device.
48 public struct InputChannelPicker: View {
49 @ObservedObject var audio: AudioRoutes
50 public init(audio: AudioRoutes) { self.audio = audio }
51 public var body: some View {
52 if audio.inputChannels.count > 1 {
53 VStack(alignment: .leading, spacing: 4) {
54 Picker(
55 "Input",
56 selection: Binding(
57 get: { audio.inputChannel }, set: { audio.use(inputChannel: $0) })
58 ) {
59 ForEach(Array(audio.inputChannels.enumerated()), id: \.offset) { index, label in
60 Text(label).tag(index)
61 }
62 }
63 .pickerStyle(.menu)
64 .accessibilityIdentifier("inputChannelPicker")
65 Text(
66 "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."
67 )
68 .font(.footnote).foregroundStyle(.secondary)
69 .fixedSize(horizontal: false, vertical: true)
70 }
71 }
72 }
73 }
74#endif
75