blob: c6ded6efdfee9976076d48b14c12b84e80402e25 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "garnet/bin/mediaplayer/core/player_core.h"
#include "garnet/bin/mediaplayer/core/demux_source_segment.h"
#include "garnet/bin/mediaplayer/core/renderer_sink_segment.h"
#include "garnet/bin/mediaplayer/core/test/fake_audio_renderer.h"
#include "garnet/bin/mediaplayer/core/test/fake_demux.h"
#include "garnet/bin/mediaplayer/core/test/fake_sink_segment.h"
#include "garnet/bin/mediaplayer/core/test/fake_source_segment.h"
#include "garnet/bin/mediaplayer/core/test/fake_video_renderer.h"
#include "garnet/bin/mediaplayer/graph/formatting.h"
#include "lib/gtest/test_loop_fixture.h"
namespace media_player {
namespace test {
std::ostream& operator<<(std::ostream& os, NodeRef value) {
if (!value) {
return os << "<none>";
}
os << value.GetNode()->label();
for (size_t output_index = 0; output_index < value.output_count();
output_index++) {
os << fostr::NewLine << "[" << output_index << "] " << fostr::Indent
<< value.output(output_index).mate().node() << fostr::Outdent;
}
return os;
}
void ExpectEqual(const StreamType* a, const StreamType* b) {
if (!a) {
EXPECT_EQ(nullptr, b);
return;
}
EXPECT_NE(nullptr, b);
EXPECT_EQ(a->medium(), b->medium());
EXPECT_EQ(a->encoding(), b->encoding());
switch (a->medium()) {
case StreamType::Medium::kAudio:
EXPECT_EQ(StreamType::Medium::kAudio, b->medium());
EXPECT_NE(nullptr, a->audio());
EXPECT_NE(nullptr, b->audio());
EXPECT_EQ(a->audio()->sample_format(), b->audio()->sample_format());
EXPECT_EQ(a->audio()->channels(), b->audio()->channels());
EXPECT_EQ(a->audio()->frames_per_second(),
b->audio()->frames_per_second());
break;
case StreamType::Medium::kVideo:
EXPECT_EQ(StreamType::Medium::kVideo, b->medium());
EXPECT_NE(nullptr, a->video());
EXPECT_NE(nullptr, b->video());
EXPECT_EQ(a->video()->pixel_format(), b->video()->pixel_format());
EXPECT_EQ(a->video()->color_space(), b->video()->color_space());
EXPECT_EQ(a->video()->width(), b->video()->width());
EXPECT_EQ(a->video()->height(), b->video()->height());
EXPECT_EQ(a->video()->coded_width(), b->video()->coded_width());
EXPECT_EQ(a->video()->coded_height(), b->video()->coded_height());
EXPECT_EQ(a->video()->pixel_aspect_ratio_width(),
b->video()->pixel_aspect_ratio_width());
EXPECT_EQ(a->video()->pixel_aspect_ratio_height(),
b->video()->pixel_aspect_ratio_height());
break;
case StreamType::Medium::kText:
EXPECT_EQ(StreamType::Medium::kText, b->medium());
EXPECT_NE(nullptr, a->text());
EXPECT_NE(nullptr, b->text());
break;
case StreamType::Medium::kSubpicture:
EXPECT_EQ(StreamType::Medium::kSubpicture, b->medium());
EXPECT_NE(nullptr, a->subpicture());
EXPECT_NE(nullptr, b->subpicture());
break;
}
}
void ExpectNoStreams(const PlayerCore& player_core, StreamType::Medium medium) {
EXPECT_FALSE(player_core.has_sink_segment(medium));
EXPECT_FALSE(player_core.content_has_medium(medium));
EXPECT_FALSE(player_core.medium_connected(medium));
}
void ExpectNoStreams(const PlayerCore& player_core) {
ExpectNoStreams(player_core, StreamType::Medium::kAudio);
ExpectNoStreams(player_core, StreamType::Medium::kVideo);
ExpectNoStreams(player_core, StreamType::Medium::kText);
ExpectNoStreams(player_core, StreamType::Medium::kSubpicture);
}
using PlayerTest = ::gtest::TestLoopFixture;
// Tests that a fresh player_core responds to simple queries as expected.
TEST_F(PlayerTest, FreshPlayer) {
PlayerCore player_core(dispatcher());
EXPECT_FALSE(player_core.has_source_segment());
ExpectNoStreams(player_core);
EXPECT_FALSE(player_core.end_of_stream());
EXPECT_EQ(nullptr, player_core.metadata());
EXPECT_EQ(nullptr, player_core.problem());
EXPECT_NE(nullptr, player_core.graph());
EXPECT_EQ(NodeRef(), player_core.source_node());
}
// Tests ClearSourceSegment.
TEST_F(PlayerTest, NullSourceSegment) {
PlayerCore player_core(dispatcher());
player_core.ClearSourceSegment();
RunLoopUntilIdle();
EXPECT_FALSE(player_core.has_source_segment());
ExpectNoStreams(player_core);
}
// Tests the player_core by setting up a fake source segment and two fake sink
// segments, exercising the player_core and then removing the segments.
TEST_F(PlayerTest, FakeSegments) {
PlayerCore player_core(dispatcher());
bool update_callback_called = false;
player_core.SetUpdateCallback(
[&update_callback_called]() { update_callback_called = true; });
EXPECT_FALSE(update_callback_called);
// Add a source segment.
bool source_segment_destroyed;
std::unique_ptr<FakeSourceSegment> source_segment = FakeSourceSegment::Create(
[&source_segment_destroyed](FakeSourceSegment* source_segment) {
source_segment_destroyed = true;
EXPECT_TRUE(source_segment->will_deprovision_called_);
EXPECT_FALSE(source_segment->TEST_provisioned());
});
FakeSourceSegment* source_segment_raw = source_segment.get();
EXPECT_FALSE(source_segment_raw->did_provision_called_);
EXPECT_FALSE(source_segment_raw->will_deprovision_called_);
EXPECT_FALSE(source_segment_raw->TEST_provisioned());
EXPECT_FALSE(player_core.has_source_segment());
source_segment->Provision(player_core.graph(), dispatcher(), nullptr,
nullptr);
bool set_source_segment_callback_called = false;
player_core.SetSourceSegment(std::move(source_segment),
[&set_source_segment_callback_called]() {
set_source_segment_callback_called = true;
});
EXPECT_TRUE(player_core.has_source_segment());
EXPECT_FALSE(update_callback_called);
EXPECT_FALSE(set_source_segment_callback_called);
EXPECT_TRUE(source_segment_raw->did_provision_called_);
source_segment_raw->did_provision_called_ = false;
EXPECT_FALSE(source_segment_raw->will_deprovision_called_);
EXPECT_TRUE(source_segment_raw->TEST_provisioned());
ExpectNoStreams(player_core);
// Add an audio stream indicating we will add more streams.
AudioStreamType audio_type(StreamType::kAudioEncodingLpcm, nullptr,
AudioStreamType::SampleFormat::kSigned16, 2,
44100);
// We need a non-null output, but it doesn't have to work.
OutputRef audio_output(reinterpret_cast<Output*>(1));
source_segment_raw->TEST_OnStreamUpdated(0, audio_type, audio_output, true);
EXPECT_FALSE(update_callback_called);
EXPECT_FALSE(set_source_segment_callback_called);
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kAudio));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kAudio));
ExpectNoStreams(player_core, StreamType::Medium::kVideo);
ExpectNoStreams(player_core, StreamType::Medium::kText);
ExpectNoStreams(player_core, StreamType::Medium::kSubpicture);
// Add a video stream indicating we will *not* add more streams.
VideoStreamType video_type(StreamType::kVideoEncodingUncompressed, nullptr,
VideoStreamType::PixelFormat::kYv12,
VideoStreamType::ColorSpace::kNotApplicable, 0, 0,
0, 0, 1, 1, 0);
// We need a non-null output, but it doesn't have to work.
OutputRef video_output(reinterpret_cast<Output*>(2));
source_segment_raw->TEST_OnStreamUpdated(1, video_type, video_output, false);
EXPECT_FALSE(update_callback_called);
EXPECT_TRUE(set_source_segment_callback_called);
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kAudio));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kAudio));
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kVideo));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kVideo));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kVideo));
ExpectNoStreams(player_core, StreamType::Medium::kText);
ExpectNoStreams(player_core, StreamType::Medium::kSubpicture);
// Make sure notification works via the source.
source_segment_raw->TEST_NotifyUpdate();
EXPECT_TRUE(update_callback_called);
update_callback_called = false;
EXPECT_FALSE(player_core.end_of_stream());
EXPECT_EQ(nullptr, player_core.metadata());
EXPECT_EQ(nullptr, player_core.problem());
// Make sure problem reporting works via the source.
source_segment_raw->TEST_ReportProblem("fake problem type",
"fake problem details");
EXPECT_TRUE(update_callback_called);
update_callback_called = false;
EXPECT_NE(nullptr, player_core.problem());
EXPECT_EQ("fake problem type", player_core.problem()->type);
EXPECT_EQ("fake problem details", player_core.problem()->details);
source_segment_raw->TEST_ReportNoProblem();
EXPECT_TRUE(update_callback_called);
update_callback_called = false;
EXPECT_EQ(nullptr, player_core.problem());
// Make sure metadata works via the source.
EXPECT_EQ(nullptr, player_core.metadata());
Metadata metadata;
metadata.emplace("title", "fake title");
metadata.emplace("artist", "fake artist");
metadata.emplace("album", "fake album");
metadata.emplace("publisher", "fake publisher");
metadata.emplace("genre", "fake genre");
metadata.emplace("composer", "fake composer");
source_segment_raw->metadata_ = &metadata;
EXPECT_EQ(&metadata, player_core.metadata());
// Add a sink segment for audio.
bool audio_sink_segment_destroyed;
std::unique_ptr<FakeSinkSegment> audio_sink_segment = FakeSinkSegment::Create(
[&audio_sink_segment_destroyed](FakeSinkSegment* sink_segment) {
audio_sink_segment_destroyed = true;
EXPECT_TRUE(sink_segment->disconnect_called_);
EXPECT_TRUE(sink_segment->will_deprovision_called_);
EXPECT_FALSE(sink_segment->TEST_provisioned());
});
FakeSinkSegment* audio_sink_segment_raw = audio_sink_segment.get();
EXPECT_FALSE(audio_sink_segment_raw->did_provision_called_);
EXPECT_FALSE(audio_sink_segment_raw->will_deprovision_called_);
EXPECT_FALSE(audio_sink_segment_raw->TEST_provisioned());
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kAudio));
player_core.SetSinkSegment(std::move(audio_sink_segment),
StreamType::Medium::kAudio);
EXPECT_TRUE(player_core.has_sink_segment(StreamType::Medium::kAudio));
EXPECT_FALSE(update_callback_called);
EXPECT_TRUE(audio_sink_segment_raw->did_provision_called_);
audio_sink_segment_raw->did_provision_called_ = false;
EXPECT_FALSE(audio_sink_segment_raw->will_deprovision_called_);
EXPECT_TRUE(audio_sink_segment_raw->TEST_provisioned());
EXPECT_TRUE(player_core.has_sink_segment(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kAudio));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kAudio));
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kVideo));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kVideo));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kVideo));
ExpectNoStreams(player_core, StreamType::Medium::kText);
ExpectNoStreams(player_core, StreamType::Medium::kSubpicture);
EXPECT_TRUE(audio_sink_segment_raw->connect_called_);
audio_sink_segment_raw->connect_called_ = false;
EXPECT_NE(nullptr, audio_sink_segment_raw->connect_call_param_type_);
ExpectEqual(&audio_type, audio_sink_segment_raw->connect_call_param_type_);
EXPECT_NE(nullptr, audio_sink_segment_raw->connect_call_param_callback_);
audio_sink_segment_raw->connected_ = true;
audio_sink_segment_raw->connect_call_param_callback_(Result::kOk);
EXPECT_TRUE(player_core.has_sink_segment(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.medium_connected(StreamType::Medium::kAudio));
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kVideo));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kVideo));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kVideo));
ExpectNoStreams(player_core, StreamType::Medium::kText);
ExpectNoStreams(player_core, StreamType::Medium::kSubpicture);
// Add a sink segment for video.
bool video_sink_segment_destroyed;
std::unique_ptr<FakeSinkSegment> video_sink_segment = FakeSinkSegment::Create(
[&video_sink_segment_destroyed](FakeSinkSegment* sink_segment) {
video_sink_segment_destroyed = true;
EXPECT_TRUE(sink_segment->disconnect_called_);
EXPECT_TRUE(sink_segment->will_deprovision_called_);
EXPECT_FALSE(sink_segment->TEST_provisioned());
});
FakeSinkSegment* video_sink_segment_raw = video_sink_segment.get();
EXPECT_FALSE(video_sink_segment_raw->did_provision_called_);
EXPECT_FALSE(video_sink_segment_raw->will_deprovision_called_);
EXPECT_FALSE(video_sink_segment_raw->TEST_provisioned());
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kVideo));
player_core.SetSinkSegment(std::move(video_sink_segment),
StreamType::Medium::kVideo);
EXPECT_TRUE(player_core.has_sink_segment(StreamType::Medium::kVideo));
EXPECT_FALSE(update_callback_called);
EXPECT_TRUE(video_sink_segment_raw->did_provision_called_);
video_sink_segment_raw->did_provision_called_ = false;
EXPECT_FALSE(video_sink_segment_raw->will_deprovision_called_);
EXPECT_TRUE(video_sink_segment_raw->TEST_provisioned());
EXPECT_TRUE(player_core.has_sink_segment(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.medium_connected(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.has_sink_segment(StreamType::Medium::kVideo));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kVideo));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kVideo));
ExpectNoStreams(player_core, StreamType::Medium::kText);
ExpectNoStreams(player_core, StreamType::Medium::kSubpicture);
EXPECT_TRUE(video_sink_segment_raw->connect_called_);
video_sink_segment_raw->connect_called_ = false;
EXPECT_NE(nullptr, video_sink_segment_raw->connect_call_param_type_);
ExpectEqual(&video_type, video_sink_segment_raw->connect_call_param_type_);
EXPECT_NE(nullptr, video_sink_segment_raw->connect_call_param_callback_);
video_sink_segment_raw->connected_ = true;
video_sink_segment_raw->connect_call_param_callback_(Result::kOk);
EXPECT_TRUE(player_core.has_sink_segment(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.medium_connected(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.has_sink_segment(StreamType::Medium::kVideo));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kVideo));
EXPECT_TRUE(player_core.medium_connected(StreamType::Medium::kVideo));
ExpectNoStreams(player_core, StreamType::Medium::kText);
ExpectNoStreams(player_core, StreamType::Medium::kSubpicture);
// Test Prime.
EXPECT_FALSE(audio_sink_segment_raw->prime_called_);
EXPECT_FALSE(video_sink_segment_raw->prime_called_);
bool prime_callback_called = false;
player_core.Prime(
[&prime_callback_called]() { prime_callback_called = true; });
EXPECT_FALSE(prime_callback_called);
EXPECT_TRUE(audio_sink_segment_raw->prime_called_);
audio_sink_segment_raw->prime_called_ = false;
EXPECT_TRUE(video_sink_segment_raw->prime_called_);
video_sink_segment_raw->prime_called_ = false;
EXPECT_NE(nullptr, audio_sink_segment_raw->prime_call_param_callback_);
EXPECT_NE(nullptr, video_sink_segment_raw->prime_call_param_callback_);
audio_sink_segment_raw->prime_call_param_callback_();
EXPECT_FALSE(prime_callback_called);
video_sink_segment_raw->prime_call_param_callback_();
RunLoopUntilIdle();
EXPECT_TRUE(prime_callback_called);
// Test Flush.
EXPECT_FALSE(source_segment_raw->flush_called_);
bool flush_callback_called = false;
player_core.Flush(
true, [&flush_callback_called]() { flush_callback_called = true; });
RunLoopUntilIdle();
EXPECT_TRUE(flush_callback_called);
EXPECT_TRUE(source_segment_raw->flush_called_);
source_segment_raw->flush_called_ = false;
EXPECT_EQ(true, source_segment_raw->flush_call_param_hold_frame_);
// Test SetTimelineFunction.
EXPECT_FALSE(audio_sink_segment_raw->set_timeline_function_called_);
EXPECT_FALSE(video_sink_segment_raw->set_timeline_function_called_);
media::TimelineFunction timeline_function(1, 2, 3, 4);
bool set_timeline_function_callback_called = false;
player_core.SetTimelineFunction(
timeline_function, [&set_timeline_function_callback_called]() {
set_timeline_function_callback_called = true;
});
EXPECT_FALSE(set_timeline_function_callback_called);
EXPECT_TRUE(audio_sink_segment_raw->set_timeline_function_called_);
audio_sink_segment_raw->set_timeline_function_called_ = false;
EXPECT_TRUE(video_sink_segment_raw->set_timeline_function_called_);
video_sink_segment_raw->set_timeline_function_called_ = false;
EXPECT_EQ(timeline_function,
audio_sink_segment_raw
->set_timeline_function_call_param_timeline_function_);
EXPECT_EQ(timeline_function,
video_sink_segment_raw
->set_timeline_function_call_param_timeline_function_);
EXPECT_NE(nullptr,
audio_sink_segment_raw->set_timeline_function_call_param_callback_);
EXPECT_NE(nullptr,
video_sink_segment_raw->set_timeline_function_call_param_callback_);
audio_sink_segment_raw->set_timeline_function_call_param_callback_();
EXPECT_FALSE(set_timeline_function_callback_called);
video_sink_segment_raw->set_timeline_function_call_param_callback_();
RunLoopUntilIdle();
EXPECT_TRUE(set_timeline_function_callback_called);
EXPECT_EQ(timeline_function, player_core.timeline_function());
// Test SetProgramRange.
EXPECT_FALSE(audio_sink_segment_raw->set_program_range_called_);
EXPECT_FALSE(video_sink_segment_raw->set_program_range_called_);
player_core.SetProgramRange(0, 1, 2);
EXPECT_TRUE(audio_sink_segment_raw->set_program_range_called_);
audio_sink_segment_raw->set_program_range_called_ = false;
EXPECT_TRUE(video_sink_segment_raw->set_program_range_called_);
video_sink_segment_raw->set_program_range_called_ = false;
EXPECT_EQ(0u, audio_sink_segment_raw->set_program_range_call_param_program_);
EXPECT_EQ(0u, video_sink_segment_raw->set_program_range_call_param_program_);
EXPECT_EQ(1, audio_sink_segment_raw->set_program_range_call_param_min_pts_);
EXPECT_EQ(1, video_sink_segment_raw->set_program_range_call_param_min_pts_);
EXPECT_EQ(2, audio_sink_segment_raw->set_program_range_call_param_max_pts_);
EXPECT_EQ(2, video_sink_segment_raw->set_program_range_call_param_max_pts_);
// Test Seek.
EXPECT_FALSE(source_segment_raw->seek_called_);
bool seek_callback_called = false;
player_core.Seek(1234,
[&seek_callback_called]() { seek_callback_called = true; });
EXPECT_FALSE(seek_callback_called);
EXPECT_TRUE(source_segment_raw->seek_called_);
source_segment_raw->seek_called_ = false;
EXPECT_EQ(1234, source_segment_raw->seek_call_param_position_);
EXPECT_NE(nullptr, source_segment_raw->seek_call_param_callback_);
source_segment_raw->seek_call_param_callback_();
RunLoopUntilIdle();
EXPECT_TRUE(seek_callback_called);
// Test end_of_stream.
EXPECT_FALSE(player_core.end_of_stream());
audio_sink_segment_raw->end_of_stream_ = true;
EXPECT_FALSE(player_core.end_of_stream());
video_sink_segment_raw->end_of_stream_ = true;
EXPECT_TRUE(player_core.end_of_stream());
// Remove the sink for audio.
EXPECT_FALSE(audio_sink_segment_raw->disconnect_called_);
EXPECT_FALSE(audio_sink_segment_raw->will_deprovision_called_);
EXPECT_FALSE(audio_sink_segment_destroyed);
player_core.SetSinkSegment(nullptr, StreamType::Medium::kAudio);
EXPECT_TRUE(audio_sink_segment_destroyed);
audio_sink_segment_raw = nullptr;
// The callback to Create above checks that the source segment was shut down
// properly.
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kAudio));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.has_sink_segment(StreamType::Medium::kVideo));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kVideo));
EXPECT_TRUE(player_core.medium_connected(StreamType::Medium::kVideo));
ExpectNoStreams(player_core, StreamType::Medium::kText);
ExpectNoStreams(player_core, StreamType::Medium::kSubpicture);
// Remove the sink for video.
EXPECT_FALSE(video_sink_segment_raw->disconnect_called_);
EXPECT_FALSE(video_sink_segment_raw->will_deprovision_called_);
EXPECT_FALSE(video_sink_segment_destroyed);
player_core.SetSinkSegment(nullptr, StreamType::Medium::kVideo);
EXPECT_TRUE(video_sink_segment_destroyed);
video_sink_segment_raw = nullptr;
// The callback to Create above checks that the source segment was shut down
// properly.
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kAudio));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kAudio));
EXPECT_FALSE(player_core.has_sink_segment(StreamType::Medium::kVideo));
EXPECT_TRUE(player_core.content_has_medium(StreamType::Medium::kVideo));
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kVideo));
ExpectNoStreams(player_core, StreamType::Medium::kText);
ExpectNoStreams(player_core, StreamType::Medium::kSubpicture);
// Remove the source.
EXPECT_FALSE(source_segment_raw->flush_called_);
EXPECT_FALSE(source_segment_destroyed);
player_core.ClearSourceSegment();
RunLoopUntilIdle();
EXPECT_TRUE(source_segment_destroyed);
source_segment_raw = nullptr;
// The callback to Create above checks that the source segment was shut down
// properly.
ExpectNoStreams(player_core);
EXPECT_FALSE(player_core.end_of_stream());
EXPECT_EQ(nullptr, player_core.metadata());
EXPECT_EQ(nullptr, player_core.problem());
EXPECT_NE(nullptr, player_core.graph());
EXPECT_EQ(NodeRef(), player_core.source_node());
}
// Expects the player_core to have built a graph based on the fake demux and
// renderers used with real source and sink segments.
void ExpectRealSegmentsGraph(const PlayerCore& player_core) {
// Check the source (demux) node.
NodeRef source_node_ref = player_core.source_node();
EXPECT_TRUE(source_node_ref);
EXPECT_EQ(0u, source_node_ref.input_count());
EXPECT_EQ(2u, source_node_ref.output_count());
EXPECT_EQ("FakeDemux", source_node_ref.GetNode()->label());
// Walk the audio segment. It has a decoder, an lpcm reformatter and a
// renderer.
NodeRef audio_decoder_node_ref = source_node_ref.output(0).mate().node();
EXPECT_TRUE(audio_decoder_node_ref);
EXPECT_EQ(1u, audio_decoder_node_ref.input_count());
EXPECT_EQ(1u, audio_decoder_node_ref.output_count());
EXPECT_TRUE(audio_decoder_node_ref.input().connected());
EXPECT_TRUE(audio_decoder_node_ref.output().connected());
EXPECT_EQ("FakeDecoder", audio_decoder_node_ref.GetNode()->label());
NodeRef audio_renderer_node_ref =
audio_decoder_node_ref.output().mate().node();
EXPECT_TRUE(audio_renderer_node_ref);
EXPECT_EQ(1u, audio_renderer_node_ref.input_count());
EXPECT_EQ(0u, audio_renderer_node_ref.output_count());
EXPECT_TRUE(audio_renderer_node_ref.input().connected());
EXPECT_EQ("FakeAudioRenderer", audio_renderer_node_ref.GetNode()->label());
// Walk the video segment. It has a decoder and a renderer.
NodeRef video_decoder_node_ref = source_node_ref.output(1).mate().node();
EXPECT_TRUE(video_decoder_node_ref);
EXPECT_EQ(1u, video_decoder_node_ref.input_count());
EXPECT_EQ(1u, video_decoder_node_ref.output_count());
EXPECT_TRUE(video_decoder_node_ref.input().connected());
EXPECT_TRUE(video_decoder_node_ref.output().connected());
EXPECT_EQ("FakeDecoder", video_decoder_node_ref.GetNode()->label());
NodeRef video_renderer_node_ref =
video_decoder_node_ref.output().mate().node();
EXPECT_TRUE(video_renderer_node_ref);
EXPECT_EQ(1u, video_renderer_node_ref.input_count());
EXPECT_EQ(0u, video_renderer_node_ref.output_count());
EXPECT_TRUE(video_renderer_node_ref.input().connected());
EXPECT_EQ("FakeVideoRenderer", video_renderer_node_ref.GetNode()->label());
// std::cout << "\n" << source_node_ref << "\n\n";
}
// Tests a player_core with real segments constructed source-first.
TEST_F(PlayerTest, BuildGraphWithRealSegmentsSourceFirst) {
PlayerCore player_core(dispatcher());
std::unique_ptr<DecoderFactory> decoder_factory =
DecoderFactory::Create(nullptr);
auto source_segment = DemuxSourceSegment::Create(FakeDemux::Create());
source_segment->Provision(player_core.graph(), dispatcher(), nullptr,
nullptr);
player_core.SetSourceSegment(std::move(source_segment), []() {});
player_core.SetSinkSegment(
RendererSinkSegment::Create(FakeAudioRenderer::Create(),
decoder_factory.get()),
StreamType::Medium::kAudio);
RunLoopUntilIdle();
EXPECT_TRUE(player_core.medium_connected(StreamType::Medium::kAudio));
player_core.SetSinkSegment(
RendererSinkSegment::Create(FakeVideoRenderer::Create(),
decoder_factory.get()),
StreamType::Medium::kVideo);
RunLoopUntilIdle();
EXPECT_TRUE(player_core.medium_connected(StreamType::Medium::kVideo));
ExpectRealSegmentsGraph(player_core);
}
// Tests a player_core with real segments constructed sinks-first.
TEST_F(PlayerTest, BuildGraphWithRealSegmentsSinksFirst) {
PlayerCore player_core(dispatcher());
std::unique_ptr<DecoderFactory> decoder_factory =
DecoderFactory::Create(nullptr);
player_core.SetSinkSegment(
RendererSinkSegment::Create(FakeAudioRenderer::Create(),
decoder_factory.get()),
StreamType::Medium::kAudio);
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kAudio));
player_core.SetSinkSegment(
RendererSinkSegment::Create(FakeVideoRenderer::Create(),
decoder_factory.get()),
StreamType::Medium::kVideo);
EXPECT_FALSE(player_core.medium_connected(StreamType::Medium::kVideo));
auto source_segment = DemuxSourceSegment::Create(FakeDemux::Create());
source_segment->Provision(player_core.graph(), dispatcher(), nullptr,
nullptr);
player_core.SetSourceSegment(std::move(source_segment), []() {});
RunLoopUntilIdle();
EXPECT_TRUE(player_core.medium_connected(StreamType::Medium::kAudio));
EXPECT_TRUE(player_core.medium_connected(StreamType::Medium::kVideo));
ExpectRealSegmentsGraph(player_core);
}
} // namespace test
} // namespace media_player