1010 lines
40 KiB
C++
1010 lines
40 KiB
C++
/*
|
|
* MediaPlayerTest.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 <algorithm>
|
|
#include <chrono>
|
|
#include <condition_variable>
|
|
#include <fstream>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <thread>
|
|
#include <unordered_map>
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <AVSCommon/Utils/Logger/Logger.h>
|
|
#include <AVSCommon/Utils/Memory/Memory.h>
|
|
#include <PlaylistParser/PlaylistParser.h>
|
|
|
|
#include "MediaPlayer/MediaPlayer.h"
|
|
|
|
namespace alexaClientSDK {
|
|
namespace mediaPlayer {
|
|
namespace test {
|
|
|
|
using namespace avsCommon::utils::mediaPlayer;
|
|
using namespace avsCommon::avs::attachment;
|
|
using namespace avsCommon::utils::memory;
|
|
using namespace ::testing;
|
|
|
|
/// String to identify log entries originating from this file.
|
|
static const std::string TAG("MediaPlayerTest");
|
|
|
|
/**
|
|
* Create a LogEntry using this file's TAG and the specified event string.
|
|
*
|
|
* @param The event string for this @c LogEntry.
|
|
*/
|
|
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
|
|
|
|
/// The path to the input Dir containing the test audio files.
|
|
std::string inputsDirPath;
|
|
|
|
/// MP3 test file path.
|
|
static const std::string MP3_FILE_PATH("/fox_dog.mp3");
|
|
|
|
static const std::string TEST_M3U_PLAYLIST_URL("fox_dog_playlist.m3u");
|
|
|
|
static std::string TEST_M3U_PLAYLIST_CONTENT;
|
|
|
|
/// file URI Prefix
|
|
static const std::string FILE_PREFIX("file://");
|
|
|
|
/// File length for the MP3 test file.
|
|
static const std::chrono::milliseconds MP3_FILE_LENGTH(2688);
|
|
|
|
// setOffset timing constants.
|
|
|
|
/// Offset to start playback at.
|
|
static const std::chrono::milliseconds OFFSET(2000);
|
|
|
|
/// Tolerance when setting expectations.
|
|
static const std::chrono::milliseconds TOLERANCE(200);
|
|
|
|
/// Padding to add to offsets when necessary.
|
|
static const std::chrono::milliseconds PADDING(10);
|
|
|
|
static std::unordered_map<std::string, std::string> urlsToContentTypes;
|
|
|
|
static std::unordered_map<std::string, std::string> urlsToContent;
|
|
|
|
/// A mock content fetcher
|
|
class MockContentFetcher : public avsCommon::sdkInterfaces::HTTPContentFetcherInterface {
|
|
public:
|
|
MockContentFetcher(const std::string& url) : m_url{url} {
|
|
}
|
|
|
|
std::unique_ptr<avsCommon::utils::HTTPContent> getContent(FetchOptions fetchOption) override {
|
|
if (fetchOption == FetchOptions::CONTENT_TYPE) {
|
|
auto urlAndContentType = urlsToContentTypes.find(m_url);
|
|
if (urlAndContentType == urlsToContentTypes.end()) {
|
|
return nullptr;
|
|
} else {
|
|
std::promise<long> statusPromise;
|
|
auto statusFuture = statusPromise.get_future();
|
|
statusPromise.set_value(200);
|
|
std::promise<std::string> contentTypePromise;
|
|
auto contentTypeFuture = contentTypePromise.get_future();
|
|
contentTypePromise.set_value(urlAndContentType->second);
|
|
return avsCommon::utils::memory::make_unique<avsCommon::utils::HTTPContent>(
|
|
avsCommon::utils::HTTPContent{std::move(statusFuture), std::move(contentTypeFuture), nullptr});
|
|
}
|
|
} else {
|
|
auto urlAndContent = urlsToContent.find(m_url);
|
|
if (urlAndContent == urlsToContent.end()) {
|
|
return nullptr;
|
|
}
|
|
std::promise<long> statusPromise;
|
|
auto statusFuture = statusPromise.get_future();
|
|
statusPromise.set_value(200);
|
|
std::promise<std::string> contentTypePromise;
|
|
auto contentTypeFuture = contentTypePromise.get_future();
|
|
contentTypePromise.set_value("");
|
|
auto attachment = writeStringIntoAttachment(urlAndContent->second);
|
|
if (!attachment) {
|
|
return nullptr;
|
|
}
|
|
return avsCommon::utils::memory::make_unique<avsCommon::utils::HTTPContent>(
|
|
avsCommon::utils::HTTPContent{std::move(statusFuture), std::move(contentTypeFuture), attachment});
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<avsCommon::avs::attachment::InProcessAttachment> writeStringIntoAttachment(
|
|
const std::string& string) {
|
|
static int id = 0;
|
|
std::shared_ptr<avsCommon::avs::attachment::InProcessAttachment> stream =
|
|
std::make_shared<avsCommon::avs::attachment::InProcessAttachment>(std::to_string(id++));
|
|
if (!stream) {
|
|
return nullptr;
|
|
}
|
|
auto writer = stream->createWriter();
|
|
if (!writer) {
|
|
return nullptr;
|
|
}
|
|
avsCommon::avs::attachment::AttachmentWriter::WriteStatus writeStatus;
|
|
writer->write(string.data(), string.size(), &writeStatus);
|
|
return stream;
|
|
};
|
|
|
|
std::string m_url;
|
|
};
|
|
|
|
/// A mock factory that creates mock content fetchers
|
|
class MockContentFetcherFactory : public avsCommon::sdkInterfaces::HTTPContentFetcherInterfaceFactoryInterface {
|
|
std::unique_ptr<avsCommon::sdkInterfaces::HTTPContentFetcherInterface> create(const std::string& url) {
|
|
return avsCommon::utils::memory::make_unique<MockContentFetcher>(url);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Mock AttachmentReader.
|
|
*/
|
|
class MockAttachmentReader : public AttachmentReader {
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param iterations The number of times this AttachmentReader will (re)read the input file before @c read
|
|
* will return a @c CLOSED status.
|
|
* @param receiveSizes An vector of sizes (in bytes) that this @c AttachmentReceiver will simulate receiving.
|
|
* Each successive element in the vector corresponds to a successive 100 millisecond interval starting from
|
|
* the time this @c MockAttachmentReader was created.
|
|
*/
|
|
MockAttachmentReader(int iterations = 1, std::vector<size_t> receiveSizes = {std::numeric_limits<size_t>::max()});
|
|
|
|
size_t read(void* buf, std::size_t numBytes, ReadStatus* readStatus, std::chrono::milliseconds timeoutMs) override;
|
|
|
|
void close(ClosePoint closePoint) override;
|
|
|
|
/**
|
|
* Receive bytes from the test file.
|
|
*
|
|
* @param buf The buffer to receive the bytes.
|
|
* @param size The number of bytes to receive.
|
|
* @return The number of bytes received.
|
|
*/
|
|
size_t receiveBytes(char* buf, std::size_t size);
|
|
|
|
/// The number of iterations of reading the input file that are left before this reader returns closed.
|
|
int m_iterationsLeft;
|
|
|
|
/**
|
|
* The total number of bytes that are supposed to have been received (and made available) by this
|
|
* @c AttachmentReader at 100 millisecond increments from @c m_startTime.
|
|
*/
|
|
std::vector<size_t> m_receiveTotals;
|
|
|
|
/// The start of time for reading from this AttachmentReader.
|
|
std::chrono::steady_clock::time_point m_startTime;
|
|
|
|
/// The number of bytes returned so far by @c read().
|
|
size_t m_totalRead;
|
|
|
|
/// The current ifstream (if any) from which to read the attachment.
|
|
std::unique_ptr<std::ifstream> m_stream;
|
|
};
|
|
|
|
MockAttachmentReader::MockAttachmentReader(int iterations, std::vector<size_t> receiveSizes) :
|
|
m_iterationsLeft{iterations},
|
|
m_startTime(std::chrono::steady_clock::now()),
|
|
m_totalRead{0} {
|
|
// Convert human friendly vector of received sizes in to a vector of received totals.
|
|
EXPECT_GT(receiveSizes.size(), 0U);
|
|
m_receiveTotals.reserve(receiveSizes.size());
|
|
size_t total = 0;
|
|
for (size_t ix = 0; ix < receiveSizes.size(); ix++) {
|
|
total += receiveSizes[ix];
|
|
m_receiveTotals.push_back(total);
|
|
}
|
|
EXPECT_EQ(m_receiveTotals.size(), receiveSizes.size());
|
|
}
|
|
|
|
size_t MockAttachmentReader::read(
|
|
void* buf,
|
|
std::size_t numBytes,
|
|
ReadStatus* readStatus,
|
|
std::chrono::milliseconds timeoutMs) {
|
|
// Convert the current time in to an index in to m_receivedTotals (time since @c m_startTime
|
|
// divided by 100 millisecond intervals).
|
|
auto now = std::chrono::steady_clock::now();
|
|
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_startTime);
|
|
auto index = static_cast<size_t>(elapsed.count() / 100);
|
|
index = std::min(index, m_receiveTotals.size() - 1);
|
|
|
|
// Use the index to find the total number of bytes received by the @c MockAttachmentReader so far. Then subtract
|
|
// the number of bytes consumed by @c read() so far to calculate the number of bytes available for @c read().
|
|
auto receivedTotal = m_receiveTotals[index];
|
|
EXPECT_LE(m_totalRead, receivedTotal);
|
|
auto available = receivedTotal - m_totalRead;
|
|
|
|
// Use the avaialable number of bytes to calculate how many bytes @c read() should return and the status
|
|
// that should accompany them. Also perform the actual read in to the output buffer.
|
|
size_t result = 0;
|
|
auto status = ReadStatus::ERROR_INTERNAL;
|
|
if (available > 0) {
|
|
auto sizeToRead = std::min(available, numBytes);
|
|
result = receiveBytes(static_cast<char*>(buf), sizeToRead);
|
|
if (result > 0) {
|
|
m_totalRead += result;
|
|
status = (result == numBytes) ? ReadStatus::OK : ReadStatus::OK_WOULDBLOCK;
|
|
} else {
|
|
status = ReadStatus::CLOSED;
|
|
}
|
|
} else {
|
|
status = ReadStatus::OK_WOULDBLOCK;
|
|
}
|
|
if (readStatus) {
|
|
*readStatus = status;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void MockAttachmentReader::close(ClosePoint closePoint) {
|
|
if (m_stream) {
|
|
m_stream->close();
|
|
}
|
|
}
|
|
|
|
size_t MockAttachmentReader::receiveBytes(char* buf, std::size_t size) {
|
|
auto pos = buf;
|
|
auto end = buf + size;
|
|
while (pos < end) {
|
|
if (!m_stream || m_stream->eof()) {
|
|
if (m_iterationsLeft-- > 0) {
|
|
m_stream = make_unique<std::ifstream>(inputsDirPath + MP3_FILE_PATH);
|
|
EXPECT_TRUE(m_stream);
|
|
EXPECT_TRUE(m_stream->good());
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
m_stream->read(pos, end - pos);
|
|
pos += m_stream->gcount();
|
|
}
|
|
auto result = pos - buf;
|
|
return result;
|
|
}
|
|
|
|
class MockPlayerObserver : public MediaPlayerObserverInterface {
|
|
public:
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
~MockPlayerObserver(){};
|
|
|
|
void onPlaybackStarted() override;
|
|
|
|
void onPlaybackFinished() override;
|
|
|
|
void onPlaybackError(const ErrorType& type, std::string error) override;
|
|
|
|
void onPlaybackPaused() override;
|
|
|
|
void onPlaybackResumed() override;
|
|
|
|
/**
|
|
* Wait for a message to be received.
|
|
*
|
|
* This function waits for a specified number of milliseconds for a message to arrive.
|
|
* @param duration Number of milliseconds to wait before giving up.
|
|
* @return true if a message was received within the specified duration, else false.
|
|
*/
|
|
bool waitForPlaybackStarted(const std::chrono::milliseconds duration = std::chrono::milliseconds(5000));
|
|
|
|
/**
|
|
* Wait for a message to be received.
|
|
*
|
|
* This function waits for a specified number of milliseconds for a message to arrive.
|
|
* @param duration Number of milliseconds to wait before giving up.
|
|
* @return true if a message was received within the specified duration, else false.
|
|
*/
|
|
bool waitForPlaybackFinished(const std::chrono::milliseconds duration = std::chrono::milliseconds(5000));
|
|
|
|
/**
|
|
* Wait for a message to be received.
|
|
*
|
|
* This function waits for a specified number of milliseconds for a message to arrive.
|
|
* @param duration Number of milliseconds to wait before giving up.
|
|
* @return true if a message was received within the specified duration, else false.
|
|
*/
|
|
bool waitForPlaybackPaused(const std::chrono::milliseconds duration = std::chrono::milliseconds(5000));
|
|
|
|
/**
|
|
* Wait for a message to be received.
|
|
*
|
|
* This function waits for a specified number of milliseconds for a message to arrive.
|
|
* @param duration Number of milliseconds to wait before giving up.
|
|
* @return true if a message was received within the specified duration, else false.
|
|
*/
|
|
bool waitForPlaybackResumed(const std::chrono::milliseconds duration = std::chrono::milliseconds(5000));
|
|
|
|
/**
|
|
* TODO: Make this class a mock and remove this.
|
|
*
|
|
* This gets the number of times onPlaybackStarted was called.
|
|
*/
|
|
int getOnPlaybackStartedCallCount();
|
|
|
|
/**
|
|
* TODO: Make this class a mock and remove this.
|
|
*
|
|
* This gets the number of times onPlaybackFinished was called.
|
|
*/
|
|
int getOnPlaybackFinishedCallCount();
|
|
|
|
private:
|
|
/// Mutex to protect the flags @c m_playbackStarted and .@c m_playbackFinished.
|
|
std::mutex m_mutex;
|
|
/// Trigger to wake up m_wakePlaybackStarted calls.
|
|
std::condition_variable m_wakePlaybackStarted;
|
|
/// Trigger to wake up m_wakePlaybackStarted calls.
|
|
std::condition_variable m_wakePlaybackFinished;
|
|
/// Trigger to wake up m_wakePlaybackPaused calls.
|
|
std::condition_variable m_wakePlaybackPaused;
|
|
/// Trigger to wake up m_wakePlaybackResumed calls.
|
|
std::condition_variable m_wakePlaybackResumed;
|
|
|
|
// TODO: Make this class a mock and remove these.
|
|
int m_onPlaybackStartedCallCount = 0;
|
|
int m_onPlaybackFinishedCallCount = 0;
|
|
|
|
/// Flag to set when a playback start message is received.
|
|
bool m_playbackStarted;
|
|
/// Flag to set when a playback finished message is received.
|
|
bool m_playbackFinished;
|
|
/// Flag to set when a playback paused message is received.
|
|
bool m_playbackPaused;
|
|
/// Flag to set when a playback paused message is received.
|
|
bool m_playbackResumed;
|
|
};
|
|
|
|
void MockPlayerObserver::onPlaybackStarted() {
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
m_playbackStarted = true;
|
|
m_playbackFinished = false;
|
|
m_wakePlaybackStarted.notify_all();
|
|
m_onPlaybackStartedCallCount++;
|
|
}
|
|
|
|
void MockPlayerObserver::onPlaybackFinished() {
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
m_playbackFinished = true;
|
|
m_playbackStarted = false;
|
|
m_wakePlaybackFinished.notify_all();
|
|
m_onPlaybackFinishedCallCount++;
|
|
}
|
|
|
|
void MockPlayerObserver::onPlaybackError(const ErrorType& type, std::string error) {
|
|
ACSDK_ERROR(LX("onPlaybackError").d("type", type).d("error", error));
|
|
};
|
|
|
|
void MockPlayerObserver::onPlaybackPaused() {
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
m_playbackPaused = true;
|
|
m_wakePlaybackPaused.notify_all();
|
|
};
|
|
|
|
void MockPlayerObserver::onPlaybackResumed() {
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
m_playbackResumed = true;
|
|
m_playbackPaused = false;
|
|
m_wakePlaybackResumed.notify_all();
|
|
};
|
|
|
|
bool MockPlayerObserver::waitForPlaybackStarted(const std::chrono::milliseconds duration) {
|
|
std::unique_lock<std::mutex> lock(m_mutex);
|
|
if (!m_wakePlaybackStarted.wait_for(lock, duration, [this]() { return m_playbackStarted; })) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool MockPlayerObserver::waitForPlaybackFinished(const std::chrono::milliseconds duration) {
|
|
std::unique_lock<std::mutex> lock(m_mutex);
|
|
if (!m_wakePlaybackFinished.wait_for(lock, duration, [this]() { return m_playbackFinished; })) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool MockPlayerObserver::waitForPlaybackPaused(const std::chrono::milliseconds duration) {
|
|
std::unique_lock<std::mutex> lock(m_mutex);
|
|
if (!m_wakePlaybackPaused.wait_for(lock, duration, [this]() { return m_playbackPaused; })) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool MockPlayerObserver::waitForPlaybackResumed(const std::chrono::milliseconds duration) {
|
|
std::unique_lock<std::mutex> lock(m_mutex);
|
|
if (!m_wakePlaybackResumed.wait_for(lock, duration, [this]() { return m_playbackResumed; })) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int MockPlayerObserver::getOnPlaybackStartedCallCount() {
|
|
return m_onPlaybackStartedCallCount;
|
|
}
|
|
|
|
int MockPlayerObserver::getOnPlaybackFinishedCallCount() {
|
|
return m_onPlaybackFinishedCallCount;
|
|
}
|
|
|
|
class MediaPlayerTest : public ::testing::Test {
|
|
public:
|
|
void SetUp() override;
|
|
|
|
/**
|
|
* Sets the audio source to play.
|
|
*
|
|
*/
|
|
void setAttachmentReaderSource(
|
|
int iterations = 1,
|
|
std::vector<size_t> receiveSizes = {std::numeric_limits<size_t>::max()});
|
|
|
|
/**
|
|
* Sets IStream source to play.
|
|
*
|
|
* @param repeat Whether to play the stream over and over until stopped.
|
|
*/
|
|
void setIStreamSource(bool repeat = false);
|
|
|
|
/// An instance of the @c MediaPlayer
|
|
std::shared_ptr<MediaPlayer> m_mediaPlayer;
|
|
|
|
/// An observer to whom the playback started and finished notifications need to be sent.
|
|
std::shared_ptr<MockPlayerObserver> m_playerObserver;
|
|
};
|
|
|
|
void MediaPlayerTest::SetUp() {
|
|
m_playerObserver = std::make_shared<MockPlayerObserver>();
|
|
m_mediaPlayer = MediaPlayer::create(std::make_shared<MockContentFetcherFactory>());
|
|
ASSERT_TRUE(m_mediaPlayer);
|
|
m_mediaPlayer->setObserver(m_playerObserver);
|
|
}
|
|
|
|
void MediaPlayerTest::setAttachmentReaderSource(int iterations, std::vector<size_t> receiveSizes) {
|
|
ASSERT_NE(
|
|
MediaPlayerStatus::FAILURE,
|
|
m_mediaPlayer->setSource(
|
|
std::unique_ptr<AttachmentReader>(new MockAttachmentReader(iterations, receiveSizes))));
|
|
}
|
|
|
|
void MediaPlayerTest::setIStreamSource(bool repeat) {
|
|
ASSERT_NE(
|
|
MediaPlayerStatus::FAILURE,
|
|
m_mediaPlayer->setSource(make_unique<std::ifstream>(inputsDirPath + MP3_FILE_PATH), repeat));
|
|
}
|
|
|
|
/**
|
|
* Read an audio file into a buffer. Set the source of the @c MediaPlayer to the buffer. Playback audio till the end.
|
|
* Check whether the playback started and playback finished notifications are received.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testStartPlayWaitForEnd) {
|
|
setAttachmentReaderSource();
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
|
|
/**
|
|
* Set the source of the @c MediaPlayer to a url representing a single audio file. Playback audio till the end.
|
|
* Check whether the playback started and playback finished notifications are received.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testStartPlayForUrl) {
|
|
std::string url_single(FILE_PREFIX + inputsDirPath + MP3_FILE_PATH);
|
|
m_mediaPlayer->setSource(url_single);
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
|
|
/**
|
|
* Set the source of the @c MediaPlayer to an empty url. The return should be a nullptr.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testSetSourceEmptyUrl) {
|
|
ASSERT_EQ(m_mediaPlayer->setSource(""), MediaPlayerStatus::FAILURE);
|
|
}
|
|
|
|
/**
|
|
* Set the source of the @c MediaPlayer twice consecutively to a url representing a single audio file.
|
|
* Playback audio till the end. Check whether the playback started and playback finished notifications
|
|
* are received.
|
|
*
|
|
* Consecutive calls to setSource(const std::string url) without play() cause tests to occasionally fail: ACSDK-508.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testConsecutiveSetSource) {
|
|
std::string url_single(FILE_PREFIX + inputsDirPath + MP3_FILE_PATH);
|
|
m_mediaPlayer->setSource("");
|
|
m_mediaPlayer->setSource(url_single);
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
|
|
/**
|
|
* Read an audio file into a buffer. Set the source of the @c MediaPlayer to the buffer. Playback audio till the end.
|
|
* Check whether the playback started and playback finished notifications are received.
|
|
* Call @c play. The audio should play again from the beginning. Wait till the end.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testStartPlayWaitForEndStartPlayAgain) {
|
|
setIStreamSource();
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
|
|
setAttachmentReaderSource();
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
|
|
/**
|
|
* Read an audio file into a buffer. Set the source of the @c MediaPlayer to the buffer. Playback audio for a few
|
|
* seconds. Playback started notification should be received when the playback starts. Then call @c stop and expect
|
|
* the playback finished notification is received.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testStopPlay) {
|
|
setIStreamSource(true);
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->stop());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
|
|
/**
|
|
* Read an audio file into a buffer. Set the source of the @c MediaPlayer to the buffer. Playback audio for a few
|
|
* seconds. Playback started notification should be received when the playback starts. Call @c stop.
|
|
* and wait for the playback finished notification is received. Call @c play again.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testStartPlayCallAfterStopPlay) {
|
|
setAttachmentReaderSource();
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->stop());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
|
|
setAttachmentReaderSource();
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->stop());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
|
|
/*
|
|
* Pause an audio after playback has started.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testPauseDuringPlay) {
|
|
setIStreamSource(true);
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->pause());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackPaused());
|
|
// onPlaybackFinish should NOT be called during a pause.
|
|
// TODO: Detect this via making the MediaPlayerObserverMock a mock object.
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackFinishedCallCount(), 0);
|
|
}
|
|
|
|
/*
|
|
* Play of a paused audio. This behavior is not supported, and will result in the
|
|
* audio being stopped.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testPlayAfterPause) {
|
|
setIStreamSource(true);
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->pause());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackPaused());
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
// TODO: Make the MediaPlayerObserverMock a mock object and ensure onPlaybackStarted should NOT be called
|
|
// during a resume.
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackStartedCallCount(), 1);
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackFinishedCallCount(), 1);
|
|
}
|
|
|
|
/*
|
|
* Stop of a paused audio after playback has started. An additional stop and play event should
|
|
* be sent.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testStopAfterPause) {
|
|
setIStreamSource(true);
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->pause());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackPaused());
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->stop());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
// TODO: Make the MediaPlayerObserverMock a mock object and ensure onPlaybackStarted should NOT be called
|
|
// during a resume.
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackStartedCallCount(), 1);
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackFinishedCallCount(), 1);
|
|
}
|
|
|
|
/*
|
|
* Pause of a paused audio after playback has started. The pause() should fail.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testPauseAfterPause) {
|
|
setIStreamSource(true);
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->pause());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackPaused());
|
|
|
|
ASSERT_EQ(MediaPlayerStatus::FAILURE, m_mediaPlayer->pause());
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->stop());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
|
|
/*
|
|
* Resume play of a paused audio after playback has started.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testResumeAfterPause) {
|
|
setIStreamSource(true);
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->pause());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackPaused());
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->resume());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackResumed());
|
|
// onPlaybackStarted should NOT be called during a pause.
|
|
// TODO: Make the MediaPlayerObserverMock a mock object and ensure onPlaybackStarted should NOT be called
|
|
// during a resume.
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackStartedCallCount(), 1);
|
|
}
|
|
|
|
/*
|
|
* Calling resume after playback has started. The resume operation should fail.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testResumeAfterPlay) {
|
|
setIStreamSource(true);
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
|
|
ASSERT_EQ(MediaPlayerStatus::FAILURE, m_mediaPlayer->resume());
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->stop());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
|
|
/**
|
|
* Read an audio file into a buffer. Set the source of the @c MediaPlayer to the buffer. Playback audio for a few
|
|
* seconds. Playback started notification should be received when the playback starts. Call @c getOffset.
|
|
* Check the offset value. Then call @c stop and expect the playback finished notification is received.
|
|
* Call @c getOffset again. Check the offset value.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testGetOffsetInMilliseconds) {
|
|
setAttachmentReaderSource();
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
|
|
std::chrono::milliseconds offset = m_mediaPlayer->getOffset();
|
|
ASSERT_TRUE((offset > std::chrono::milliseconds::zero()) && (offset <= MP3_FILE_LENGTH));
|
|
|
|
ASSERT_NE(MEDIA_PLAYER_INVALID_OFFSET, offset);
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->stop());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
ASSERT_EQ(MEDIA_PLAYER_INVALID_OFFSET, m_mediaPlayer->getOffset());
|
|
}
|
|
|
|
/**
|
|
* Test getOffset with a null pipeline. Expect that MEDIA_PLAYER_INVALID_OFFSET is returned.
|
|
* This currently results in errors on shutdown. Will be fixed by ACSDK-446.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testGetOffsetInMillisecondsNullPipeline) {
|
|
ASSERT_EQ(MEDIA_PLAYER_INVALID_OFFSET, m_mediaPlayer->getOffset());
|
|
}
|
|
|
|
/**
|
|
* Check playing two attachments back to back.
|
|
* Read an audio file into a buffer. Set the source of the @c MediaPlayer to the buffer. Playback audio for a few
|
|
* seconds. Playback started notification should be received when the playback starts. Call @c getOffset.
|
|
* Check the offset value. Wait for playback to finish and expect the playback finished notification is received.
|
|
* Repeat the above for a new source.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testPlayingTwoAttachments) {
|
|
setAttachmentReaderSource();
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
ASSERT_NE(MEDIA_PLAYER_INVALID_OFFSET, m_mediaPlayer->getOffset());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
|
|
setAttachmentReaderSource();
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
ASSERT_NE(MEDIA_PLAYER_INVALID_OFFSET, m_mediaPlayer->getOffset());
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->stop());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
|
|
/**
|
|
* Check playback of an attachment that is received sporadically. Playback started notification should be received
|
|
* when the playback starts. Wait for playback to finish and expect the playback finished notification is received.
|
|
* To a human ear the playback of this test is expected to sound reasonably smooth.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testUnsteadyReads) {
|
|
// clang-format off
|
|
setAttachmentReaderSource(
|
|
3, {
|
|
// Sporadic receive sizes averaging out to about 6000 bytes per second.
|
|
// Each element corresponds to a 100 millisecond time interval, so each
|
|
// row of 10 corresponds to a second's worth of sizes of data.
|
|
4000, 1000, 500, 500, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 500, 0, 500, 0, 1000, 0, 4000,
|
|
0, 100, 100, 100, 100, 100, 0, 2500, 0, 3000,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 6000, 0, 0, 0, 6000,
|
|
0, 0, 0, 3000, 0, 0, 0, 0, 0, 3000,
|
|
0, 2000, 0, 0, 2000, 0, 0, 0, 2000, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 12000,
|
|
0, 0, 0, 1000, 0, 0, 0, 1000, 0, 1000,
|
|
0, 0, 0, 0, 3000, 0, 0, 0, 0, 6000
|
|
});
|
|
// clang-format on
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished(std::chrono::milliseconds(15000)));
|
|
}
|
|
|
|
// TODO: ACSDK-300 This test fails frequently on the Raspberry Pi platform.
|
|
#ifdef RESOLVED_ACSDK_300
|
|
/**
|
|
* Check playback of an attachment whose receipt is interrupted for about 3 seconds. Playback started notification
|
|
* should be received when the playback starts. Wait for playback to finish and expect the playback finished
|
|
* notification is received. To a human ear the playback of this test is expected to sound reasonably smooth
|
|
* initially, then be interrupted for a few seconds, and then continue fairly smoothly.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testRecoveryFromPausedReads) {
|
|
// clang-format off
|
|
setAttachmentReaderSource(
|
|
3, {
|
|
// Receive sizes averaging out to 6000 bytes per second with a 3 second gap.
|
|
// Each element corresponds to a 100 millisecond time interval, so each
|
|
// row of 10 corresponds to a second's worth of sizes of data.
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 6000,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 6000,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 6000,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 18000,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 6000,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 6000,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 6000,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 6000
|
|
});
|
|
// clang-format on
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished(std::chrono::milliseconds(20000)));
|
|
}
|
|
|
|
#endif
|
|
|
|
TEST_F(MediaPlayerTest, testStartPlayWithUrlPlaylistWaitForEnd) {
|
|
m_mediaPlayer->setSource(TEST_M3U_PLAYLIST_URL);
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted(std::chrono::milliseconds(10000)));
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished(std::chrono::milliseconds(10000)));
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackStartedCallCount(), 1);
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackFinishedCallCount(), 1);
|
|
}
|
|
|
|
// TODO: ACSDK-627 This test fails frequently on Ubuntu Linux platforms.
|
|
#ifdef RESOLVED_ACSDK_627
|
|
/**
|
|
* Test setting the offset to a seekable source. Setting the offset should succeed and playback should start from the
|
|
* offset.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testSetOffsetSeekableSource) {
|
|
std::chrono::milliseconds offset(OFFSET);
|
|
|
|
std::string url_single(FILE_PREFIX + inputsDirPath + MP3_FILE_PATH);
|
|
m_mediaPlayer->setSource(url_single);
|
|
ASSERT_EQ(MediaPlayerStatus::SUCCESS, m_mediaPlayer->setOffset(offset));
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
auto start = std::chrono::steady_clock::now();
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
|
|
std::chrono::milliseconds timeElapsed =
|
|
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
|
|
ACSDK_INFO(LX("MediaPlayerTest").d("timeElapsed", timeElapsed.count()));
|
|
|
|
// Time elapsed should be total file length minus the offset.
|
|
ASSERT_TRUE(timeElapsed < (MP3_FILE_LENGTH - offset + TOLERANCE));
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackStartedCallCount(), 1);
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackFinishedCallCount(), 1);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Test setting the offset to an un-seekable pipeline. Setting the offset should succeed, but
|
|
* no seeking should occur. Playback will start from the beginning.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testSetOffsetUnseekable) {
|
|
std::chrono::milliseconds offset(OFFSET);
|
|
|
|
setAttachmentReaderSource();
|
|
// Ensure that source is set to not seekable.
|
|
gst_app_src_set_stream_type(m_mediaPlayer->getAppSrc(), GST_APP_STREAM_TYPE_STREAM);
|
|
|
|
ASSERT_EQ(MediaPlayerStatus::SUCCESS, m_mediaPlayer->setOffset(offset));
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
auto start = std::chrono::steady_clock::now();
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
|
|
std::chrono::milliseconds timeElapsed =
|
|
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
|
|
ACSDK_INFO(LX("MediaPlayerTest").d("timeElapsed", timeElapsed.count()));
|
|
|
|
// Time elapsed should be the length of the file.
|
|
ASSERT_TRUE(timeElapsed >= (MP3_FILE_LENGTH));
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackStartedCallCount(), 1);
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackFinishedCallCount(), 1);
|
|
}
|
|
|
|
/**
|
|
* Test setting the offset outside the bounds of the source. Playback will immediately end.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testSetOffsetOutsideBounds) {
|
|
std::chrono::milliseconds outOfBounds(MP3_FILE_LENGTH + PADDING);
|
|
|
|
std::string url_single(FILE_PREFIX + inputsDirPath + MP3_FILE_PATH);
|
|
m_mediaPlayer->setSource(url_single);
|
|
ASSERT_EQ(MediaPlayerStatus::SUCCESS, m_mediaPlayer->setOffset(outOfBounds));
|
|
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
auto start = std::chrono::steady_clock::now();
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
|
|
std::chrono::milliseconds timeElapsed =
|
|
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
|
|
ACSDK_INFO(LX("MediaPlayerTest").d("timeElapsed", timeElapsed.count()));
|
|
|
|
// Time elapsed should be zero.
|
|
ASSERT_TRUE(timeElapsed < std::chrono::milliseconds::zero() + TOLERANCE);
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackStartedCallCount(), 1);
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackFinishedCallCount(), 1);
|
|
}
|
|
|
|
/**
|
|
* Test calling setSource resets the offset.
|
|
*
|
|
* Consecutive calls to setSource(const std::string url) without play() cause tests to occasionally fail: ACSDK-508.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testSetSourceResetsOffset) {
|
|
std::chrono::milliseconds offset(OFFSET);
|
|
|
|
std::string url_single(FILE_PREFIX + inputsDirPath + MP3_FILE_PATH);
|
|
m_mediaPlayer->setSource(url_single);
|
|
ASSERT_EQ(MediaPlayerStatus::SUCCESS, m_mediaPlayer->setOffset(offset));
|
|
|
|
m_mediaPlayer->setSource(url_single);
|
|
// Play, expect full file.
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
auto start = std::chrono::steady_clock::now();
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
|
|
std::chrono::milliseconds timeElapsed =
|
|
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
|
|
ACSDK_INFO(LX("MediaPlayerTest").d("timeElapsed", timeElapsed.count()));
|
|
|
|
// Time elapsed should be the full file.
|
|
ASSERT_TRUE(timeElapsed >= MP3_FILE_LENGTH);
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackStartedCallCount(), 1);
|
|
ASSERT_EQ(m_playerObserver->getOnPlaybackFinishedCallCount(), 1);
|
|
}
|
|
|
|
/**
|
|
* Test consecutive setSource() and play() calls. Expect the PlaybackStarted and PlaybackFinished will be received
|
|
* before the timeout.
|
|
*/
|
|
TEST_F(MediaPlayerTest, testRepeatUrl) {
|
|
std::string url_single(FILE_PREFIX + inputsDirPath + MP3_FILE_PATH);
|
|
for (int i = 0; i < 10; i++) {
|
|
m_mediaPlayer->setSource(url_single);
|
|
ASSERT_NE(MediaPlayerStatus::FAILURE, m_mediaPlayer->play());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackStarted());
|
|
ASSERT_TRUE(m_playerObserver->waitForPlaybackFinished());
|
|
}
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace mediaPlayer
|
|
} // namespace alexaClientSDK
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
if (argc < 2) {
|
|
std::cerr << "Usage: MediaPlayerTest <absolute path to test inputs folder>" << std::endl;
|
|
} else {
|
|
alexaClientSDK::mediaPlayer::test::inputsDirPath = std::string(argv[1]);
|
|
alexaClientSDK::mediaPlayer::test::urlsToContentTypes.insert(
|
|
{alexaClientSDK::mediaPlayer::test::FILE_PREFIX + alexaClientSDK::mediaPlayer::test::inputsDirPath +
|
|
alexaClientSDK::mediaPlayer::test::MP3_FILE_PATH,
|
|
"audio/mpeg"});
|
|
alexaClientSDK::mediaPlayer::test::urlsToContentTypes.insert(
|
|
{alexaClientSDK::mediaPlayer::test::TEST_M3U_PLAYLIST_URL, "audio/mpegurl"});
|
|
alexaClientSDK::mediaPlayer::test::TEST_M3U_PLAYLIST_CONTENT =
|
|
std::string("EXTINF:2,fox_dog.mp3\n") +
|
|
std::string(
|
|
alexaClientSDK::mediaPlayer::test::FILE_PREFIX + alexaClientSDK::mediaPlayer::test::inputsDirPath +
|
|
alexaClientSDK::mediaPlayer::test::MP3_FILE_PATH) +
|
|
'\n' + std::string("EXTINF:2,fox_dog.mp3\n") +
|
|
std::string(
|
|
alexaClientSDK::mediaPlayer::test::FILE_PREFIX + alexaClientSDK::mediaPlayer::test::inputsDirPath +
|
|
alexaClientSDK::mediaPlayer::test::MP3_FILE_PATH) +
|
|
'\n';
|
|
alexaClientSDK::mediaPlayer::test::urlsToContent.insert(
|
|
{alexaClientSDK::mediaPlayer::test::TEST_M3U_PLAYLIST_URL,
|
|
alexaClientSDK::mediaPlayer::test::TEST_M3U_PLAYLIST_CONTENT});
|
|
return RUN_ALL_TESTS();
|
|
}
|
|
}
|