avs-device-sdk/CapabilityAgents/SpeechSynthesizer/test/SpeechSynthesizerTest.cpp

1925 lines
98 KiB
C++

/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <chrono>
#include <future>
#include <memory>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <AVSCommon/SDKInterfaces/MockExceptionEncounteredSender.h>
#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/SDKInterfaces/MockPowerResourceManager.h>
#include <AVSCommon/AVS/Attachment/AttachmentManager.h>
#include <AVSCommon/Utils/MediaPlayer/MockMediaPlayer.h>
#include <AVSCommon/Utils/Metrics/MockMetricRecorder.h>
#include <AVSCommon/Utils/JSON/JSONGenerator.h>
#include <MockCaptionManager.h>
#include "SpeechSynthesizer/SpeechSynthesizer.h"
namespace alexaClientSDK {
namespace capabilityAgents {
namespace speechSynthesizer {
namespace test {
using namespace avsCommon::utils;
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;
using namespace avsCommon::utils::mediaPlayer::test;
using namespace avsCommon::utils::metrics;
using namespace captions::test;
using namespace ::testing;
using MediaPlayerState = avsCommon::utils::mediaPlayer::MediaPlayerState;
using PowerResourceLevel = PowerResourceManagerInterface::PowerResourceLevel;
/// Plenty of time for a test to complete.
static const std::chrono::milliseconds MY_WAIT_TIMEOUT(1000);
/// Default media player state for all playback events
static const MediaPlayerState DEFAULT_MEDIA_PLAYER_STATE = {std::chrono::milliseconds(0)};
/// 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);
/// The name of the @c FocusManager channel used by the @c SpeechSynthesizer.
static const std::string CHANNEL_NAME(avsCommon::sdkInterfaces::FocusManagerInterface::DIALOG_CHANNEL_NAME);
/// Namespace for SpeechSynthesizer.
static const std::string NAMESPACE_SPEECH_SYNTHESIZER("SpeechSynthesizer");
/// Name for SpeechSynthesizer directive.
static const std::string NAME_SPEAK("Speak");
/// The name of the event to send to the AVS server once audio starting playing.
static std::string SPEECH_STARTED_EVENT_NAME{"SpeechStarted"};
/// The name of the event to send to the AVS server once audio finishes playing.
static std::string SPEECH_FINISHED_EVENT_NAME{"SpeechFinished"};
/// The name of the event to send to the AVS server once audio playing has been interrupted.
static std::string SPEECH_INTERRUPTED_EVENT_NAME{"SpeechInterrupted"};
/// 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");
/// Message Id for testing.
static const std::string MESSAGE_ID_TEST_2("MessageId_Test_2");
/// 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");
/// Context ID for testing
static const std::string CONTEXT_ID_TEST_2("ContextId_Test_2");
static const std::string CAPTION_CONTENT_SAMPLE =
"WEBVTT\\n"
"\\n"
"1\\n"
"00:00.000 --> 00:01.260\\n"
"The time is 2:17 PM.";
/// A payload for testing
// clang-format off
static const std::string PAYLOAD_TEST =
"{"
"\"url\":\"" + URL_TEST + "\","
"\"format\":\"" + FORMAT_TEST + "\","
"\"token\":\""+ TOKEN_TEST + "\","
"\"caption\": {"
"\"content\":\"" + CAPTION_CONTENT_SAMPLE + "\","
"\"type\":\"WEBVTT\""
"}"
"}";
// clang-format on
/// A payload for testing with single audio analyzer entry
// clang-format off
static const std::string PAYLOAD_TEST_SINGLE_ANALYZER =
"{"
"\"url\":\"" + URL_TEST + "\","
"\"format\":\"" + FORMAT_TEST + "\","
"\"token\":\""+ TOKEN_TEST + "\","
"\"caption\": {"
"\"content\":\"" + CAPTION_CONTENT_SAMPLE + "\","
"\"type\":\"WEBVTT\""
"},"
"\"analyzers\":[{\"interface\":\"analyzername\", \"enabled\":\"YES\"}]"
"}";
// clang-format on
/// A payload for testing with multiple audio analyzer entry
// clang-format off
static const std::string PAYLOAD_TEST_MULTIPLE_ANALYZER =
"{"
"\"url\":\"" + URL_TEST + "\","
"\"format\":\"" + FORMAT_TEST + "\","
"\"token\":\""+ TOKEN_TEST + "\","
"\"caption\": {"
"\"content\":\"" + CAPTION_CONTENT_SAMPLE + "\","
"\"type\":\"WEBVTT\""
"},"
"\"analyzers\":["
"{\"interface\":\"analyzername1\", \"enabled\":\"YES\"},"
"{\"interface\":\"analyzername2\", \"enabled\":\"NO\"}"
"]"
"}";
// clang-format on
/// 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 @c INTERRUPTED state of the @c SpeechSynthesizer
static const std::string INTERRUPTED_STATE{"INTERRUPTED"};
/// The offset in milliseconds returned by the mock media player.
static const long OFFSET_IN_MILLISECONDS_TEST{100};
/// An std::chrono::milliseconds representation of the offset.
static const std::chrono::milliseconds OFFSET_IN_CHRONO_MILLISECONDS_TEST{100};
/// The expected state when the @c SpeechSynthesizer is in @c PLAYING state.
// clang-format off
static const std::string PLAYING_STATE_TEST =
"{"
"\"token\":\"" + TOKEN_TEST + "\","
"\"offsetInMilliseconds\":" + std::to_string(OFFSET_IN_MILLISECONDS_TEST) + ","
"\"playerActivity\":\"" + PLAYING_STATE + "\""
"}";
// clang-format on
/// The expected state when the @c SpeechSynthesizer is in @c FINISHED state.
// clang-format off
static const std::string FINISHED_STATE_TEST =
"{"
"\"token\":\"" + TOKEN_TEST + "\","
"\"offsetInMilliseconds\":" + std::to_string(0) + ","
"\"playerActivity\":\"" + FINISHED_STATE + "\""
"}";
// clang-format on
/// The expected state when the @c SpeechSynthesizer is in @c INTERRUPTED state.
// clang-format off
static const std::string INTERRUPTED_STATE_TEST =
"{"
"\"token\":\"" + TOKEN_TEST + "\","
"\"offsetInMilliseconds\":" + std::to_string(OFFSET_IN_MILLISECONDS_TEST) + ","
"\"playerActivity\":\"" + INTERRUPTED_STATE + "\""
"}";
// clang-format on
/// The expected state when the @c SpeechSynthesizer is not handling any directive.
// clang-format off
static const std::string IDLE_STATE_TEST =
"{"
"\"token\":\"\","
"\"offsetInMilliseconds\":" + std::to_string(0) + ","
"\"playerActivity\":\"" + FINISHED_STATE + "\""
"}";
// clang-format on
/// Provide State Token for testing.
static const unsigned int PROVIDE_STATE_TOKEN_TEST{1};
/// Component name for power resource management.
static const std::string COMPONENT_NAME("SpeechSynthesizer");
/**
* Store useful information about a mock Speak Directive.
*/
struct SpeakTestInfo {
/// The payload content.
const std::string payload;
/// The message id.
const std::string messageId;
/// The directive token.
const std::string token;
};
static SpeakTestInfo generateSpeakInfo(PlayBehavior playBehavior) {
json::JsonGenerator generator;
static int id = 0;
std::string idStr = "_" + std::to_string(id++);
std::string token = TOKEN_TEST + idStr;
generator.addMember("url", URL_TEST + idStr);
generator.addMember("format", FORMAT_TEST);
generator.addMember("playBehavior", playBehaviorToString(playBehavior));
generator.addMember("token", token);
return SpeakTestInfo{generator.toString(), (MESSAGE_ID_TEST + idStr), token};
}
static std::string generatePlayingState(const SpeakTestInfo& info) {
return std::string(PLAYING_STATE_TEST).replace(PLAYING_STATE_TEST.find(TOKEN_TEST), TOKEN_TEST.size(), info.token);
}
static std::string generateFinishedState(const SpeakTestInfo& info) {
return std::string(FINISHED_STATE_TEST)
.replace(FINISHED_STATE_TEST.find(TOKEN_TEST), TOKEN_TEST.size(), info.token);
}
static std::string generateInterruptedState(const SpeakTestInfo& info) {
return std::string(INTERRUPTED_STATE_TEST)
.replace(INTERRUPTED_STATE_TEST.find(TOKEN_TEST), TOKEN_TEST.size(), info.token);
}
class MockSpeechSynthesizerObserver : public SpeechSynthesizerObserverInterface {
public:
MOCK_METHOD4(
onStateChanged,
void(
SpeechSynthesizerObserverInterface::SpeechSynthesizerState state,
const mediaPlayer::MediaPlayerInterface::SourceId mediaSourceId,
const Optional<mediaPlayer::MediaPlayerState>& mediaPlayerState,
const std::vector<audioAnalyzer::AudioAnalyzerState>& audioAnalyzerState));
};
class SpeechSynthesizerTest : public ::testing::Test {
public:
SpeechSynthesizerTest();
void SetUp() override;
void TearDown() override;
/// @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;
/// Mock SpeechSynthesizerObserver for testing.
std::shared_ptr<MockSpeechSynthesizerObserver> m_mockSpeechSynthesizerObserver;
/**
* 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;
/**
* 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;
/// 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;
/**
* 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;
/// 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;
/// Metric recorder used to record metric.
std::shared_ptr<MetricRecorderInterface> m_metricRecorder;
/// The @c DialogUXStateAggregator to test with.
std::shared_ptr<avsCommon::avs::DialogUXStateAggregator> m_dialogUXStateAggregator;
/// A mock @c CaptionManager instance to handle captions parsing.
std::shared_ptr<MockCaptionManager> m_mockCaptionManager;
/// The mock @c PowerResourceManagerInterface
std::shared_ptr<avsCommon::sdkInterfaces::test::MockPowerResourceManager> m_mockPowerResourceManager;
/**
* Setup speech synthesizer to have a pending speech directive.
*
* @param resultHandler the result handler for the new speech directive.
* @param info Information used to generate the new speech directive.
* @return @c true if it succeed; @c false otherwise.
*/
bool setupPendingSpeech(std::unique_ptr<DirectiveHandlerResultInterface> resultHandler, const SpeakTestInfo& info);
/**
* Setup speech synthesizer to have an active speech directive.
*
* @param resultHandler the result handler for the new speech directive.
* @param info Information used to generate and activate the new speech directive.
* @return @c true if it succeed; @c false otherwise.
*/
bool setupActiveSpeech(std::unique_ptr<DirectiveHandlerResultInterface> resultHandler, const SpeakTestInfo& info);
};
SpeechSynthesizerTest::SpeechSynthesizerTest() :
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{},
m_wakeSendMessageFuture{m_wakeSendMessagePromise.get_future()},
m_wakeStoppedPromise{},
m_wakeStoppedFuture{m_wakeStoppedPromise.get_future()} {
}
void SpeechSynthesizerTest::SetUp() {
m_metricRecorder = std::make_shared<NiceMock<avsCommon::utils::metrics::test::MockMetricRecorder>>();
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();
m_dialogUXStateAggregator = std::make_shared<avsCommon::avs::DialogUXStateAggregator>();
m_mockCaptionManager = std::make_shared<NiceMock<MockCaptionManager>>();
m_mockPowerResourceManager = std::make_shared<avsCommon::sdkInterfaces::test::MockPowerResourceManager>();
m_mockSpeechSynthesizerObserver = std::make_shared<MockSpeechSynthesizerObserver>();
m_speechSynthesizer = SpeechSynthesizer::create(
m_mockSpeechPlayer,
m_mockMessageSender,
m_mockFocusManager,
m_mockContextManager,
m_mockExceptionSender,
m_metricRecorder,
m_dialogUXStateAggregator,
m_mockCaptionManager,
m_mockPowerResourceManager);
m_mockDirHandlerResult.reset(new MockDirectiveHandlerResult);
ASSERT_TRUE(m_speechSynthesizer);
m_speechSynthesizer->addObserver(m_dialogUXStateAggregator);
}
void SpeechSynthesizerTest::TearDown() {
m_speechSynthesizer->shutdown();
m_mockSpeechPlayer->shutdown();
}
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();
}
void SpeechSynthesizerTest::wakeOnSetFailed() {
m_wakeSetFailedPromise.set_value();
}
void SpeechSynthesizerTest::wakeOnSendMessage() {
m_wakeSendMessagePromise.set_value();
}
void SpeechSynthesizerTest::wakeOnStopped() {
m_wakeStoppedPromise.set_value();
}
/**
* Match request by the event content. This does a simple string search.
*
* @param request The request to be checked.
* @param expectedContent The content that should be included in the request.
* @return If the content was found or not.
*/
static bool matchEvent(std::shared_ptr<MessageRequest> request, const std::string& expectedContent) {
return request && (request->getJsonContent().find(expectedContent) != std::string::npos);
}
MATCHER(IsStartedEvent, "") {
return matchEvent(arg, SPEECH_STARTED_EVENT_NAME);
}
MATCHER(IsFinishedEvent, "") {
return matchEvent(arg, SPEECH_FINISHED_EVENT_NAME);
}
MATCHER(IsInterruptedEvent, "") {
return matchEvent(arg, SPEECH_INTERRUPTED_EVENT_NAME);
}
/**
* 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.
*/
TEST_F(SpeechSynthesizerTest, test_callingHandleImmediately) {
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, _))
.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_mockSpeechPlayer.get()), getMediaPlayerState(_)).Times(AtLeast(2));
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_mockCaptionManager, onCaption(_, _)).Times(1);
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
std::vector<audioAnalyzer::AudioAnalyzerState> data;
EXPECT_CALL(
*m_mockSpeechSynthesizerObserver,
onStateChanged(SpeechSynthesizerObserverInterface::SpeechSynthesizerState::GAINING_FOCUS, _, _, _))
.Times(1);
EXPECT_CALL(
*m_mockSpeechSynthesizerObserver,
onStateChanged(SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING, _, _, Eq(data)))
.Times(1);
m_speechSynthesizer->addObserver(m_mockSpeechSynthesizerObserver);
m_speechSynthesizer->handleDirectiveImmediately(directive);
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
}
/**
* 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.
*/
TEST_F(SpeechSynthesizerTest, test_callingHandle) {
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, _))
.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_mockSpeechPlayer.get()), getMediaPlayerState(_)).Times(AtLeast(2));
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));
EXPECT_CALL(*m_mockCaptionManager, onCaption(_, _)).Times(1);
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
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(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_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.
*/
TEST_F(SpeechSynthesizerTest, test_callingCancel) {
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_mockContextManager.get()), setState(_, _, _, _)).Times(0);
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 INTERRUPTED.
* Expect @c sendMessage is called twice (SpeechStarted and SpeechInterrupted).
*/
TEST_F(SpeechSynthesizerTest, test_callingCancelAfterHandle) {
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, _))
.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(AtLeast(2))
.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, INTERRUPTED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
.Times(AtLeast(1))
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(IsStartedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*(m_mockFocusManager.get()), releaseChannel(CHANNEL_NAME, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnReleaseChannel));
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_))
.Times(1)
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetFailed));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
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(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(IsInterruptedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStopped());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
}
/**
* Testing provideState.
* Call @c provideState and expect that setState is called.
*/
TEST_F(SpeechSynthesizerTest, test_callingProvideStateWhenNotPlaying) {
EXPECT_CALL(*(m_mockSpeechPlayer.get()), getOffset(_)).Times(0);
EXPECT_CALL(
*(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));
m_speechSynthesizer->provideState(NAMESPACE_AND_NAME_SPEECH_STATE, PROVIDE_STATE_TOKEN_TEST);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
}
/**
* Testing provideState when playing.
* Call @c provideState after the state of the @c SpeechSynthesizer has changed to @c PLAYING.
* Expect @c getOffset is called. Expect @c setState is called when state changes and when state is
* requested via @c provideState.
*/
TEST_F(SpeechSynthesizerTest, test_callingProvideStateWhenPlaying) {
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, _))
.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(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(
NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, PROVIDE_STATE_TOKEN_TEST))
.Times(1)
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(_))
.Times(AtLeast(1))
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
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(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->provideState(NAMESPACE_AND_NAME_SPEECH_STATE, PROVIDE_STATE_TOKEN_TEST);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
}
/**
* Testing barge-in via @c handleDirectiveImmediately when audio is playing back.
* Call @c handleDirective. Once playback started notification is received, call @c handleDirectiveImmediately.
*/
TEST_F(SpeechSynthesizerTest, testTimer_bargeInWhilePlaying) {
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, _))
.Times(AtLeast(1))
.WillRepeatedly(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(AtLeast(2))
.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, INTERRUPTED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
.Times(AtLeast(1))
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(IsStartedEvent()))
.Times(1)
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_))
.Times(1)
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetFailed));
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(IsInterruptedEvent()))
.Times(1)
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*(m_mockFocusManager.get()), releaseChannel(CHANNEL_NAME, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnReleaseChannel));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
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(MY_WAIT_TIMEOUT));
m_wakeAcquireChannelPromise = std::promise<void>();
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
m_speechSynthesizer->handleDirectiveImmediately(directive2);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStopped());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
}
/**
* Testing SpeechSynthesizer won't be calling stop() in @c MediaPlayer twice.
* 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.
* Call onFocusChanged, expect the stop() to not be called again.
* Expect when handleDirectiveImmediately with a valid SPEAK directive is called, @c SpeechSynthesizer
* will react correctly.
*/
TEST_F(SpeechSynthesizerTest, testTimer_notCallStopTwice) {
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, _))
.Times(AtLeast(1))
.WillRepeatedly(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(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, INTERRUPTED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
.Times(AtLeast(1))
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(IsStartedEvent()))
.Times(AtLeast(1))
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(IsInterruptedEvent())).Times(AtLeast(1));
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(Invoke([this](avsCommon::utils::mediaPlayer::MediaPlayerInterface::SourceId id) {
wakeOnStopped();
m_speechSynthesizer->onPlaybackStopped(id, DEFAULT_MEDIA_PLAYER_STATE);
return true;
}))
.WillRepeatedly(Return(true));
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setCompleted()).Times(AtLeast(0));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
// 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(MY_WAIT_TIMEOUT));
m_wakeAcquireChannelPromise = std::promise<void>();
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
// 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(MY_WAIT_TIMEOUT));
// goes to background, this should not result in calling the 2nd stop()
m_speechSynthesizer->onFocusChanged(FocusState::BACKGROUND, MixingBehavior::MUST_PAUSE);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_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(MY_WAIT_TIMEOUT));
m_wakeReleaseChannelPromise = std::promise<void>();
m_wakeReleaseChannelFuture = m_wakeReleaseChannelPromise.get_future();
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
// send second speak directive and make sure it working
m_speechSynthesizer->handleDirectiveImmediately(directive2);
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
}
/**
* Testing executeCancel() completes execution before onFocusChanged() is called.
*
* The directive that was cancelled should never play. The second speech should play without any problem.
*/
TEST_F(SpeechSynthesizerTest, testSlow_callingCancelBeforeOnFocusChanged) {
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, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
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(MY_WAIT_TIMEOUT));
m_wakeAcquireChannelPromise = std::promise<void>();
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
// Expect speech synthesizer to release the focus since it is no longer needed.
EXPECT_CALL(*(m_mockFocusManager.get()), releaseChannel(CHANNEL_NAME, _))
.Times(AtLeast(1))
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnReleaseChannel));
m_speechSynthesizer->CapabilityAgent::cancelDirective(MESSAGE_ID_TEST);
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeReleaseChannelPromise = std::promise<void>();
m_wakeReleaseChannelFuture = m_wakeReleaseChannelPromise.get_future();
// FocusManager might still be processing the initial acquire focus.
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
m_speechSynthesizer->onFocusChanged(FocusState::NONE, MixingBehavior::MUST_STOP);
// Expect the next directive to start playing.
EXPECT_CALL(*m_mockFocusManager, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
EXPECT_CALL(
*m_mockContextManager,
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(
*m_mockSpeechPlayer,
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr));
EXPECT_CALL(*m_mockSpeechPlayer, play(_));
EXPECT_CALL(*m_mockSpeechPlayer, getOffset(_)).WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
// send second speak directive and make sure it working
m_speechSynthesizer->handleDirectiveImmediately(directive2);
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
}
/**
* Testing executeCancel() completes execution before executeStateChange() is called.
*/
TEST_F(SpeechSynthesizerTest, test_callingCancelBeforeOnExecuteStateChanged) {
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, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
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(MY_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, MixingBehavior::PRIMARY);
// Expect the next directive to start playing.
EXPECT_CALL(*m_mockFocusManager, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
EXPECT_CALL(
*m_mockContextManager,
setState(NAMESPACE_AND_NAME_SPEECH_STATE, PLAYING_STATE_TEST, StateRefreshPolicy::ALWAYS, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(
*m_mockSpeechPlayer,
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr));
EXPECT_CALL(*m_mockSpeechPlayer, play(_));
EXPECT_CALL(*m_mockSpeechPlayer, getOffset(_)).WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
// send second speak directive and make sure it working
m_speechSynthesizer->handleDirectiveImmediately(directive2);
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
}
/**
* 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.
*/
TEST_F(SpeechSynthesizerTest, test_mediaPlayerFailedToStop) {
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, _))
.Times(AtLeast(1))
.WillRepeatedly(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(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, INTERRUPTED_STATE_TEST, StateRefreshPolicy::NEVER, 0))
.Times(AtLeast(1))
.WillRepeatedly(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*(m_mockMessageSender.get()), sendMessage(IsStartedEvent()))
.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(_))
.WillOnce(Invoke([this](avsCommon::utils::mediaPlayer::MediaPlayerInterface::SourceId id) {
wakeOnStopped();
return false;
}));
EXPECT_CALL(*(m_mockDirHandlerResult.get()), setFailed(_)).Times(AtLeast(0));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
// 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(MY_WAIT_TIMEOUT));
m_wakeAcquireChannelPromise = std::promise<void>();
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
// 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(MY_WAIT_TIMEOUT));
// goes to background, this should not result in calling the 2nd stop()
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::BACKGROUND, MixingBehavior::MUST_PAUSE);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_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(MY_WAIT_TIMEOUT));
m_wakeReleaseChannelPromise = std::promise<void>();
m_wakeReleaseChannelFuture = m_wakeReleaseChannelPromise.get_future();
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
// send second speak directive and make sure it working
m_speechSynthesizer->handleDirectiveImmediately(directive2);
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
}
/**
* 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.
*/
TEST_F(SpeechSynthesizerTest, testTimer_mediaPlayerAlwaysFailToStop) {
auto speechSynthesizer = SpeechSynthesizer::create(
m_mockSpeechPlayer,
m_mockMessageSender,
m_mockFocusManager,
m_mockContextManager,
m_mockExceptionSender,
m_metricRecorder,
m_dialogUXStateAggregator,
m_mockCaptionManager);
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);
EXPECT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
speechSynthesizer->shutdown();
speechSynthesizer.reset();
}
/**
* Testing SpeechSynthesizer will call stop() if the SpeechSynthesizer experienced a state change timeout to PLAYING
* state.
*/
TEST_F(SpeechSynthesizerTest, testSlow_setStateTimeout) {
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, _))
.Times(AtLeast(1))
.WillRepeatedly(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(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));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
// 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(MY_WAIT_TIMEOUT));
m_wakeAcquireChannelPromise = std::promise<void>();
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
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(), DEFAULT_MEDIA_PLAYER_STATE);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_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(), DEFAULT_MEDIA_PLAYER_STATE);
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
ASSERT_TRUE(std::future_status::ready == m_wakeReleaseChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::BACKGROUND, MixingBehavior::MUST_PAUSE);
}
/**
* 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.
*/
TEST_F(SpeechSynthesizerTest, test_givenPlayingStateFocusBecomesNone) {
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, _))
.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(AtLeast(2))
.WillRepeatedly(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);
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
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(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
EXPECT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
m_speechSynthesizer->onFocusChanged(FocusState::NONE, MixingBehavior::MUST_STOP);
EXPECT_TRUE(std::future_status::ready == m_wakeSetFailedFuture.wait_for(STATE_CHANGE_TIMEOUT));
}
/**
* Testing SpeechSynthesizer will call setFailed() if the SpeechSynthesizer got a onPlaybackStopped() callback while
* it is in PLAYING state.
*/
TEST_F(SpeechSynthesizerTest, testTimer_onPlayedStopped) {
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, _))
.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(_)).WillRepeatedly(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);
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
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(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
EXPECT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
m_speechSynthesizer->onPlaybackStopped(m_mockSpeechPlayer->getCurrentSourceId(), DEFAULT_MEDIA_PLAYER_STATE);
EXPECT_TRUE(std::future_status::ready == m_wakeSetFailedFuture.wait_for(STATE_CHANGE_TIMEOUT));
}
bool SpeechSynthesizerTest::setupActiveSpeech(
std::unique_ptr<DirectiveHandlerResultInterface> resultHandler,
const SpeakTestInfo& info) {
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, info.messageId, DIALOG_REQUEST_ID_TEST);
std::shared_ptr<AVSDirective> directive =
AVSDirective::create("", avsMessageHeader, info.payload, m_attachmentManager, CONTEXT_ID_TEST);
EXPECT_CALL(*m_mockFocusManager, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
EXPECT_CALL(
*m_mockSpeechPlayer,
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr));
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(NAMESPACE_AND_NAME_SPEECH_STATE, generatePlayingState(info), StateRefreshPolicy::ALWAYS, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsStartedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(resultHandler));
m_speechSynthesizer->CapabilityAgent::handleDirective(info.messageId);
EXPECT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
EXPECT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
// Reset promises.
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
m_wakeAcquireChannelPromise = std::promise<void>();
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
return !Test::HasFailure();
}
bool SpeechSynthesizerTest::setupPendingSpeech(
std::unique_ptr<DirectiveHandlerResultInterface> resultHandler,
const SpeakTestInfo& info) {
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, info.messageId, DIALOG_REQUEST_ID_TEST);
std::shared_ptr<AVSDirective> directive =
AVSDirective::create("", avsMessageHeader, info.payload, m_attachmentManager, CONTEXT_ID_TEST);
EXPECT_CALL(*m_mockFocusManager, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(resultHandler));
m_speechSynthesizer->CapabilityAgent::handleDirective(info.messageId);
EXPECT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeAcquireChannelPromise = std::promise<void>();
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
return !Test::HasFailure();
}
/**
* Test SpeechSynthesizer REPLACE_ALL when there is no active directive.
*
* Expect the speech synthesizer to play the new speech and go to idle after.
*/
TEST_F(SpeechSynthesizerTest, test_replaceAllWithEmptyQueue) {
auto mockActiveResultHandler = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult());
auto info = generateSpeakInfo(PlayBehavior::REPLACE_ALL);
EXPECT_CALL(*mockActiveResultHandler, setCompleted())
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetCompleted));
EXPECT_TRUE(setupActiveSpeech(std::move(mockActiveResultHandler), info));
EXPECT_CALL(
*m_mockContextManager,
setState(NAMESPACE_AND_NAME_SPEECH_STATE, generateFinishedState(info), StateRefreshPolicy::NEVER, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsFinishedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
m_mockSpeechPlayer->mockFinished(m_mockSpeechPlayer->getCurrentSourceId());
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSetCompletedFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
}
/**
* Test SpeechSynthesizer REPLACE_ALL when the queue has one speak directive that hasn't started yet.
*
* Expect the speech synthesizer to cancel the enqueued directive and play the new speech.
*/
TEST_F(SpeechSynthesizerTest, test_replaceAllWithNonEmptyQueue) {
{
SCOPED_TRACE("Setup Queue");
auto mockEnqueuedResultHandler = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult());
auto pending = generateSpeakInfo(PlayBehavior::ENQUEUE);
ASSERT_TRUE(setupPendingSpeech(std::move(mockEnqueuedResultHandler), pending));
}
auto mockResultHandler = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult());
EXPECT_CALL(*mockResultHandler, setCompleted())
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetCompleted));
auto speak = generateSpeakInfo(PlayBehavior::REPLACE_ALL);
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, speak.messageId, DIALOG_REQUEST_ID_TEST);
std::shared_ptr<AVSDirective> directive =
AVSDirective::create("", avsMessageHeader, speak.payload, m_attachmentManager, CONTEXT_ID_TEST);
{
SCOPED_TRACE("Setup Expectations");
EXPECT_CALL(*m_mockFocusManager, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
EXPECT_CALL(
*m_mockSpeechPlayer,
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr));
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(NAMESPACE_AND_NAME_SPEECH_STATE, generatePlayingState(speak), StateRefreshPolicy::ALWAYS, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsStartedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
}
{
SCOPED_TRACE("Test Directive Handling");
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(mockResultHandler));
m_speechSynthesizer->CapabilityAgent::handleDirective(speak.messageId);
EXPECT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
}
{
SCOPED_TRACE("Check Speech Playback");
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
EXPECT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
}
{
SCOPED_TRACE("Check Speech Playback");
EXPECT_CALL(
*m_mockContextManager,
setState(NAMESPACE_AND_NAME_SPEECH_STATE, generateFinishedState(speak), StateRefreshPolicy::NEVER, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsFinishedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
m_mockSpeechPlayer->mockFinished(m_mockSpeechPlayer->getCurrentSourceId());
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSetCompletedFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
}
}
/**
* Test SpeechSynthesizer REPLACE_ALL when there is an ongoing speech.
*
* Expect the speech synthesizer to cancel the active speech, send an interrupted event and play the new speech.
*/
TEST_F(SpeechSynthesizerTest, test_replaceAllStopActiveSpeech) {
auto active = generateSpeakInfo(PlayBehavior::ENQUEUE);
{
SCOPED_TRACE("Setup Queue");
auto mockEnqueuedResultHandler = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult());
EXPECT_CALL(*mockEnqueuedResultHandler, setFailed(_));
ASSERT_TRUE(setupActiveSpeech(std::move(mockEnqueuedResultHandler), active));
}
auto mockResultHandler = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult());
EXPECT_CALL(*mockResultHandler, setCompleted())
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetCompleted));
auto speak = generateSpeakInfo(PlayBehavior::REPLACE_ALL);
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, speak.messageId, DIALOG_REQUEST_ID_TEST);
std::shared_ptr<AVSDirective> directive =
AVSDirective::create("", avsMessageHeader, speak.payload, m_attachmentManager, CONTEXT_ID_TEST);
{
SCOPED_TRACE("Setup Expectations");
// Interrupted event.
EXPECT_CALL(*m_mockSpeechPlayer, stop(_));
EXPECT_CALL(
*m_mockContextManager,
setState(NAMESPACE_AND_NAME_SPEECH_STATE, generateInterruptedState(active), StateRefreshPolicy::NEVER, 0));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsInterruptedEvent()));
// New directive handling.
EXPECT_CALL(*m_mockFocusManager, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
EXPECT_CALL(
*m_mockSpeechPlayer,
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr));
EXPECT_CALL(*m_mockSpeechPlayer, play(_)).Times(AtLeast(1));
EXPECT_CALL(*m_mockSpeechPlayer, getOffset(_))
.Times(AtLeast(2))
.WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
EXPECT_CALL(
*m_mockContextManager,
setState(NAMESPACE_AND_NAME_SPEECH_STATE, generatePlayingState(speak), StateRefreshPolicy::ALWAYS, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsStartedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
}
{
SCOPED_TRACE("Test Directive Handling");
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(mockResultHandler));
m_speechSynthesizer->CapabilityAgent::handleDirective(speak.messageId);
EXPECT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
}
{
SCOPED_TRACE("Check Speech Playback");
m_speechSynthesizer->onFocusChanged(FocusState::NONE, MixingBehavior::MUST_STOP);
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
EXPECT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
}
{
SCOPED_TRACE("Check Speech Playback");
EXPECT_CALL(
*m_mockContextManager,
setState(NAMESPACE_AND_NAME_SPEECH_STATE, generateFinishedState(speak), StateRefreshPolicy::NEVER, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsFinishedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
m_mockSpeechPlayer->mockFinished(m_mockSpeechPlayer->getCurrentSourceId());
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
}
}
/**
* Test SpeechSynthesizer ENQUEUE play behavior when there is already an active directive.
*
* Expect the speech synthesizer to finish playing the first directive and play the enqueued directive right after.
*/
TEST_F(SpeechSynthesizerTest, test_enqueueWithActiveSpeech) {
auto firstDirective = generateSpeakInfo(PlayBehavior::ENQUEUE);
{
SCOPED_TRACE("Setup First");
auto mockEnqueuedResultHandler = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult());
EXPECT_CALL(*mockEnqueuedResultHandler, setCompleted());
ASSERT_TRUE(setupActiveSpeech(std::move(mockEnqueuedResultHandler), firstDirective));
}
auto mockResultHandler = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult());
EXPECT_CALL(*mockResultHandler, setCompleted());
auto secondDirective = generateSpeakInfo(PlayBehavior::ENQUEUE);
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, secondDirective.messageId, DIALOG_REQUEST_ID_TEST);
std::shared_ptr<AVSDirective> directive =
AVSDirective::create("", avsMessageHeader, secondDirective.payload, m_attachmentManager, CONTEXT_ID_TEST);
{
SCOPED_TRACE("Add Second");
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(mockResultHandler));
}
{
SCOPED_TRACE("Finish First");
EXPECT_CALL(
*m_mockContextManager,
setState(
NAMESPACE_AND_NAME_SPEECH_STATE, generateFinishedState(firstDirective), StateRefreshPolicy::NEVER, 0));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsFinishedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
m_mockSpeechPlayer->mockFinished(m_mockSpeechPlayer->getCurrentSourceId());
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
}
// Reset promises.
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
{
// Start new speech speech.
SCOPED_TRACE("Start Second");
EXPECT_CALL(*m_mockFocusManager, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
m_speechSynthesizer->CapabilityAgent::handleDirective(secondDirective.messageId);
EXPECT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_CALL(
*m_mockSpeechPlayer,
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr));
EXPECT_CALL(*m_mockSpeechPlayer, play(_));
EXPECT_CALL(*m_mockSpeechPlayer, getOffset(_)).WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
EXPECT_CALL(
*m_mockContextManager,
setState(
NAMESPACE_AND_NAME_SPEECH_STATE, generatePlayingState(secondDirective), StateRefreshPolicy::ALWAYS, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsStartedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
m_speechSynthesizer->onFocusChanged(FocusState::NONE, MixingBehavior::MUST_STOP);
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
}
// Reset promises.
m_wakeAcquireChannelPromise = std::promise<void>();
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
{
SCOPED_TRACE("Finish Second");
EXPECT_CALL(
*m_mockContextManager,
setState(
NAMESPACE_AND_NAME_SPEECH_STATE, generateFinishedState(secondDirective), StateRefreshPolicy::NEVER, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsFinishedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
m_mockSpeechPlayer->mockFinished(m_mockSpeechPlayer->getCurrentSourceId());
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
}
}
/**
* Test SpeechSynthesizer REPLACE_ENQUEUED play behavior when there is one directive playing and one in the queue.
*
* Expect the speech synthesizer to finish playing the first directive, skip the second and play the third directive.
*/
TEST_F(SpeechSynthesizerTest, test_replaceEnqueuedWithAnotherEnqueuedItem) {
auto firstDirective = generateSpeakInfo(PlayBehavior::ENQUEUE);
{
SCOPED_TRACE("Setup First");
auto mockEnqueuedResultHandler = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult());
EXPECT_CALL(*mockEnqueuedResultHandler, setCompleted());
ASSERT_TRUE(setupActiveSpeech(std::move(mockEnqueuedResultHandler), firstDirective));
}
{
SCOPED_TRACE("Add Second");
auto secondDirective = generateSpeakInfo(PlayBehavior::ENQUEUE);
auto secondMessageHeader = std::make_shared<AVSMessageHeader>(
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, secondDirective.messageId, DIALOG_REQUEST_ID_TEST);
std::shared_ptr<AVSDirective> directive = AVSDirective::create(
"", secondMessageHeader, secondDirective.payload, m_attachmentManager, CONTEXT_ID_TEST);
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, nullptr);
}
auto mockResultHandler = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult());
EXPECT_CALL(*mockResultHandler, setCompleted());
auto thirdDirective = generateSpeakInfo(PlayBehavior::REPLACE_ENQUEUED);
auto avsMessageHeader = std::make_shared<AVSMessageHeader>(
NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEAK, thirdDirective.messageId, DIALOG_REQUEST_ID_TEST);
std::shared_ptr<AVSDirective> directive =
AVSDirective::create("", avsMessageHeader, thirdDirective.payload, m_attachmentManager, CONTEXT_ID_TEST);
{
SCOPED_TRACE("Add Third");
m_speechSynthesizer->CapabilityAgent::preHandleDirective(directive, std::move(mockResultHandler));
m_speechSynthesizer->CapabilityAgent::handleDirective(thirdDirective.messageId);
}
{
SCOPED_TRACE("Finish First");
EXPECT_CALL(
*m_mockContextManager,
setState(
NAMESPACE_AND_NAME_SPEECH_STATE, generateFinishedState(firstDirective), StateRefreshPolicy::NEVER, 0));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsFinishedEvent()));
// New speech.
EXPECT_CALL(*m_mockFocusManager, acquireChannel(CHANNEL_NAME, _))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnAcquireChannel));
m_mockSpeechPlayer->mockFinished(m_mockSpeechPlayer->getCurrentSourceId());
EXPECT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_wakeAcquireChannelPromise = std::promise<void>();
m_wakeAcquireChannelFuture = m_wakeAcquireChannelPromise.get_future();
}
{
// Start new speech speech.
SCOPED_TRACE("Start Second");
EXPECT_CALL(
*m_mockSpeechPlayer,
attachmentSetSource(A<std::shared_ptr<avsCommon::avs::attachment::AttachmentReader>>(), nullptr));
EXPECT_CALL(*m_mockSpeechPlayer, play(_));
EXPECT_CALL(*m_mockSpeechPlayer, getOffset(_)).WillRepeatedly(Return(OFFSET_IN_CHRONO_MILLISECONDS_TEST));
EXPECT_CALL(
*m_mockContextManager,
setState(
NAMESPACE_AND_NAME_SPEECH_STATE, generatePlayingState(thirdDirective), StateRefreshPolicy::ALWAYS, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsStartedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
m_speechSynthesizer->onFocusChanged(FocusState::NONE, MixingBehavior::MUST_STOP);
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
}
// Reset promises.
m_wakeSendMessagePromise = std::promise<void>();
m_wakeSendMessageFuture = m_wakeSendMessagePromise.get_future();
m_wakeSetStatePromise = std::promise<void>();
m_wakeSetStateFuture = m_wakeSetStatePromise.get_future();
{
SCOPED_TRACE("Finish Second");
EXPECT_CALL(
*m_mockContextManager,
setState(
NAMESPACE_AND_NAME_SPEECH_STATE, generateFinishedState(thirdDirective), StateRefreshPolicy::NEVER, 0))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSetState));
EXPECT_CALL(*m_mockMessageSender, sendMessage(IsFinishedEvent()))
.WillOnce(InvokeWithoutArgs(this, &SpeechSynthesizerTest::wakeOnSendMessage));
EXPECT_CALL(*m_mockPowerResourceManager, releasePowerResource(COMPONENT_NAME)).Times(AtLeast(1));
m_mockSpeechPlayer->mockFinished(m_mockSpeechPlayer->getCurrentSourceId());
EXPECT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
EXPECT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
}
}
/**
* Test call to test audio analyzer config parsing logic.
*/
TEST_F(SpeechSynthesizerTest, test_parsingSingleAnalyzerConfig) {
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_SINGLE_ANALYZER, m_attachmentManager, CONTEXT_ID_TEST);
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _))
.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_mockSpeechPlayer.get()), getMediaPlayerState(_)).Times(AtLeast(2));
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_mockCaptionManager, onCaption(_, _)).Times(1);
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
std::vector<audioAnalyzer::AudioAnalyzerState> data;
data.push_back(audioAnalyzer::AudioAnalyzerState("analyzername", "YES"));
EXPECT_CALL(
*m_mockSpeechSynthesizerObserver,
onStateChanged(SpeechSynthesizerObserverInterface::SpeechSynthesizerState::GAINING_FOCUS, _, _, _))
.Times(1);
EXPECT_CALL(
*m_mockSpeechSynthesizerObserver,
onStateChanged(SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING, _, _, Eq(data)))
.Times(1);
m_speechSynthesizer->addObserver(m_mockSpeechSynthesizerObserver);
m_speechSynthesizer->handleDirectiveImmediately(directive);
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
}
TEST_F(SpeechSynthesizerTest, test_parsingMultipleAnalyzerConfig) {
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_MULTIPLE_ANALYZER, m_attachmentManager, CONTEXT_ID_TEST);
EXPECT_CALL(*(m_mockFocusManager.get()), acquireChannel(CHANNEL_NAME, _))
.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_mockSpeechPlayer.get()), getMediaPlayerState(_)).Times(AtLeast(2));
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_mockCaptionManager, onCaption(_, _)).Times(1);
EXPECT_CALL(*m_mockPowerResourceManager, acquirePowerResource(COMPONENT_NAME, PowerResourceLevel::ACTIVE_HIGH))
.Times(AtLeast(1));
std::vector<audioAnalyzer::AudioAnalyzerState> data;
data.push_back(audioAnalyzer::AudioAnalyzerState("analyzername1", "YES"));
data.push_back(audioAnalyzer::AudioAnalyzerState("analyzername2", "NO"));
EXPECT_CALL(
*m_mockSpeechSynthesizerObserver,
onStateChanged(SpeechSynthesizerObserverInterface::SpeechSynthesizerState::GAINING_FOCUS, _, _, _))
.Times(1);
EXPECT_CALL(
*m_mockSpeechSynthesizerObserver,
onStateChanged(SpeechSynthesizerObserverInterface::SpeechSynthesizerState::PLAYING, _, _, Eq(data)))
.Times(1);
m_speechSynthesizer->addObserver(m_mockSpeechSynthesizerObserver);
m_speechSynthesizer->handleDirectiveImmediately(directive);
ASSERT_TRUE(std::future_status::ready == m_wakeAcquireChannelFuture.wait_for(MY_WAIT_TIMEOUT));
m_speechSynthesizer->onFocusChanged(FocusState::FOREGROUND, MixingBehavior::PRIMARY);
ASSERT_TRUE(m_mockSpeechPlayer->waitUntilPlaybackStarted());
ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT));
ASSERT_TRUE(std::future_status::ready == m_wakeSendMessageFuture.wait_for(MY_WAIT_TIMEOUT));
}
} // namespace test
} // namespace speechSynthesizer
} // namespace capabilityAgents
} // namespace alexaClientSDK