Commit 6323cda4 authored by Fabrice de Gans-Riberi's avatar Fabrice de Gans-Riberi Committed by Chromium LUCI CQ

[fuchsia] Add a Test Cast Streaming Sender.

* Add an implementation for a Cast Streaming Sender for testing at
  // fuchsia/cast_streaming:cast_streaming_test_sender
* Move some common conversion code to its own header

Bug: 1087537
Change-Id: Icdf95dea5436646b5a6f9da72735720f64f6a359
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2573238
Commit-Queue: Fabrice de Gans-Riberi <fdegans@chromium.org>
Reviewed-by: default avatarSergey Ulanov <sergeyu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#834502}
parent 95ec7338
...@@ -6,6 +6,19 @@ assert(is_fuchsia) ...@@ -6,6 +6,19 @@ assert(is_fuchsia)
import("//testing/test.gni") import("//testing/test.gni")
source_set("cast_streaming_config_conversions") {
deps = [
"//base",
"//media",
"//third_party/openscreen/src/cast/streaming:common",
]
visibility = [ ":*" ]
sources = [
"config_conversions.cc",
"config_conversions.h",
]
}
source_set("cast_streaming_message_port") { source_set("cast_streaming_message_port") {
deps = [ deps = [
"//base", "//base",
...@@ -25,6 +38,7 @@ source_set("cast_streaming_message_port") { ...@@ -25,6 +38,7 @@ source_set("cast_streaming_message_port") {
source_set("cast_streaming") { source_set("cast_streaming") {
deps = [ deps = [
":cast_streaming_config_conversions",
":cast_streaming_message_port", ":cast_streaming_message_port",
"//base", "//base",
"//components/openscreen_platform", "//components/openscreen_platform",
...@@ -52,6 +66,33 @@ source_set("cast_streaming") { ...@@ -52,6 +66,33 @@ source_set("cast_streaming") {
] ]
} }
source_set("cast_streaming_test_sender") {
testonly = true
deps = [
":cast_streaming_config_conversions",
":cast_streaming_message_port",
"//base",
"//components/openscreen_platform",
"//components/openscreen_platform:openscreen_platform_network_service",
"//media",
"//media/mojo/common",
"//media/mojo/mojom",
"//mojo/public/cpp/system",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.web",
"//third_party/openscreen/src/cast/common:public",
"//third_party/openscreen/src/cast/streaming:sender",
"//third_party/openscreen/src/platform:api",
"//third_party/openscreen/src/util",
]
visibility = [ ":*" ]
sources = [
"test/cast_message_port_sender_impl.cc",
"test/cast_message_port_sender_impl.h",
"test/cast_streaming_test_sender.cc",
"test/cast_streaming_test_sender.h",
]
}
test("cast_streaming_unittests") { test("cast_streaming_unittests") {
sources = [ "cast_message_port_impl_unittest.cc" ] sources = [ "cast_message_port_impl_unittest.cc" ]
deps = [ deps = [
......
...@@ -5,14 +5,13 @@ ...@@ -5,14 +5,13 @@
#include "fuchsia/cast_streaming/public/cast_streaming_session.h" #include "fuchsia/cast_streaming/public/cast_streaming_session.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/notreached.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "components/openscreen_platform/network_context.h" #include "components/openscreen_platform/network_context.h"
#include "components/openscreen_platform/network_util.h" #include "components/openscreen_platform/network_util.h"
#include "components/openscreen_platform/task_runner.h" #include "components/openscreen_platform/task_runner.h"
#include "fuchsia/cast_streaming/cast_message_port_impl.h" #include "fuchsia/cast_streaming/cast_message_port_impl.h"
#include "fuchsia/cast_streaming/config_conversions.h"
#include "fuchsia/cast_streaming/stream_consumer.h" #include "fuchsia/cast_streaming/stream_consumer.h"
#include "media/base/media_util.h"
#include "media/mojo/common/mojo_decoder_buffer_converter.h" #include "media/mojo/common/mojo_decoder_buffer_converter.h"
#include "mojo/public/cpp/system/data_pipe.h" #include "mojo/public/cpp/system/data_pipe.h"
#include "third_party/openscreen/src/cast/streaming/receiver.h" #include "third_party/openscreen/src/cast/streaming/receiver.h"
...@@ -20,63 +19,6 @@ ...@@ -20,63 +19,6 @@
namespace { namespace {
media::AudioDecoderConfig AudioCaptureConfigToAudioDecoderConfig(
const openscreen::cast::AudioCaptureConfig& audio_capture_config) {
// Gather data for the audio decoder config.
media::AudioCodec media_audio_codec = media::AudioCodec::kUnknownAudioCodec;
switch (audio_capture_config.codec) {
case openscreen::cast::AudioCodec::kAac:
media_audio_codec = media::AudioCodec::kCodecAAC;
break;
case openscreen::cast::AudioCodec::kOpus:
media_audio_codec = media::AudioCodec::kCodecOpus;
break;
default:
NOTREACHED();
break;
}
return media::AudioDecoderConfig(
media_audio_codec, media::SampleFormat::kSampleFormatF32,
media::GuessChannelLayout(audio_capture_config.channels),
audio_capture_config.sample_rate /* samples_per_second */,
media::EmptyExtraData(), media::EncryptionScheme::kUnencrypted);
}
media::VideoDecoderConfig VideoCaptureConfigToVideoDecoderConfig(
const openscreen::cast::VideoCaptureConfig& video_capture_config) {
// Gather data for the video decoder config.
uint32_t video_width = video_capture_config.resolutions[0].width;
uint32_t video_height = video_capture_config.resolutions[0].height;
gfx::Size video_size(video_width, video_height);
gfx::Rect video_rect(video_width, video_height);
media::VideoCodec media_video_codec = media::VideoCodec::kUnknownVideoCodec;
media::VideoCodecProfile video_codec_profile =
media::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN;
switch (video_capture_config.codec) {
case openscreen::cast::VideoCodec::kH264:
media_video_codec = media::VideoCodec::kCodecH264;
video_codec_profile = media::VideoCodecProfile::H264PROFILE_BASELINE;
break;
case openscreen::cast::VideoCodec::kVp8:
media_video_codec = media::VideoCodec::kCodecVP8;
video_codec_profile = media::VideoCodecProfile::VP8PROFILE_MIN;
break;
case openscreen::cast::VideoCodec::kHevc:
case openscreen::cast::VideoCodec::kVp9:
default:
NOTREACHED();
break;
}
return media::VideoDecoderConfig(
media_video_codec, video_codec_profile,
media::VideoDecoderConfig::AlphaMode::kIsOpaque, media::VideoColorSpace(),
media::VideoTransformation(), video_size, video_rect, video_size,
media::EmptyExtraData(), media::EncryptionScheme::kUnencrypted);
}
bool CreateDataPipeForStreamType(media::DemuxerStream::Type type, bool CreateDataPipeForStreamType(media::DemuxerStream::Type type,
mojo::ScopedDataPipeProducerHandle* producer, mojo::ScopedDataPipeProducerHandle* producer,
mojo::ScopedDataPipeConsumerHandle* consumer) { mojo::ScopedDataPipeConsumerHandle* consumer) {
......
// Copyright 2020 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.
#include "fuchsia/cast_streaming/config_conversions.h"
#include "base/notreached.h"
#include "media/base/media_util.h"
namespace cast_streaming {
openscreen::cast::AudioCaptureConfig AudioDecoderConfigToAudioCaptureConfig(
const media::AudioDecoderConfig& audio_config) {
openscreen::cast::AudioCaptureConfig audio_capture_config;
switch (audio_config.codec()) {
case media::AudioCodec::kCodecAAC:
audio_capture_config.codec = openscreen::cast::AudioCodec::kAac;
break;
case media::AudioCodec::kCodecOpus:
audio_capture_config.codec = openscreen::cast::AudioCodec::kOpus;
break;
default:
NOTREACHED();
}
audio_capture_config.channels =
media::ChannelLayoutToChannelCount(audio_config.channel_layout());
audio_capture_config.sample_rate = audio_config.samples_per_second();
return audio_capture_config;
}
openscreen::cast::VideoCaptureConfig VideoDecoderConfigToVideoCaptureConfig(
const media::VideoDecoderConfig& video_config) {
openscreen::cast::VideoCaptureConfig video_capture_config;
switch (video_config.codec()) {
case media::VideoCodec::kCodecH264:
video_capture_config.codec = openscreen::cast::VideoCodec::kH264;
break;
case media::VideoCodec::kCodecVP8:
video_capture_config.codec = openscreen::cast::VideoCodec::kVp8;
break;
default:
NOTREACHED();
}
video_capture_config.resolutions.push_back(
{video_config.visible_rect().width(),
video_config.visible_rect().height()});
return video_capture_config;
}
media::AudioDecoderConfig AudioCaptureConfigToAudioDecoderConfig(
const openscreen::cast::AudioCaptureConfig& audio_capture_config) {
// Gather data for the audio decoder config.
media::AudioCodec media_audio_codec = media::AudioCodec::kUnknownAudioCodec;
switch (audio_capture_config.codec) {
case openscreen::cast::AudioCodec::kAac:
media_audio_codec = media::AudioCodec::kCodecAAC;
break;
case openscreen::cast::AudioCodec::kOpus:
media_audio_codec = media::AudioCodec::kCodecOpus;
break;
default:
NOTREACHED();
break;
}
return media::AudioDecoderConfig(
media_audio_codec, media::SampleFormat::kSampleFormatF32,
media::GuessChannelLayout(audio_capture_config.channels),
audio_capture_config.sample_rate /* samples_per_second */,
media::EmptyExtraData(), media::EncryptionScheme::kUnencrypted);
}
media::VideoDecoderConfig VideoCaptureConfigToVideoDecoderConfig(
const openscreen::cast::VideoCaptureConfig& video_capture_config) {
// Gather data for the video decoder config.
uint32_t video_width = video_capture_config.resolutions[0].width;
uint32_t video_height = video_capture_config.resolutions[0].height;
gfx::Size video_size(video_width, video_height);
gfx::Rect video_rect(video_width, video_height);
media::VideoCodec media_video_codec = media::VideoCodec::kUnknownVideoCodec;
media::VideoCodecProfile video_codec_profile =
media::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN;
switch (video_capture_config.codec) {
case openscreen::cast::VideoCodec::kH264:
media_video_codec = media::VideoCodec::kCodecH264;
video_codec_profile = media::VideoCodecProfile::H264PROFILE_BASELINE;
break;
case openscreen::cast::VideoCodec::kVp8:
media_video_codec = media::VideoCodec::kCodecVP8;
video_codec_profile = media::VideoCodecProfile::VP8PROFILE_MIN;
break;
case openscreen::cast::VideoCodec::kHevc:
case openscreen::cast::VideoCodec::kVp9:
default:
NOTREACHED();
break;
}
return media::VideoDecoderConfig(
media_video_codec, video_codec_profile,
media::VideoDecoderConfig::AlphaMode::kIsOpaque, media::VideoColorSpace(),
media::VideoTransformation(), video_size, video_rect, video_size,
media::EmptyExtraData(), media::EncryptionScheme::kUnencrypted);
}
} // namespace cast_streaming
// Copyright 2020 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 FUCHSIA_CAST_STREAMING_CONFIG_CONVERSIONS_H_
#define FUCHSIA_CAST_STREAMING_CONFIG_CONVERSIONS_H_
#include "media/base/audio_decoder_config.h"
#include "media/base/video_decoder_config.h"
#include "third_party/openscreen/src/cast/streaming/capture_configs.h"
namespace cast_streaming {
// Utility functions to convert between media and Open Screen types.
openscreen::cast::AudioCaptureConfig AudioDecoderConfigToAudioCaptureConfig(
const media::AudioDecoderConfig& audio_config);
openscreen::cast::VideoCaptureConfig VideoDecoderConfigToVideoCaptureConfig(
const media::VideoDecoderConfig& video_config);
media::AudioDecoderConfig AudioCaptureConfigToAudioDecoderConfig(
const openscreen::cast::AudioCaptureConfig& audio_capture_config);
media::VideoDecoderConfig VideoCaptureConfigToVideoDecoderConfig(
const openscreen::cast::VideoCaptureConfig& video_capture_config);
} // namespace cast_streaming
#endif // FUCHSIA_CAST_STREAMING_CONFIG_CONVERSIONS_H_
// Copyright 2020 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.
#include "fuchsia/cast_streaming/test/cast_message_port_sender_impl.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/values.h"
#include "fuchsia/cast_streaming/message_serialization.h"
#include "third_party/openscreen/src/platform/base/error.h"
namespace cast_streaming {
CastMessagePortSenderImpl::CastMessagePortSenderImpl(
std::unique_ptr<cast_api_bindings::MessagePort> message_port,
base::OnceClosure on_close)
: message_port_(std::move(message_port)), on_close_(std::move(on_close)) {
VLOG(1) << __func__;
message_port_->SetReceiver(this);
}
CastMessagePortSenderImpl::~CastMessagePortSenderImpl() = default;
void CastMessagePortSenderImpl::MaybeClose() {
if (message_port_) {
message_port_.reset();
}
if (client_) {
client_->OnError(
openscreen::Error(openscreen::Error::Code::kCastV2CastSocketError));
if (on_close_) {
std::move(on_close_).Run();
}
}
}
void CastMessagePortSenderImpl::SetClient(
openscreen::cast::MessagePort::Client* client,
std::string client_sender_id) {
VLOG(2) << __func__;
CHECK(client);
CHECK(!client_);
client_ = client;
}
void CastMessagePortSenderImpl::ResetClient() {
client_ = nullptr;
MaybeClose();
}
void CastMessagePortSenderImpl::PostMessage(
const std::string& sender_id,
const std::string& message_namespace,
const std::string& message) {
VLOG(3) << __func__;
if (!message_port_) {
return;
}
VLOG(3) << "Received Open Screen message. SenderId: " << sender_id
<< ". Namespace: " << message_namespace << ". Message: " << message;
message_port_->PostMessage(
SerializeCastMessage(sender_id, message_namespace, message));
}
bool CastMessagePortSenderImpl::OnMessage(
base::StringPiece message,
std::vector<std::unique_ptr<cast_api_bindings::MessagePort>> ports) {
VLOG(3) << __func__;
// If |client_| was cleared, |message_port_| should have been reset.
CHECK(client_);
if (!ports.empty()) {
// We should never receive any ports for Cast Streaming.
MaybeClose();
return false;
}
std::string sender_id;
std::string message_namespace;
std::string str_message;
if (!DeserializeCastMessage(message, &sender_id, &message_namespace,
&str_message)) {
LOG(ERROR) << "Received bad message. " << message;
client_->OnError(
openscreen::Error(openscreen::Error::Code::kCastV2InvalidMessage));
return false;
}
VLOG(3) << "Received Cast message. SenderId: " << sender_id
<< ". Namespace: " << message_namespace
<< ". Message: " << str_message;
client_->OnMessage(sender_id, message_namespace, str_message);
return true;
}
void CastMessagePortSenderImpl::OnPipeError() {
VLOG(3) << __func__;
MaybeClose();
}
} // namespace cast_streaming
// Copyright 2020 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 FUCHSIA_CAST_STREAMING_TEST_CAST_MESSAGE_PORT_SENDER_IMPL_H_
#define FUCHSIA_CAST_STREAMING_TEST_CAST_MESSAGE_PORT_SENDER_IMPL_H_
#include "base/callback.h"
#include "components/cast/message_port/message_port.h"
#include "third_party/openscreen/src/cast/common/public/message_port.h"
namespace cast_streaming {
// Adapter for a cast MessagePort that provides an Open Screen MessagePort
// implementation for a Cast Streaming Sender.
class CastMessagePortSenderImpl
: public openscreen::cast::MessagePort,
public cast_api_bindings::MessagePort::Receiver {
public:
explicit CastMessagePortSenderImpl(
std::unique_ptr<cast_api_bindings::MessagePort> message_port,
base::OnceClosure on_close);
~CastMessagePortSenderImpl() final;
CastMessagePortSenderImpl(const CastMessagePortSenderImpl&) = delete;
CastMessagePortSenderImpl& operator=(const CastMessagePortSenderImpl&) =
delete;
// openscreen::cast::MessagePort implementation.
void SetClient(Client* client, std::string client_sender_id) final;
void ResetClient() final;
void PostMessage(const std::string& sender_id,
const std::string& message_namespace,
const std::string& message) final;
private:
// Resets |message_port_| if it is open and signals an error to |client_| if
// |client_| is set.
void MaybeClose();
// cast_api_bindings::MessagePort::Receiver implementation.
bool OnMessage(
base::StringPiece message,
std::vector<std::unique_ptr<cast_api_bindings::MessagePort>> ports) final;
void OnPipeError() final;
Client* client_ = nullptr;
std::unique_ptr<cast_api_bindings::MessagePort> message_port_;
base::OnceClosure on_close_;
};
} // namespace cast_streaming
#endif // FUCHSIA_CAST_STREAMING_TEST_CAST_MESSAGE_PORT_SENDER_IMPL_H_
// Copyright 2020 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 FUCHSIA_CAST_STREAMING_TEST_CAST_STREAMING_SENDER_SESSION_TEST_H_
#define FUCHSIA_CAST_STREAMING_TEST_CAST_STREAMING_SENDER_SESSION_TEST_H_
#include "fuchsia/cast_streaming/test/cast_streaming_test_sender.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "fuchsia/cast_streaming/config_conversions.h"
#include "third_party/openscreen/src/cast/streaming/capture_recommendations.h"
namespace cast_streaming {
namespace {
// Converts |data_buffer| into an Open Screen EncodedFrame. The caller must keep
// a reference to |data_buffer| while using the returned EncodedFrame since they
// point to the same data.
openscreen::cast::EncodedFrame DataBufferToEncodedFrame(
const scoped_refptr<media::DataBuffer>& data_buffer,
bool is_key_frame,
openscreen::cast::FrameId frame_id,
openscreen::cast::FrameId* last_referenced_frame_id,
int rtp_timebase) {
CHECK(data_buffer);
CHECK(!data_buffer->end_of_stream());
openscreen::cast::EncodedFrame encoded_frame;
encoded_frame.frame_id = frame_id;
if (is_key_frame) {
encoded_frame.dependency =
openscreen::cast::EncodedFrame::Dependency::KEY_FRAME;
*last_referenced_frame_id = encoded_frame.frame_id;
} else {
encoded_frame.dependency =
openscreen::cast::EncodedFrame::Dependency::DEPENDS_ON_ANOTHER;
}
encoded_frame.referenced_frame_id = *last_referenced_frame_id;
std::chrono::milliseconds timestamp(
data_buffer->timestamp().InMilliseconds());
encoded_frame.rtp_timestamp =
openscreen::cast::RtpTimeTicks::FromTimeSinceOrigin<
std::chrono::milliseconds>(timestamp, rtp_timebase);
encoded_frame.reference_time = openscreen::Clock::time_point(timestamp);
encoded_frame.data = absl::Span<uint8_t>(data_buffer->writable_data(),
data_buffer->data_size());
return encoded_frame;
}
} // namespace
CastStreamingTestSender::CastStreamingTestSender()
: task_runner_(base::SequencedTaskRunnerHandle::Get()),
environment_(&openscreen::Clock::now, &task_runner_) {}
CastStreamingTestSender::~CastStreamingTestSender() = default;
bool CastStreamingTestSender::Start(
std::unique_ptr<cast_api_bindings::MessagePort> message_port,
net::IPAddress receiver_address,
base::Optional<media::AudioDecoderConfig> audio_config,
base::Optional<media::VideoDecoderConfig> video_config) {
VLOG(1) << __func__;
CHECK(!is_active_);
CHECK(!sender_session_);
CHECK(audio_config || video_config);
// Instantiate the |sender_session_|.
message_port_ = std::make_unique<CastMessagePortSenderImpl>(
std::move(message_port),
base::BindOnce(&CastStreamingTestSender::OnCastChannelClosed,
base::Unretained(this)));
sender_session_ = std::make_unique<openscreen::cast::SenderSession>(
openscreen::IPAddress::kV6LoopbackAddress(), this, &environment_,
message_port_.get());
std::vector<openscreen::cast::AudioCaptureConfig> audio_configs;
if (audio_config) {
audio_configs.push_back(
AudioDecoderConfigToAudioCaptureConfig(audio_config.value()));
}
std::vector<openscreen::cast::VideoCaptureConfig> video_configs;
if (video_config) {
video_configs.push_back(
VideoDecoderConfigToVideoCaptureConfig(video_config.value()));
}
openscreen::Error error = sender_session_->Negotiate(
std::move(audio_configs), std::move(video_configs));
if (error == openscreen::Error::None()) {
return true;
}
LOG(ERROR) << "Failed to start sender session. " << error.ToString();
sender_session_.reset();
message_port_.reset();
return false;
}
void CastStreamingTestSender::Stop() {
VLOG(1) << __func__;
sender_session_.reset();
message_port_.reset();
audio_sender_ = nullptr;
video_sender_ = nullptr;
audio_decoder_config_.reset();
video_decoder_config_.reset();
is_active_ = false;
if (sender_stopped_closure_) {
std::move(sender_stopped_closure_).Run();
}
}
void CastStreamingTestSender::SendAudioBuffer(
scoped_refptr<media::DataBuffer> audio_buffer) {
VLOG(3) << __func__;
CHECK(audio_sender_);
if (audio_sender_->EnqueueFrame(DataBufferToEncodedFrame(
audio_buffer, true /* is_key_frame */,
audio_sender_->GetNextFrameId(), &last_audio_reference_frame_id_,
audio_sender_->rtp_timebase())) !=
openscreen::cast::Sender::EnqueueFrameResult::OK) {
Stop();
}
}
void CastStreamingTestSender::SendVideoBuffer(
scoped_refptr<media::DataBuffer> video_buffer,
bool is_key_frame) {
VLOG(3) << __func__;
CHECK(video_sender_);
if (video_sender_->EnqueueFrame(DataBufferToEncodedFrame(
video_buffer, is_key_frame, video_sender_->GetNextFrameId(),
&last_video_reference_frame_id_, video_sender_->rtp_timebase())) !=
openscreen::cast::Sender::EnqueueFrameResult::OK) {
Stop();
}
}
void CastStreamingTestSender::RunUntilStarted() {
VLOG(1) << __func__;
while (!is_active_) {
base::RunLoop run_loop;
CHECK(!sender_started_closure_);
sender_started_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
}
void CastStreamingTestSender::RunUntilStopped() {
VLOG(1) << __func__;
while (is_active_) {
base::RunLoop run_loop;
CHECK(!sender_stopped_closure_);
sender_stopped_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
}
void CastStreamingTestSender::OnCastChannelClosed() {
VLOG(1) << __func__;
Stop();
}
void CastStreamingTestSender::OnNegotiated(
const openscreen::cast::SenderSession* session,
openscreen::cast::SenderSession::ConfiguredSenders senders,
openscreen::cast::capture_recommendations::Recommendations
capture_recommendations) {
VLOG(1) << __func__;
CHECK_EQ(session, sender_session_.get());
CHECK(senders.audio_sender || senders.video_sender);
if (senders.audio_sender) {
audio_sender_ = senders.audio_sender;
audio_decoder_config_ =
AudioCaptureConfigToAudioDecoderConfig(senders.audio_config);
}
if (senders.video_sender) {
video_sender_ = senders.video_sender;
video_decoder_config_ =
VideoCaptureConfigToVideoDecoderConfig(senders.video_config);
}
is_active_ = true;
if (sender_started_closure_) {
std::move(sender_started_closure_).Run();
}
}
void CastStreamingTestSender::OnError(
const openscreen::cast::SenderSession* session,
openscreen::Error error) {
LOG(ERROR) << "Sender Session error: " << error.ToString();
CHECK_EQ(session, sender_session_.get());
Stop();
}
} // namespace cast_streaming
#endif // FUCHSIA_CAST_STREAMING_TEST_CAST_STREAMING_SENDER_SESSION_TEST_H_
// Copyright 2020 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 FUCHSIA_CAST_STREAMING_TEST_CAST_STREAMING_TEST_SENDER_H_
#define FUCHSIA_CAST_STREAMING_TEST_CAST_STREAMING_TEST_SENDER_H_
#include "base/callback.h"
#include "base/optional.h"
#include "base/sequenced_task_runner.h"
#include "components/cast/message_port/message_port.h"
#include "components/openscreen_platform/task_runner.h"
#include "fuchsia/cast_streaming/test/cast_message_port_sender_impl.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/data_buffer.h"
#include "media/base/video_decoder_config.h"
#include "net/base/ip_address.h"
#include "third_party/openscreen/src/cast/streaming/sender_session.h"
namespace cast_streaming {
// Cast Streaming Sender implementation for testing. This class provides basic
// functionality for starting a Cast Streaming Sender and sending audio and
// video frames to a Cast Streaming Receiver. Example usage:
//
// std::unique_ptr<cast_api_bindings::MessagePort> sender_message_port;
// std::unique_ptr<cast_api_bindings::MessagePort> receiver_message_port;
// cast_api_bindings::MessagePort::CreatePair(&sender_message_port,
// &receiver_message_port);
//
// // Send |receiver_message_port| to a Receiver and start it.
//
// CastStreamingTestSender sender;
// if !(sender.Start(
// std::move(sender_message_port), net::IPAddress::IPv6Localhost(),
// audio_config, video_config)) {
// return;
// }
// sender.RunUntilStarted();
// sender.SendAudioBuffer(audio_buffer);
// sender.SendVideoBuffer(video_buffer);
// sender.Stop();
// sender.RunUntilStopped();
class CastStreamingTestSender : public openscreen::cast::SenderSession::Client {
public:
CastStreamingTestSender();
~CastStreamingTestSender() final;
CastStreamingTestSender(const CastStreamingTestSender&) = delete;
CastStreamingTestSender& operator=(const CastStreamingTestSender&) = delete;
// Uses |message_port| as the Sender-end of a Cast Streaming MessagePort to
// start a Cast Streaming Session with a Cast Streaming Receiver at
// |receiver_address|. At least one of |audio_config| or |video_config| must
// be set. Returns true on success.
bool Start(std::unique_ptr<cast_api_bindings::MessagePort> message_port,
net::IPAddress receiver_address,
base::Optional<media::AudioDecoderConfig> audio_config,
base::Optional<media::VideoDecoderConfig> video_config);
// Ends the Cast Streaming Session.
void Stop();
// Sends |audio_buffer| or |video_buffer| to the Receiver. These can only be
// called when is_active() returns true.
void SendAudioBuffer(scoped_refptr<media::DataBuffer> audio_buffer);
void SendVideoBuffer(scoped_refptr<media::DataBuffer> video_buffer,
bool is_key_frame);
// After a successful call to Start(), will run until the Cast Streaming
// Sender Session is active. After this call, is_active() will return true
// and at least one of audio_decoder_config() or video_decoder_config() will
// be set.
void RunUntilStarted();
// Runs until is_active() returns false.
void RunUntilStopped();
bool is_active() const { return is_active_; }
const base::Optional<media::AudioDecoderConfig>& audio_decoder_config()
const {
return audio_decoder_config_;
}
const base::Optional<media::VideoDecoderConfig>& video_decoder_config()
const {
return video_decoder_config_;
}
private:
void OnCastChannelClosed();
// openscreen::cast::SenderSession::Client implementation.
void OnNegotiated(const openscreen::cast::SenderSession* session,
openscreen::cast::SenderSession::ConfiguredSenders senders,
openscreen::cast::capture_recommendations::Recommendations
capture_recommendations) final;
void OnError(const openscreen::cast::SenderSession* session,
openscreen::Error error) final;
openscreen_platform::TaskRunner task_runner_;
openscreen::cast::Environment environment_;
std::unique_ptr<openscreen::cast::SenderSession> sender_session_;
std::unique_ptr<CastMessagePortSenderImpl> message_port_;
openscreen::cast::Sender* audio_sender_ = nullptr;
openscreen::cast::Sender* video_sender_ = nullptr;
openscreen::cast::FrameId last_audio_reference_frame_id_;
openscreen::cast::FrameId last_video_reference_frame_id_;
bool is_active_ = false;
base::Optional<media::AudioDecoderConfig> audio_decoder_config_;
base::Optional<media::VideoDecoderConfig> video_decoder_config_;
// Used to implement RunUntilStarted() and RunUntilStopped().
base::OnceClosure sender_started_closure_;
base::OnceClosure sender_stopped_closure_;
};
} // namespace cast_streaming
#endif // FUCHSIA_CAST_STREAMING_TEST_CAST_STREAMING_TEST_SENDER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment