avs-device-sdk/MediaPlayer/include/MediaPlayer/MediaPlayer.h

428 lines
15 KiB
C++

/*
* MediaPlayer.h
*
* 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.
*/
#ifndef ALEXA_CLIENT_SDK_MEDIA_PLAYER_INCLUDE_MEDIA_PLAYER_MEDIA_PLAYER_H_
#define ALEXA_CLIENT_SDK_MEDIA_PLAYER_INCLUDE_MEDIA_PLAYER_MEDIA_PLAYER_H_
#include <chrono>
#include <cstdint>
#include <functional>
#include <future>
#include <memory>
#include <string>
#include <thread>
#include <queue>
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <AVSCommon/SDKInterfaces/HTTPContentFetcherInterfaceFactoryInterface.h>
#include <AVSCommon/Utils/MediaPlayer/MediaPlayerObserverInterface.h>
#include <AVSCommon/Utils/MediaPlayer/MediaPlayerInterface.h>
#include <AVSCommon/Utils/PlaylistParser/PlaylistParserInterface.h>
#include "MediaPlayer/OffsetManager.h"
#include "MediaPlayer/PipelineInterface.h"
#include "MediaPlayer/SourceInterface.h"
namespace alexaClientSDK {
namespace mediaPlayer {
/**
* Class that handles creation of audio pipeline and playing of audio data.
*/
class MediaPlayer
: public avsCommon::utils::mediaPlayer::MediaPlayerInterface
, private PipelineInterface {
public:
/**
* Creates an instance of the @c MediaPlayer.
*
* @param contentFetcherFactory Used to create objects that can fetch remote HTTP content.
* @return An instance of the @c MediaPlayer if successful else a @c nullptr.
*/
static std::shared_ptr<MediaPlayer> create(
std::shared_ptr<avsCommon::sdkInterfaces::HTTPContentFetcherInterfaceFactoryInterface> contentFetcherFactory =
nullptr);
/**
* Destructor.
*/
~MediaPlayer();
/// @name Overridden MediaPlayerInterface methods.
/// @{
avsCommon::utils::mediaPlayer::MediaPlayerStatus setSource(
std::shared_ptr<avsCommon::avs::attachment::AttachmentReader> attachmentReader) override;
avsCommon::utils::mediaPlayer::MediaPlayerStatus setSource(std::shared_ptr<std::istream> stream, bool repeat)
override;
avsCommon::utils::mediaPlayer::MediaPlayerStatus setSource(const std::string& url) override;
avsCommon::utils::mediaPlayer::MediaPlayerStatus play() override;
avsCommon::utils::mediaPlayer::MediaPlayerStatus stop() override;
avsCommon::utils::mediaPlayer::MediaPlayerStatus pause() override;
/**
* To resume playback after a pause, call @c resume. Calling @c play
* will reset the pipeline and source, and will not resume playback.
*/
avsCommon::utils::mediaPlayer::MediaPlayerStatus resume() override;
std::chrono::milliseconds getOffset() override;
/**
* This function is a setter, storing @c offset to be consumed internally by @c play().
* The function will always return MediaPlayerStatus::SUCCESS.
*/
avsCommon::utils::mediaPlayer::MediaPlayerStatus setOffset(std::chrono::milliseconds offset) override;
void setObserver(std::shared_ptr<avsCommon::utils::mediaPlayer::MediaPlayerObserverInterface> observer) override;
/// @}
/// @name Overridden PipelineInterface methods.
/// @{
void setAppSrc(GstAppSrc* appSrc) override;
GstAppSrc* getAppSrc() const override;
void setDecoder(GstElement* decoder) override;
GstElement* getDecoder() const override;
GstElement* getPipeline() const override;
guint queueCallback(const std::function<gboolean()>* callback) override;
/// @}
private:
/**
* The @c AudioPipeline consists of the following elements:
* @li @c appsrc The appsrc element is used as the source to which audio data is provided.
* @li @c decoder Decodebin is used as the decoder element to decode audio.
* @li @c converter An audio-converter is used to convert between audio formats.
* @li @c audioSink Sink for the audio.
* @li @c pipeline The pipeline is a bin consisting of the @c appsrc, the @c decoder, the @c converter, and the
* @c audioSink.
*
* The data flow through the elements is appsrc -> decoder -> converter -> audioSink.
*/
struct AudioPipeline {
/// The source element.
GstAppSrc* appsrc;
/// The decoder element.
GstElement* decoder;
/// The converter element.
GstElement* converter;
/// The sink element.
GstElement* audioSink;
/// Pipeline element.
GstElement* pipeline;
/// Constructor.
AudioPipeline() :
appsrc{nullptr},
decoder{nullptr},
converter{nullptr},
audioSink{nullptr},
pipeline{nullptr} {};
};
/**
* Constructor.
*
* @param contentFetcherFactory Used to create objects that can fetch remote HTTP content.
*/
MediaPlayer(
std::shared_ptr<avsCommon::sdkInterfaces::HTTPContentFetcherInterfaceFactoryInterface> contentFetcherFactory);
/**
* Initializes GStreamer and starts a main event loop on a new thread.
*
* @return @c SUCCESS if initialization was successful. Else @c FAILURE.
*/
bool init();
/**
* Worker thread handler for setting m_workerThreadId.
*
* @return Whether the callback should be called back when worker thread is once again idle (always @c false).
*/
static gboolean onSetWorkerThreadId(gpointer pointer);
/**
* Notification of a callback to execute on the worker thread.
*
* @param callback The callback to execute.
* @return Whether the callback should be called back when worker thread is once again idle.
*/
static gboolean onCallback(const std::function<gboolean()>* callback);
/**
* Creates the @c AudioPipeline with the permanent elements and links them together. The permanent elements
* are converter and audioSink.
*
* @return @c true if all the elements were created and linked successfully else @c false.
*/
bool setupPipeline();
/**
* Stops the currently playing audio and removes the transient elements. The transient elements
* are appsrc and decoder.
*/
void tearDownTransientPipelineElements();
/*
* Resets the @c AudioPipeline.
*/
void resetPipeline();
/**
* This handles linking the source pad of the decoder to the sink pad of the converter once the pad-added signal
* has been emitted by the decoder element.
*
* @note Pads are the element's interface. Data streams from one element's source pad to another element's sink pad.
*
* @param src The element for which the pad has been added.
* @param pad The pad added to the @c src element.
* @param mediaPlayer The instance of the mediaPlayer that the @c src is part of.
*/
static void onPadAdded(GstElement* src, GstPad* pad, gpointer mediaPlayer);
/**
* Performs the linking of the decoder and converter elements once the pads have been added to the decoder element.
*
* @param promise A void promise to fulfill once this method completes.
* @param src The element for which the pad has been added.
* @param pad The pad added to the @c src element.
*/
void handlePadAdded(std::promise<void>* promise, GstElement* src, GstPad* pad);
/**
* The callback for processing messages posted on the bus.
*
* @param bus GStreamer bus.
* @param msg The message posted to the bus.
* @param mediaPlayer The instance of the mediaPlayer that the @c bus is a part of.
*
* @return @c true. GStreamer needs this functions to return true always. On @c false, the main-loop thread on which
* this function is executed exits.
*/
static gboolean onBusMessage(GstBus* bus, GstMessage* msg, gpointer mediaPlayer);
/**
* Performs actions based on the message.
*
* @param message The message posted on the bus.
*
* @return Always @c true.
*/
gboolean handleBusMessage(GstMessage* message);
/**
* Worker thread handler for setting the source of audio to play.
*
* @param promise A promise to fulfill with a @ MediaPlayerStatus value once the source has been set
* (or the operation failed).
* @param reader The @c AttachmentReader with which to receive the audio to play.
*/
void handleSetAttachmentReaderSource(
std::promise<avsCommon::utils::mediaPlayer::MediaPlayerStatus>* promise,
std::shared_ptr<avsCommon::avs::attachment::AttachmentReader> reader);
void handleSetSource(std::promise<avsCommon::utils::mediaPlayer::MediaPlayerStatus> promise, std::string url);
/**
* Worker thread handler for setting the source of audio to play.
*
* @param promise A promise to fulfill with a @ MediaPlayerStatus value once the source has been set
* (or the operation failed).
* @param stream The source from which to receive the audio to play.
*/
void handleSetIStreamSource(
std::promise<avsCommon::utils::mediaPlayer::MediaPlayerStatus>* promise,
std::shared_ptr<std::istream> stream,
bool repeat);
/**
* Worker thread handler for starting playback of the current audio source.
*
* @param promise A promise to fulfill with a @c MediaPlayerStatus value once playback has been initiated
* (or the operation has failed).
*/
void handlePlay(std::promise<avsCommon::utils::mediaPlayer::MediaPlayerStatus>* promise);
/**
* Worker thread handler for stopping audio playback.
*
* @param promise A promise to fulfill with a @c MediaPlayerStatus once playback stop has been initiated
* (or the operation has failed).
*/
void handleStop(std::promise<avsCommon::utils::mediaPlayer::MediaPlayerStatus>* promise);
/**
* Actually trigger a stop of audio playback.
*
* @return The status of the operation.
*/
avsCommon::utils::mediaPlayer::MediaPlayerStatus doStop();
/**
* Worker thread handler for pausing playback of the current audio source.
*
* @param promise A promise to fulfill with a @c MediaPlayerStatus value once playback has been paused
* (or the operation has failed).
*/
void handlePause(std::promise<avsCommon::utils::mediaPlayer::MediaPlayerStatus>* promise);
/**
* Worker thread handler for resume playback of the current audio source.
*
* @param promise A promise to fulfill with a @c MediaPlayerStatus value once playback has been resumed
* (or the operation has failed).
*/
void handleResume(std::promise<avsCommon::utils::mediaPlayer::MediaPlayerStatus>* promise);
/**
* Worker thread handler for getting the current playback position.
*
* @param promise A promise to fulfill with the offset once the value has been determined.
*/
void handleGetOffset(std::promise<std::chrono::milliseconds>* promise);
/**
* Worker thread handler for setting the playback position.
*
* @param promise A promise to fulfill with a @c MediaPlayerStatus value once the offset has been set.
* @param offset The offset to start playing from.
*/
void handleSetOffset(
std::promise<avsCommon::utils::mediaPlayer::MediaPlayerStatus>* promise,
std::chrono::milliseconds offset);
/**
* Worker thread handler for setting the observer.
*
* @param promise A void promise to fulfill once the observer has been set.
* @param observer The new observer.
*/
void handleSetObserver(
std::promise<void>* promise,
std::shared_ptr<avsCommon::utils::mediaPlayer::MediaPlayerObserverInterface> observer);
/**
* Sends the playback started notification to the observer.
*/
void sendPlaybackStarted();
/**
* Sends the playback finished notification to the observer.
*/
void sendPlaybackFinished();
/**
* Sends the playback paused notification to the observer.
*/
void sendPlaybackPaused();
/**
* Sends the playback resumed notification to the observer.
*/
void sendPlaybackResumed();
/**
* Sends the playback error notification to the observer.
*
* @param type The error type.
* @param error The error details.
*/
void sendPlaybackError(
const alexaClientSDK::avsCommon::utils::mediaPlayer::ErrorType& type,
const std::string& error);
/**
* Sends the buffer underrun notification to the observer.
*/
void sendBufferUnderrun();
/**
* Sends the buffer refilled notification to the observer.
*/
void sendBufferRefilled();
/**
* Used to obtain seeking information about the pipeline.
*
* @param isSeekable A boolean indicating whether the stream is seekable.
* @return A boolean indicating whether the operation was successful.
*/
bool queryIsSeekable(bool* isSeekable);
/**
* Used to obtain the current buffering status of the pipeline.
*
* @param[out] buffering Whether the pipeline is currently buffering.
* @return A boolean indicating whether the operation was successful.
*/
bool queryBufferingStatus(bool* buffering);
/**
* Performs a seek to the @c seekPoint.
*
* @return A boolean indicating whether the seek operation was successful.
*/
bool seek();
/// An instance of the @c OffsetManager.
OffsetManager m_offsetManager;
/// Used to create objects that can fetch remote HTTP content.
std::shared_ptr<avsCommon::sdkInterfaces::HTTPContentFetcherInterfaceFactoryInterface> m_contentFetcherFactory;
/// An instance of the @c AudioPipeline.
AudioPipeline m_pipeline;
/// Main event loop.
GMainLoop* m_mainLoop;
// Main loop thread
std::thread m_mainLoopThread;
// Set Source thread.
std::thread m_setSourceThread;
/// Bus Id to track the bus.
guint m_busWatchId;
/// Flag to indicate when a playback started notification has been sent to the observer.
bool m_playbackStartedSent;
/// Flag to indicate when a playback finished notification has been sent to the observer.
bool m_playbackFinishedSent;
/// Flag to indicate whether a playback is paused.
bool m_isPaused;
/// Flag to indicate whether a buffer underrun is occurring.
bool m_isBufferUnderrun;
/// @c MediaPlayerObserverInterface instance to notify when the playback state changes.
std::shared_ptr<avsCommon::utils::mediaPlayer::MediaPlayerObserverInterface> m_playerObserver;
/// @c SourceInterface instance set to the appropriate source.
std::shared_ptr<SourceInterface> m_source;
};
} // namespace mediaPlayer
} // namespace alexaClientSDK
#endif // ALEXA_CLIENT_SDK_MEDIA_PLAYER_INCLUDE_MEDIA_PLAYER_MEDIA_PLAYER_H_