blob: ff539a56c678d37035452bc988701c7e0b104ce5 [file] [log] [blame]
// Copyright 2022 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 COMPONENTS_CAST_STREAMING_BROWSER_DEMUXER_STREAM_DATA_PROVIDER_H_
#define COMPONENTS_CAST_STREAMING_BROWSER_DEMUXER_STREAM_DATA_PROVIDER_H_
#include <type_traits>
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "components/cast_streaming/browser/demuxer_stream_client.h"
#include "components/cast_streaming/public/mojom/demuxer_connector.mojom.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/system/data_pipe.h"
namespace cast_streaming {
// Forward declarations of concrete types. Definitions to follow.
template <typename TMojoReceiverType,
typename TStreamInfoType,
typename TGetBufferResponseType>
class DemuxerStreamDataProvider;
using AudioDemuxerStreamDataProvider =
DemuxerStreamDataProvider<mojom::AudioBufferRequester,
mojom::AudioStreamInfoPtr,
mojom::GetAudioBufferResponsePtr>;
using VideoDemuxerStreamDataProvider =
DemuxerStreamDataProvider<mojom::VideoBufferRequester,
mojom::VideoStreamInfoPtr,
mojom::GetVideoBufferResponsePtr>;
// Helper class to simplify responding to calls made over AudioBufferRequester
// and VideoBufferRequester mojo APIs.
//
// |TMojoReceiverType| is the interface used for requesting data buffers.
// Currently expected to be either AudioBufferRequester or VideoBufferRequester.
// |TStreamInfoType| is the StreamInfo that may be returned by this call, either
// AudioStreamInfo or VideoStreamInfo.
// |TGetBufferResponseType| is the response type to a GetBuffer() call. Either
// GetAudioBufferResponse or GetVideoBufferResponse.
template <typename TMojoReceiverType,
typename TStreamInfoType,
typename TGetBufferResponseType>
class DemuxerStreamDataProvider : public TMojoReceiverType {
public:
// Deduce the Config type associated with this Mojo API (either
// media::AudioDecoderConfig or media::VideoDecoderConfig).
typedef decltype(TStreamInfoType::element_type::decoder_config) ConfigType;
// The callback type which will be used to request a new buffer be read. The
// callback is expected to call ProvideBuffer() once a buffer is available.
// The callback parameter provided when calling a RequestBufferCB is to be
// called if there no buffers available for reading at time of calling.
typedef base::RepeatingCallback<void(base::OnceClosure)> RequestBufferCB;
// |request_buffer| is the callback which will be used to request a new
// buffer be read. The callback is expected to call ProvideBuffer() once a
// buffer is available.
DemuxerStreamDataProvider(
mojo::PendingReceiver<TMojoReceiverType> pending_receiver,
RequestBufferCB request_buffer,
base::OnceClosure on_mojo_disconnect,
ConfigType config)
: config_(std::move(config)),
request_buffer_(std::move(request_buffer)),
on_mojo_disconnect_(std::move(on_mojo_disconnect)),
receiver_(this, std::move(pending_receiver)),
weak_factory_(this) {
receiver_.set_disconnect_handler(base::BindOnce(
&DemuxerStreamDataProvider::OnFatalError, weak_factory_.GetWeakPtr()));
}
// Sets the new config to be passed to the renderer process as part of the
// response to the ongoing GetBuffer() request.
void OnNewStreamInfo(ConfigType config,
mojo::ScopedDataPipeConsumerHandle handle) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
config_ = std::move(config);
next_stream_info_ =
TStreamInfoType::element_type::New(config_, std::move(handle));
if (current_callback_) {
std::move(current_callback_)
.Run(TGetBufferResponseType::element_type::NewStreamInfo(
std::move(next_stream_info_)));
}
}
// Sets the buffer to be passed to the renderer process as part of the
// response to the ongoing GetBuffer() request.
void ProvideBuffer(media::mojom::DecoderBufferPtr buffer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(current_callback_);
DCHECK(!next_stream_info_);
std::move(current_callback_)
.Run(
TGetBufferResponseType::element_type::NewBuffer(std::move(buffer)));
}
const ConfigType& config() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return config_;
}
void SetClient(base::WeakPtr<DemuxerStreamClient> client) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
client_ = std::move(client);
}
private:
using GetBufferCallback = typename TMojoReceiverType::GetBufferCallback;
using EnableBitstreamConverterCallback =
typename TMojoReceiverType::EnableBitstreamConverterCallback;
void OnFatalError() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (client_) {
client_->OnError();
}
std::move(on_mojo_disconnect_).Run();
}
// TMojoReceiverType implementation.
void GetBuffer(GetBufferCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (current_callback_) {
// This should never occur if the API is being used as intended, as only
// one GetBuffer() call should be ongoing at a time.
mojo::ReportBadMessage(
"Multiple calls made to BufferRequester::GetBuffer()");
return;
}
if (next_stream_info_) {
std::move(callback).Run(
TGetBufferResponseType::element_type::NewStreamInfo(
std::move(next_stream_info_)));
return;
}
current_callback_ = std::move(callback);
request_buffer_.Run(
base::BindOnce(&DemuxerStreamClient::OnNoBuffersAvailable, client_));
}
void EnableBitstreamConverter(
EnableBitstreamConverterCallback callback) override {
if (client_) {
client_->EnableBitstreamConverter(std::move(callback));
} else {
std::move(callback).Run(true);
LOG(WARNING)
<< "EnableBitstreamConverter() called when no client was available";
}
}
// The most recently set config.
ConfigType config_;
// The stream info to be sent to the remote upon its next GetBuffer() call,
// or empty.
TStreamInfoType next_stream_info_;
// The callback associated with the most recent GetBuffer() call.
GetBufferCallback current_callback_;
// Callback to request a new buffer be read from the receiver.
RequestBufferCB request_buffer_;
// Client to use when the associated DemuxerStream requires an action be
// performed.
base::WeakPtr<DemuxerStreamClient> client_;
// Callback called upon a mojo disconnection.
base::OnceClosure on_mojo_disconnect_;
SEQUENCE_CHECKER(sequence_checker_);
mojo::Receiver<TMojoReceiverType> receiver_;
base::WeakPtrFactory<DemuxerStreamDataProvider> weak_factory_;
};
} // namespace cast_streaming
#endif // COMPONENTS_CAST_STREAMING_BROWSER_DEMUXER_STREAM_DATA_PROVIDER_H_