1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Wake-word recording cues.
//!
//! The two short sounds the hands-free voice path plays when a recording
//! starts and when it stops. They are the product's own samples — two assets
//! embedded in the binary and played through the machine's normal audio output
//! — so they never consult an operating-system sound API, library, theme or
//! preference.
//!
//! Cue playback deliberately bypasses [`crate::audio::tts`]'s read-aloud path:
//! the cues play with read-aloud off, and they must not raise the TTS playback
//! flag that makes the voice pipeline drop microphone audio. A host without an
//! audio output device is skipped silently rather than warned about on every
//! activation.
use cratetts;
use Cursor;
use ;
/// The start cue: a short rising two-tone blip.
///
/// Short by construction — the still-open microphone captures it, so its length
/// belongs to the recording-side budget documented at
/// [`crate::audio::voice::POST_FIRE_DISCARD_SAMPLES`].
const START_WAV: & = include_bytes!;
/// The end cue: a short lower blip, distinct from the start cue. Short as
/// well: the recording is over, but the microphone is still open.
const END_WAV: & = include_bytes!;
/// Which cue to play.
/// Latched once an output-device open has failed, so a host that cannot open one
/// is not re-probed (a device open is costly) on every activation. [`warm_up`]
/// clears it once per listening session, so a transient failure cannot silence
/// the cues for the whole process. The latch only suppresses the probe: as soon
/// as any path opens the device, cues play through the same mixer.
static NO_OUTPUT: AtomicBool = new;
/// Play `cue` through the machine's normal audio output.
///
/// Best-effort and non-blocking: the cue is mixed into the shared output and
/// neither held nor waited for. A host without audio output stays silent.
/// Warm the shared output device so a later [`play`] is not delayed by a cold
/// device open.
///
/// Called when the wake-word microphone starts. The start cue is captured by
/// that still-open microphone and has to fall inside the opening the recording
/// discards, so a device open on the detection path could push the cue into
/// recognized audio. Also gives each listening session one fresh probe of a
/// device that previously failed to open.
/// The shared output mixer, opening the device on first use.
///
/// Unlike the read-aloud path this opens the device silently and latches a
/// failure, so a host without audio output neither warns nor re-probes a costly
/// device open on every activation.