avs-device-sdk/SampleApp/src/SampleApplication.cpp

694 lines
29 KiB
C++

/*
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include "SampleApp/ConnectionObserver.h"
#include "SampleApp/GuiRenderer.h"
#include "SampleApp/KeywordObserver.h"
#include "SampleApp/SampleApplication.h"
#ifdef KWD
#include <KWDProvider/KeywordDetectorProvider.h>
#endif
#ifdef ENABLE_ESP
#include <ESP/ESPDataProvider.h>
#else
#include <ESP/DummyESPDataProvider.h>
#endif
#include <AVSCommon/AVS/Initialization/AlexaClientSDKInit.h>
#include <AVSCommon/Utils/Configuration/ConfigurationNode.h>
#include <AVSCommon/Utils/DeviceInfo.h>
#include <AVSCommon/Utils/LibcurlUtils/HTTPContentFetcherFactory.h>
#include <AVSCommon/Utils/LibcurlUtils/HttpPut.h>
#include <AVSCommon/Utils/Logger/Logger.h>
#include <AVSCommon/Utils/Logger/LoggerSinkManager.h>
#include <AVSCommon/Utils/Network/InternetConnectionMonitor.h>
#include <Alerts/Storage/SQLiteAlertStorage.h>
#include <Audio/AudioFactory.h>
#include <Bluetooth/SQLiteBluetoothStorage.h>
#include <CBLAuthDelegate/CBLAuthDelegate.h>
#include <CBLAuthDelegate/SQLiteCBLAuthDelegateStorage.h>
#include <CapabilitiesDelegate/CapabilitiesDelegate.h>
#include <MediaPlayer/MediaPlayer.h>
#include <Notifications/SQLiteNotificationsStorage.h>
#include <Settings/SQLiteSettingStorage.h>
#include <SQLiteStorage/SQLiteMiscStorage.h>
#include <algorithm>
#include <cctype>
#include <fstream>
#include <csignal>
namespace alexaClientSDK {
namespace sampleApp {
/// The sample rate of microphone audio data.
static const unsigned int SAMPLE_RATE_HZ = 16000;
/// The number of audio channels.
static const unsigned int NUM_CHANNELS = 1;
/// The size of each word within the stream.
static const size_t WORD_SIZE = 2;
/// The maximum number of readers of the stream.
static const size_t MAX_READERS = 10;
/// The amount of audio data to keep in the ring buffer.
static const std::chrono::seconds AMOUNT_OF_AUDIO_DATA_IN_BUFFER = std::chrono::seconds(15);
/// The size of the ring buffer.
static const size_t BUFFER_SIZE_IN_SAMPLES = (SAMPLE_RATE_HZ)*AMOUNT_OF_AUDIO_DATA_IN_BUFFER.count();
/// Key for the root node value containing configuration values for SampleApp.
static const std::string SAMPLE_APP_CONFIG_KEY("sampleApp");
/// Key for the @c firmwareVersion value under the @c SAMPLE_APP_CONFIG_KEY configuration node.
static const std::string FIRMWARE_VERSION_KEY("firmwareVersion");
/// Key for the @c endpoint value under the @c SAMPLE_APP_CONFIG_KEY configuration node.
static const std::string ENDPOINT_KEY("endpoint");
/// Key for setting if display cards are supported or not under the @c SAMPLE_APP_CONFIG_KEY configuration node.
static const std::string DISPLAY_CARD_KEY("displayCardsSupported");
using namespace capabilityAgents::externalMediaPlayer;
/// The @c m_playerToMediaPlayerMap Map of the adapter to their speaker-type and MediaPlayer creation methods.
std::unordered_map<std::string, SampleApplication::SpeakerTypeAndCreateFunc>
SampleApplication::m_playerToMediaPlayerMap;
/// The singleton map from @c playerId to @c ExternalMediaAdapter creation functions.
std::unordered_map<std::string, ExternalMediaPlayer::AdapterCreateFunction> SampleApplication::m_adapterToCreateFuncMap;
/// String to identify log entries originating from this file.
static const std::string TAG("SampleApplication");
/**
* Create a LogEntry using this file's TAG and the specified event string.
*
* @param The event string for this @c LogEntry.
*/
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
/// A set of all log levels.
static const std::set<alexaClientSDK::avsCommon::utils::logger::Level> allLevels = {
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG9,
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG8,
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG7,
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG6,
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG5,
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG4,
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG3,
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG2,
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG1,
alexaClientSDK::avsCommon::utils::logger::Level::DEBUG0,
alexaClientSDK::avsCommon::utils::logger::Level::INFO,
alexaClientSDK::avsCommon::utils::logger::Level::WARN,
alexaClientSDK::avsCommon::utils::logger::Level::ERROR,
alexaClientSDK::avsCommon::utils::logger::Level::CRITICAL,
alexaClientSDK::avsCommon::utils::logger::Level::NONE};
/**
* Gets a log level consumable by the SDK based on the user input string for log level.
*
* @param userInputLogLevel The string to be parsed into a log level.
* @return The log level. This will default to NONE if the input string is not properly parsable.
*/
static alexaClientSDK::avsCommon::utils::logger::Level getLogLevelFromUserInput(std::string userInputLogLevel) {
std::transform(userInputLogLevel.begin(), userInputLogLevel.end(), userInputLogLevel.begin(), ::toupper);
return alexaClientSDK::avsCommon::utils::logger::convertNameToLevel(userInputLogLevel);
}
/**
* Allows the process to ignore the SIGPIPE signal.
* The SIGPIPE signal may be received when the application performs a write to a closed socket.
* This is a case that arises in the use of certain networking libraries.
*
* @return true if the action for handling SIGPIPEs was correctly set to ignore, else false.
*/
static bool ignoreSigpipeSignals() {
#ifndef NO_SIGPIPE
if (std::signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
return false;
}
#endif
return true;
}
std::unique_ptr<SampleApplication> SampleApplication::create(
const std::vector<std::string>& configFiles,
const std::string& pathToInputFolder,
const std::string& logLevel) {
auto clientApplication = std::unique_ptr<SampleApplication>(new SampleApplication);
if (!clientApplication->initialize(configFiles, pathToInputFolder, logLevel)) {
ACSDK_CRITICAL(LX("Failed to initialize SampleApplication"));
return nullptr;
}
if (!ignoreSigpipeSignals()) {
ACSDK_CRITICAL(LX("Failed to set a signal handler for SIGPIPE"));
return nullptr;
}
return clientApplication;
}
SampleApplication::AdapterRegistration::AdapterRegistration(
const std::string& playerId,
ExternalMediaPlayer::AdapterCreateFunction createFunction) {
if (m_adapterToCreateFuncMap.find(playerId) != m_adapterToCreateFuncMap.end()) {
ACSDK_WARN(LX("Adapter already exists").d("playerID", playerId));
}
m_adapterToCreateFuncMap[playerId] = createFunction;
}
SampleApplication::MediaPlayerRegistration::MediaPlayerRegistration(
const std::string& playerId,
avsCommon::sdkInterfaces::SpeakerInterface::Type speakerType,
MediaPlayerCreateFunction createFunction) {
if (m_playerToMediaPlayerMap.find(playerId) != m_playerToMediaPlayerMap.end()) {
ACSDK_WARN(LX("MediaPlayer already exists").d("playerId", playerId));
}
m_playerToMediaPlayerMap[playerId] =
std::pair<avsCommon::sdkInterfaces::SpeakerInterface::Type, MediaPlayerCreateFunction>(
speakerType, createFunction);
}
void SampleApplication::run() {
m_userInputManager->run();
}
SampleApplication::~SampleApplication() {
if (m_capabilitiesDelegate) {
m_capabilitiesDelegate->shutdown();
}
// First clean up anything that depends on the the MediaPlayers.
m_userInputManager.reset();
m_externalMusicProviderMediaPlayersMap.clear();
if (m_interactionManager) {
m_interactionManager->shutdown();
}
// Now it's safe to shut down the MediaPlayers.
for (auto& mediaPlayer : m_adapterMediaPlayers) {
mediaPlayer->shutdown();
}
if (m_speakMediaPlayer) {
m_speakMediaPlayer->shutdown();
}
if (m_audioMediaPlayer) {
m_audioMediaPlayer->shutdown();
}
if (m_alertsMediaPlayer) {
m_alertsMediaPlayer->shutdown();
}
if (m_notificationsMediaPlayer) {
m_notificationsMediaPlayer->shutdown();
}
if (m_bluetoothMediaPlayer) {
m_bluetoothMediaPlayer->shutdown();
}
if (m_ringtoneMediaPlayer) {
m_ringtoneMediaPlayer->shutdown();
}
}
bool SampleApplication::createMediaPlayersForAdapters(
std::shared_ptr<avsCommon::utils::libcurlUtils::HTTPContentFetcherFactory> httpContentFetcherFactory,
std::vector<std::shared_ptr<avsCommon::sdkInterfaces::SpeakerInterface>>& additionalSpeakers) {
for (auto& entry : m_playerToMediaPlayerMap) {
auto mediaPlayer =
entry.second.second(httpContentFetcherFactory, entry.second.first, entry.first + "MediaPlayer");
if (mediaPlayer) {
m_externalMusicProviderMediaPlayersMap[entry.first] = mediaPlayer;
m_externalMusicProviderSpeakersMap[entry.first] = mediaPlayer;
additionalSpeakers.push_back(
std::static_pointer_cast<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface>(mediaPlayer));
m_adapterMediaPlayers.push_back(mediaPlayer);
} else {
ACSDK_CRITICAL(LX("Failed to create mediaPlayer").d("playerId", entry.first));
return false;
}
}
return true;
}
bool SampleApplication::initialize(
const std::vector<std::string>& configFiles,
const std::string& pathToInputFolder,
const std::string& logLevel) {
/*
* Set up the SDK logging system to write to the SampleApp's ConsolePrinter. Also adjust the logging level
* if requested.
*/
std::shared_ptr<alexaClientSDK::avsCommon::utils::logger::Logger> consolePrinter =
std::make_shared<alexaClientSDK::sampleApp::ConsolePrinter>();
if (!logLevel.empty()) {
auto logLevelValue = getLogLevelFromUserInput(logLevel);
if (alexaClientSDK::avsCommon::utils::logger::Level::UNKNOWN == logLevelValue) {
alexaClientSDK::sampleApp::ConsolePrinter::simplePrint("Unknown log level input!");
alexaClientSDK::sampleApp::ConsolePrinter::simplePrint("Possible log level options are: ");
for (auto it = allLevels.begin(); it != allLevels.end(); ++it) {
alexaClientSDK::sampleApp::ConsolePrinter::simplePrint(
alexaClientSDK::avsCommon::utils::logger::convertLevelToName(*it));
}
return false;
}
alexaClientSDK::sampleApp::ConsolePrinter::simplePrint(
"Running app with log level: " +
alexaClientSDK::avsCommon::utils::logger::convertLevelToName(logLevelValue));
consolePrinter->setLevel(logLevelValue);
}
alexaClientSDK::avsCommon::utils::logger::LoggerSinkManager::instance().initialize(consolePrinter);
std::vector<std::shared_ptr<std::istream>> configJsonStreams;
for (auto configFile : configFiles) {
if (configFile.empty()) {
alexaClientSDK::sampleApp::ConsolePrinter::simplePrint("Config filename is empty!");
return false;
}
auto configInFile = std::shared_ptr<std::ifstream>(new std::ifstream(configFile));
if (!configInFile->good()) {
ACSDK_CRITICAL(LX("Failed to read config file").d("filename", configFile));
alexaClientSDK::sampleApp::ConsolePrinter::simplePrint("Failed to read config file " + configFile);
return false;
}
configJsonStreams.push_back(configInFile);
}
if (!avsCommon::avs::initialization::AlexaClientSDKInit::initialize(configJsonStreams)) {
ACSDK_CRITICAL(LX("Failed to initialize SDK!"));
return false;
}
auto config = alexaClientSDK::avsCommon::utils::configuration::ConfigurationNode::getRoot();
auto sampleAppConfig = config[SAMPLE_APP_CONFIG_KEY];
auto httpContentFetcherFactory = std::make_shared<avsCommon::utils::libcurlUtils::HTTPContentFetcherFactory>();
m_speakMediaPlayer = alexaClientSDK::mediaPlayer::MediaPlayer::create(
httpContentFetcherFactory, avsCommon::sdkInterfaces::SpeakerInterface::Type::AVS_SYNCED, "SpeakMediaPlayer");
if (!m_speakMediaPlayer) {
ACSDK_CRITICAL(LX("Failed to create media player for speech!"));
return false;
}
m_audioMediaPlayer = alexaClientSDK::mediaPlayer::MediaPlayer::create(
httpContentFetcherFactory, avsCommon::sdkInterfaces::SpeakerInterface::Type::AVS_SYNCED, "AudioMediaPlayer");
if (!m_audioMediaPlayer) {
ACSDK_CRITICAL(LX("Failed to create media player for content!"));
return false;
}
m_notificationsMediaPlayer = alexaClientSDK::mediaPlayer::MediaPlayer::create(
httpContentFetcherFactory,
avsCommon::sdkInterfaces::SpeakerInterface::Type::AVS_SYNCED,
"NotificationsMediaPlayer");
if (!m_notificationsMediaPlayer) {
ACSDK_CRITICAL(LX("Failed to create media player for notifications!"));
return false;
}
m_bluetoothMediaPlayer = alexaClientSDK::mediaPlayer::MediaPlayer::create(
httpContentFetcherFactory,
avsCommon::sdkInterfaces::SpeakerInterface::Type::AVS_SYNCED,
"BluetoothMediaPlayer");
if (!m_bluetoothMediaPlayer) {
ACSDK_CRITICAL(LX("Failed to create media player for bluetooth!"));
}
m_ringtoneMediaPlayer = alexaClientSDK::mediaPlayer::MediaPlayer::create(
httpContentFetcherFactory, avsCommon::sdkInterfaces::SpeakerInterface::Type::AVS_SYNCED, "RingtoneMediaPlayer");
if (!m_ringtoneMediaPlayer) {
alexaClientSDK::sampleApp::ConsolePrinter::simplePrint("Failed to create media player for ringtones!");
return false;
}
/*
* The ALERTS speaker type will cause volume control to be independent and localized. By assigning this type,
* Alerts volume/mute changes will not be in sync with AVS. No directives or events will be associated with volume
* control.
*/
m_alertsMediaPlayer = alexaClientSDK::mediaPlayer::MediaPlayer::create(
httpContentFetcherFactory, avsCommon::sdkInterfaces::SpeakerInterface::Type::LOCAL, "AlertsMediaPlayer");
if (!m_alertsMediaPlayer) {
ACSDK_CRITICAL(LX("Failed to create media player for alerts!"));
return false;
}
/*
* Create Speaker interfaces to control the volume. For the SDK, the MediaPlayer happens to also provide
* volume control functionality, but this does not have to be case.
* Note the externalMusicProviderMediaPlayer is not added to the set of SpeakerInterfaces as there would be
* more actions needed for these beyond setting the volume control on the MediaPlayer.
*/
std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface> speakSpeaker =
std::static_pointer_cast<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface>(m_speakMediaPlayer);
std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface> audioSpeaker =
std::static_pointer_cast<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface>(m_audioMediaPlayer);
std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface> alertsSpeaker =
std::static_pointer_cast<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface>(m_alertsMediaPlayer);
std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface> notificationsSpeaker =
std::static_pointer_cast<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface>(
m_notificationsMediaPlayer);
std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface> bluetoothSpeaker =
std::static_pointer_cast<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface>(m_bluetoothMediaPlayer);
std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface> ringtoneSpeaker =
std::static_pointer_cast<alexaClientSDK::avsCommon::sdkInterfaces::SpeakerInterface>(m_ringtoneMediaPlayer);
std::vector<std::shared_ptr<avsCommon::sdkInterfaces::SpeakerInterface>> additionalSpeakers;
if (!createMediaPlayersForAdapters(httpContentFetcherFactory, additionalSpeakers)) {
ACSDK_CRITICAL(LX("Could not create mediaPlayers for adapters"));
return false;
}
auto audioFactory = std::make_shared<alexaClientSDK::applicationUtilities::resources::audio::AudioFactory>();
// Creating the alert storage object to be used for rendering and storing alerts.
auto alertStorage =
alexaClientSDK::capabilityAgents::alerts::storage::SQLiteAlertStorage::create(config, audioFactory->alerts());
// Creating the message storage object to be used for storing message to be sent later.
auto messageStorage = alexaClientSDK::certifiedSender::SQLiteMessageStorage::create(config);
/*
* Creating notifications storage object to be used for storing notification indicators.
*/
auto notificationsStorage =
alexaClientSDK::capabilityAgents::notifications::SQLiteNotificationsStorage::create(config);
/*
* Creating settings storage object to be used for storing <key, value> pairs of AVS Settings.
*/
auto settingsStorage = alexaClientSDK::capabilityAgents::settings::SQLiteSettingStorage::create(config);
// Creating the misc DB object to be used by various components.
std::shared_ptr<alexaClientSDK::storage::sqliteStorage::SQLiteMiscStorage> miscStorage =
alexaClientSDK::storage::sqliteStorage::SQLiteMiscStorage::create(config);
// Create HTTP Put handler
std::shared_ptr<avsCommon::utils::libcurlUtils::HttpPut> httpPut =
avsCommon::utils::libcurlUtils::HttpPut::create();
/*
* Creating bluetooth storage object to be used for storing uuid to mac mappings for devices.
*/
auto bluetoothStorage = alexaClientSDK::capabilityAgents::bluetooth::SQLiteBluetoothStorage::create(config);
/*
* Creating the UI component that observes various components and prints to the console accordingly.
*/
auto userInterfaceManager = std::make_shared<alexaClientSDK::sampleApp::UIManager>();
/*
* Creating customerDataManager which will be used by the registrationManager and all classes that extend
* CustomerDataHandler
*/
auto customerDataManager = std::make_shared<registrationManager::CustomerDataManager>();
/*
* Creating the deviceInfo object
*/
std::shared_ptr<avsCommon::utils::DeviceInfo> deviceInfo = avsCommon::utils::DeviceInfo::create(config);
if (!deviceInfo) {
ACSDK_CRITICAL(LX("Creation of DeviceInfo failed!"));
return false;
}
/*
* Creating the AuthDelegate - this component takes care of LWA and authorization of the client.
*/
auto authDelegateStorage = authorization::cblAuthDelegate::SQLiteCBLAuthDelegateStorage::create(config);
std::shared_ptr<avsCommon::sdkInterfaces::AuthDelegateInterface> authDelegate =
authorization::cblAuthDelegate::CBLAuthDelegate::create(
config, customerDataManager, std::move(authDelegateStorage), userInterfaceManager, nullptr, deviceInfo);
if (!authDelegate) {
ACSDK_CRITICAL(LX("Creation of AuthDelegate failed!"));
return false;
}
/*
* Creating the CapabilitiesDelegate - This component provides the client with the ability to send messages to the
* Capabilities API.
*/
m_capabilitiesDelegate = alexaClientSDK::capabilitiesDelegate::CapabilitiesDelegate::create(
authDelegate, miscStorage, httpPut, config, deviceInfo);
if (!m_capabilitiesDelegate) {
alexaClientSDK::sampleApp::ConsolePrinter::simplePrint("Creation of CapabilitiesDelegate failed!");
return false;
}
authDelegate->addAuthObserver(userInterfaceManager);
m_capabilitiesDelegate->addCapabilitiesObserver(userInterfaceManager);
// INVALID_FIRMWARE_VERSION is passed to @c getInt() as a default in case FIRMWARE_VERSION_KEY is not found.
int firmwareVersion = static_cast<int>(avsCommon::sdkInterfaces::softwareInfo::INVALID_FIRMWARE_VERSION);
sampleAppConfig.getInt(FIRMWARE_VERSION_KEY, &firmwareVersion, firmwareVersion);
/*
* Check to see if displayCards is supported on the device. The default is supported unless specified otherwise in
* the configuration.
*/
bool displayCardsSupported;
config[SAMPLE_APP_CONFIG_KEY].getBool(DISPLAY_CARD_KEY, &displayCardsSupported, true);
/*
* Creating the InternetConnectionMonitor that will notify observers of internet connection status changes.
*/
auto internetConnectionMonitor =
avsCommon::utils::network::InternetConnectionMonitor::create(httpContentFetcherFactory);
if (!internetConnectionMonitor) {
ACSDK_CRITICAL(LX("Failed to create InternetConnectionMonitor"));
return false;
}
/*
* Creating the DefaultClient - this component serves as an out-of-box default object that instantiates and "glues"
* together all the modules.
*/
std::shared_ptr<alexaClientSDK::defaultClient::DefaultClient> client =
alexaClientSDK::defaultClient::DefaultClient::create(
deviceInfo,
customerDataManager,
m_externalMusicProviderMediaPlayersMap,
m_externalMusicProviderSpeakersMap,
m_adapterToCreateFuncMap,
m_speakMediaPlayer,
m_audioMediaPlayer,
m_alertsMediaPlayer,
m_notificationsMediaPlayer,
m_bluetoothMediaPlayer,
m_ringtoneMediaPlayer,
speakSpeaker,
audioSpeaker,
alertsSpeaker,
notificationsSpeaker,
bluetoothSpeaker,
ringtoneSpeaker,
additionalSpeakers,
audioFactory,
authDelegate,
std::move(alertStorage),
std::move(messageStorage),
std::move(notificationsStorage),
std::move(settingsStorage),
std::move(bluetoothStorage),
{userInterfaceManager},
{userInterfaceManager},
std::move(internetConnectionMonitor),
displayCardsSupported,
m_capabilitiesDelegate,
firmwareVersion,
true,
nullptr);
if (!client) {
ACSDK_CRITICAL(LX("Failed to create default SDK client!"));
return false;
}
// Add userInterfaceManager as observer of locale setting.
client->addSettingObserver("locale", userInterfaceManager);
client->addSpeakerManagerObserver(userInterfaceManager);
client->addNotificationsObserver(userInterfaceManager);
/*
* Add GUI Renderer as an observer if display cards are supported.
*/
if (displayCardsSupported) {
auto guiRenderer = std::make_shared<GuiRenderer>();
client->addTemplateRuntimeObserver(guiRenderer);
}
/*
* Creating the buffer (Shared Data Stream) that will hold user audio data. This is the main input into the SDK.
*/
size_t bufferSize = alexaClientSDK::avsCommon::avs::AudioInputStream::calculateBufferSize(
BUFFER_SIZE_IN_SAMPLES, WORD_SIZE, MAX_READERS);
auto buffer = std::make_shared<alexaClientSDK::avsCommon::avs::AudioInputStream::Buffer>(bufferSize);
std::shared_ptr<alexaClientSDK::avsCommon::avs::AudioInputStream> sharedDataStream =
alexaClientSDK::avsCommon::avs::AudioInputStream::create(buffer, WORD_SIZE, MAX_READERS);
if (!sharedDataStream) {
ACSDK_CRITICAL(LX("Failed to create shared data stream!"));
return false;
}
alexaClientSDK::avsCommon::utils::AudioFormat compatibleAudioFormat;
compatibleAudioFormat.sampleRateHz = SAMPLE_RATE_HZ;
compatibleAudioFormat.sampleSizeInBits = WORD_SIZE * CHAR_BIT;
compatibleAudioFormat.numChannels = NUM_CHANNELS;
compatibleAudioFormat.endianness = alexaClientSDK::avsCommon::utils::AudioFormat::Endianness::LITTLE;
compatibleAudioFormat.encoding = alexaClientSDK::avsCommon::utils::AudioFormat::Encoding::LPCM;
/*
* Creating each of the audio providers. An audio provider is a simple package of data consisting of the stream
* of audio data, as well as metadata about the stream. For each of the three audio providers created here, the same
* stream is used since this sample application will only have one microphone.
*/
// Creating tap to talk audio provider
bool tapAlwaysReadable = true;
bool tapCanOverride = true;
bool tapCanBeOverridden = true;
alexaClientSDK::capabilityAgents::aip::AudioProvider tapToTalkAudioProvider(
sharedDataStream,
compatibleAudioFormat,
alexaClientSDK::capabilityAgents::aip::ASRProfile::NEAR_FIELD,
tapAlwaysReadable,
tapCanOverride,
tapCanBeOverridden);
// Creating hold to talk audio provider
bool holdAlwaysReadable = false;
bool holdCanOverride = true;
bool holdCanBeOverridden = false;
alexaClientSDK::capabilityAgents::aip::AudioProvider holdToTalkAudioProvider(
sharedDataStream,
compatibleAudioFormat,
alexaClientSDK::capabilityAgents::aip::ASRProfile::CLOSE_TALK,
holdAlwaysReadable,
holdCanOverride,
holdCanBeOverridden);
std::shared_ptr<alexaClientSDK::sampleApp::PortAudioMicrophoneWrapper> micWrapper =
alexaClientSDK::sampleApp::PortAudioMicrophoneWrapper::create(sharedDataStream);
if (!micWrapper) {
ACSDK_CRITICAL(LX("Failed to create PortAudioMicrophoneWrapper!"));
return false;
}
// Creating wake word audio provider, if necessary
#ifdef KWD
bool wakeAlwaysReadable = true;
bool wakeCanOverride = false;
bool wakeCanBeOverridden = true;
alexaClientSDK::capabilityAgents::aip::AudioProvider wakeWordAudioProvider(
sharedDataStream,
compatibleAudioFormat,
alexaClientSDK::capabilityAgents::aip::ASRProfile::NEAR_FIELD,
wakeAlwaysReadable,
wakeCanOverride,
wakeCanBeOverridden);
#ifdef ENABLE_ESP
// Creating ESP connector
std::shared_ptr<esp::ESPDataProviderInterface> espProvider = esp::ESPDataProvider::create(wakeWordAudioProvider);
std::shared_ptr<esp::ESPDataModifierInterface> espModifier = nullptr;
#else
// Create dummy ESP connector
auto dummyEspProvider = std::make_shared<esp::DummyESPDataProvider>();
std::shared_ptr<esp::ESPDataProviderInterface> espProvider = dummyEspProvider;
std::shared_ptr<esp::ESPDataModifierInterface> espModifier = dummyEspProvider;
#endif
// This observer is notified any time a keyword is detected and notifies the DefaultClient to start recognizing.
auto keywordObserver =
std::make_shared<alexaClientSDK::sampleApp::KeywordObserver>(client, wakeWordAudioProvider, espProvider);
m_keywordDetector = alexaClientSDK::kwd::KeywordDetectorProvider::create(
sharedDataStream,
compatibleAudioFormat,
{keywordObserver},
std::unordered_set<
std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::KeyWordDetectorStateObserverInterface>>(),
pathToInputFolder);
if (!m_keywordDetector) {
ACSDK_CRITICAL(LX("Failed to create keyword detector!"));
}
// If wake word is enabled, then creating the interaction manager with a wake word audio provider.
m_interactionManager = std::make_shared<alexaClientSDK::sampleApp::InteractionManager>(
client,
micWrapper,
userInterfaceManager,
holdToTalkAudioProvider,
tapToTalkAudioProvider,
wakeWordAudioProvider,
espProvider,
espModifier);
#else
// If wake word is not enabled, then creating the interaction manager without a wake word audio provider.
m_interactionManager = std::make_shared<alexaClientSDK::sampleApp::InteractionManager>(
client, micWrapper, userInterfaceManager, holdToTalkAudioProvider, tapToTalkAudioProvider);
#endif
client->addAlexaDialogStateObserver(m_interactionManager);
// Creating the input observer.
m_userInputManager = alexaClientSDK::sampleApp::UserInputManager::create(m_interactionManager);
if (!m_userInputManager) {
ACSDK_CRITICAL(LX("Failed to create UserInputManager!"));
return false;
}
authDelegate->addAuthObserver(m_userInputManager);
m_capabilitiesDelegate->addCapabilitiesObserver(m_userInputManager);
m_capabilitiesDelegate->addCapabilitiesObserver(client);
// Connect once configuration is all set.
std::string endpoint;
sampleAppConfig.getString(ENDPOINT_KEY, &endpoint);
client->connect(m_capabilitiesDelegate, endpoint);
// Send default settings set by the user to AVS.
client->sendDefaultSettings();
return true;
}
} // namespace sampleApp
} // namespace alexaClientSDK