Loopback Detector Module¶
Overview¶
The Loopback Detector
module enables your Alexa Auto SDK client application to monitor wake word detection to cancel out self references.
In some environments where acoustic echo cancellation capabilities are limited, the microphone may pick up the wake word from speakers, which will cause false wake word detection. For example, if the user says "Alexa, what's your name?", Alexa responds with "My name is Alexa", which may cause false wake word detection and interrupt the current speech output.
The Loopback Detector
module solves this issue by capturing speaker reference "loopback" audio and trying to detect the wake word at the same time.
Configuring the Loopback Detector Module¶
The Loopback Detector
module can be optionally configured with the following configuration structure:
{
"aace.loopbackDetector" : {
"wakewordEngine" : "<WAKEWORD ENGINE NAME>"
}
}
Setting up the Loopback Detector Module¶
Providing Audio¶
The Loopback Detector
module requests audio through the StartAudioInput
AASB message. The StartAudioInput
message payload contains a field audioType
set to LOOPBACK
. The StopAudioInput
AASB message is sent to request that audio input be stopped. The example below shows how to handle the StartAudioInput
and StopAudioInput
messages.
#include <AASB/Message/Audio/AudioInput/StartAudioInputMessage.h>
#include <AASB/Message/Audio/AudioInput/StopAudioInputMessage.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
// Loopback stream id
std::string m_streamId;
// subscribe to the StartAudioInput message
messageBroker->subscribe([=](const std::string& msg) {
// parse the json message
StartAudioInputMessage _msg = json::parse(msg);
m_streamId = _msg.payload.streamId;
auto audioType = _msg.payload.audioType;
if (audioType == "LOOPBACK") {
// open the stream for writing
auto stream = messageBroker->openStream(
m_streamId,
MessageStream::Mode::WRITE);
if (stream != nullptr)
startAudioInput(m_streamId, stream)
}
}),
StartAudioInputMessage::topic(),
StartAudioInputMessage::action());
// subscribe to the StopAudioInput message
messageBroker->subscribe([=](const std::string& msg) {
// parse the json message
StopAudioInputMessage _msg = json::parse(msg);
auto streamId = _msg.payload.streamId;
if (streamId == m_streamId) {
stopAudioInput(streamId);
m_streamId = "";
}
}),
StopAudioInputMessage::topic(),
StopAudioInputMessage::action());
void startAudioInput(const std::string& streamId, std::shared_ptr<MessageStream> stream) {
// On another thread, write data to the stream until
// you receive a StopAudioInput message with the same streamId
// ...
// Return quickly to avoid blocking the MessageBroker's outgoing thread!
}
void stopAudioInput(const std::string& streamId) {
// Stop writing audio data to the stream
// ...
// Return quickly to avoid blocking the MessageBroker's outgoing thread!
}
This audio source should be the final mix of audio output (i.e. speaker reference/monitor).
Note: If you are using the System Audio module, see the
System Audio
module documentation for details about how to specifyLOOPBACK
audio input provider.
Building with the Loopback Detector Module¶
To build the Alexa Auto SDK with the Loopback Detector module, simply include the module when running the Auto SDK builder:
$ builder/build.py -m loopback-detector
Note: Additionally include any other modules you want to use in the same command.
Example Setup in Ubuntu Linux¶
Here is an example of how to provide loopback audio into the Alexa Auto SDK.
You will need the following software running on a Linux system:
- PulseAudio
- GStreamer
- Advanced Linux Sound Architecture (ALSA)
snd_aloop
module
If you are using the System Audio
module, the Auto SDK (and all other applications on Linux) will use PulseAudio to output audio by default. PulseAudio mixes all audio then plays it through a hardware device. We need to capture this "final mix result" into the GStreamer pipeline and pass it through directly into the ALSA loopback device so the Auto SDK can capture this audio. To do this, follow these steps:
- Make sure the
snd_aloop
module is loaded into kernel by runningsudo modprobe snd_aloop
. -
Use this command to launch the GStreamer pipeline:
gst-launch-1.0 -v autoaudiosrc ! audio/x-raw,format=S16LE,channels=1,rate=16000,layout=interleaved ! audioconvert ! audioresample ! alsasink device=hw:Loopback,0,0
Note: You need to keep this process throughout the testing.
-
Open the PulseAudio control panel (
pavucontrol
), and go to the Recording panel. - You will see that the gst-launch-1.0 process is capturing the audio. Change the audio source to Monitor of Built-in Audio Analog Stereo.
- Set the SampleApp Record Stream to microphone device.
At this point, all speaker outputs (through PulseAudio) will be eventually routed to the ALSA loopback device.
If you are using the System Audio module, ensure the LOOPBACK
type and loopback
device are configured correctly.
"aace.systemAudio": {
"AudioInputProvider": {
"devices": {
"default": {
"module": "GStreamer"
},
"loopback": {
"module": "GStreamer",
"card": "hw:Loopback,1,0",
"shared": true
}
},
"types": {
"LOOPBACK": "loopback"
}
},
"AudioOutputProvider": {
"devices": {
"default": {
"module": "GStreamer"
}
}
}
}
After this, the Auto SDK can capture audio loopback from the hw:Loopback,1,0
device.
The following diagram illustrates how the audio output data is routed to the Loopback Detector on Linux: