avs-device-sdk/AVSCommon/Utils/test/Common/MockMediaPlayer.cpp

288 lines
9.6 KiB
C++
Raw Normal View History

Version 1.2.0 alexa-client-sdk Changes in this update * **Enhancements** * Updated MediaPlayer to solve stability issues * All capability agents were refined to work with the updated MediaPlayer * Added the TemplateRuntime capability agent * Added the SpeakerManager capability agent * Added a configuration option ("sampleApp":"endpoint") that allows the endpoint that SampleApp connects to to be specified without changing code or rebuilding * Added very verbose capture of libcurl debug information * Added an observer interface to observer audio state changes from AudioPlayer * Added support for StreamMetadataExtracted Event. Stream tags found in the stream are represented in JSON and sent to AVS * Added to the SampleApp a simple GuiRenderer as an observer to the TemplateRuntime Capability Agent * Moved shared libcurl functionality to AVSCommon/Utils * Added a CMake option to exclude tests from the "make all" build. Use "cmake <absolute-path-to-source> -DACSDK_EXCLUDE_TEST_FROM_ALL=ON" to enable it. When this option is enabled "make unit" and "make integration" still could be used to build and run the tests * **Bug fixes**: * Previously scheduled alerts now play following a restart * General stability fixes * Bug fix for CertifiedSender blocking forever if the network goes down while it's trying to send a message to AVS * Fixes for known issue of Alerts integration tests fail: AlertsTest.UserLongUnrelatedBargeInOnActiveTimer and AlertsTest.handleOneTimerWithVocalStop * Attempting to end a tap-to-talk interaction with the tap-to-talk button wouldn't work * SharedDataStream could encounter a race condition due to a combination of a blocking Reader and a Writer closing before writing any data * Bug-fix for the ordering of notifications within alerts scheduling. This fixes the issue where a local-stop on an alert would also stop a subsequent alert if it were to begin without delay * **Known Issues** * Capability agent for Notifications is not included in this release * Inconsistent playback behavior when resuming content ("Alexa, pause." / "Alexa, resume."). Specifically, handling playback offsets, which causes the content to play from the start. This behavior is also occasionally seen with "Next" / "Previous". * `ACL`'s asynchronous receipt of audio attachments may manage resources poorly in scenarios where attachments are received but not consumed.
2017-10-30 22:14:38 +00:00
/*
* MockMediaPlayer.cpp
*
* Copyright 2017 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 "AVSCommon/Utils/MediaPlayer/MediaPlayerObserverInterface.h"
#include "AVSCommon/Utils/MediaPlayer/MockMediaPlayer.h"
namespace alexaClientSDK {
namespace avsCommon {
namespace utils {
namespace mediaPlayer {
namespace test {
using namespace testing;
std::shared_ptr<NiceMock<MockMediaPlayer>> MockMediaPlayer::create() {
auto result = std::make_shared<NiceMock<MockMediaPlayer>>();
ON_CALL(*result.get(), attachmentSetSource(_))
.WillByDefault(InvokeWithoutArgs(result.get(), &MockMediaPlayer::mockSetSource));
ON_CALL(*result.get(), urlSetSource(_))
.WillByDefault(InvokeWithoutArgs(result.get(), &MockMediaPlayer::mockSetSource));
ON_CALL(*result.get(), streamSetSource(_, _))
.WillByDefault(InvokeWithoutArgs(result.get(), &MockMediaPlayer::mockSetSource));
ON_CALL(*result.get(), play(_)).WillByDefault(Invoke(result.get(), &MockMediaPlayer::mockPlay));
ON_CALL(*result.get(), stop(_)).WillByDefault(Invoke(result.get(), &MockMediaPlayer::mockStop));
ON_CALL(*result.get(), pause(_)).WillByDefault(Invoke(result.get(), &MockMediaPlayer::mockPause));
ON_CALL(*result.get(), resume(_)).WillByDefault(Invoke(result.get(), &MockMediaPlayer::mockResume));
ON_CALL(*result.get(), getOffset(_)).WillByDefault(Invoke(result.get(), &MockMediaPlayer::mockGetOffset));
return result;
}
MockMediaPlayer::MockMediaPlayer() :
m_sourceId{ERROR},
m_offset{MEDIA_PLAYER_INVALID_OFFSET},
m_play{false},
m_stop{false},
m_pause{false},
m_resume{false},
m_shutdown{false},
m_wakePlayPromise{},
m_wakePlayFuture{m_wakePlayPromise.get_future()},
m_wakeStopPromise{},
m_wakeStopFuture{m_wakeStopPromise.get_future()},
m_wakePausePromise{},
m_wakePauseFuture{m_wakePausePromise.get_future()},
m_playerObserver{nullptr} {
}
MockMediaPlayer::~MockMediaPlayer() {
{
std::lock_guard<std::mutex> lock(m_mutex);
m_shutdown = true;
}
m_wakeTriggerPlay.notify_all();
m_wakeTriggerStop.notify_all();
m_wakeTriggerPause.notify_all();
m_wakeTriggerResume.notify_all();
if (m_playThread.joinable()) {
m_playThread.join();
}
if (m_playThread_2.joinable()) {
m_playThread_2.join();
}
if (m_stopThread.joinable()) {
m_stopThread.join();
}
if (m_pauseThread.joinable()) {
m_pauseThread.join();
}
if (m_pauseThread_2.joinable()) {
m_pauseThread_2.join();
}
if (m_resumeThread.joinable()) {
m_resumeThread.join();
}
}
void MockMediaPlayer::setObserver(
std::shared_ptr<avsCommon::utils::mediaPlayer::MediaPlayerObserverInterface> playerObserver) {
m_playerObserver = playerObserver;
}
MediaPlayerInterface::SourceId MockMediaPlayer::setSource(
std::shared_ptr<avsCommon::avs::attachment::AttachmentReader> attachmentReader) {
return attachmentSetSource(attachmentReader);
}
v1.3.0 released 12/08/2017: **Enhancements** * ContextManager now passes the namespace/name of the desired state to StateProv iderInterface::provideState(). This is helpful when a single StateProvider obje ct provides multiple states, and needs to know which one ContextManager is askin g for. * The mime parser was hardened against duplicate boundaries. * Added functionality to add and remove AudioPlayer observers to the DefaultClie nt. * Unit tests for Alerts were added. * Added en-IN, en-CA and ja-JP to the SampleApp locale selection menu. * Added default alert and timer audio data to the SDK SampleApp. There is no lo nger a requirement to download these audio files and configure them in the json configuration file. * Added support in SDS Reader and AttachmentReader for seeking into the future. This allows a reader to move to an index which has not yet arrived in the SDS a nd poll/block until it arrives. * Added support for blocking Writers in the SharedDataStream class. * Changed the default status code sent by MessageRequestObserverInterface::onSen dCompleted() to SERVER_OTHER_ERROR, and mapped HTTP code 500 to SERVER_INTERNAL_ ERROR_V2. * Added support for parsing stream duration out of playlists. * Added a configuration option ("sampleApp":"displayCardsSupported") that allows the displaying of display cards to be enabled or disabled. * Named Timers and Reminders have been updated to fall back to the on-device bac kground audio sound when cloud urls cannot be accessed or rendered. **Bug Fixes** * Removed floating point dependencies from core SDK libraries. * Fixed bug in SpeechSynthesizer where it's erroneously calling stop more than once. * Fixed an issue in ContentFetcher where it could hang during destruction until an active GET request completed. * Fixed a couple of parsing bugs in LibCurlHttpContentFetcher related to case-sensitivity and mime-type handling. * Fixed a bug where MediaPlayerObserverInterface::onPlaybackResumed() wasn't being called after resuming from a pause with a pending play/resume. * Fixed a bug in LibCurlContentFetcher where it could error out if data is written to the SDS faster than it is consumed. * The GStreamer-based MediaPlayer reference implementation now uses the ACL HTTP configured client. * An API change has been made to MediaPlayerInterface::setSource(). This method now takes in an optional offset as well to allow for immediately streaming to the offset if possible. * Next and Previous buttons now work with Audible. * Pandora resume stuttering is addressed. * Pausing and resuming Amazon music no longer seeks back to the beginning of the song. * libcurl CURLOPT_NOSIGNAL option is set to 1 (https://curl.haxx.se/libcurl/c/CURLOPT_NOSIGNAL.html) to avoid crashes observed in SampleApp. * Fixed the timing of the PlaybackReportIntervalEvent and PlaybackReportDelayEvent as specified in the directives. * Fixed potential deadlocks in MediaPlayer during shutdown related to queued callbacks. * Fixed a crash in MediaPlayer that could occur if the network is disconnected during playback. * Fixed a bug where music could keep playing while Alexa is speaking. * Fixed a bug which was causing problems with pause/resume and next/previous with Amazon Music. * Fixed a bug where music could briefly start playing between speaks. * Fixed a bug where HLS playlists would stop streaming after the initial playlist had been played to completion. * Fixed a bug where Audible playback could not advance to the next chapter. * Fixed some occurrences of SDK entering the IDLE state during the transition between Listening and Speaking states. * Fixed a bug where PlaybackFinished events were not reporting the correct offset. * An API change has been made to MediaPlayerInterface::getOffset(). This method is now required to return the final offset when called after playback has stopped. * Fixed a problem where AIP was erroneously resetting its state upon getting a cancelDirective() callback. **Known Issues** * Capability agent for Notifications is not included in this release. * `ACL`'s asynchronous receipt of audio attachments may manage resources poorly in scenarios where attachments are received but not consumed. * GUI cards don't show for Kindle. * The new SpeechSynthesizerState state values GAINING_FOCUS and LOSING_FOCUS were added as part of a work-around. The will likely be removed in subsequent releases. * With the gstreamer-based MediaPlayer, after muting and unmuting, the next item starts playing rather than continuing with the current item.
2017-12-09 00:07:37 +00:00
MediaPlayerInterface::SourceId MockMediaPlayer::setSource(const std::string& url, std::chrono::milliseconds offset) {
Version 1.2.0 alexa-client-sdk Changes in this update * **Enhancements** * Updated MediaPlayer to solve stability issues * All capability agents were refined to work with the updated MediaPlayer * Added the TemplateRuntime capability agent * Added the SpeakerManager capability agent * Added a configuration option ("sampleApp":"endpoint") that allows the endpoint that SampleApp connects to to be specified without changing code or rebuilding * Added very verbose capture of libcurl debug information * Added an observer interface to observer audio state changes from AudioPlayer * Added support for StreamMetadataExtracted Event. Stream tags found in the stream are represented in JSON and sent to AVS * Added to the SampleApp a simple GuiRenderer as an observer to the TemplateRuntime Capability Agent * Moved shared libcurl functionality to AVSCommon/Utils * Added a CMake option to exclude tests from the "make all" build. Use "cmake <absolute-path-to-source> -DACSDK_EXCLUDE_TEST_FROM_ALL=ON" to enable it. When this option is enabled "make unit" and "make integration" still could be used to build and run the tests * **Bug fixes**: * Previously scheduled alerts now play following a restart * General stability fixes * Bug fix for CertifiedSender blocking forever if the network goes down while it's trying to send a message to AVS * Fixes for known issue of Alerts integration tests fail: AlertsTest.UserLongUnrelatedBargeInOnActiveTimer and AlertsTest.handleOneTimerWithVocalStop * Attempting to end a tap-to-talk interaction with the tap-to-talk button wouldn't work * SharedDataStream could encounter a race condition due to a combination of a blocking Reader and a Writer closing before writing any data * Bug-fix for the ordering of notifications within alerts scheduling. This fixes the issue where a local-stop on an alert would also stop a subsequent alert if it were to begin without delay * **Known Issues** * Capability agent for Notifications is not included in this release * Inconsistent playback behavior when resuming content ("Alexa, pause." / "Alexa, resume."). Specifically, handling playback offsets, which causes the content to play from the start. This behavior is also occasionally seen with "Next" / "Previous". * `ACL`'s asynchronous receipt of audio attachments may manage resources poorly in scenarios where attachments are received but not consumed.
2017-10-30 22:14:38 +00:00
return urlSetSource(url);
}
MediaPlayerInterface::SourceId MockMediaPlayer::setSource(std::shared_ptr<std::istream> stream, bool repeat) {
return streamSetSource(stream, repeat);
}
MediaPlayerInterface::SourceId MockMediaPlayer::mockSetSource() {
std::lock_guard<std::mutex> lock(m_mutex);
return ++m_sourceId;
}
bool MockMediaPlayer::mockSetOffset(SourceId id, std::chrono::milliseconds offset) {
std::lock_guard<std::mutex> lock(m_mutex);
EXPECT_NE(id, static_cast<SourceId>(ERROR));
EXPECT_EQ(id, m_sourceId);
if (ERROR == id || id != m_sourceId) {
return false;
}
m_offset = offset;
return true;
}
bool MockMediaPlayer::mockPlay(SourceId id) {
std::lock_guard<std::mutex> lock(m_mutex);
EXPECT_NE(id, static_cast<SourceId>(ERROR));
EXPECT_EQ(id, m_sourceId);
if (ERROR == id || id != m_sourceId) {
return false;
}
if (!m_play) {
m_playThread = std::thread(&MockMediaPlayer::waitForPlay, this, DEFAULT_TIME);
} else {
m_wakePlayPromise = std::promise<void>();
m_playThread_2 = std::thread(&MockMediaPlayer::waitForPlay, this, DEFAULT_TIME);
}
m_play = true;
m_wakeTriggerPlay.notify_one();
return true;
}
bool MockMediaPlayer::mockStop(SourceId id) {
std::lock_guard<std::mutex> lock(m_mutex);
EXPECT_NE(id, static_cast<SourceId>(ERROR));
EXPECT_EQ(id, m_sourceId);
if (ERROR == id || id != m_sourceId) {
return false;
}
if (!m_stop) {
m_stopThread = std::thread(&MockMediaPlayer::waitForStop, this, DEFAULT_TIME);
m_stop = true;
m_wakeTriggerStop.notify_one();
}
return true;
}
bool MockMediaPlayer::mockPause(SourceId id) {
std::lock_guard<std::mutex> lock(m_mutex);
EXPECT_NE(id, static_cast<SourceId>(ERROR));
EXPECT_EQ(id, m_sourceId);
if (ERROR == id || id != m_sourceId) {
return false;
}
if (!m_pause) {
m_pauseThread = std::thread(&MockMediaPlayer::waitForPause, this, DEFAULT_TIME);
} else {
m_wakePausePromise = std::promise<void>();
m_pauseThread_2 = std::thread(&MockMediaPlayer::waitForPause, this, DEFAULT_TIME);
}
m_pause = true;
m_wakeTriggerPause.notify_one();
return true;
}
bool MockMediaPlayer::mockResume(SourceId id) {
std::lock_guard<std::mutex> lock(m_mutex);
EXPECT_NE(id, static_cast<SourceId>(ERROR));
EXPECT_EQ(id, m_sourceId);
if (ERROR == id || id != m_sourceId) {
return false;
}
m_resumeThread = std::thread(&MockMediaPlayer::waitForResume, this, DEFAULT_TIME);
m_resume = true;
m_wakeTriggerResume.notify_one();
return true;
}
std::chrono::milliseconds MockMediaPlayer::mockGetOffset(SourceId id) {
std::lock_guard<std::mutex> lock(m_mutex);
EXPECT_NE(id, static_cast<SourceId>(ERROR));
EXPECT_EQ(id, m_sourceId);
if (ERROR == id || id != m_sourceId) {
return MEDIA_PLAYER_INVALID_OFFSET;
}
return m_offset;
}
bool MockMediaPlayer::waitForPlay(const std::chrono::milliseconds duration) {
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_wakeTriggerPlay.wait_for(lock, duration, [this]() { return (m_play || m_shutdown); })) {
if (m_playerObserver) {
m_playerObserver->onPlaybackError(m_sourceId, ErrorType::MEDIA_ERROR_UNKNOWN, "waitForPlay timed out");
}
return false;
}
m_wakePlayPromise.set_value();
if (m_playerObserver) {
m_playerObserver->onPlaybackStarted(m_sourceId);
}
return true;
}
bool MockMediaPlayer::waitForStop(const std::chrono::milliseconds duration) {
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_wakeTriggerStop.wait_for(lock, duration, [this]() { return (m_stop || m_shutdown); })) {
if (m_playerObserver) {
m_playerObserver->onPlaybackError(m_sourceId, ErrorType::MEDIA_ERROR_UNKNOWN, "waitForStop timed out");
}
return false;
}
m_wakeStopPromise.set_value();
if (m_playerObserver) {
m_playerObserver->onPlaybackStopped(m_sourceId);
}
return true;
}
bool MockMediaPlayer::waitForPause(const std::chrono::milliseconds duration) {
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_wakeTriggerPause.wait_for(lock, duration, [this]() { return (m_pause || m_shutdown); })) {
if (m_playerObserver) {
m_playerObserver->onPlaybackError(m_sourceId, ErrorType::MEDIA_ERROR_UNKNOWN, "waitForPause timed out");
}
return false;
}
m_wakePausePromise.set_value();
if (m_playerObserver) {
m_playerObserver->onPlaybackPaused(m_sourceId);
}
return true;
}
bool MockMediaPlayer::waitForResume(const std::chrono::milliseconds duration) {
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_wakeTriggerResume.wait_for(lock, duration, [this]() { return (m_resume || m_shutdown); })) {
if (m_playerObserver) {
m_playerObserver->onPlaybackError(m_sourceId, ErrorType::MEDIA_ERROR_UNKNOWN, "waitForResume timed out");
}
return false;
}
m_wakeResumePromise.set_value();
if (m_playerObserver) {
m_playerObserver->onPlaybackResumed(m_sourceId);
}
return true;
}
bool MockMediaPlayer::waitUntilPlaybackStarted(std::chrono::milliseconds timeout) {
return m_wakePlayFuture.wait_for(timeout) == std::future_status::ready;
}
bool MockMediaPlayer::waitUntilPlaybackFinished(std::chrono::milliseconds timeout) {
return m_wakeStopFuture.wait_for(timeout) == std::future_status::ready;
}
bool MockMediaPlayer::waitUntilPlaybackPaused(std::chrono::milliseconds timeout) {
return m_wakePauseFuture.wait_for(timeout) == std::future_status::ready;
}
bool MockMediaPlayer::waitUntilPlaybackResumed(std::chrono::milliseconds timeout) {
return m_wakeResumeFuture.wait_for(timeout) == std::future_status::ready;
}
v1.3.0 released 12/08/2017: **Enhancements** * ContextManager now passes the namespace/name of the desired state to StateProv iderInterface::provideState(). This is helpful when a single StateProvider obje ct provides multiple states, and needs to know which one ContextManager is askin g for. * The mime parser was hardened against duplicate boundaries. * Added functionality to add and remove AudioPlayer observers to the DefaultClie nt. * Unit tests for Alerts were added. * Added en-IN, en-CA and ja-JP to the SampleApp locale selection menu. * Added default alert and timer audio data to the SDK SampleApp. There is no lo nger a requirement to download these audio files and configure them in the json configuration file. * Added support in SDS Reader and AttachmentReader for seeking into the future. This allows a reader to move to an index which has not yet arrived in the SDS a nd poll/block until it arrives. * Added support for blocking Writers in the SharedDataStream class. * Changed the default status code sent by MessageRequestObserverInterface::onSen dCompleted() to SERVER_OTHER_ERROR, and mapped HTTP code 500 to SERVER_INTERNAL_ ERROR_V2. * Added support for parsing stream duration out of playlists. * Added a configuration option ("sampleApp":"displayCardsSupported") that allows the displaying of display cards to be enabled or disabled. * Named Timers and Reminders have been updated to fall back to the on-device bac kground audio sound when cloud urls cannot be accessed or rendered. **Bug Fixes** * Removed floating point dependencies from core SDK libraries. * Fixed bug in SpeechSynthesizer where it's erroneously calling stop more than once. * Fixed an issue in ContentFetcher where it could hang during destruction until an active GET request completed. * Fixed a couple of parsing bugs in LibCurlHttpContentFetcher related to case-sensitivity and mime-type handling. * Fixed a bug where MediaPlayerObserverInterface::onPlaybackResumed() wasn't being called after resuming from a pause with a pending play/resume. * Fixed a bug in LibCurlContentFetcher where it could error out if data is written to the SDS faster than it is consumed. * The GStreamer-based MediaPlayer reference implementation now uses the ACL HTTP configured client. * An API change has been made to MediaPlayerInterface::setSource(). This method now takes in an optional offset as well to allow for immediately streaming to the offset if possible. * Next and Previous buttons now work with Audible. * Pandora resume stuttering is addressed. * Pausing and resuming Amazon music no longer seeks back to the beginning of the song. * libcurl CURLOPT_NOSIGNAL option is set to 1 (https://curl.haxx.se/libcurl/c/CURLOPT_NOSIGNAL.html) to avoid crashes observed in SampleApp. * Fixed the timing of the PlaybackReportIntervalEvent and PlaybackReportDelayEvent as specified in the directives. * Fixed potential deadlocks in MediaPlayer during shutdown related to queued callbacks. * Fixed a crash in MediaPlayer that could occur if the network is disconnected during playback. * Fixed a bug where music could keep playing while Alexa is speaking. * Fixed a bug which was causing problems with pause/resume and next/previous with Amazon Music. * Fixed a bug where music could briefly start playing between speaks. * Fixed a bug where HLS playlists would stop streaming after the initial playlist had been played to completion. * Fixed a bug where Audible playback could not advance to the next chapter. * Fixed some occurrences of SDK entering the IDLE state during the transition between Listening and Speaking states. * Fixed a bug where PlaybackFinished events were not reporting the correct offset. * An API change has been made to MediaPlayerInterface::getOffset(). This method is now required to return the final offset when called after playback has stopped. * Fixed a problem where AIP was erroneously resetting its state upon getting a cancelDirective() callback. **Known Issues** * Capability agent for Notifications is not included in this release. * `ACL`'s asynchronous receipt of audio attachments may manage resources poorly in scenarios where attachments are received but not consumed. * GUI cards don't show for Kindle. * The new SpeechSynthesizerState state values GAINING_FOCUS and LOSING_FOCUS were added as part of a work-around. The will likely be removed in subsequent releases. * With the gstreamer-based MediaPlayer, after muting and unmuting, the next item starts playing rather than continuing with the current item.
2017-12-09 00:07:37 +00:00
void MockMediaPlayer::doShutdown() {
}
Version 1.2.0 alexa-client-sdk Changes in this update * **Enhancements** * Updated MediaPlayer to solve stability issues * All capability agents were refined to work with the updated MediaPlayer * Added the TemplateRuntime capability agent * Added the SpeakerManager capability agent * Added a configuration option ("sampleApp":"endpoint") that allows the endpoint that SampleApp connects to to be specified without changing code or rebuilding * Added very verbose capture of libcurl debug information * Added an observer interface to observer audio state changes from AudioPlayer * Added support for StreamMetadataExtracted Event. Stream tags found in the stream are represented in JSON and sent to AVS * Added to the SampleApp a simple GuiRenderer as an observer to the TemplateRuntime Capability Agent * Moved shared libcurl functionality to AVSCommon/Utils * Added a CMake option to exclude tests from the "make all" build. Use "cmake <absolute-path-to-source> -DACSDK_EXCLUDE_TEST_FROM_ALL=ON" to enable it. When this option is enabled "make unit" and "make integration" still could be used to build and run the tests * **Bug fixes**: * Previously scheduled alerts now play following a restart * General stability fixes * Bug fix for CertifiedSender blocking forever if the network goes down while it's trying to send a message to AVS * Fixes for known issue of Alerts integration tests fail: AlertsTest.UserLongUnrelatedBargeInOnActiveTimer and AlertsTest.handleOneTimerWithVocalStop * Attempting to end a tap-to-talk interaction with the tap-to-talk button wouldn't work * SharedDataStream could encounter a race condition due to a combination of a blocking Reader and a Writer closing before writing any data * Bug-fix for the ordering of notifications within alerts scheduling. This fixes the issue where a local-stop on an alert would also stop a subsequent alert if it were to begin without delay * **Known Issues** * Capability agent for Notifications is not included in this release * Inconsistent playback behavior when resuming content ("Alexa, pause." / "Alexa, resume."). Specifically, handling playback offsets, which causes the content to play from the start. This behavior is also occasionally seen with "Next" / "Previous". * `ACL`'s asynchronous receipt of audio attachments may manage resources poorly in scenarios where attachments are received but not consumed.
2017-10-30 22:14:38 +00:00
} // namespace test
} // namespace mediaPlayer
} // namespace utils
} // namespace avsCommon
} // namespace alexaClientSDK