blob: 3aa12066252b695e0d5eb442aae1f96ed5f8c1e9 [file] [log] [blame]
// 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 {
const char kSenderId[] = "testSenderId";
const char kReceiverId[] = "testReceiverId";
// 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(), kSenderId, kReceiverId);
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_