blob: d21ea3ad037346f2851f7aae7a41c958c20ba2b1 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_REMOTING_STREAM_PROVIDER_H_
#define MEDIA_REMOTING_STREAM_PROVIDER_H_
#include "base/callback_forward.h"
#include "base/containers/circular_deque.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/single_thread_task_runner.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/demuxer.h"
#include "media/base/demuxer_stream.h"
#include "media/base/video_decoder_config.h"
#include "media/mojo/mojom/remoting.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/openscreen/src/cast/streaming/remoting.pb.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace openscreen {
namespace cast {
class RpcMessenger;
}
} // namespace openscreen
namespace media {
class MojoDecoderBufferReader;
namespace remoting {
class ReceiverController;
// The media stream provider for Media Remoting receiver.
class StreamProvider final : public Demuxer {
public:
StreamProvider(
ReceiverController* receiver_controller,
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner);
// Demuxer implementation.
std::vector<DemuxerStream*> GetAllStreams() override;
std::string GetDisplayName() const override;
void Initialize(DemuxerHost* host, PipelineStatusCallback status_cb) override;
void AbortPendingReads() override;
void StartWaitingForSeek(base::TimeDelta seek_time) override;
void CancelPendingSeek(base::TimeDelta seek_time) override;
void Seek(base::TimeDelta time, PipelineStatusCallback status_cb) override;
void Stop() override;
base::TimeDelta GetStartTime() const override;
base::Time GetTimelineOffset() const override;
int64_t GetMemoryUsage() const override;
absl::optional<container_names::MediaContainerName> GetContainerForMetrics()
const override;
void OnEnabledAudioTracksChanged(const std::vector<MediaTrack::Id>& track_ids,
base::TimeDelta curr_time,
TrackChangeCB change_completed_cb) override;
void OnSelectedVideoTrackChanged(const std::vector<MediaTrack::Id>& track_ids,
base::TimeDelta curr_time,
TrackChangeCB change_completed_cb) override;
protected:
// Deletion is only allowed via Destroy().
~StreamProvider() override;
private:
// An implementation of media::DemuxerStream on Media Remoting receiver.
// Receives data from mojo data pipe, and returns one frame or/and status when
// Read() is called.
class MediaStream final : public DemuxerStream,
public mojom::RemotingDataStreamReceiver {
public:
using UniquePtr =
std::unique_ptr<MediaStream, std::function<void(MediaStream*)>>;
// MediaStream should be created on the main thread to be able to get unique
// handle ID from |rpc_messenger_|.
static void CreateOnMainThread(
openscreen::cast::RpcMessenger* rpc_messenger,
Type type,
int32_t handle,
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
base::OnceCallback<void(MediaStream::UniquePtr)> callback);
// In order to destroy members in the right thread, MediaStream has to use
// DestructionHelper() to destroy itself.
static void DestructionHelper(MediaStream* stream);
MediaStream(
openscreen::cast::RpcMessenger* rpc_messenger,
Type type,
int32_t remote_handle,
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner);
// DemuxerStream implementation.
void Read(ReadCB read_cb) override;
AudioDecoderConfig audio_decoder_config() override;
VideoDecoderConfig video_decoder_config() override;
DemuxerStream::Type type() const override;
Liveness liveness() const override;
bool SupportsConfigChanges() override;
void Initialize(base::OnceClosure init_done_cb);
mojo::PendingRemote<mojom::RemotingDataStreamReceiver>
BindNewPipeAndPassRemote() {
return receiver_.BindNewPipeAndPassRemote();
}
private:
friend class base::DeleteHelper<MediaStream>; // For using DeleteSoon().
// For testing.
friend class StreamProviderTest;
// Prevent from unique_ptr using ~MediaStream() to destroy MediaStream
// instances. Use DestructionHelper() as the custom deleter with unique_ptr
// to destroy MediaStream instances.
~MediaStream() override;
void Destroy();
// Send RPC message on |main_task_runner_|.
void SendRpcMessageOnMainThread(
std::unique_ptr<openscreen::cast::RpcMessage> message);
// mojom::RemotingDataStreamReceiver implementation.
void InitializeDataPipe(
mojo::ScopedDataPipeConsumerHandle data_pipe) override;
void ReceiveFrame(uint32_t count, mojom::DecoderBufferPtr buffer) override;
void FlushUntil(uint32_t count) override;
// RPC messages handlers.
void OnReceivedRpc(std::unique_ptr<openscreen::cast::RpcMessage> message);
void OnInitializeCallback(
std::unique_ptr<openscreen::cast::RpcMessage> message);
void OnReadUntilCallback(
std::unique_ptr<openscreen::cast::RpcMessage> message);
// Issues the ReadUntil RPC message when read is pending and buffer is
// empty.
void SendReadUntil();
// Run |init_done_callback_| when MojoDecoderBufferReader is created and
// received RPC_DS_INITIALIZE_CALLBACK
void CompleteInitialize();
// Append a frame into |buffers_|.
void AppendBuffer(uint32_t count, scoped_refptr<DecoderBuffer> buffer);
// Run and reset the read callback.
void CompleteRead(DemuxerStream::Status status);
// Update the audio/video decoder config. When config changes in the mid
// stream, the new config will be stored in |next_audio_decoder_config_|.
// Old config will be dropped when all associated frames are consumed.
void UpdateAudioConfig(
const openscreen::cast::AudioDecoderConfig& audio_message);
void UpdateVideoConfig(
const openscreen::cast::VideoDecoderConfig& video_message);
// Called when any error occurs.
void OnError(const std::string& error);
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
openscreen::cast::RpcMessenger* const rpc_messenger_;
const Type type_;
const int remote_handle_;
const int rpc_handle_;
// Set when Initialize() is called.
base::OnceClosure init_done_callback_;
// The frame count of the frame to be returned on the next Read call. It
// will be increased whenever a frame is read. It will be updated when
// FlushUntil() is called.
uint32_t current_frame_count_ = 0;
// One plus the last frame count received over RTP. Used for continuity
// check.
uint32_t buffered_frame_count_ = 0;
// The total number of frames received from the sender side. It will be used
// as the base value for sending ReadUntil() to request more frames and be
// updated in OnReadUntilCallback() which would get the message that
// contains how many frames are sent.
uint32_t total_received_frame_count_ = 0;
// Indicates whether a ReadUntil RPC message was sent without receiving the
// ReadUntilCallback message yet.
bool read_until_sent_ = false;
// Indicates whether RPC_DS_INITIALIZE_CALLBACK received.
bool rpc_initialized_ = false;
// Set when Read() is called. Run only once when read completes.
ReadCB read_complete_callback_;
// The frame data would be sent via Mojo IPC as MojoDecoderBuffer. When a
// frame is sent to |this| from host by calling ReceiveFrame(),
// |decoder_buffer_reader_| is used to read the frame date from data pipe.
std::unique_ptr<MojoDecoderBufferReader> decoder_buffer_reader_;
base::circular_deque<scoped_refptr<DecoderBuffer>> buffers_;
// Current audio/video config.
AudioDecoderConfig audio_decoder_config_;
VideoDecoderConfig video_decoder_config_;
// Stores the new audio/video config when config changes.
AudioDecoderConfig next_audio_decoder_config_;
VideoDecoderConfig next_video_decoder_config_;
mojo::Receiver<mojom::RemotingDataStreamReceiver> receiver_{this};
base::WeakPtr<MediaStream> media_weak_this_;
base::WeakPtrFactory<MediaStream> media_weak_factory_{this};
};
friend std::default_delete<StreamProvider>;
friend class base::DeleteHelper<StreamProvider>; // For using DeleteSoon().
// For testing.
friend class StreamProviderTest;
void Destroy();
// RPC messages handlers.
void OnReceivedRpc(std::unique_ptr<openscreen::cast::RpcMessage> message);
void OnAcquireDemuxer(std::unique_ptr<openscreen::cast::RpcMessage> message);
// Called when audio/video stream is created and initialized.
void InitializeDataPipe();
void OnAudioStreamCreated(MediaStream::UniquePtr stream);
void OnVideoStreamCreated(MediaStream::UniquePtr stream);
void OnAudioStreamInitialized();
void OnVideoStreamInitialized();
void CompleteInitialize();
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
ReceiverController* const receiver_controller_;
openscreen::cast::RpcMessenger* const rpc_messenger_;
MediaStream::UniquePtr audio_stream_;
MediaStream::UniquePtr video_stream_;
bool has_audio_{false};
bool has_video_{false};
bool audio_stream_initialized_{false};
bool video_stream_initialized_{false};
// Set when Initialize() is called, and will run when both video and audio
// streams are initialized or error occurs.
PipelineStatusCallback init_done_callback_;
base::WeakPtr<StreamProvider> media_weak_this_;
base::WeakPtrFactory<StreamProvider> media_weak_factory_{this};
};
} // namespace remoting
} // namespace media
namespace std {
// Specialize std::default_delete to call Destroy().
template <>
struct default_delete<media::remoting::StreamProvider> {
constexpr default_delete() = default;
template <typename U,
typename = typename std::enable_if<std::is_convertible<
U*,
media::remoting::StreamProvider*>::value>::type>
explicit default_delete(const default_delete<U>& d) {}
void operator()(media::remoting::StreamProvider* ptr) const;
};
} // namespace std
#endif // MEDIA_REMOTING_STREAM_PROVIDER_H_