2017-05-26 23:06:14 +00:00
|
|
|
/*
|
Version 1.12 alexa-client-sdk
Changes in this update:
**Enhancements**
* Support was added for the `fr_CA` locale.
* The Executor has been optimized to run a single thread when there are active job in the queue, and to remain idle when there are not active jobs.
* An additional parameter of `alertType` has been added to the Alerts capability agent. This will allow observers of alerts to know the type of alert being delivered.
* Support for programmatic unload and load of PulseAudio Bluetooth modules was added. To enable this feature, there is a [new CMake option](https://github.com/alexa/avs-device-sdk/wiki/CMake-parameters#bluetooth): `BLUETOOTH_BLUEZ_PULSEAUDIO_OVERRIDE_ENDPOINTS`. Note that [libpulse-dev is a required dependency](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#bluetooth) of this feature.
* An observer interface was added for when an active Bluetooth device connects and disconnects.
* The `BluetoothDeviceManagerInterface` instantiation was moved from `DefaultClient` to `SampleApp` to allow applications to override it.
* The `MediaPlayerInterface` now supports repeating playback of URL sources.
* The Kitt.AI wake word engine (WWE) is now compatible with GCC5+.
* Stop of ongoing alerts, management of MessageObservers, and management of CallStateObservers have been exposed through DefaultClient.
**Bug Fixes**
* [Issue 953](https://github.com/alexa/avs-device-sdk/issues/953) - The `MediaPlayerInterface` requirement that callbacks not be made upon a callers thread has been removed.
* [Issue 1136](https://github.com/alexa/avs-device-sdk/issues/1136) - Added a missing default virtual destructor.
* [Issue 1140](https://github.com/alexa/avs-device-sdk/issues/1140) - Fixed an issue where DND states were not synchronized to the AVS cloud after device reset.
* [Issue 1143](https://github.com/alexa/avs-device-sdk/issues/1143) - Fixed an issue in which the SpeechSynthesizer couldn't enter a sleeping state.
* [Issue 1183](https://github.com/alexa/avs-device-sdk/issues/1183) - Fixed an issue where alarm is not sounding for certain timezones
* Changing an alert's volume from the Alexa app now works when an alert is playing.
* Added missing shutdown handling for ContentDecrypter to prevent the `Stop` command from triggering a crash when SAMPLE-AES encrypted content was streaming.
* Fixed a bug where if the Notifications database is empty, due to a crash or corruption, the SDK initialization process enters an infinite loop when it retries to get context from the Notifications capability agent.
* Fixed a race condition that caused `AlertsRenderer` observers to miss notification that an alert has been completed.
**Known Issues**
* `PlaylistParser` and `IterativePlaylistParser` generate two HTTP requests (one to fetch the content type, and one to fetch the audio data) for each audio stream played.
* Music playback history isn't being displayed in the Alexa app for certain account and device types.
* On GCC 8+, issues related to `-Wclass-memaccess` will trigger warnings. However, this won't cause the build to fail and these warnings can be ignored.
* Android error ("libDefaultClient.so" not found) can be resolved by upgrading to ADB version 1.0.40
* When network connection is lost, lost connection status is not returned via local TTS.
* `ACL` may encounter issues if audio attachments are received but not consumed.
* `SpeechSynthesizerState` currently uses `GAINING_FOCUS` and `LOSING_FOCUS` as a workaround for handling intermediate state. These states may be removed in a future release.
* The Alexa app doesn't always indicate when a device is successfully connected via Bluetooth.
* Connecting a product to streaming media via Bluetooth will sometimes stop media playback within the source application. Resuming playback through the source application or toggling next/previous will correct playback.
* When a source device is streaming silence via Bluetooth, the Alexa app indicates that audio content is streaming.
* The Bluetooth agent assumes that the Bluetooth adapter is always connected to a power source. Disconnecting from a power source during operation is not yet supported.
* On some products, interrupted Bluetooth playback may not resume if other content is locally streamed.
* `make integration` is currently not available for Android. In order to run integration tests on Android, you'll need to manually upload the test binary file along with any input file. At that point, the adb can be used to run the integration tests.
* On Raspberry Pi running Android Things with HDMI output audio, beginning of speech is truncated when Alexa responds to user text-to-speech (TTS).
* When the sample app is restarted and network connection is lost, Reminder TTS does not play. Instead, the default alarm tone will play twice.
2019-02-26 00:45:37 +00:00
|
|
|
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2017-05-26 23:06:14 +00:00
|
|
|
*
|
|
|
|
* 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 <chrono>
|
|
|
|
#include <future>
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
#include <gmock/gmock.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
2017-06-23 23:26:34 +00:00
|
|
|
#include <AVSCommon/SDKInterfaces/MockExceptionEncounteredSender.h>
|
2017-05-26 23:06:14 +00:00
|
|
|
#include <AVSCommon/AVS/Attachment/AttachmentManagerInterface.h>
|
|
|
|
#include <AVSCommon/SDKInterfaces/MockContextManager.h>
|
|
|
|
#include <AVSCommon/SDKInterfaces/MockFocusManager.h>
|
|
|
|
#include <AVSCommon/SDKInterfaces/MockMessageSender.h>
|
|
|
|
#include <AVSCommon/SDKInterfaces/MockDirectiveSequencer.h>
|
|
|
|
#include <AVSCommon/SDKInterfaces/MockDirectiveHandlerResult.h>
|
|
|
|
#include <AVSCommon/AVS/Attachment/AttachmentManager.h>
|
2017-10-30 22:14:38 +00:00
|
|
|
#include <AVSCommon/Utils/MediaPlayer/MockMediaPlayer.h>
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
#include "SpeechSynthesizer/SpeechSynthesizer.h"
|
|
|
|
|
|
|
|
namespace alexaClientSDK {
|
2017-06-09 23:23:31 +00:00
|
|
|
namespace capabilityAgents {
|
2017-05-26 23:06:14 +00:00
|
|
|
namespace speechSynthesizer {
|
|
|
|
namespace test {
|
|
|
|
|
2017-06-23 23:26:34 +00:00
|
|
|
using namespace avsCommon::utils;
|
2017-05-26 23:06:14 +00:00
|
|
|
using namespace avsCommon;
|
|
|
|
using namespace avsCommon::avs;
|
|
|
|
using namespace avsCommon::avs::attachment;
|
|
|
|
using namespace avsCommon::sdkInterfaces;
|
|
|
|
using namespace avsCommon::sdkInterfaces::test;
|
|
|
|
using namespace avsCommon::utils::mediaPlayer;
|
2017-10-30 22:14:38 +00:00
|
|
|
using namespace avsCommon::utils::mediaPlayer::test;
|
2017-05-26 23:06:14 +00:00
|
|
|
using namespace ::testing;
|
|
|
|
|
|
|
|
/// Plenty of time for a test to complete.
|
2018-01-12 23:45:42 +00:00
|
|
|
static const std::chrono::milliseconds WAIT_TIMEOUT(1000);
|
|
|
|
|
|
|
|
/// Time to wait for state change timeout. This should be set to be longer than STATE_CHANGE_TIMEOUT in
|
|
|
|
/// SpeechSynthesizer.
|
|
|
|
static const std::chrono::milliseconds STATE_CHANGE_TIMEOUT(10000);
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
/// The name of the @c FocusManager channel used by the @c SpeechSynthesizer.
|
2018-03-09 00:55:39 +00:00
|
|
|
static const std::string CHANNEL_NAME(avsCommon::sdkInterfaces::FocusManagerInterface::DIALOG_CHANNEL_NAME);
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
/// Namespace for SpeechSynthesizer.
|
|
|
|
static const std::string NAMESPACE_SPEECH_SYNTHESIZER("SpeechSynthesizer");
|
|
|
|
|
|
|
|
/// Name for SpeechSynthesizer directive.
|
|
|
|
static const std::string NAME_SPEAK("Speak");
|
|
|
|
|
|
|
|
/// Wrong name for testing.
|
|
|
|
static const std::string NAME_RECOGNIZE("Recognize");
|
|
|
|
|
|
|
|
/// The @c NamespaceAndName to send to the @c ContextManager.
|
|
|
|
static const NamespaceAndName NAMESPACE_AND_NAME_SPEECH_STATE{NAMESPACE_SPEECH_SYNTHESIZER, "SpeechState"};
|
|
|
|
|
|
|
|
/// Message Id for testing.
|
|
|
|
static const std::string MESSAGE_ID_TEST("MessageId_Test");
|
|
|
|
|
2017-07-18 22:25:37 +00:00
|
|
|
/// Message Id for testing.
|
|
|
|
static const std::string MESSAGE_ID_TEST_2("MessageId_Test_2");
|
|
|
|
|
2017-05-26 23:06:14 +00:00
|
|
|
/// DialogRequestId for testing.
|
|
|
|
static const std::string DIALOG_REQUEST_ID_TEST("DialogRequestId_Test");
|
|
|
|
|
|
|
|
/// Token for testing.
|
|
|
|
static const std::string TOKEN_TEST("Token_Test");
|
|
|
|
|
|
|
|
/// Format of the audio.
|
|
|
|
static const std::string FORMAT_TEST("AUDIO_MPEG");
|
|
|
|
|
|
|
|
/// URL for testing.
|
|
|
|
static const std::string URL_TEST("cid:Test");
|
|
|
|
|
|
|
|
/// Context ID for testing
|
|
|
|
static const std::string CONTEXT_ID_TEST("ContextId_Test");
|
|
|
|
|
2017-07-18 22:25:37 +00:00
|
|
|
/// Context ID for testing
|
|
|
|
static const std::string CONTEXT_ID_TEST_2("ContextId_Test_2");
|
|
|
|
|
2017-05-26 23:06:14 +00:00
|
|
|
/// A payload for testing
|
2017-10-02 22:59:05 +00:00
|
|
|
// clang-format off
|
2017-05-26 23:06:14 +00:00
|
|
|
static const std::string PAYLOAD_TEST =
|
|
|
|
"{"
|
|
|
|
"\"url\":\"" + URL_TEST + "\","
|
|
|
|
"\"format\":\"" + FORMAT_TEST + "\","
|
|
|
|
"\"token\":\""+ TOKEN_TEST + "\""
|
|
|
|
"}";
|
2017-10-02 22:59:05 +00:00
|
|
|
// clang-format on
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
/// The @c FINISHED state of the @c SpeechSynthesizer.
|
|
|
|
static const std::string FINISHED_STATE("FINISHED");
|
|
|
|
|
|
|
|
/// The @c PLAYING state of the @c SpeechSynthesizer
|
|
|
|
static const std::string PLAYING_STATE{"PLAYING"};
|
|
|
|
|
|
|
|
/// The offset in milliseconds returned by the mock media player.
|
|
|
|
static const long OFFSET_IN_MILLISECONDS_TEST{100};
|
|
|
|
|
2017-10-02 22:59:05 +00:00
|
|
|
/// An std::chrono::milliseconds representation of the offset.
|
|
|
|
static const std::chrono::milliseconds OFFSET_IN_CHRONO_MILLISECONDS_TEST{100};
|
|
|
|
|
2017-05-26 23:06:14 +00:00
|
|
|
/// The expected state when the @c SpeechSynthesizer is in @c PLAYING state.
|
2017-10-02 22:59:05 +00:00
|
|
|
// clang-format off
|
2017-05-26 23:06:14 +00:00
|
|
|
static const std::string PLAYING_STATE_TEST =
|
|
|
|
"{"
|
|
|
|
"\"token\":\"" + TOKEN_TEST + "\","
|
|
|
|
"\"offsetInMilliseconds\":" + std::to_string(OFFSET_IN_MILLISECONDS_TEST) + ","
|
|
|
|
"\"playerActivity\":\"" + PLAYING_STATE + "\""
|
|
|
|
"}";
|
2017-10-02 22:59:05 +00:00
|
|
|
// clang-format on
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
/// The expected state when the @c SpeechSynthesizer is in @c FINISHED state.
|
2017-10-02 22:59:05 +00:00
|
|
|
// clang-format off
|
2017-05-26 23:06:14 +00:00
|
|
|
static const std::string FINISHED_STATE_TEST =
|
|
|
|
"{"
|
|
|
|
"\"token\":\"" + TOKEN_TEST + "\","
|
|
|
|
"\"offsetInMilliseconds\":" + std::to_string(0) + ","
|
|
|
|
"\"playerActivity\":\"" + FINISHED_STATE + "\""
|
|
|
|
"}";
|
2017-10-02 22:59:05 +00:00
|
|
|
// clang-format on
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
/// The expected state when the @c SpeechSynthesizer is not handling any directive.
|
2017-10-02 22:59:05 +00:00
|
|
|
// clang-format off
|
2017-05-26 23:06:14 +00:00
|
|
|
static const std::string IDLE_STATE_TEST =
|
|
|
|
"{"
|
|
|
|
"\"token\":\"\","
|
|
|
|
"\"offsetInMilliseconds\":" + std::to_string(0) + ","
|
|
|
|
"\"playerActivity\":\"" + FINISHED_STATE + "\""
|
|
|
|
"}";
|
2017-10-02 22:59:05 +00:00
|
|
|
// clang-format on
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
/// Provide State Token for testing.
|
|
|
|
static const unsigned int PROVIDE_STATE_TOKEN_TEST{1};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MockAttachmentManager
|
|
|
|
*/
|
|
|
|
class MockAttachmentManager : public AttachmentManagerInterface {
|
|
|
|
public:
|
|
|
|
MOCK_CONST_METHOD2(generateAttachmentId, std::string(const std::string&, const std::string&));
|
|
|
|
MOCK_METHOD1(setAttachmentTimeoutMinutes, bool(std::chrono::minutes timeoutMinutes));
|
2018-01-12 23:45:42 +00:00
|
|
|
MOCK_METHOD2(
|
|
|
|
createWriter,
|
2018-02-12 23:31:53 +00:00
|
|
|
std::unique_ptr<AttachmentWriter>(const std::string& attachmentId, sds::WriterPolicy policy));
|
2017-10-02 22:59:05 +00:00
|
|
|
MOCK_METHOD2(
|
|
|
|
createReader,
|
2018-02-12 23:31:53 +00:00
|
|
|
std::unique_ptr<AttachmentReader>(const std::string& attachmentId, sds::ReaderPolicy policy));
|
2017-05-26 23:06:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class SpeechSynthesizerTest : public ::testing::Test {
|
|
|
|
public:
|
|
|
|
SpeechSynthesizerTest();
|
|
|
|
|
|
|
|
void SetUp() override;
|
2017-08-17 00:13:40 +00:00
|
|
|
void TearDown() override;
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
/// @c SpeechSynthesizer to test
|
|
|
|
std::shared_ptr<SpeechSynthesizer> m_speechSynthesizer;
|
|
|
|
|
|
|
|
/// Player to send the audio to.
|
|
|
|
std::shared_ptr<MockMediaPlayer> m_mockSpeechPlayer;
|
|
|
|
|
|
|
|
/// @c ContextManager to provide state and update state.
|
|
|
|
std::shared_ptr<MockContextManager> m_mockContextManager;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fulfills the @c m_wakeSetStatePromise. This is invoked in response to a @c setState call.
|
|
|
|
*
|
|
|
|
* @return @c SUCCESS.
|
|
|
|
*/
|
|
|
|
SetStateResult wakeOnSetState();
|
|
|
|
|
|
|
|
/// Promise to be fulfilled when @c setState is called.
|
|
|
|
std::promise<void> m_wakeSetStatePromise;
|
|
|
|
|
|
|
|
/// Future to notify when @c setState is called.
|
|
|
|
std::future<void> m_wakeSetStateFuture;
|
|
|
|
|
|
|
|
/// @c FocusManager to request focus to the DIALOG channel.
|
|
|
|
std::shared_ptr<MockFocusManager> m_mockFocusManager;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fulfills the @c m_wakeAcquireChannelPromise. This is invoked in response to a @c acquireChannel call.
|
|
|
|
*
|
|
|
|
* @return @c true
|
|
|
|
*/
|
|
|
|
bool wakeOnAcquireChannel();
|
|
|
|
|
|
|
|
/// Promise to be fulfilled when @c acquireChannel is called.
|
|
|
|
std::promise<void> m_wakeAcquireChannelPromise;
|
|
|
|
|
|
|
|
/// Future to notify when @c acquireChannel is called.
|
|
|
|
std::future<void> m_wakeAcquireChannelFuture;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fulfills the @c m_wakeReleaseChannelPromise. This is invoked in response to a @c releaseChannel call.
|
|
|
|
*
|
|
|
|
* @return @c true
|
|
|
|
*/
|
|
|
|
std::future<bool> wakeOnReleaseChannel();
|
|
|
|
|
|
|
|
/// Promise to be fulfilled when @c releaseChannel is called.
|
|
|
|
std::promise<void> m_wakeReleaseChannelPromise;
|
|
|
|
|
|
|
|
/// Future to notify when @c releaseChannel is called.
|
|
|
|
std::future<void> m_wakeReleaseChannelFuture;
|
|
|
|
|
|
|
|
/// A directive handler result to send the result to.
|
|
|
|
std::unique_ptr<MockDirectiveHandlerResult> m_mockDirHandlerResult;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fulfills the @c m_wakeSetCompletedPromise. This is invoked in response to a @c setCompleted call.
|
|
|
|
*/
|
|
|
|
void wakeOnSetCompleted();
|
|
|
|
|
|
|
|
/// Promise to be fulfilled when @c setCompleted is called.
|
|
|
|
std::promise<void> m_wakeSetCompletedPromise;
|
|
|
|
|
|
|
|
/// Future to notify when @c setCompleted is called.
|
|
|
|
std::future<void> m_wakeSetCompletedFuture;
|
|
|
|
|
2017-07-18 22:25:37 +00:00
|
|
|
/**
|
|
|
|
* Fulfills the @c m_wakeSetFailedPromise. This is invoked in response to a @c setFailed call.
|
|
|
|
*/
|
|
|
|
void wakeOnSetFailed();
|
|
|
|
|
|
|
|
/// Promise to be fulfilled when @c setFailed is called.
|
|
|
|
std::promise<void> m_wakeSetFailedPromise;
|
|
|
|
|
|
|
|
/// Future to notify when @c setFailed is called.
|
|
|
|
std::future<void> m_wakeSetFailedFuture;
|
|
|
|
|
2017-05-26 23:06:14 +00:00
|
|
|
/// A message sender used to send events to AVS.
|
|
|
|
std::shared_ptr<MockMessageSender> m_mockMessageSender;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fulfills the @c m_wakeSendMessagePromise. This is invoked in response to a @c sendMessage call.
|
|
|
|
*/
|
|
|
|
void wakeOnSendMessage();
|
|
|
|
|
|
|
|
/// Promise to be fulfilled when @c sendMessage is called.
|
|
|
|
std::promise<void> m_wakeSendMessagePromise;
|
|
|
|
|
|
|
|
/// Future to notify when @c sendMessage is called.
|
|
|
|
std::future<void> m_wakeSendMessageFuture;
|
|
|
|
|
2017-11-17 02:49:28 +00:00
|
|
|
/**
|
|
|
|
* Fulfills the @c m_wakeStoppedPromise. This is invoked in response to a @c stop call.
|
|
|
|
*/
|
|
|
|
void wakeOnStopped();
|
|
|
|
|
|
|
|
/// Promise to be fulfilled when @c stop is called.
|
|
|
|
std::promise<void> m_wakeStoppedPromise;
|
|
|
|
|
|
|
|
/// Future to notify when @c stop is called.
|
|
|
|
std::future<void> m_wakeStoppedFuture;
|
|
|
|
|
2017-05-26 23:06:14 +00:00
|
|
|
/// An exception sender used to send exception encountered events to AVS.
|
|
|
|
std::shared_ptr<MockExceptionEncounteredSender> m_mockExceptionSender;
|
|
|
|
|
|
|
|
/// Attachment manager used to create a reader.
|
|
|
|
std::shared_ptr<AttachmentManager> m_attachmentManager;
|
2017-12-09 00:07:37 +00:00
|
|
|
|
|
|
|
/// The @c DialogUXStateAggregator to test with.
|
|
|
|
std::shared_ptr<avsCommon::avs::DialogUXStateAggregator> m_dialogUXStateAggregator;
|
2017-05-26 23:06:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
SpeechSynthesizerTest::SpeechSynthesizerTest() :
|
2017-10-02 22:59:05 +00:00
|
|
|
m_wakeSetStatePromise{},
|
|
|
|
m_wakeSetStateFuture{m_wakeSetStatePromise.get_future()},
|
|
|
|
m_wakeAcquireChannelPromise{},
|
|
|
|
m_wakeAcquireChannelFuture{m_wakeAcquireChannelPromise.get_future()},
|
|
|
|
m_wakeReleaseChannelPromise{},
|
|
|
|
m_wakeReleaseChannelFuture{m_wakeReleaseChannelPromise.get_future()},
|
|
|
|
m_wakeSetCompletedPromise{},
|
|
|
|
m_wakeSetCompletedFuture{m_wakeSetCompletedPromise.get_future()},
|
|
|
|
m_wakeSetFailedPromise{},
|
|
|
|
m_wakeSetFailedFuture{m_wakeSetFailedPromise.get_future()},
|
|
|
|
m_wakeSendMessagePromise{},
|
2017-11-17 02:49:28 +00:00
|
|
|
m_wakeSendMessageFuture{m_wakeSendMessagePromise.get_future()},
|
|
|
|
m_wakeStoppedPromise{},
|
|
|
|
m_wakeStoppedFuture{m_wakeStoppedPromise.get_future()} {
|
2017-05-26 23:06:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SpeechSynthesizerTest::SetUp() {
|
|
|
|
m_mockContextManager = std::make_shared<NiceMock<MockContextManager>>();
|
|
|
|
m_mockFocusManager = std::make_shared<NiceMock<MockFocusManager>>();
|
|
|
|
m_mockMessageSender = std::make_shared<NiceMock<MockMessageSender>>();
|
|
|
|
m_mockExceptionSender = std::make_shared<NiceMock<MockExceptionEncounteredSender>>();
|
|
|
|
m_attachmentManager = std::make_shared<AttachmentManager>(AttachmentManager::AttachmentType::IN_PROCESS);
|
|
|
|
m_mockSpeechPlayer = MockMediaPlayer::create();
|
2017-12-09 00:07:37 +00:00
|
|
|
m_dialogUXStateAggregator = std::make_shared<avsCommon::avs::DialogUXStateAggregator>();
|
2017-05-26 23:06:14 +00:00
|
|
|
m_speechSynthesizer = SpeechSynthesizer::create(
|
2017-10-02 22:59:05 +00:00
|
|
|
m_mockSpeechPlayer,
|
|
|
|
m_mockMessageSender,
|
|
|
|
m_mockFocusManager,
|
|
|
|
m_mockContextManager,
|
2017-12-09 00:07:37 +00:00
|
|
|
m_mockExceptionSender,
|
|
|
|
m_dialogUXStateAggregator);
|
2017-05-26 23:06:14 +00:00
|
|
|
m_mockDirHandlerResult.reset(new MockDirectiveHandlerResult);
|
|
|
|
|
|
|
|
ASSERT_TRUE(m_speechSynthesizer);
|
2017-12-09 00:07:37 +00:00
|
|
|
|
|
|
|
m_speechSynthesizer->addObserver(m_dialogUXStateAggregator);
|
2017-05-26 23:06:14 +00:00
|
|
|
}
|
|
|
|
|
2017-08-17 00:13:40 +00:00
|
|
|
void SpeechSynthesizerTest::TearDown() {
|
2017-12-09 00:07:37 +00:00
|
|
|
m_speechSynthesizer->removeObserver(m_dialogUXStateAggregator);
|
2017-08-17 00:13:40 +00:00
|
|
|
m_speechSynthesizer->shutdown();
|
|
|
|
}
|
|
|
|
|
2017-05-26 23:06:14 +00:00
|
|
|
SetStateResult SpeechSynthesizerTest::wakeOnSetState() {
|
|
|
|
m_wakeSetStatePromise.set_value();
|
|
|
|
return SetStateResult::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SpeechSynthesizerTest::wakeOnAcquireChannel() {
|
|
|
|
m_wakeAcquireChannelPromise.set_value();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::future<bool> SpeechSynthesizerTest::wakeOnReleaseChannel() {
|
|
|
|
std::promise<bool> releaseChannelSuccess;
|
|
|
|
std::future<bool> returnValue = releaseChannelSuccess.get_future();
|
|
|
|
releaseChannelSuccess.set_value(true);
|
|
|
|
m_wakeReleaseChannelPromise.set_value();
|
|
|
|
return returnValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpeechSynthesizerTest::wakeOnSetCompleted() {
|
|
|
|
m_wakeSetCompletedPromise.set_value();
|
|
|
|
}
|
|
|
|
|
2017-07-18 22:25:37 +00:00
|
|
|
void SpeechSynthesizerTest::wakeOnSetFailed() {
|
|
|
|
m_wakeSetFailedPromise.set_value();
|
|
|
|
}
|
|
|
|
|
2017-05-26 23:06:14 +00:00
|
|
|
void SpeechSynthesizerTest::wakeOnSendMessage() {
|
|
|
|
m_wakeSendMessagePromise.set_value();
|
|
|
|
}
|
|
|
|
|
2017-11-17 02:49:28 +00:00
|
|
|
void SpeechSynthesizerTest::wakeOnStopped() {
|
|
|
|
m_wakeStoppedPromise.set_value();
|
|
|
|
}
|
|
|
|
|
2017-06-23 23:26:34 +00:00
|
|
|
/**
|
2017-06-09 23:23:31 +00:00
|
|
|
* Test call to handleDirectiveImmediately.
|
|
|
|
* Expected result is that @c acquireChannel is called with the correct channel. On focus changed @c FOREGROUND, audio
|
|
|
|
* should play. Expect the @c ContextManager @c setState is called when state changes to @c PLAYING.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_callingHandleImmediately) {
|
2017-06-09 23:23:31 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
2017-10-02 22:59:05 +00:00
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
2017-06-09 23:23:31 +00:00
|
|
|
|
2018-03-09 00:55:39 +00:00
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
2017-08-08 00:04:43 +00:00
|
|
|
EXPECT_CALL(
|
2017-10-30 22:14:38 +00:00
|
|
|
*(m_mockSpeechPlayer.get()),
|
2018-02-12 23:31:53 +00:00
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(AtLeast(1));
|
2017-10-30 22:14:38 +00:00
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
2017-10-02 22:59:05 +00:00
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
|
2017-06-09 23:23:31 +00:00
|
|
|
|
|
|
|
m_speechSynthesizer->handleDirectiveImmediately(directive);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
}
|
|
|
|
|
2017-06-23 23:26:34 +00:00
|
|
|
/**
|
2017-05-26 23:06:14 +00:00
|
|
|
* Tests preHandleDirective and HandleDirective
|
|
|
|
* Call preHandle with a valid SPEAK directive. Then call handleDirective. Expected result is that @c acquireChannel
|
|
|
|
* is called with the correct channel. On focus changed @c FOREGROUND, audio should play. Expect the @c ContextManager
|
|
|
|
* @c setState is called when state changes to @c PLAYING.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_callingHandle) {
|
2017-05-26 23:06:14 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
2017-10-02 22:59:05 +00:00
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
2017-05-26 23:06:14 +00:00
|
|
|
|
2018-03-09 00:55:39 +00:00
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
2017-08-08 00:04:43 +00:00
|
|
|
EXPECT_CALL(
|
2017-10-30 22:14:38 +00:00
|
|
|
*(m_mockSpeechPlayer.get()),
|
2018-02-12 23:31:53 +00:00
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(AtLeast(1));
|
2017-10-30 22:14:38 +00:00
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
2017-10-02 22:59:05 +00:00
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
|
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetFailed));
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tests cancelDirective.
|
|
|
|
* Call preHandle with a valid SPEAK directive. Then call cancelDirective. Expect that neither @c setState nor
|
|
|
|
* @c sendMessage are called since handle was never called to start playing audio.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_callingCancel) {
|
2017-05-26 23:06:14 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
2017-10-02 22:59:05 +00:00
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
2017-05-26 23:06:14 +00:00
|
|
|
|
2017-10-02 22:59:05 +00:00
|
|
|
EXPECT_CALL(*(m_mockContextManager.get()), setState(_, _, _, _)).Times(0);
|
2017-05-26 23:06:14 +00:00
|
|
|
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_)).Times(0);
|
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Testing cancelDirective after calling
|
|
|
|
* Call preHandle with a valid SPEAK directive. Then call handleDirective. Expected result is that @c acquireChannel
|
|
|
|
* is called once. On Focus Changed to foreground, audio should play. Call cancel directive. Expect the
|
|
|
|
* @c ContextManager @c setState is called when the state changes to @c PLAYING and then to @c FINISHED.
|
|
|
|
* Expect @c sendMessage is called only once. On cancel, message should not be sent to AVS.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_callingCancelAfterHandle) {
|
2017-05-26 23:06:14 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
2017-10-02 22:59:05 +00:00
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
2017-05-26 23:06:14 +00:00
|
|
|
|
2018-03-09 00:55:39 +00:00
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
2017-08-08 00:04:43 +00:00
|
|
|
EXPECT_CALL(
|
2017-10-30 22:14:38 +00:00
|
|
|
*(m_mockSpeechPlayer.get()),
|
2018-02-12 23:31:53 +00:00
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(AtLeast(1));
|
2017-10-30 22:14:38 +00:00
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
2017-10-02 22:59:05 +00:00
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, FINISHED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), releaseChannel(CHANNEL_NAME, _))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnReleaseChannel));
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
|
2018-01-12 23:45:42 +00:00
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStopped());
|
2017-05-26 23:06:14 +00:00
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Testing provideState.
|
|
|
|
* Call @c provideState and expect that setState is called.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_callingProvideStateWhenNotPlaying) {
|
2017-10-30 22:14:38 +00:00
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_)).Times(0);
|
2017-05-26 23:06:14 +00:00
|
|
|
EXPECT_CALL(
|
2017-10-02 22:59:05 +00:00
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, IDLE_STATE_TEST, StateRefreshPolicy::NEVER, PROVIDE_STATE_TOKEN_TEST))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
2017-05-26 23:06:14 +00:00
|
|
|
|
2017-12-09 00:07:37 +00:00
|
|
|
m_speechSynthesizer->provideState(NAMESPACE_AND_NAME_SPEECH_STATE, PROVIDE_STATE_TOKEN_TEST);
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Testing provideState when playing.
|
|
|
|
* Call @c provideState after the state of the @c SpeechSynthesizer has changed to @c PLAYING.
|
2017-10-02 22:59:05 +00:00
|
|
|
* Expect @c getOffset is called. Expect @c setState is called when state changes and when state is
|
2017-05-26 23:06:14 +00:00
|
|
|
* requested via @c provideState.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_callingProvideStateWhenPlaying) {
|
2017-05-26 23:06:14 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
2017-10-02 22:59:05 +00:00
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
2017-05-26 23:06:14 +00:00
|
|
|
|
2018-03-09 00:55:39 +00:00
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
2017-08-08 00:04:43 +00:00
|
|
|
EXPECT_CALL(
|
2017-10-30 22:14:38 +00:00
|
|
|
*(m_mockSpeechPlayer.get()),
|
2018-02-12 23:31:53 +00:00
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(AtLeast(1));
|
2017-10-30 22:14:38 +00:00
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(
|
2017-05-26 23:06:14 +00:00
|
|
|
NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, PROVIDE_STATE_TOKEN_TEST))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, FINISHED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(Return(SetStateResult::SUCCESS));
|
|
|
|
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), releaseChannel(CHANNEL_NAME, _))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnReleaseChannel));
|
2017-05-26 23:06:14 +00:00
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(WAIT_TIMEOUT));
|
2017-12-09 00:07:37 +00:00
|
|
|
m_speechSynthesizer->provideState(NAMESPACE_AND_NAME_SPEECH_STATE, PROVIDE_STATE_TOKEN_TEST);
|
2017-05-26 23:06:14 +00:00
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
|
2018-01-12 23:45:42 +00:00
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStopped());
|
2017-05-26 23:06:14 +00:00
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(WAIT_TIMEOUT));
|
2017-07-18 22:25:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Testing barge-in via @c handleDirectiveImmediately when audio is playing back.
|
|
|
|
* Call @c handleDirective. Once playback started notification is received, call @c handleDirectiveImmediately.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, testTimer_bargeInWhilePlaying) {
|
2017-07-18 22:25:37 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
2017-10-02 22:59:05 +00:00
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
|
|
|
|
|
|
|
auto avsMessageHeader2 =
|
|
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST_2);
|
|
|
|
std::shared_ptr<AVSDirective> directive2 =
|
|
|
|
AVSDirective::create("", avsMessageHeader2, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST_2);
|
|
|
|
|
2018-03-09 00:55:39 +00:00
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
2017-08-08 00:04:43 +00:00
|
|
|
EXPECT_CALL(
|
2017-10-30 22:14:38 +00:00
|
|
|
*(m_mockSpeechPlayer.get()),
|
2018-02-12 23:31:53 +00:00
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
2017-10-02 22:59:05 +00:00
|
|
|
.Times(AtLeast(1));
|
2017-10-30 22:14:38 +00:00
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
2017-10-02 22:59:05 +00:00
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, FINISHED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), releaseChannel(CHANNEL_NAME, _))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnReleaseChannel));
|
2017-07-18 22:25:37 +00:00
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeAcquireChannelPromise = std::promise<void>();
|
|
|
|
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->handleDirectiveImmediately(directive2);
|
|
|
|
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
|
2018-01-12 23:45:42 +00:00
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStopped());
|
2017-07-18 22:25:37 +00:00
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(WAIT_TIMEOUT));
|
2017-08-08 00:04:43 +00:00
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
2017-05-26 23:06:14 +00:00
|
|
|
}
|
|
|
|
|
2017-11-17 02:49:28 +00:00
|
|
|
/**
|
2017-12-09 00:07:37 +00:00
|
|
|
* Testing SpeechSynthesizer won't be calling stop() in @c MediaPlayer twice.
|
2017-11-17 02:49:28 +00:00
|
|
|
* Call preHandle with a valid SPEAK directive. Then call handleDirective. Expected result is that @c acquireChannel
|
|
|
|
* is called once. On Focus Changed to foreground, audio should play.
|
|
|
|
* Call cancel directive. Expect the stop() to be called once.
|
2017-12-09 00:07:37 +00:00
|
|
|
* Call onFocusChanged, expect the stop() to not be called again.
|
|
|
|
* Expect when handleDirectiveImmediately with a valid SPEAK directive is called, @c SpeechSynthesizer
|
2017-11-17 02:49:28 +00:00
|
|
|
* will react correctly.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, testTimer_notCallStopTwice) {
|
2017-11-17 02:49:28 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
|
|
|
|
|
|
|
auto avsMessageHeader2 =
|
|
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST_2);
|
|
|
|
std::shared_ptr<AVSDirective> directive2 =
|
|
|
|
AVSDirective::create("", avsMessageHeader2, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST_2);
|
|
|
|
|
2018-03-09 00:55:39 +00:00
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
2017-11-17 02:49:28 +00:00
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockSpeechPlayer.get()),
|
2018-02-12 23:31:53 +00:00
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
2017-11-17 02:49:28 +00:00
|
|
|
.Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, FINISHED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), releaseChannel(CHANNEL_NAME, _))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnReleaseChannel));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), stop(_))
|
2017-12-09 00:07:37 +00:00
|
|
|
.Times(2)
|
2017-11-17 02:49:28 +00:00
|
|
|
.WillOnce(Invoke([this](avsCommon::utils::mediaPlayer::MediaPlayerInterface::SourceId id) {
|
|
|
|
wakeOnStopped();
|
2017-12-09 00:07:37 +00:00
|
|
|
m_speechSynthesizer->onPlaybackStopped(id);
|
2017-11-17 02:49:28 +00:00
|
|
|
return true;
|
|
|
|
}))
|
2017-12-09 00:07:37 +00:00
|
|
|
.WillRepeatedly(Return(true));
|
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setCompleted()).Times(AtLeast(0));
|
|
|
|
|
|
|
|
// send Speak directive and getting focus and wait until playback started
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeAcquireChannelPromise = std::promise<void>();
|
|
|
|
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSendMessagePromise = std::promise<void>();
|
|
|
|
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
|
|
|
|
|
|
|
|
// cancel directive, this should result in calling stop()
|
|
|
|
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeStoppedFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
|
|
|
|
// goes to background, this should not result in calling the 2nd stop()
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::BACKGROUND);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* onPlaybackStopped, this will result in an error with reason=nullptrDirectiveInfo. But this shouldn't break the
|
|
|
|
* SpeechSynthesizer
|
|
|
|
*/
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeReleaseChannelPromise = std::promise<void>();
|
|
|
|
m_wakeReleaseChannelFuture = m_wakeReleaseChannelPromise.get_future();
|
|
|
|
|
|
|
|
// send second speak directive and make sure it working
|
|
|
|
m_speechSynthesizer->handleDirectiveImmediately(directive2);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
}
|
|
|
|
|
Version 1.12 alexa-client-sdk
Changes in this update:
**Enhancements**
* Support was added for the `fr_CA` locale.
* The Executor has been optimized to run a single thread when there are active job in the queue, and to remain idle when there are not active jobs.
* An additional parameter of `alertType` has been added to the Alerts capability agent. This will allow observers of alerts to know the type of alert being delivered.
* Support for programmatic unload and load of PulseAudio Bluetooth modules was added. To enable this feature, there is a [new CMake option](https://github.com/alexa/avs-device-sdk/wiki/CMake-parameters#bluetooth): `BLUETOOTH_BLUEZ_PULSEAUDIO_OVERRIDE_ENDPOINTS`. Note that [libpulse-dev is a required dependency](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#bluetooth) of this feature.
* An observer interface was added for when an active Bluetooth device connects and disconnects.
* The `BluetoothDeviceManagerInterface` instantiation was moved from `DefaultClient` to `SampleApp` to allow applications to override it.
* The `MediaPlayerInterface` now supports repeating playback of URL sources.
* The Kitt.AI wake word engine (WWE) is now compatible with GCC5+.
* Stop of ongoing alerts, management of MessageObservers, and management of CallStateObservers have been exposed through DefaultClient.
**Bug Fixes**
* [Issue 953](https://github.com/alexa/avs-device-sdk/issues/953) - The `MediaPlayerInterface` requirement that callbacks not be made upon a callers thread has been removed.
* [Issue 1136](https://github.com/alexa/avs-device-sdk/issues/1136) - Added a missing default virtual destructor.
* [Issue 1140](https://github.com/alexa/avs-device-sdk/issues/1140) - Fixed an issue where DND states were not synchronized to the AVS cloud after device reset.
* [Issue 1143](https://github.com/alexa/avs-device-sdk/issues/1143) - Fixed an issue in which the SpeechSynthesizer couldn't enter a sleeping state.
* [Issue 1183](https://github.com/alexa/avs-device-sdk/issues/1183) - Fixed an issue where alarm is not sounding for certain timezones
* Changing an alert's volume from the Alexa app now works when an alert is playing.
* Added missing shutdown handling for ContentDecrypter to prevent the `Stop` command from triggering a crash when SAMPLE-AES encrypted content was streaming.
* Fixed a bug where if the Notifications database is empty, due to a crash or corruption, the SDK initialization process enters an infinite loop when it retries to get context from the Notifications capability agent.
* Fixed a race condition that caused `AlertsRenderer` observers to miss notification that an alert has been completed.
**Known Issues**
* `PlaylistParser` and `IterativePlaylistParser` generate two HTTP requests (one to fetch the content type, and one to fetch the audio data) for each audio stream played.
* Music playback history isn't being displayed in the Alexa app for certain account and device types.
* On GCC 8+, issues related to `-Wclass-memaccess` will trigger warnings. However, this won't cause the build to fail and these warnings can be ignored.
* Android error ("libDefaultClient.so" not found) can be resolved by upgrading to ADB version 1.0.40
* When network connection is lost, lost connection status is not returned via local TTS.
* `ACL` may encounter issues if audio attachments are received but not consumed.
* `SpeechSynthesizerState` currently uses `GAINING_FOCUS` and `LOSING_FOCUS` as a workaround for handling intermediate state. These states may be removed in a future release.
* The Alexa app doesn't always indicate when a device is successfully connected via Bluetooth.
* Connecting a product to streaming media via Bluetooth will sometimes stop media playback within the source application. Resuming playback through the source application or toggling next/previous will correct playback.
* When a source device is streaming silence via Bluetooth, the Alexa app indicates that audio content is streaming.
* The Bluetooth agent assumes that the Bluetooth adapter is always connected to a power source. Disconnecting from a power source during operation is not yet supported.
* On some products, interrupted Bluetooth playback may not resume if other content is locally streamed.
* `make integration` is currently not available for Android. In order to run integration tests on Android, you'll need to manually upload the test binary file along with any input file. At that point, the adb can be used to run the integration tests.
* On Raspberry Pi running Android Things with HDMI output audio, beginning of speech is truncated when Alexa responds to user text-to-speech (TTS).
* When the sample app is restarted and network connection is lost, Reminder TTS does not play. Instead, the default alarm tone will play twice.
2019-02-26 00:45:37 +00:00
|
|
|
/**
|
|
|
|
* Testing executeCancel() completes execution before onFocusChanged() is called.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, testSlow_callingCancelBeforeOnFocusChanged) {
|
Version 1.12 alexa-client-sdk
Changes in this update:
**Enhancements**
* Support was added for the `fr_CA` locale.
* The Executor has been optimized to run a single thread when there are active job in the queue, and to remain idle when there are not active jobs.
* An additional parameter of `alertType` has been added to the Alerts capability agent. This will allow observers of alerts to know the type of alert being delivered.
* Support for programmatic unload and load of PulseAudio Bluetooth modules was added. To enable this feature, there is a [new CMake option](https://github.com/alexa/avs-device-sdk/wiki/CMake-parameters#bluetooth): `BLUETOOTH_BLUEZ_PULSEAUDIO_OVERRIDE_ENDPOINTS`. Note that [libpulse-dev is a required dependency](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#bluetooth) of this feature.
* An observer interface was added for when an active Bluetooth device connects and disconnects.
* The `BluetoothDeviceManagerInterface` instantiation was moved from `DefaultClient` to `SampleApp` to allow applications to override it.
* The `MediaPlayerInterface` now supports repeating playback of URL sources.
* The Kitt.AI wake word engine (WWE) is now compatible with GCC5+.
* Stop of ongoing alerts, management of MessageObservers, and management of CallStateObservers have been exposed through DefaultClient.
**Bug Fixes**
* [Issue 953](https://github.com/alexa/avs-device-sdk/issues/953) - The `MediaPlayerInterface` requirement that callbacks not be made upon a callers thread has been removed.
* [Issue 1136](https://github.com/alexa/avs-device-sdk/issues/1136) - Added a missing default virtual destructor.
* [Issue 1140](https://github.com/alexa/avs-device-sdk/issues/1140) - Fixed an issue where DND states were not synchronized to the AVS cloud after device reset.
* [Issue 1143](https://github.com/alexa/avs-device-sdk/issues/1143) - Fixed an issue in which the SpeechSynthesizer couldn't enter a sleeping state.
* [Issue 1183](https://github.com/alexa/avs-device-sdk/issues/1183) - Fixed an issue where alarm is not sounding for certain timezones
* Changing an alert's volume from the Alexa app now works when an alert is playing.
* Added missing shutdown handling for ContentDecrypter to prevent the `Stop` command from triggering a crash when SAMPLE-AES encrypted content was streaming.
* Fixed a bug where if the Notifications database is empty, due to a crash or corruption, the SDK initialization process enters an infinite loop when it retries to get context from the Notifications capability agent.
* Fixed a race condition that caused `AlertsRenderer` observers to miss notification that an alert has been completed.
**Known Issues**
* `PlaylistParser` and `IterativePlaylistParser` generate two HTTP requests (one to fetch the content type, and one to fetch the audio data) for each audio stream played.
* Music playback history isn't being displayed in the Alexa app for certain account and device types.
* On GCC 8+, issues related to `-Wclass-memaccess` will trigger warnings. However, this won't cause the build to fail and these warnings can be ignored.
* Android error ("libDefaultClient.so" not found) can be resolved by upgrading to ADB version 1.0.40
* When network connection is lost, lost connection status is not returned via local TTS.
* `ACL` may encounter issues if audio attachments are received but not consumed.
* `SpeechSynthesizerState` currently uses `GAINING_FOCUS` and `LOSING_FOCUS` as a workaround for handling intermediate state. These states may be removed in a future release.
* The Alexa app doesn't always indicate when a device is successfully connected via Bluetooth.
* Connecting a product to streaming media via Bluetooth will sometimes stop media playback within the source application. Resuming playback through the source application or toggling next/previous will correct playback.
* When a source device is streaming silence via Bluetooth, the Alexa app indicates that audio content is streaming.
* The Bluetooth agent assumes that the Bluetooth adapter is always connected to a power source. Disconnecting from a power source during operation is not yet supported.
* On some products, interrupted Bluetooth playback may not resume if other content is locally streamed.
* `make integration` is currently not available for Android. In order to run integration tests on Android, you'll need to manually upload the test binary file along with any input file. At that point, the adb can be used to run the integration tests.
* On Raspberry Pi running Android Things with HDMI output audio, beginning of speech is truncated when Alexa responds to user text-to-speech (TTS).
* When the sample app is restarted and network connection is lost, Reminder TTS does not play. Instead, the default alarm tone will play twice.
2019-02-26 00:45:37 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
|
|
|
|
|
|
|
auto avsMessageHeader2 =
|
|
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST_2);
|
|
|
|
std::shared_ptr<AVSDirective> directive2 =
|
|
|
|
AVSDirective::create("", avsMessageHeader2, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST_2);
|
|
|
|
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
|
|
|
.Times(2)
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetFailed));
|
|
|
|
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(2)
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, FINISHED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
|
|
|
|
.Times(1)
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockSpeechPlayer.get()),
|
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
|
|
|
.Times(2);
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(2);
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(2)
|
|
|
|
.WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeAcquireChannelPromise = std::promise<void>();
|
|
|
|
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
|
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetFailedFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetFailedPromise = std::promise<void>();
|
|
|
|
m_wakeSetFailedFuture = m_wakeSetFailedPromise.get_future();
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
|
|
|
|
// send second speak directive and make sure it working
|
|
|
|
m_speechSynthesizer->handleDirectiveImmediately(directive2);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Testing executeCancel() completes execution before executeStateChange() is called.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_callingCancelBeforeOnExecuteStateChanged) {
|
Version 1.12 alexa-client-sdk
Changes in this update:
**Enhancements**
* Support was added for the `fr_CA` locale.
* The Executor has been optimized to run a single thread when there are active job in the queue, and to remain idle when there are not active jobs.
* An additional parameter of `alertType` has been added to the Alerts capability agent. This will allow observers of alerts to know the type of alert being delivered.
* Support for programmatic unload and load of PulseAudio Bluetooth modules was added. To enable this feature, there is a [new CMake option](https://github.com/alexa/avs-device-sdk/wiki/CMake-parameters#bluetooth): `BLUETOOTH_BLUEZ_PULSEAUDIO_OVERRIDE_ENDPOINTS`. Note that [libpulse-dev is a required dependency](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#bluetooth) of this feature.
* An observer interface was added for when an active Bluetooth device connects and disconnects.
* The `BluetoothDeviceManagerInterface` instantiation was moved from `DefaultClient` to `SampleApp` to allow applications to override it.
* The `MediaPlayerInterface` now supports repeating playback of URL sources.
* The Kitt.AI wake word engine (WWE) is now compatible with GCC5+.
* Stop of ongoing alerts, management of MessageObservers, and management of CallStateObservers have been exposed through DefaultClient.
**Bug Fixes**
* [Issue 953](https://github.com/alexa/avs-device-sdk/issues/953) - The `MediaPlayerInterface` requirement that callbacks not be made upon a callers thread has been removed.
* [Issue 1136](https://github.com/alexa/avs-device-sdk/issues/1136) - Added a missing default virtual destructor.
* [Issue 1140](https://github.com/alexa/avs-device-sdk/issues/1140) - Fixed an issue where DND states were not synchronized to the AVS cloud after device reset.
* [Issue 1143](https://github.com/alexa/avs-device-sdk/issues/1143) - Fixed an issue in which the SpeechSynthesizer couldn't enter a sleeping state.
* [Issue 1183](https://github.com/alexa/avs-device-sdk/issues/1183) - Fixed an issue where alarm is not sounding for certain timezones
* Changing an alert's volume from the Alexa app now works when an alert is playing.
* Added missing shutdown handling for ContentDecrypter to prevent the `Stop` command from triggering a crash when SAMPLE-AES encrypted content was streaming.
* Fixed a bug where if the Notifications database is empty, due to a crash or corruption, the SDK initialization process enters an infinite loop when it retries to get context from the Notifications capability agent.
* Fixed a race condition that caused `AlertsRenderer` observers to miss notification that an alert has been completed.
**Known Issues**
* `PlaylistParser` and `IterativePlaylistParser` generate two HTTP requests (one to fetch the content type, and one to fetch the audio data) for each audio stream played.
* Music playback history isn't being displayed in the Alexa app for certain account and device types.
* On GCC 8+, issues related to `-Wclass-memaccess` will trigger warnings. However, this won't cause the build to fail and these warnings can be ignored.
* Android error ("libDefaultClient.so" not found) can be resolved by upgrading to ADB version 1.0.40
* When network connection is lost, lost connection status is not returned via local TTS.
* `ACL` may encounter issues if audio attachments are received but not consumed.
* `SpeechSynthesizerState` currently uses `GAINING_FOCUS` and `LOSING_FOCUS` as a workaround for handling intermediate state. These states may be removed in a future release.
* The Alexa app doesn't always indicate when a device is successfully connected via Bluetooth.
* Connecting a product to streaming media via Bluetooth will sometimes stop media playback within the source application. Resuming playback through the source application or toggling next/previous will correct playback.
* When a source device is streaming silence via Bluetooth, the Alexa app indicates that audio content is streaming.
* The Bluetooth agent assumes that the Bluetooth adapter is always connected to a power source. Disconnecting from a power source during operation is not yet supported.
* On some products, interrupted Bluetooth playback may not resume if other content is locally streamed.
* `make integration` is currently not available for Android. In order to run integration tests on Android, you'll need to manually upload the test binary file along with any input file. At that point, the adb can be used to run the integration tests.
* On Raspberry Pi running Android Things with HDMI output audio, beginning of speech is truncated when Alexa responds to user text-to-speech (TTS).
* When the sample app is restarted and network connection is lost, Reminder TTS does not play. Instead, the default alarm tone will play twice.
2019-02-26 00:45:37 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
|
|
|
|
|
|
|
auto avsMessageHeader2 =
|
|
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST_2);
|
|
|
|
std::shared_ptr<AVSDirective> directive2 =
|
|
|
|
AVSDirective::create("", avsMessageHeader2, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST_2);
|
|
|
|
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
|
|
|
.Times(2)
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetFailed));
|
|
|
|
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(2)
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, FINISHED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
|
|
|
|
.Times(1)
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockSpeechPlayer.get()),
|
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
|
|
|
.Times(2);
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(2);
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(2)
|
|
|
|
.WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeAcquireChannelPromise = std::promise<void>();
|
|
|
|
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
|
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetFailedFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetFailedPromise = std::promise<void>();
|
|
|
|
m_wakeSetFailedFuture = m_wakeSetFailedPromise.get_future();
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
|
|
|
|
// send second speak directive and make sure it working
|
|
|
|
m_speechSynthesizer->handleDirectiveImmediately(directive2);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
}
|
|
|
|
|
2017-12-09 00:07:37 +00:00
|
|
|
/**
|
|
|
|
* Testing SpeechSynthesizer will continue to function properly if stop() in @c MediaPlayer returned with an error.
|
|
|
|
* Call preHandle with a valid SPEAK directive. Then call handleDirective. Expected result is that @c acquireChannel
|
|
|
|
* is called once. On Focus Changed to foreground, audio should play.
|
|
|
|
* Call cancel directive. Expect the stop() to be called once, and we force MediaPlayer to return an error.
|
|
|
|
* Expect when handleDirectiveImmediately with a valid SPEAK directive is called, @c SpeechSynthesizer
|
|
|
|
* will react correctly.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_mediaPlayerFailedToStop) {
|
2017-12-09 00:07:37 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
|
|
|
|
|
|
|
auto avsMessageHeader2 =
|
|
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST_2);
|
|
|
|
std::shared_ptr<AVSDirective> directive2 =
|
|
|
|
AVSDirective::create("", avsMessageHeader2, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST_2);
|
|
|
|
|
2018-03-09 00:55:39 +00:00
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
2017-12-09 00:07:37 +00:00
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockSpeechPlayer.get()),
|
2018-02-12 23:31:53 +00:00
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
2017-12-09 00:07:37 +00:00
|
|
|
.Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, FINISHED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), releaseChannel(CHANNEL_NAME, _))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnReleaseChannel));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), stop(_))
|
|
|
|
.Times(2)
|
2017-11-17 02:49:28 +00:00
|
|
|
.WillOnce(Invoke([this](avsCommon::utils::mediaPlayer::MediaPlayerInterface::SourceId id) {
|
|
|
|
wakeOnStopped();
|
|
|
|
return false;
|
|
|
|
}))
|
|
|
|
.WillRepeatedly(Return(true));
|
2017-12-09 00:07:37 +00:00
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_)).Times(AtLeast(0));
|
2017-11-17 02:49:28 +00:00
|
|
|
|
|
|
|
// send Speak directive and getting focus and wait until playback started
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeAcquireChannelPromise = std::promise<void>();
|
|
|
|
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSendMessagePromise = std::promise<void>();
|
|
|
|
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
|
|
|
|
|
|
|
|
// cancel directive, this should result in calling stop()
|
|
|
|
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeStoppedFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
|
2017-12-09 00:07:37 +00:00
|
|
|
// goes to background, this should not result in calling the 2nd stop()
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(WAIT_TIMEOUT));
|
2017-11-17 02:49:28 +00:00
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::BACKGROUND);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* onPlaybackStopped, this will result in an error with reason=nullptrDirectiveInfo. But this shouldn't break the
|
|
|
|
* SpeechSynthesizer
|
|
|
|
*/
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeReleaseChannelPromise = std::promise<void>();
|
|
|
|
m_wakeReleaseChannelFuture = m_wakeReleaseChannelPromise.get_future();
|
|
|
|
|
|
|
|
// send second speak directive and make sure it working
|
|
|
|
m_speechSynthesizer->handleDirectiveImmediately(directive2);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
}
|
|
|
|
|
Version 1.10 alexa-client-sdk
Changes in this update:
**Enhancements**
* New optional configuration for [EqualizerController](https://github.com/alexa/avs-device-sdk/blob/v1.10.0/Integration/AlexaClientSDKConfig.json#L154). The EqualizerController interface allows you to adjust equalizer settings on your product, such as decibel (dB) levels and modes.
* Added reference implementation of the EqualizerController for GStreamer-based (MacOS, Linux, and Raspberry Pi) and OpenSL ES-based (Android) MediaPlayers. Note: In order to use with Android, it must support OpenSL ES.
* New optional configuration for the [TemplateRuntime display card value](https://github.com/alexa/avs-device-sdk/blob/v1.10.0/Integration/AlexaClientSDKConfig.json#L144).
* A configuration file generator script, `genConfig.sh` is now included with the SDK in the **tools/Install** directory. `genConfig.sh` and it's associated arguments populate `AlexaClientSDKConfig.json` with the data required to authorize with LWA.
* Added Bluetooth A2DP source and AVRCP target support for Linux.
* Added Amazon for Business (A4B) support, which includes support for handling the new [RevokeAuthorization](https://developer.amazon.com/docs/alexa-voice-service/system.html#revokeauth) directive in the Settings interface. A new CMake option has been added to enable A4B within the SDK, `-DA4B`.
* Added locale support for IT and ES.
* The Alexa Communication Library (ACL), `CBLAUthDelegate`, and sample app have been enhanced to detect de-authorization using the new `z` command.
* Added `ExternalMediaPlayerObserver`, which receives notification of player state, track, and username changes.
* `HTTP2ConnectionInterface` was factored out of `HTTP2Transport` to enable unit testing of `HTTP2Transport` and re-use of `HTTP2Connection` logic.
**Bug Fixes**
* Fixed a bug in which `ExternalMediaPlayer` adapter playback wasn't being recognized by AVS.
* [Issue 973](https://github.com/alexa/avs-device-sdk/issues/973) - Fixed issues related to `AudioPlayer` where progress reports were being sent out of order or with incorrect offsets.
* An `EXPECTING`, state has been added to `DialogUXState` in order to handle `EXPECT_SPEECH` state for hold-to-talk devices.
* [Issue 948](https://github.com/alexa/avs-device-sdk/issues/948) - Fixed a bug in which the sample app was stuck in a listening state.
* Fixed a bug where there was a delay between receiving a `DeleteAlert` directive, and deleting the alert.
* [Issue 839](https://github.com/alexa/avs-device-sdk/issues/839) - Fixed an issue where speech was being truncated due to the `DialogUXStateAggregator` transitioning between a `THINKING` and `IDLE` state.
* Fixed a bug in which the `AudioPlayer` attempted to play when it wasn't in the `FOREGROUND` focus.
* `CapabilitiesDelegateTest` now works on Android.
* [Issue 950](https://github.com/alexa/avs-device-sdk/issues/950) - Improved Android Media Player audio quality.
* [Issue 908](https://github.com/alexa/avs-device-sdk/issues/908) - Fixed compile error on g++ 7.x in which includes were missing.
2018-10-24 17:01:29 +00:00
|
|
|
/**
|
|
|
|
* Test SpeechSynthesizer shutdown when speech is playing and @c MediaPlayerInterface.stop() fails (ACSDK-1859).
|
|
|
|
*
|
|
|
|
* Expected result is that shutdown should succeeded no matter the @c stop return.
|
|
|
|
*/
|
Version 1.15 alexa-client-sdk
Changes in this update:
**Enhancements**
* Added `SystemSoundPlayer` to [ApplicationUtilities](https://alexa.github.io/avs-device-sdk/namespacealexa_client_s_d_k_1_1application_utilities.html). `SystemSoundPlayer` is a new class that plays pre-defined sounds. Sounds currently supported include the wake word notification and the end of speech tone. This change is internal and you don't need to update your code.
* Removed [Echo Spatial Perception (ESP)](https://developer.amazon.com/blogs/alexa/post/042be85c-5a62-4c55-a18d-d7a82cf394df/esp-moves-to-the-cloud-for-alexa-enabled-devices) functionality from the Alexa Voice Service (AVS) device SDK. Make sure you download and test your devices using the new AVS SDK sample app. If you're using an older version of the sample app, manually remove any references to ESP or errors occur during compile.
* Added `onNotificationReceived` to `NotificationsObserverInterface`. `onNotificationReceived` broadcasts when `NotificationsObserverInterface` receives a new notification, instead of only sending the indicator state. This is important if you support a feature that requires a distinct signal for each notification received. See [NotificationsObserverInterface](https://alexa.github.io/avs-device-sdk/classalexa_client_s_d_k_1_1avs_common_1_1sdk_interfaces_1_1_notifications_observer_interface.html) for more details.
* Added support for [Multilingual Mode](https://developer.amazon.com/docs/alexa-voice-service/system.html#localecombinations). With this enabled, Alexa automatically detects what language a user speaks by analyzing the spoken wake word and proceeding utterances. Once Alexa identifies the language, all corresponding responses are in the same language. The current supported language pairs are:
- `[ "en-US", "es-US" ]`
- `[ "es-US", "en-US" ]`
- `[ "en-IN", "hi-IN" ]`
- `[ "hi-IN", "en-IN" ]`
- `[ "en-CA", "fr-CA" ]`
- `[ "fr-CA", "en-CA" ]`
<br/> **IMPORTANT**: Specify the locales your device supports in the [localeCombinations](https://developer.amazon.com/docs/alexa-voice-service/system.html#localecombinations) field in AlexaClientSDKConfig.json. This field can't be empty. If you don't set these values, the sample app fails to run.
* Added two new system settings, [Timezone](https://developer.amazon.com/docs/alexa-voice-service/system.html#settimezone) and [Locale](https://developer.amazon.com/docs/alexa-voice-service/system.html#locales).
- Timezone: For example, you can set the `defaultTimezone` to `America/Vancouver`. If you don't set a value, `GMT` is set as the default value. If you set a new timezone, make sure that your AVS system settings and default timezone stay in sync. To handle this, use the new class `SystemTimeZoneInterface`. See [System Interface > SetTimeZone](https://developer.amazon.com/docs/alexa-voice-service/system.html#settimezone) for more information.
- Locale: For example, you can set `defaultLocale` to `en-GB`, instead of the default `en-US`.
* The [SpeechRecognizer](https://developer.amazon.com/docs/alexa-voice-service/speechrecognizer.html) interface now supports the following functionalities.
- Change wake word (`Alexa` supported for now).
- Toggle start of request tone on/off.
- Toggle End of request tone on/off.
* Deprecated the [CapabilityAgents](https://alexa.github.io/avs-device-sdk/classalexa_client_s_d_k_1_1avs_common_1_1avs_1_1_capability_agent.html) `Settings{…}` library. `Settings {…}` now maps to an interface that's no longer supported. You might need to update your code to handle these changes. Read [Settings Interface](https://developer.amazon.com/docs/alexa-voice-service/per-interface-settings.html) for more details.
* Added support for three new locals: Spanish - United States (ES_US), Hindi - India (HI_IN), and Brazilian - Portuguese (PT_BR).
* Linked the atomic library to the sample app to prevent build errors on Raspberry Pi.
**Bug Fixes**
* Fixed resource leaking in [EqualizerCapabilityAgent](https://alexa.github.io/avs-device-sdk/classalexa_client_s_d_k_1_1capability_agents_1_1equalizer_1_1_equalizer_capability_agent.html) after engine shutdown.
* [Issue 1391:](https://github.com/alexa/avs-device-sdk/pull/1391) Fixed an issue where [SQLiteDeviceSettingsStorage::open](https://alexa.github.io/avs-device-sdk/classalexa_client_s_d_k_1_1settings_1_1storage_1_1_s_q_lite_device_setting_storage.html#a7733e56145916f7ff265c5c950add492) tries to acquire a mutex twice, resulting in deadlock.
* [Issue 1468:](https://github.com/alexa/avs-device-sdk/issues/1468) Fixed a bug in [AudioPlayer::cancelDirective](https://alexa.github.io/avs-device-sdk/classalexa_client_s_d_k_1_1capability_agents_1_1audio_player_1_1_audio_player.html#a2c710c16f3627790fcc3238d34da9361) that causes a crash.
* Fixed Windows install script that caused the sample app build to fail - removed pip, flask, requests, and commentjson dependencies from the mingw.sh helper script.
* Fixed issue: notifications failed to sync upon device initialization. For example, let's say you had two devices - one turned on and the other turned off. After clearing the notification on the first device, it still showed up on the second device after turning it on.
* Fixed issue: barging in on a reminder caused it to stick in an inconsistent state, blocking subsequent reminders. For example, if a reminder was going off and you interrupted it, the reminder would get persist indefinitely. You could schedule future reminders, but they wouldn't play. Saying “Alexa stop” or rebooting the device fixed the “stuck” reminder.
**Known Issues**
* Music playback history isn't displayed in the Alexa app for certain account and device types.
* When using Gnu Compiler Collection 8+ (GCC 8+), `-Wclass-memaccess` triggers warnings. You can ignore these, they don't cause the build to fail.
* Android error `libDefaultClient.so not found` might occur. Resolve this by upgrading to ADB version 1.0.40.
* If a device loses a network connection, the lost connection status isn't returned via local TTS.
* ACL encounters issues if it receives audio attachments but doesn't consume them.
* `SpeechSynthesizerState` uses `GAINING_FOCUS` and `LOSING_FOCUS` as a workaround for handling intermediate states.
* Media steamed through Bluetooth might abruptly stop. To restart playback, resume the media in the source application or toggle next/previous.
* If a connected Bluetooth device is inactive, the Alexa app might indicates that audio is playing.
* The Bluetooth agent assumes that the Bluetooth adapter is always connected to a power source. Disconnecting from a power source during operation isn't yet supported.
* When using some products, interrupted Bluetooth playback might not resume if other content is locally streamed.
* `make integration` isn't available for Android. To run Android integration tests, manually upload the test binary and input file and run ADB.
* Alexa might truncate the beginning of speech when responding to text-to-speech (TTS) user events. This only impacts Raspberry Pi devices running Android Things with HDMI output audio.
* A reminder TTS message doesn't play if the sample app restarts and loses a network connection. Instead, the default alarm tone plays twice.
* `ServerDisconnectIntegratonTest` tests are disabled until they are updated to reflect new service behavior.
* Bluetooth initialization must complete before connecting devices, otherwise devices are ignored.
* The `DirectiveSequencerTest.test_handleBlockingThenImmediatelyThenNonBockingOnSameDialogId` test fails intermittently.
2019-09-25 18:49:09 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, testTimer_mediaPlayerAlwaysFailToStop) {
|
Version 1.10 alexa-client-sdk
Changes in this update:
**Enhancements**
* New optional configuration for [EqualizerController](https://github.com/alexa/avs-device-sdk/blob/v1.10.0/Integration/AlexaClientSDKConfig.json#L154). The EqualizerController interface allows you to adjust equalizer settings on your product, such as decibel (dB) levels and modes.
* Added reference implementation of the EqualizerController for GStreamer-based (MacOS, Linux, and Raspberry Pi) and OpenSL ES-based (Android) MediaPlayers. Note: In order to use with Android, it must support OpenSL ES.
* New optional configuration for the [TemplateRuntime display card value](https://github.com/alexa/avs-device-sdk/blob/v1.10.0/Integration/AlexaClientSDKConfig.json#L144).
* A configuration file generator script, `genConfig.sh` is now included with the SDK in the **tools/Install** directory. `genConfig.sh` and it's associated arguments populate `AlexaClientSDKConfig.json` with the data required to authorize with LWA.
* Added Bluetooth A2DP source and AVRCP target support for Linux.
* Added Amazon for Business (A4B) support, which includes support for handling the new [RevokeAuthorization](https://developer.amazon.com/docs/alexa-voice-service/system.html#revokeauth) directive in the Settings interface. A new CMake option has been added to enable A4B within the SDK, `-DA4B`.
* Added locale support for IT and ES.
* The Alexa Communication Library (ACL), `CBLAUthDelegate`, and sample app have been enhanced to detect de-authorization using the new `z` command.
* Added `ExternalMediaPlayerObserver`, which receives notification of player state, track, and username changes.
* `HTTP2ConnectionInterface` was factored out of `HTTP2Transport` to enable unit testing of `HTTP2Transport` and re-use of `HTTP2Connection` logic.
**Bug Fixes**
* Fixed a bug in which `ExternalMediaPlayer` adapter playback wasn't being recognized by AVS.
* [Issue 973](https://github.com/alexa/avs-device-sdk/issues/973) - Fixed issues related to `AudioPlayer` where progress reports were being sent out of order or with incorrect offsets.
* An `EXPECTING`, state has been added to `DialogUXState` in order to handle `EXPECT_SPEECH` state for hold-to-talk devices.
* [Issue 948](https://github.com/alexa/avs-device-sdk/issues/948) - Fixed a bug in which the sample app was stuck in a listening state.
* Fixed a bug where there was a delay between receiving a `DeleteAlert` directive, and deleting the alert.
* [Issue 839](https://github.com/alexa/avs-device-sdk/issues/839) - Fixed an issue where speech was being truncated due to the `DialogUXStateAggregator` transitioning between a `THINKING` and `IDLE` state.
* Fixed a bug in which the `AudioPlayer` attempted to play when it wasn't in the `FOREGROUND` focus.
* `CapabilitiesDelegateTest` now works on Android.
* [Issue 950](https://github.com/alexa/avs-device-sdk/issues/950) - Improved Android Media Player audio quality.
* [Issue 908](https://github.com/alexa/avs-device-sdk/issues/908) - Fixed compile error on g++ 7.x in which includes were missing.
2018-10-24 17:01:29 +00:00
|
|
|
auto speechSynthesizer = SpeechSynthesizer::create(
|
|
|
|
m_mockSpeechPlayer,
|
|
|
|
m_mockMessageSender,
|
|
|
|
m_mockFocusManager,
|
|
|
|
m_mockContextManager,
|
|
|
|
m_mockExceptionSender,
|
|
|
|
m_dialogUXStateAggregator);
|
|
|
|
|
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
|
|
|
|
|
|
|
EXPECT_CALL(*m_mockFocusManager, acquireChannel(_, _, _))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
|
|
|
EXPECT_CALL(*m_mockSpeechPlayer, attachmentSetSource(_, _)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*m_mockSpeechPlayer, play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*m_mockSpeechPlayer, getOffset(_)).WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
|
|
|
EXPECT_CALL(*m_mockContextManager, setState(_, _, _, _)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*m_mockMessageSender, sendMessage(_));
|
|
|
|
EXPECT_CALL(*m_mockFocusManager, releaseChannel(_, _)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*m_mockSpeechPlayer, stop(_)).WillRepeatedly(Return(false));
|
|
|
|
EXPECT_CALL(*m_mockDirHandlerResult, setFailed(_));
|
|
|
|
|
|
|
|
// send Speak directive and getting focus and wait until playback started
|
|
|
|
speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
|
|
|
|
speechSynthesizer->shutdown();
|
|
|
|
speechSynthesizer.reset();
|
|
|
|
}
|
|
|
|
|
2018-01-12 23:45:42 +00:00
|
|
|
/**
|
|
|
|
* Testing SpeechSynthesizer will call stop() if the SpeechSynthesizer experienced a state change timeout to PLAYING
|
|
|
|
* state.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, testSlow_setStateTimeout) {
|
2018-01-12 23:45:42 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
|
|
|
|
2018-03-09 00:55:39 +00:00
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
2018-01-12 23:45:42 +00:00
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockSpeechPlayer.get()),
|
2018-02-12 23:31:53 +00:00
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
2018-01-12 23:45:42 +00:00
|
|
|
.Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(1).WillOnce(Return(true));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
|
|
|
EXPECT_CALL(*(m_mockExceptionSender.get()), sendExceptionEncountered(_, _, _)).Times(1);
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockContextManager.get()),
|
|
|
|
setState(NAMESPACE_AND_NAME_SPEECH_STATE, FINISHED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
|
|
|
|
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_)).Times(0);
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), releaseChannel(CHANNEL_NAME, _))
|
|
|
|
.Times(AtLeast(1))
|
|
|
|
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnReleaseChannel));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), stop(_)).Times(1).WillOnce(Return(true));
|
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetFailed));
|
|
|
|
|
|
|
|
// Send Speak directive and getting focus and wait until state change timeout.
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeAcquireChannelPromise = std::promise<void>();
|
|
|
|
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetFailedFuture.wait_for(STATE_CHANGE_TIMEOUT));
|
|
|
|
|
|
|
|
// Upon getting onPlaybackedStarted, expect state to be updated, but SpeechStarted event will not be sent.
|
|
|
|
m_speechSynthesizer->onPlaybackStarted(m_mockSpeechPlayer->getCurrentSourceId());
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
|
|
|
|
// Upon getting onPlaybackStopped, expect state to be updated, but SpeechFinished event will not be sent.
|
|
|
|
m_speechSynthesizer->onPlaybackStopped(m_mockSpeechPlayer->getCurrentSourceId());
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_wakeSetStatePromise = std::promise<void>();
|
|
|
|
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::BACKGROUND);
|
|
|
|
}
|
|
|
|
|
Version 1.10 alexa-client-sdk
Changes in this update:
**Enhancements**
* New optional configuration for [EqualizerController](https://github.com/alexa/avs-device-sdk/blob/v1.10.0/Integration/AlexaClientSDKConfig.json#L154). The EqualizerController interface allows you to adjust equalizer settings on your product, such as decibel (dB) levels and modes.
* Added reference implementation of the EqualizerController for GStreamer-based (MacOS, Linux, and Raspberry Pi) and OpenSL ES-based (Android) MediaPlayers. Note: In order to use with Android, it must support OpenSL ES.
* New optional configuration for the [TemplateRuntime display card value](https://github.com/alexa/avs-device-sdk/blob/v1.10.0/Integration/AlexaClientSDKConfig.json#L144).
* A configuration file generator script, `genConfig.sh` is now included with the SDK in the **tools/Install** directory. `genConfig.sh` and it's associated arguments populate `AlexaClientSDKConfig.json` with the data required to authorize with LWA.
* Added Bluetooth A2DP source and AVRCP target support for Linux.
* Added Amazon for Business (A4B) support, which includes support for handling the new [RevokeAuthorization](https://developer.amazon.com/docs/alexa-voice-service/system.html#revokeauth) directive in the Settings interface. A new CMake option has been added to enable A4B within the SDK, `-DA4B`.
* Added locale support for IT and ES.
* The Alexa Communication Library (ACL), `CBLAUthDelegate`, and sample app have been enhanced to detect de-authorization using the new `z` command.
* Added `ExternalMediaPlayerObserver`, which receives notification of player state, track, and username changes.
* `HTTP2ConnectionInterface` was factored out of `HTTP2Transport` to enable unit testing of `HTTP2Transport` and re-use of `HTTP2Connection` logic.
**Bug Fixes**
* Fixed a bug in which `ExternalMediaPlayer` adapter playback wasn't being recognized by AVS.
* [Issue 973](https://github.com/alexa/avs-device-sdk/issues/973) - Fixed issues related to `AudioPlayer` where progress reports were being sent out of order or with incorrect offsets.
* An `EXPECTING`, state has been added to `DialogUXState` in order to handle `EXPECT_SPEECH` state for hold-to-talk devices.
* [Issue 948](https://github.com/alexa/avs-device-sdk/issues/948) - Fixed a bug in which the sample app was stuck in a listening state.
* Fixed a bug where there was a delay between receiving a `DeleteAlert` directive, and deleting the alert.
* [Issue 839](https://github.com/alexa/avs-device-sdk/issues/839) - Fixed an issue where speech was being truncated due to the `DialogUXStateAggregator` transitioning between a `THINKING` and `IDLE` state.
* Fixed a bug in which the `AudioPlayer` attempted to play when it wasn't in the `FOREGROUND` focus.
* `CapabilitiesDelegateTest` now works on Android.
* [Issue 950](https://github.com/alexa/avs-device-sdk/issues/950) - Improved Android Media Player audio quality.
* [Issue 908](https://github.com/alexa/avs-device-sdk/issues/908) - Fixed compile error on g++ 7.x in which includes were missing.
2018-10-24 17:01:29 +00:00
|
|
|
/**
|
|
|
|
* Testing changing focus state to NONE (local stop) during a speak.
|
|
|
|
* Expect @c setFailed to be called so any subsequent directives with the same dialogRequestId will be dropped.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_givenPlayingStateFocusBecomesNone) {
|
Version 1.10 alexa-client-sdk
Changes in this update:
**Enhancements**
* New optional configuration for [EqualizerController](https://github.com/alexa/avs-device-sdk/blob/v1.10.0/Integration/AlexaClientSDKConfig.json#L154). The EqualizerController interface allows you to adjust equalizer settings on your product, such as decibel (dB) levels and modes.
* Added reference implementation of the EqualizerController for GStreamer-based (MacOS, Linux, and Raspberry Pi) and OpenSL ES-based (Android) MediaPlayers. Note: In order to use with Android, it must support OpenSL ES.
* New optional configuration for the [TemplateRuntime display card value](https://github.com/alexa/avs-device-sdk/blob/v1.10.0/Integration/AlexaClientSDKConfig.json#L144).
* A configuration file generator script, `genConfig.sh` is now included with the SDK in the **tools/Install** directory. `genConfig.sh` and it's associated arguments populate `AlexaClientSDKConfig.json` with the data required to authorize with LWA.
* Added Bluetooth A2DP source and AVRCP target support for Linux.
* Added Amazon for Business (A4B) support, which includes support for handling the new [RevokeAuthorization](https://developer.amazon.com/docs/alexa-voice-service/system.html#revokeauth) directive in the Settings interface. A new CMake option has been added to enable A4B within the SDK, `-DA4B`.
* Added locale support for IT and ES.
* The Alexa Communication Library (ACL), `CBLAUthDelegate`, and sample app have been enhanced to detect de-authorization using the new `z` command.
* Added `ExternalMediaPlayerObserver`, which receives notification of player state, track, and username changes.
* `HTTP2ConnectionInterface` was factored out of `HTTP2Transport` to enable unit testing of `HTTP2Transport` and re-use of `HTTP2Connection` logic.
**Bug Fixes**
* Fixed a bug in which `ExternalMediaPlayer` adapter playback wasn't being recognized by AVS.
* [Issue 973](https://github.com/alexa/avs-device-sdk/issues/973) - Fixed issues related to `AudioPlayer` where progress reports were being sent out of order or with incorrect offsets.
* An `EXPECTING`, state has been added to `DialogUXState` in order to handle `EXPECT_SPEECH` state for hold-to-talk devices.
* [Issue 948](https://github.com/alexa/avs-device-sdk/issues/948) - Fixed a bug in which the sample app was stuck in a listening state.
* Fixed a bug where there was a delay between receiving a `DeleteAlert` directive, and deleting the alert.
* [Issue 839](https://github.com/alexa/avs-device-sdk/issues/839) - Fixed an issue where speech was being truncated due to the `DialogUXStateAggregator` transitioning between a `THINKING` and `IDLE` state.
* Fixed a bug in which the `AudioPlayer` attempted to play when it wasn't in the `FOREGROUND` focus.
* `CapabilitiesDelegateTest` now works on Android.
* [Issue 950](https://github.com/alexa/avs-device-sdk/issues/950) - Improved Android Media Player audio quality.
* [Issue 908](https://github.com/alexa/avs-device-sdk/issues/908) - Fixed compile error on g++ 7.x in which includes were missing.
2018-10-24 17:01:29 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
|
|
|
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockSpeechPlayer.get()),
|
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
|
|
|
.Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetFailed));
|
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setCompleted()).Times(0);
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
EXPECT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
EXPECT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::NONE);
|
|
|
|
EXPECT_TRUE(std::future_status::ready == m_wakeSetFailedFuture.wait_for(STATE_CHANGE_TIMEOUT));
|
|
|
|
}
|
|
|
|
|
Version 1.11 alexa-client-sdk
Changes in this update:
**Enhancements**
* Added support for the new Alexa [DoNotDisturb](https://developer.amazon.com/docs/alexa-voice-service/donotdisturb.html) interface, which enables users to toggle the do not disturb (DND) function on their Alexa built-in products.
* The SDK now supports [Opus](https://opus-codec.org/license/) encoding, which is optional. To enable Opus, you must [set the CMake flag to `-DOPUS=ON`](https://github.com/alexa/avs-device-sdk/wiki/Build-Options#Opus-encoding), and include the [libopus library](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#core-dependencies) dependency in your build.
* The MediaPlayer reference implementation has been expanded to support the SAMPLE-AES and AES-128 encryption methods for HLS streaming.
* AES-128 encryption is dependent on libcrypto, which is part of the required openSSL library, and is enabled by default.
* To enable [SAMPLE-AES](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#core-dependencies/Enable-SAMPLE-AES-decryption) encryption, you must set the `-DSAMPLE_AES=ON` in your CMake command, and include the [FFMPEG](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#core-dependencies/Enable-SAMPLE-AES-decryption) library dependency in your build.
* A new configuration for [deviceSettings](https://github.com/alexa/avs-device-sdk/blob/v1.11.0/Integration/AlexaClientSDKConfig.json#L59) has been added.This configuration allows you to specify the location of the device settings database.
* Added locale support for es-MX.
**Bug Fixes**
* Fixed an issue where music wouldn't resume playback in the Android app.
* Now all equalizer capabilities are fully disabled when equalizer is turned off in configuration file. Previously, devices were unconditionally required to provide support for equalizer in order to run the SDK.
* [Issue 1106](https://github.com/alexa/avs-device-sdk/issues/1106) - Fixed an issue in which the `CBLAuthDelegate` wasn't using the correct timeout during request refresh.
* [Issue 1128](https://github.com/alexa/avs-device-sdk/issues/1128) - Fixed an issue in which the `AudioPlayer` instance persisted at shutdown, due to a shared dependency with the `ProgressTimer`.
* Fixed in issue that occurred when a connection to streaming content was interrupted, the SDK did not attempt to resume the connection, and appeared to assume that the content had been fully downloaded. This triggered the next track to be played, assuming it was a playlist.
* [Issue 1040](https://github.com/alexa/avs-device-sdk/issues/1040) - Fixed an issue where alarms would continue to play after user barge-in.
**Known Issues**
* `PlaylistParser` and `IterativePlaylistParser` generate two HTTP requests (one to fetch the content type, and one to fetch the audio data) for each audio stream played.
* Music playback history isn't being displayed in the Alexa app for certain account and device types.
* On GCC 8+, issues related to `-Wclass-memaccess` will trigger warnings. However, this won't cause the build to fail, and these warnings can be ignored.
* In order to use Bluetooth source and sink PulseAudio, you must manually load and unload PulseAudio modules after the SDK starts.
* The `ACL` may encounter issues if audio attachments are received but not consumed.
* `SpeechSynthesizerState` currently uses `GAINING_FOCUS` and `LOSING_FOCUS` as a workaround for handling intermediate state. These states may be removed in a future release.
* The Alexa app doesn't always indicate when a device is successfully connected via Bluetooth.
* Connecting a product to streaming media via Bluetooth will sometimes stop media playback within the source application. Resuming playback through the source application or toggling next/previous will correct playback.
* When a source device is streaming silence via Bluetooth, the Alexa app indicates that audio content is streaming.
* The Bluetooth agent assumes that the Bluetooth adapter is always connected to a power source. Disconnecting from a power source during operation is not yet supported.
* On some products, interrupted Bluetooth playback may not resume if other content is locally streamed.
* `make integration` is currently not available for Android. In order to run integration tests on Android, you'll need to manually upload the test binary file along with any input file. At that point, the adb can be used to run the integration tests.
* On Raspberry Pi running Android Things with HDMI output audio, beginning of speech is truncated when Alexa responds to user TTS.
* When the sample app is restarted and network connection is lost, alerts don't play.
* When network connection is lost, lost connection status is not returned via local Text-to Speech (TTS).
2018-12-19 19:13:36 +00:00
|
|
|
/**
|
|
|
|
* Testing SpeechSynthesizer will call setFailed() if the SpeechSynthesizer got a onPlaybackStopped() callback while
|
|
|
|
* it is in PLAYING state.
|
|
|
|
*/
|
2019-05-22 23:06:18 +00:00
|
|
|
TEST_F(SpeechSynthesizerTest, test_onPlayedStopped) {
|
Version 1.11 alexa-client-sdk
Changes in this update:
**Enhancements**
* Added support for the new Alexa [DoNotDisturb](https://developer.amazon.com/docs/alexa-voice-service/donotdisturb.html) interface, which enables users to toggle the do not disturb (DND) function on their Alexa built-in products.
* The SDK now supports [Opus](https://opus-codec.org/license/) encoding, which is optional. To enable Opus, you must [set the CMake flag to `-DOPUS=ON`](https://github.com/alexa/avs-device-sdk/wiki/Build-Options#Opus-encoding), and include the [libopus library](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#core-dependencies) dependency in your build.
* The MediaPlayer reference implementation has been expanded to support the SAMPLE-AES and AES-128 encryption methods for HLS streaming.
* AES-128 encryption is dependent on libcrypto, which is part of the required openSSL library, and is enabled by default.
* To enable [SAMPLE-AES](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#core-dependencies/Enable-SAMPLE-AES-decryption) encryption, you must set the `-DSAMPLE_AES=ON` in your CMake command, and include the [FFMPEG](https://github.com/alexa/avs-device-sdk/wiki/Dependencies#core-dependencies/Enable-SAMPLE-AES-decryption) library dependency in your build.
* A new configuration for [deviceSettings](https://github.com/alexa/avs-device-sdk/blob/v1.11.0/Integration/AlexaClientSDKConfig.json#L59) has been added.This configuration allows you to specify the location of the device settings database.
* Added locale support for es-MX.
**Bug Fixes**
* Fixed an issue where music wouldn't resume playback in the Android app.
* Now all equalizer capabilities are fully disabled when equalizer is turned off in configuration file. Previously, devices were unconditionally required to provide support for equalizer in order to run the SDK.
* [Issue 1106](https://github.com/alexa/avs-device-sdk/issues/1106) - Fixed an issue in which the `CBLAuthDelegate` wasn't using the correct timeout during request refresh.
* [Issue 1128](https://github.com/alexa/avs-device-sdk/issues/1128) - Fixed an issue in which the `AudioPlayer` instance persisted at shutdown, due to a shared dependency with the `ProgressTimer`.
* Fixed in issue that occurred when a connection to streaming content was interrupted, the SDK did not attempt to resume the connection, and appeared to assume that the content had been fully downloaded. This triggered the next track to be played, assuming it was a playlist.
* [Issue 1040](https://github.com/alexa/avs-device-sdk/issues/1040) - Fixed an issue where alarms would continue to play after user barge-in.
**Known Issues**
* `PlaylistParser` and `IterativePlaylistParser` generate two HTTP requests (one to fetch the content type, and one to fetch the audio data) for each audio stream played.
* Music playback history isn't being displayed in the Alexa app for certain account and device types.
* On GCC 8+, issues related to `-Wclass-memaccess` will trigger warnings. However, this won't cause the build to fail, and these warnings can be ignored.
* In order to use Bluetooth source and sink PulseAudio, you must manually load and unload PulseAudio modules after the SDK starts.
* The `ACL` may encounter issues if audio attachments are received but not consumed.
* `SpeechSynthesizerState` currently uses `GAINING_FOCUS` and `LOSING_FOCUS` as a workaround for handling intermediate state. These states may be removed in a future release.
* The Alexa app doesn't always indicate when a device is successfully connected via Bluetooth.
* Connecting a product to streaming media via Bluetooth will sometimes stop media playback within the source application. Resuming playback through the source application or toggling next/previous will correct playback.
* When a source device is streaming silence via Bluetooth, the Alexa app indicates that audio content is streaming.
* The Bluetooth agent assumes that the Bluetooth adapter is always connected to a power source. Disconnecting from a power source during operation is not yet supported.
* On some products, interrupted Bluetooth playback may not resume if other content is locally streamed.
* `make integration` is currently not available for Android. In order to run integration tests on Android, you'll need to manually upload the test binary file along with any input file. At that point, the adb can be used to run the integration tests.
* On Raspberry Pi running Android Things with HDMI output audio, beginning of speech is truncated when Alexa responds to user TTS.
* When the sample app is restarted and network connection is lost, alerts don't play.
* When network connection is lost, lost connection status is not returned via local Text-to Speech (TTS).
2018-12-19 19:13:36 +00:00
|
|
|
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
|
|
|
|
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST);
|
|
|
|
std::shared_ptr<AVSDirective> directive =
|
|
|
|
AVSDirective::create("", avsMessageHeader, PAYLOAD_TEST, m_attachmentManager, CONTEXT_ID_TEST);
|
|
|
|
|
|
|
|
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _, NAMESPACE_SPEECH_SYNTHESIZER))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
|
|
|
|
EXPECT_CALL(
|
|
|
|
*(m_mockSpeechPlayer.get()),
|
|
|
|
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr))
|
|
|
|
.Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), play(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
|
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_))
|
|
|
|
.Times(1)
|
|
|
|
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetFailed));
|
|
|
|
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setCompleted()).Times(0);
|
|
|
|
|
|
|
|
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirHandlerResult));
|
|
|
|
m_speechSynthesizer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST);
|
|
|
|
EXPECT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(WAIT_TIMEOUT));
|
|
|
|
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND);
|
|
|
|
EXPECT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
|
|
|
|
m_speechSynthesizer->onPlaybackStopped(m_mockSpeechPlayer->getCurrentSourceId());
|
|
|
|
EXPECT_TRUE(std::future_status::ready == m_wakeSetFailedFuture.wait_for(STATE_CHANGE_TIMEOUT));
|
|
|
|
}
|
|
|
|
|
2017-10-02 22:59:05 +00:00
|
|
|
} // namespace test
|
|
|
|
} // namespace speechSynthesizer
|
|
|
|
} // namespace capabilityAgents
|
|
|
|
} // namespace alexaClientSDK
|