From 63b4c4754945ffbdc1ec9daca740304f23c80b53 Mon Sep 17 00:00:00 2001 From: Egor Nemtsev Date: Wed, 14 Aug 2019 12:50:26 +0300 Subject: Add QSettings property for changing capture device - It might be needed to change default capture (microphone) device. For this case app reads QSettings with "Luxoft Sweden AB"/"AlexaApp" and from "capture/device_name" section reads device name. App prints avail devices in "--verbose" mode to console upon startup. Change-Id: I948435ecd29e7b31ed70ec0f25c2c60d155de037 Reviewed-by: Bramastyo Harimukti Santoso --- plugins/alexainterface/AlexaInterface.cpp | 21 +++-- plugins/alexainterface/AlexaInterface.h | 4 + plugins/alexainterface/QtMicrophoneWrapper.cpp | 105 ++++++++++++++++--------- plugins/alexainterface/QtMicrophoneWrapper.h | 7 +- 4 files changed, 92 insertions(+), 45 deletions(-) diff --git a/plugins/alexainterface/AlexaInterface.cpp b/plugins/alexainterface/AlexaInterface.cpp index 7f37995..6577177 100644 --- a/plugins/alexainterface/AlexaInterface.cpp +++ b/plugins/alexainterface/AlexaInterface.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "KeywordObserver.h" #include "AlexaInterface.h" @@ -309,7 +310,7 @@ void AlexaInterface::initAlexaQMLClient() // If avs-device-sdk is built without keyword support, kwdModelPath remains empty QString kwdModelPath; -#if KWD +#ifdef KWD if (!qEnvironmentVariableIsSet("ALEXA_KWD_MODEL_PATH")) { qCritical() << "ALEXA_KWD_MODEL_PATH not defined"; return; @@ -329,7 +330,7 @@ void AlexaInterface::initAlexaQMLClient() kwdModelPath.toStdString(), m_logLevelString.toStdString())) { qCritical() << "Failed to initialize AlexaInterface."; -#if KWD +#ifdef KWD qDebug() << "ALEXA_KWD_MODEL_PATH: " << qEnvironmentVariable("ALEXA_KWD_MODEL_PATH"); #endif qDebug() << "ALEXA_SDK_CONFIG_FILE: " << qEnvironmentVariable("ALEXA_SDK_CONFIG_FILE"); @@ -903,9 +904,15 @@ bool AlexaInterface::initialize( holdCanOverride, holdCanBeOverridden); - - std::shared_ptr micWrapper = QtMicrophoneWrapper::create(sharedDataStream); - if (!micWrapper) { + /* + * Read device name to change system default microphone input + */ + QSettings settings(QStringLiteral("Luxoft Sweden AB"), QStringLiteral("AlexaApp")); + QString captureDeviceName = settings.value(QStringLiteral("capture/device_name"), + QStringLiteral("default")).toString(); + std::shared_ptr m_micWrapper = QtMicrophoneWrapper::create(sharedDataStream, + captureDeviceName); + if (!m_micWrapper) { ACSDK_CRITICAL(LX("Failed to create QtMicrophoneWrapper!")); return false; } @@ -954,7 +961,7 @@ bool AlexaInterface::initialize( m_interactionManager = std::make_shared( this, client, - micWrapper, + m_micWrapper, m_userInterfaceManager, holdToTalkAudioProvider, tapToTalkAudioProvider, @@ -966,7 +973,7 @@ bool AlexaInterface::initialize( #else // If wake word is not enabled, then creating the interaction manager without a wake word audio provider. m_interactionManager = std::make_shared( - this, client, micWrapper, m_userInterfaceManager, holdToTalkAudioProvider, tapToTalkAudioProvider, m_guiRenderer); + this, client, m_micWrapper, m_userInterfaceManager, holdToTalkAudioProvider, tapToTalkAudioProvider, m_guiRenderer); #endif client->addAlexaDialogStateObserver(m_interactionManager); diff --git a/plugins/alexainterface/AlexaInterface.h b/plugins/alexainterface/AlexaInterface.h index 3c43824..46cb138 100644 --- a/plugins/alexainterface/AlexaInterface.h +++ b/plugins/alexainterface/AlexaInterface.h @@ -44,6 +44,7 @@ #include "ConnectionManager.h" #include "DialogStateManager.h" #include "CapabilitiesManager.h" +#include "QtMicrophoneWrapper.h" #ifdef KWD #include @@ -274,6 +275,9 @@ private: // Capabilities Manager std::shared_ptr m_capabilitiesManager; + // Microphone Wrapper + std::shared_ptr m_micWrapper; + /// The @c GuiRender which provides an abstraction to visual rendering std::shared_ptr m_guiRenderer; diff --git a/plugins/alexainterface/QtMicrophoneWrapper.cpp b/plugins/alexainterface/QtMicrophoneWrapper.cpp index cfbfed4..c3fe0ef 100644 --- a/plugins/alexainterface/QtMicrophoneWrapper.cpp +++ b/plugins/alexainterface/QtMicrophoneWrapper.cpp @@ -41,14 +41,15 @@ static const int SAMPLE_SIZE = 16; static const double LATENCY = 0.2; //seconds -std::unique_ptr QtMicrophoneWrapper::create( - std::shared_ptr stream) { +std::unique_ptr QtMicrophoneWrapper::create(std::shared_ptr stream, + const QString &deviceName) +{ if (!stream) { qWarning() << "QtMicrophoneWrapper: Invalid stream passed to QtMicrophoneWrapper"; return nullptr; } std::unique_ptr qtMicrophoneWrapper(new QtMicrophoneWrapper(stream)); - if (!qtMicrophoneWrapper->initialize()) { + if (!qtMicrophoneWrapper->initialize(deviceName)) { qWarning() << "QtMicrophoneWrapper: Failed to initialize QtMicrophoneWrapper"; return nullptr; } @@ -62,45 +63,14 @@ QtMicrophoneWrapper::QtMicrophoneWrapper(std::shared_ptr strea QtMicrophoneWrapper::~QtMicrophoneWrapper() { } -bool QtMicrophoneWrapper::initialize() { +bool QtMicrophoneWrapper::initialize(const QString &deviceName) { m_writer = m_audioInputStream->createWriter(AudioInputStream::Writer::Policy::NONBLOCKABLE); if (!m_writer) { qWarning("QtMicrophoneWrapper: Failed to create stream writer"); return false; } - QAudioFormat format; - format.setSampleRate(SAMPLE_RATE); - format.setChannelCount(NUM_INPUT_CHANNELS); - format.setSampleSize(SAMPLE_SIZE); - format.setCodec("audio/pcm"); - format.setByteOrder(QAudioFormat::LittleEndian); - format.setSampleType(QAudioFormat::SignedInt); - - QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice(); - if (!info.isFormatSupported(format)) { - qWarning() << "QtMicrophoneWrapper: Default format not supported, trying to use the nearest."; - format = info.nearestFormat(format); - } - - m_audioInput = new QAudioInput(format, this); - QObject::connect( m_audioInput, &QAudioInput::notify, this, [this](){ - QByteArray readBytes = m_audioInputIODevice->readAll(); - m_readAudioData.append(readBytes); - m_readAudioDataBytes += readBytes.count(); - - size_t nWords = m_writer->getWordSize() != 0 ? - static_cast(m_readAudioDataBytes)/m_writer->getWordSize() : - static_cast(m_readAudioDataBytes); - m_writer->write(m_readAudioData.data(), nWords); - - m_readAudioData.clear(); - m_readAudioDataBytes = 0; - }); - - int latency = static_cast(LATENCY * 1000); - m_audioInput->setNotifyInterval(latency); - qDebug("QtMicrophoneWrapper: Latency is configured to: %d ms", m_audioInput->notifyInterval()); + setAudioDevice(deviceName); return true; } @@ -110,6 +80,18 @@ bool QtMicrophoneWrapper::startStreamingMicrophoneData() { m_readAudioDataBytes = 0; m_audioInputIODevice = m_audioInput->start(); + + if (m_audioInput->error() != QAudio::NoError) { + qWarning() << "Start stream error:" << m_audioInput->error(); + return false; + } + + if (m_audioInput->state() != QAudio::ActiveState + && m_audioInput->state() != QAudio::IdleState) { + qWarning() << "Wrong input state:" << m_audioInput->state(); + return false; + } + QByteArray readBytes = m_audioInputIODevice->readAll(); m_readAudioData.append(readBytes); @@ -128,3 +110,54 @@ bool QtMicrophoneWrapper::stopStreamingMicrophoneData() { return true; } +void QtMicrophoneWrapper::setAudioDevice(const QString &deviceName) { + qDebug() << "Trying to select input device: " << deviceName; + + QAudioFormat format; + format.setSampleRate(SAMPLE_RATE); + format.setChannelCount(NUM_INPUT_CHANNELS); + format.setSampleSize(SAMPLE_SIZE); + format.setCodec("audio/pcm"); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + + m_audioInfo = QAudioDeviceInfo::defaultInputDevice(); + + QList devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); + + qDebug() << "Available capture devices:" << devices.size(); + for (QAudioDeviceInfo &device : devices) { + qDebug() << " device name: " << device.deviceName(); + if (device.deviceName() == deviceName) { + m_audioInfo = device; + } + } + + qDebug() << "Selected capture device:" << m_audioInfo.deviceName(); + qDebug() << "Requested format" << format; + + if (!m_audioInfo.isFormatSupported(format)) { + qWarning() << "QtMicrophoneWrapper: Default format not supported, trying to use the nearest."; + format = m_audioInfo.nearestFormat(format); + qWarning() << "QtMicrophoneWrapper: Nearest format" << format; + } + + m_audioInput = new QAudioInput(m_audioInfo, format, this); + QObject::connect(m_audioInput, &QAudioInput::notify, this, [this](){ + + QByteArray readBytes = m_audioInputIODevice->readAll(); + m_readAudioData.append(readBytes); + m_readAudioDataBytes += readBytes.count(); + + size_t nWords = m_writer->getWordSize() != 0 ? + static_cast(m_readAudioDataBytes)/m_writer->getWordSize() : + static_cast(m_readAudioDataBytes); + m_writer->write(m_readAudioData.data(), nWords); + m_readAudioData.clear(); + m_readAudioDataBytes = 0; + }); + + int latency = static_cast(LATENCY * 1000); + m_audioInput->setNotifyInterval(latency); + qDebug("QtMicrophoneWrapper: Latency is configured to: %d ms", m_audioInput->notifyInterval()); +} diff --git a/plugins/alexainterface/QtMicrophoneWrapper.h b/plugins/alexainterface/QtMicrophoneWrapper.h index d3d5d12..cf81596 100644 --- a/plugins/alexainterface/QtMicrophoneWrapper.h +++ b/plugins/alexainterface/QtMicrophoneWrapper.h @@ -51,7 +51,8 @@ public: * @param stream The shared data stream to write to. * @return A unique_ptr to a @c QtMicrophoneWrapper if creation was successful and @c nullptr otherwise. */ - static std::unique_ptr create(std::shared_ptr stream); + static std::unique_ptr create(std::shared_ptr stream, + const QString &deviceName); /** * Stops streaming from the microphone. @@ -76,13 +77,15 @@ private: */ QtMicrophoneWrapper(std::shared_ptr stream); + QAudioDeviceInfo m_audioInfo; QAudioInput *m_audioInput = nullptr; QIODevice *m_audioInputIODevice = nullptr; int m_readAudioDataBytes = 0; QByteArray m_readAudioData; /// Initializes Audio - bool initialize(); + bool initialize(const QString &deviceName); + void setAudioDevice(const QString &deviceName); /// The stream of audio data. const std::shared_ptr m_audioInputStream; -- cgit v1.2.3