From 1e0103b402e1b333a43f8b27a6db6f7a4536f3fb Mon Sep 17 00:00:00 2001 From: Tyler Holcombe Date: Wed, 11 Dec 2024 01:09:55 +0000 Subject: [PATCH 1/5] Disable Vulkan for Cobalt (#4552) b/371272304 --- cobalt/cobalt.cc | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/cobalt/cobalt.cc b/cobalt/cobalt.cc index 69d8ce25830ec..877226e4f6e97 100644 --- a/cobalt/cobalt.cc +++ b/cobalt/cobalt.cc @@ -28,22 +28,23 @@ int main(int argc, const char** argv) { // TODO: (cobalt b/375241103) Reimplement this in a clean way. - constexpr auto cobalt_args = std::to_array({ - // Disable first run experience, kiosk, etc. - "--disable-fre", "--no-first-run", "--kiosk", - // Enable Blink to work in overlay video mode - "--force-video-overlays", - // Disable multiprocess mode. - "--single-process", - // TODO(mcasas): Add "--ozone-platform=starboard". - // Enable remote Devtools access. - "--remote-debugging-port=9222", - "--remote-allow-origins=http://localhost:9222", - // This flag is added specifically for m114 and should be removed after - // rebasing to m120+ - "--user-level-memory-pressure-signal-params", - "https://www.youtube.com/tv" - }); + constexpr auto cobalt_args = std::to_array( + {// Disable first run experience, kiosk, etc. + "--disable-fre", "--no-first-run", "--kiosk", + // Enable Blink to work in overlay video mode + "--force-video-overlays", + // Disable multiprocess mode. + "--single-process", + // Disable Vulkan. + "--disable-features=Vulkan", + // TODO(mcasas): Add "--ozone-platform=starboard". + // Enable remote Devtools access. + "--remote-debugging-port=9222", + "--remote-allow-origins=http://localhost:9222", + // This flag is added specifically for m114 and should be removed after + // rebasing to m120+ + "--user-level-memory-pressure-signal-params", + "https://www.youtube.com/tv"}); std::vector args(argv, argv + argc); args.insert(args.end(), cobalt_args.begin(), cobalt_args.end()); From f337d65daaa27636dd14545915050aac26d5c097 Mon Sep 17 00:00:00 2001 From: Yavor Goulishev Date: Tue, 10 Dec 2024 19:31:16 -0800 Subject: [PATCH 2/5] Enable nplb on Linux. (#4543) b/378879686 --- .github/actions/build/action.yaml | 2 +- .github/actions/on_host_tests/action.yaml | 2 +- cobalt/build/configs/BUILD.gn | 5 ----- cobalt/testing/linux/nplb_filter.json | 13 +++++++++++++ starboard/common/test_main.cc | 21 ++++++++++++++------- 5 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 cobalt/testing/linux/nplb_filter.json diff --git a/.github/actions/build/action.yaml b/.github/actions/build/action.yaml index d186f25449e5d..e1ff24b2f25a7 100644 --- a/.github/actions/build/action.yaml +++ b/.github/actions/build/action.yaml @@ -65,7 +65,7 @@ runs: run: | set -x cd src - tar cvf - out/${{ matrix.platform }}_${{ matrix.config }}/*tests out/${{ matrix.platform }}_${{ matrix.config }}/*.so out/${{ matrix.platform }}_${{ matrix.config }}/*.so.* out/${{ matrix.platform }}_${{ matrix.config }}/starboard/*.so.* | xz -T0 -1 -z - > test_artifacts.tar.xz + tar cvf - out/${{ matrix.platform }}_${{ matrix.config }}/*tests out/${{ matrix.platform }}_${{ matrix.config }}/nplb out/${{ matrix.platform }}_${{ matrix.config }}/*.so out/${{ matrix.platform }}_${{ matrix.config }}/*.so.* out/${{ matrix.platform }}_${{ matrix.config }}/starboard/*.so.* out/${{ matrix.platform }}_${{ matrix.config }}/content/test | xz -T0 -1 -z - > test_artifacts.tar.xz shell: bash - name: Upload Test artifacts if: startsWith(matrix.platform, 'linux') && matrix.config == 'devel' diff --git a/.github/actions/on_host_tests/action.yaml b/.github/actions/on_host_tests/action.yaml index 371f932606a24..55105b3921952 100644 --- a/.github/actions/on_host_tests/action.yaml +++ b/.github/actions/on_host_tests/action.yaml @@ -38,7 +38,7 @@ runs: export LD_LIBRARY_PATH="${GITHUB_WORKSPACE}"/unit_test/out/${{ matrix.platform }}_${{ matrix.config }}/starboard:"${GITHUB_WORKSPACE}"/unit_test/out/${{ matrix.platform }}_${{ matrix.config }} cd ${GITHUB_WORKSPACE}/unit_test - for test_binary in $(ls -d out/**/*tests); do + for test_binary in $(ls -d out/**/*tests out/**/nplb); do # TODO(b/372303096): Need dedicated xvfb runner. echo "Running tests for suite: ${test_binary}" diff --git a/cobalt/build/configs/BUILD.gn b/cobalt/build/configs/BUILD.gn index 8fecc74e25f97..c74188b0c22db 100644 --- a/cobalt/build/configs/BUILD.gn +++ b/cobalt/build/configs/BUILD.gn @@ -22,11 +22,6 @@ config("cobalt_config") { if (current_toolchain == starboard_toolchain) { configs += [ "//${starboard_path}/platform_configuration" ] } - - defines = [ - "ENABLE_BUILDFLAG_IS_COBALT", - "OS_STARBOARD", - ] } config("default_includes") { diff --git a/cobalt/testing/linux/nplb_filter.json b/cobalt/testing/linux/nplb_filter.json new file mode 100644 index 0000000000000..c5d6feeb3bddd --- /dev/null +++ b/cobalt/testing/linux/nplb_filter.json @@ -0,0 +1,13 @@ +{ + "failing_tests": [ + "SbDrmTest.AnySupportedKeySystems", + "SbMediaCanPlayMimeAndKeySystem.AnySupportedKeySystems", + "SbSystemGetLocaleIdTest.SunnyDay", + "SbMediaSetAudioWriteDurationTests/SbMediaSetAudioWriteDurationTest.*", + "MultiplePlayerTests/MultiplePlayerTest.*", + "SbPlayerGetAudioConfigurationTests/SbPlayerGetAudioConfigurationTest.*", + "SbPlayerGetMediaTimeTests/SbPlayerGetMediaTimeTest.*", + "SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.*", + "VerticalVideoTests/VerticalVideoTest.*" + ] +} diff --git a/starboard/common/test_main.cc b/starboard/common/test_main.cc index 94da2f171f557..f0e590b9956b2 100644 --- a/starboard/common/test_main.cc +++ b/starboard/common/test_main.cc @@ -13,12 +13,12 @@ // limitations under the License. #include "starboard/configuration.h" -#include "testing/gtest/include/gtest/gtest.h" -#if SB_IS(EVERGREEN) +#include "build/build_config.h" #include "starboard/client_porting/wrap_main/wrap_main.h" #include "starboard/event.h" #include "starboard/system.h" +#include "testing/gtest/include/gtest/gtest.h" namespace { int InitAndRunAllTests(int argc, char** argv) { @@ -27,12 +27,19 @@ int InitAndRunAllTests(int argc, char** argv) { } } // namespace -// When we are building Evergreen we need to export SbEventHandle so that the -// ELF loader can find and invoke it. +#if BUILDFLAG(IS_STARBOARD) +// For the Starboard OS define SbEventHandle as the entry point SB_EXPORT STARBOARD_WRAP_SIMPLE_MAIN(InitAndRunAllTests); + +#if !SB_IS(EVERGREEN) +// Define main() for non-Evergreen Starboard OS. +int main(int argc, char** argv) { + return SbRunStarboardMain(argc, argv, SbEventHandle); +} +#endif // !SB_IS(EVERGREEN) #else +// If the OS is not Starboard use the regular main e.g. ATV. int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + return InitAndRunAllTests(argc, argv); } -#endif +#endif // BUILDFLAG(IS_STARBOARD) From 43d0507ff11804ffae9ce414e8b91704a77e7888 Mon Sep 17 00:00:00 2001 From: Austin Osagie Date: Wed, 11 Dec 2024 11:44:19 -0800 Subject: [PATCH 3/5] [media] Change local and remote audio write durations (#4501) This change sets the audio write ahead duration for local audio sinks to 0.5s, and the audio write ahead duration for remote audio sinks to 10s. b/326652276 --- content/renderer/media/media_factory.cc | 16 +- media/starboard/BUILD.gn | 3 - media/starboard/starboard_renderer.cc | 179 ++++++++++++++++-- media/starboard/starboard_renderer.h | 65 +++++-- media/starboard/starboard_renderer_factory.cc | 13 +- media/starboard/starboard_renderer_factory.h | 8 +- 6 files changed, 250 insertions(+), 34 deletions(-) diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc index 0ecfe9253ebd5..4a4d8d97ddc05 100644 --- a/content/renderer/media/media_factory.cc +++ b/content/renderer/media/media_factory.cc @@ -144,6 +144,17 @@ namespace { // to be many of those. See http://crbug.com/1232649 constexpr size_t kDefaultMaxWebMediaPlayers = 1000; +#if BUILDFLAG(USE_STARBOARD_MEDIA) +// The following variables match |kSbPlayerWriteDurationLocal| +// and |kSbplayerWriteDurationRemote| in //starboard/player.h. +// +// The audio write duration when all the audio connectors are local. +const base::TimeDelta kWriteDurationLocal = base::Milliseconds(500); +// The audio write duration when at least one of the audio connectors are +// remote. +const base::TimeDelta kWriteDurationRemote = base::Seconds(10); +#endif // BUILDFLAG(USE_STARBOARD_MEDIA) + size_t GetMaxWebMediaPlayers() { static const size_t kMaxWebMediaPlayers = []() { auto* command_line = base::CommandLine::ForCurrentProcess(); @@ -752,7 +763,10 @@ MediaFactory::CreateRendererFactorySelector( // TODO(b/326827007): Revisit renderer to support secondary videos. factory_selector->AddFactory( RendererType::kStarboard, - std::make_unique(media_log)); + std::make_unique( + media_log, + // TODO: b/383327725 - Cobalt: Inject these values from the web app. + kWriteDurationLocal, kWriteDurationRemote)); factory_selector->SetBaseRendererType(RendererType::kStarboard); #else // BUILDFLAG(USE_STARBOARD_MEDIA) auto renderer_impl_factory = CreateRendererImplFactory( diff --git a/media/starboard/BUILD.gn b/media/starboard/BUILD.gn index 4dd119dcc3e38..9edff19095623 100644 --- a/media/starboard/BUILD.gn +++ b/media/starboard/BUILD.gn @@ -21,9 +21,6 @@ source_set("starboard") { visibility = [ "//media" ] defines = [ - # TODO(b/326652276): Support audio write ahead - "COBALT_MEDIA_ENABLE_AUDIO_DURATION=0", - # TODO(b/326508279): Revisit background mode "COBALT_MEDIA_ENABLE_BACKGROUND_MODE=0", diff --git a/media/starboard/starboard_renderer.cc b/media/starboard/starboard_renderer.cc index 959bd5a99e9c4..b9f033f7cc71b 100644 --- a/media/starboard/starboard_renderer.cc +++ b/media/starboard/starboard_renderer.cc @@ -24,6 +24,18 @@ namespace media { namespace { +using ::starboard::GetMediaAudioConnectorName; + +// In the OnNeedData(), it attempts to write one more audio access +// unit than the audio write duration. Specifically, the check +// |time_ahead_of_playback_for_preroll| > |adjusted_write_duration_for_preroll| +// is used to skip audio writing, using '>' instead of '>='. +// Since the calculated write duration during preroll may align exactly +// with the audio write duration, the current check can fail, leading to an +// additional call to SbPlayerWriteSamples(). By writing an extra guard audio +// buffer, this extra write during preroll can be eliminated. +const int kPrerollGuardAudioBuffer = 1; + bool HasRemoteAudioOutputs( const std::vector& configurations) { for (auto&& configuration : configurations) { @@ -36,14 +48,14 @@ bool HasRemoteAudioOutputs( case kSbMediaAudioConnectorSpdif: case kSbMediaAudioConnectorUsb: LOG(INFO) << "Encountered local audio connector: " - << starboard::GetMediaAudioConnectorName(connector); + << GetMediaAudioConnectorName(connector); break; case kSbMediaAudioConnectorBluetooth: case kSbMediaAudioConnectorRemoteWired: case kSbMediaAudioConnectorRemoteWireless: case kSbMediaAudioConnectorRemoteOther: LOG(INFO) << "Encountered remote audio connector: " - << starboard::GetMediaAudioConnectorName(connector); + << GetMediaAudioConnectorName(connector); return true; } } @@ -53,16 +65,57 @@ bool HasRemoteAudioOutputs( return false; } +// The function adjusts audio write duration proportionally to the playback +// rate, when the playback rate is greater than 1.0. +// +// Having the right write duration is important: +// 1. Too small of it causes audio underflow. +// 2. Too large of it causes excessive audio switch latency. +// When playback rate is 2x, an 0.5 seconds of write duration effectively only +// lasts for 0.25 seconds and causes audio underflow, and the function will +// adjust it to 1 second in this case. +TimeDelta AdjustWriteDurationForPlaybackRate(TimeDelta write_duration, + float playback_rate) { + if (playback_rate <= 1.0) { + return write_duration; + } + + return write_duration * playback_rate; +} + +// The function returns the default frames per DecoderBuffer. +// +// The number of frames is used to estimate the number of samples per write for +// audio preroll according to |audio_write_duration_|. +int GetDefaultAudioFramesPerBuffer(AudioCodec codec) { + switch (codec) { + case AudioCodec::kOpus: + return 960; + case AudioCodec::kAAC: + return 1024; + case AudioCodec::kAC3: + case AudioCodec::kEAC3: + return 1536; + default: + NOTREACHED(); + return 1; + } +} + } // namespace StarboardRenderer::StarboardRenderer( const scoped_refptr& task_runner, VideoRendererSink* video_renderer_sink, - MediaLog* media_log) + MediaLog* media_log, + TimeDelta audio_write_duration_local, + TimeDelta audio_write_duration_remote) : state_(STATE_UNINITIALIZED), task_runner_(task_runner), video_renderer_sink_(video_renderer_sink), media_log_(media_log), + audio_write_duration_local_(audio_write_duration_local), + audio_write_duration_remote_(audio_write_duration_remote), video_overlay_factory_(std::make_unique()), set_bounds_helper_(new SbPlayerSetBoundsHelper), cdm_context_(nullptr) { @@ -229,7 +282,7 @@ void StarboardRenderer::Flush(base::OnceClosure flush_cb) { } } -void StarboardRenderer::StartPlayingFrom(base::TimeDelta time) { +void StarboardRenderer::StartPlayingFrom(TimeDelta time) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); LOG(INFO) << "StarboardRenderer::StartPlayingFrom() called with " << time @@ -237,6 +290,18 @@ void StarboardRenderer::StartPlayingFrom(base::TimeDelta time) { LOG_IF(WARNING, time < base::Seconds(0)) << "Potentially invalid start time " << time << '.'; + timestamp_of_last_written_audio_ = TimeDelta(); + is_video_eos_written_ = false; + StoreMediaTime(time); + // Ignore pending delayed calls to OnNeedData, and update variables used to + // decide when to delay. + audio_read_delayed_ = false; + + { + base::AutoLock auto_lock(lock_); + seek_time_ = time; + } + if (state_ != STATE_FLUSHED) { DCHECK_EQ(state_, STATE_ERROR); return; @@ -301,15 +366,16 @@ void StarboardRenderer::SetVolume(float volume) { } // TODO(b/376328722): Revisit playback time reporting. -base::TimeDelta StarboardRenderer::GetMediaTime() { +TimeDelta StarboardRenderer::GetMediaTime() { base::AutoLock auto_lock(lock_); if (!player_bridge_) { + StoreMediaTime(TimeDelta()); return base::Microseconds(0); } uint32_t video_frames_decoded, video_frames_dropped; - base::TimeDelta media_time; + TimeDelta media_time; player_bridge_->GetInfo(&video_frames_decoded, &video_frames_dropped, &media_time); @@ -338,6 +404,7 @@ base::TimeDelta StarboardRenderer::GetMediaTime() { FROM_HERE, base::BindOnce(&RendererClient::OnStatisticsUpdate, base::Unretained(client_), statistics)); } + StoreMediaTime(media_time); return media_time; } @@ -416,12 +483,12 @@ void StarboardRenderer::CreatePlayerBridge() { // TODO(b/267678497): When `player_bridge_->GetAudioConfigurations()` // returns no audio configurations, update the write durations again // before the SbPlayer reaches `kSbPlayerStatePresenting`. - audio_write_duration_ = + audio_write_duration_for_preroll_ = audio_write_duration_ = HasRemoteAudioOutputs(player_bridge_->GetAudioConfigurations()) ? audio_write_duration_remote_ : audio_write_duration_local_; LOG(INFO) << "SbPlayerBridge created, with audio write duration at " - << audio_write_duration_; + << audio_write_duration_for_preroll_; } else { error_message = player_bridge_->GetPlayerCreationErrorMessage(); player_bridge_.reset(); @@ -445,14 +512,14 @@ void StarboardRenderer::CreatePlayerBridge() { return; } - LOG(INFO) << "SbPlayerPipeline::CreatePlayerBridge() failed to create a" + LOG(INFO) << "StarboardRenderer::CreatePlayerBridge() failed to create a" " valid SbPlayerBridge - \"" << error_message << "\""; state_ = STATE_ERROR; std::move(init_cb_).Run(PipelineStatus( DECODER_ERROR_NOT_SUPPORTED, - "SbPlayerPipeline::CreatePlayerBridge() failed to create a valid" + "StarboardRenderer::CreatePlayerBridge() failed to create a valid" " SbPlayerBridge - \"" + error_message + "\"")); } @@ -524,10 +591,20 @@ void StarboardRenderer::OnDemuxerStreamRead( if (stream == audio_stream_) { DCHECK(audio_read_in_progress_); audio_read_in_progress_ = false; + for (const auto& buffer : buffers) { + last_audio_sample_interval_ = + buffer->timestamp() - timestamp_of_last_written_audio_; + timestamp_of_last_written_audio_ = buffer->timestamp(); + } player_bridge_->WriteBuffers(DemuxerStream::AUDIO, buffers); } else { DCHECK(video_read_in_progress_); video_read_in_progress_ = false; + for (const auto& buffer : buffers) { + if (buffer->end_of_stream()) { + is_video_eos_written_ = true; + } + } player_bridge_->WriteBuffers(DemuxerStream::VIDEO, buffers); } } else if (status == DemuxerStream::kAborted) { @@ -594,7 +671,6 @@ void StarboardRenderer::OnNeedData(DemuxerStream::Type type, return; } -#if COBALT_MEDIA_ENABLE_AUDIO_DURATION // If we haven't checked the media time recently, update it now. if (Time::Now() - last_time_media_time_retrieved_ > kMediaTimeCheckInterval) { @@ -605,7 +681,7 @@ void StarboardRenderer::OnNeedData(DemuxerStream::Type type, // after the player has received enough audio for preroll, taking into // account that our estimate of playback time might be behind by // |kMediaTimeCheckInterval|. - base::TimeDelta time_ahead_of_playback_for_preroll = + TimeDelta time_ahead_of_playback_for_preroll = timestamp_of_last_written_audio_ - seek_time_; auto adjusted_write_duration_for_preroll = AdjustWriteDurationForPlaybackRate(audio_write_duration_for_preroll_, @@ -631,7 +707,8 @@ void StarboardRenderer::OnNeedData(DemuxerStream::Type type, (adjusted_write_duration + kMediaTimeCheckInterval)) { task_runner_->PostDelayedTask( FROM_HERE, - base::Bind(&SbPlayerPipeline::DelayedNeedData, this, max_buffers), + base::BindOnce(&StarboardRenderer::DelayedNeedData, weak_this_, + max_buffers), kMediaTimeCheckInterval); audio_read_delayed_ = true; return; @@ -660,7 +737,6 @@ void StarboardRenderer::OnNeedData(DemuxerStream::Type type, max_buffers = std::min(max_buffers, estimated_max_buffers); audio_read_delayed_ = false; -#endif // COBALT_MEDIA_ENABLE_AUDIO_DURATION audio_read_in_progress_ = true; } else { DCHECK_EQ(type, DemuxerStream::VIDEO); @@ -713,7 +789,7 @@ void StarboardRenderer::OnPlayerStatus(SbPlayerState state) { case kSbPlayerStatePresenting: client_->OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, BUFFERING_CHANGE_REASON_UNKNOWN); - audio_write_duration_ = + audio_write_duration_for_preroll_ = audio_write_duration_ = HasRemoteAudioOutputs(player_bridge_->GetAudioConfigurations()) ? audio_write_duration_remote_ : audio_write_duration_local_; @@ -765,4 +841,77 @@ void StarboardRenderer::OnPlayerError(SbPlayerError error, } } +void StarboardRenderer::DelayedNeedData(int max_number_of_buffers_to_write) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + if (audio_read_delayed_) { + OnNeedData(DemuxerStream::AUDIO, max_number_of_buffers_to_write); + } +} + +void StarboardRenderer::StoreMediaTime(TimeDelta media_time) { + last_media_time_ = media_time; + last_time_media_time_retrieved_ = Time::Now(); +} + +int StarboardRenderer::GetDefaultMaxBuffers(AudioCodec codec, + TimeDelta duration_to_write, + bool is_preroll) { + // Return default maximum samples per write to speed up the initial sample + // write, including guard number of samples per write for audio preroll. + // The guard number kPrerollGuardAudioBuffer is used to ensure Cobalt + // can do one initial write for audio preroll. + int default_max_buffers = static_cast( + std::ceil(duration_to_write.InSecondsF() * + audio_stream_->audio_decoder_config().samples_per_second() / + GetDefaultAudioFramesPerBuffer(codec))); + if (is_preroll) { + default_max_buffers += kPrerollGuardAudioBuffer; + } + DCHECK_GT(default_max_buffers, 0); + return default_max_buffers; +} + +int StarboardRenderer::GetEstimatedMaxBuffers(TimeDelta write_duration, + TimeDelta time_ahead_of_playback, + bool is_preroll) { + DCHECK_GE(time_ahead_of_playback.InMicroseconds(), 0); + + int estimated_max_buffers = 1; + if (!(max_audio_samples_per_write_ > 1) || + write_duration <= time_ahead_of_playback) { + return estimated_max_buffers; + } + + TimeDelta duration_to_write = write_duration - time_ahead_of_playback; + DCHECK_GT(duration_to_write.InMicroseconds(), 0); + switch (audio_stream_->audio_decoder_config().codec()) { + case AudioCodec::kOpus: + case AudioCodec::kAAC: + case AudioCodec::kAC3: + case AudioCodec::kEAC3: + if (last_audio_sample_interval_.is_zero()) { + estimated_max_buffers = + GetDefaultMaxBuffers(audio_stream_->audio_decoder_config().codec(), + duration_to_write, is_preroll); + break; + } + // TODO(b/41486346): Support multiple samples per write on the format IAMF. + // case AudioCodec::kIAMF: + default: + if (!last_audio_sample_interval_.is_zero()) { + DCHECK_GT(last_audio_sample_interval_.InMicroseconds(), 0); + estimated_max_buffers = + duration_to_write.InMillisecondsRoundedUp() / + last_audio_sample_interval_.InMilliseconds() + + 1; + } + } + DCHECK_GT(estimated_max_buffers, 0); + // Return 1 if |estimated_max_buffers| is non-positive. This ensures + // in corner cases, |estimated_max_buffers| falls back to 1. + // The maximum number samples of write should be guarded by + // SbPlayerGetMaximumNumberOfSamplesPerWrite() in OnNeedData(). + return estimated_max_buffers > 0 ? estimated_max_buffers : 1; +} + } // namespace media diff --git a/media/starboard/starboard_renderer.h b/media/starboard/starboard_renderer.h index 5b8b30ad31d53..eece9a751ea92 100644 --- a/media/starboard/starboard_renderer.h +++ b/media/starboard/starboard_renderer.h @@ -39,6 +39,9 @@ namespace media { +using base::Time; +using base::TimeDelta; + // SbPlayer based Renderer implementation, the entry point for all video // playbacks on Starboard platforms. class MEDIA_EXPORT StarboardRenderer final : public Renderer, @@ -46,7 +49,9 @@ class MEDIA_EXPORT StarboardRenderer final : public Renderer, public: StarboardRenderer(const scoped_refptr& task_runner, VideoRendererSink* video_renderer_sink, - MediaLog* media_log); + MediaLog* media_log, + TimeDelta audio_write_duration_local, + TimeDelta audio_write_duration_remote); ~StarboardRenderer() final; @@ -55,15 +60,15 @@ class MEDIA_EXPORT StarboardRenderer final : public Renderer, RendererClient* client, PipelineStatusCallback init_cb) final; void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) final; - void SetLatencyHint(absl::optional latency_hint) final { + void SetLatencyHint(absl::optional latency_hint) final { // TODO(b/380935131): Consider to implement `LatencyHint` for SbPlayer. NOTIMPLEMENTED(); } void Flush(base::OnceClosure flush_cb) final; - void StartPlayingFrom(base::TimeDelta time) final; + void StartPlayingFrom(TimeDelta time) final; void SetPlaybackRate(double playback_rate) final; void SetVolume(float volume) final; - base::TimeDelta GetMediaTime() final; + TimeDelta GetMediaTime() final; RendererType GetRendererType() final { return RendererType::kStarboard; } SetBoundsCB GetSetBoundsCB() override; @@ -88,6 +93,23 @@ class MEDIA_EXPORT StarboardRenderer final : public Renderer, void OnPlayerStatus(SbPlayerState state) final; void OnPlayerError(SbPlayerError error, const std::string& message) final; + // Used to make a delayed call to OnNeedData() if |audio_read_delayed_| is + // true. If |audio_read_delayed_| is false, that means the delayed call has + // been cancelled due to a seek. + void DelayedNeedData(int max_number_of_buffers_to_write); + + // Store the media time retrieved by GetMediaTime so we can cache it as an + // estimate and avoid calling SbPlayerGetInfo too frequently. + void StoreMediaTime(TimeDelta media_time); + + int GetDefaultMaxBuffers(AudioCodec codec, + TimeDelta duration_to_write, + bool is_preroll); + + int GetEstimatedMaxBuffers(TimeDelta write_duration, + TimeDelta time_ahead_of_playback, + bool is_preroll); + State state_; scoped_refptr task_runner_; @@ -113,24 +135,45 @@ class MEDIA_EXPORT StarboardRenderer final : public Renderer, raw_ptr cdm_context_; DefaultSbPlayerInterface sbplayer_interface_; - // TODO(b/326652276): Support audio write duration. - const base::TimeDelta audio_write_duration_local_ = base::Milliseconds(500); - const base::TimeDelta audio_write_duration_remote_ = base::Seconds(10); + + TimeDelta seek_time_; + + const TimeDelta audio_write_duration_local_; + const TimeDelta audio_write_duration_remote_; + // The two variables below should always contain the same value. They are + // kept as separate variables so we can keep the existing implementation as + // is, which simplifies the implementation across multiple Starboard versions. + TimeDelta audio_write_duration_; + TimeDelta audio_write_duration_for_preroll_ = audio_write_duration_; + // Only call GetMediaTime() from OnNeedData if it has been + // |kMediaTimeCheckInterval| since the last call to GetMediaTime(). + static constexpr TimeDelta kMediaTimeCheckInterval = base::Microseconds(100); + // Timestamp for the last written audio. + TimeDelta timestamp_of_last_written_audio_; + // Indicates if video end of stream has been written into the underlying + // player. + bool is_video_eos_written_ = false; + TimeDelta last_audio_sample_interval_ = base::Microseconds(0); + int last_estimated_max_buffers_for_preroll_ = 1; + // Last media time reported by GetMediaTime(). + TimeDelta last_media_time_; + // Timestamp microseconds when we last checked the media time. + Time last_time_media_time_retrieved_; + + bool audio_read_delayed_ = false; // TODO(b/375674101): Support batched samples write. const int max_audio_samples_per_write_ = 1; SbDrmSystem drm_system_{kSbDrmSystemInvalid}; - base::Lock lock_; + mutable base::Lock lock_; std::unique_ptr player_bridge_; bool player_bridge_initialized_ = false; - std::optional playing_start_from_time_; + std::optional playing_start_from_time_; base::OnceClosure pending_flush_cb_; - base::TimeDelta audio_write_duration_ = audio_write_duration_local_; - bool audio_read_in_progress_ = false; bool video_read_in_progress_ = false; diff --git a/media/starboard/starboard_renderer_factory.cc b/media/starboard/starboard_renderer_factory.cc index d819c63fa133b..f72b0472e5098 100644 --- a/media/starboard/starboard_renderer_factory.cc +++ b/media/starboard/starboard_renderer_factory.cc @@ -16,12 +16,18 @@ #include "base/check.h" #include "base/task/sequenced_task_runner.h" +#include "base/time/time.h" #include "media/starboard/starboard_renderer.h" namespace media { -StarboardRendererFactory::StarboardRendererFactory(MediaLog* media_log) - : media_log_(media_log) {} +StarboardRendererFactory::StarboardRendererFactory( + MediaLog* media_log, + base::TimeDelta audio_write_duration_local, + base::TimeDelta audio_write_duration_remote) + : media_log_(media_log), + audio_write_duration_local_(audio_write_duration_local), + audio_write_duration_remote_(audio_write_duration_remote) {} StarboardRendererFactory::~StarboardRendererFactory() = default; @@ -35,7 +41,8 @@ std::unique_ptr StarboardRendererFactory::CreateRenderer( DCHECK(video_renderer_sink); DCHECK(media_log_); return std::make_unique( - media_task_runner, video_renderer_sink, media_log_); + media_task_runner, video_renderer_sink, media_log_, + audio_write_duration_local_, audio_write_duration_remote_); } } // namespace media diff --git a/media/starboard/starboard_renderer_factory.h b/media/starboard/starboard_renderer_factory.h index 753d7a3a7b9fa..8ff866ff0b875 100644 --- a/media/starboard/starboard_renderer_factory.h +++ b/media/starboard/starboard_renderer_factory.h @@ -17,6 +17,7 @@ #include "base/memory/raw_ptr.h" #include "base/task/sequenced_task_runner.h" +#include "base/time/time.h" #include "media/base/media_log.h" #include "media/base/renderer_factory.h" @@ -25,7 +26,10 @@ namespace media { // Creates Renderers using Starboard. class MEDIA_EXPORT StarboardRendererFactory final : public RendererFactory { public: - explicit StarboardRendererFactory(MediaLog* media_log); + explicit StarboardRendererFactory( + MediaLog* media_log, + base::TimeDelta audio_write_duration_local, + base::TimeDelta audio_write_duration_remote); StarboardRendererFactory(const StarboardRendererFactory&) = delete; StarboardRendererFactory& operator=(const StarboardRendererFactory&) = delete; @@ -43,6 +47,8 @@ class MEDIA_EXPORT StarboardRendererFactory final : public RendererFactory { private: raw_ptr media_log_; + const base::TimeDelta audio_write_duration_local_; + const base::TimeDelta audio_write_duration_remote_; }; } // namespace media From 89303c21d393761d373cc20d2a61109db1e3be2f Mon Sep 17 00:00:00 2001 From: Brian Ting Date: Tue, 19 Nov 2024 14:37:36 -0800 Subject: [PATCH 4/5] derp --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d97abb225b3a4..f02a969b2cd66 100644 --- a/DEPS +++ b/DEPS @@ -261,10 +261,10 @@ vars = { # Fetch configuration files required for the 'use_remoteexec' gn arg 'download_remoteexec_cfg': False, # RBE instance to use for running remote builds - 'rbe_instance': Str('projects/rbe-chrome-untrusted/instances/default_instance'), + 'rbe_instance': Str('projects/cobalt-actions-devel/instances/default_instance'), # RBE project to download rewrapper config files for. Only needed if # different from the project used in 'rbe_instance' - 'rewrapper_cfg_project': Str(''), + 'rewrapper_cfg_project': Str('rbe-chrome-untrusted'), # reclient CIPD package 'reclient_package': 'infra/rbe/client/', # reclient CIPD package version From dce5faa5ae4314400372f85ef18230515dde74f0 Mon Sep 17 00:00:00 2001 From: Brian Ting Date: Wed, 11 Dec 2024 15:10:31 -0800 Subject: [PATCH 5/5] fix docker compose --- docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 656d567a5ec33..1bd9a0de3d133 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,8 +4,8 @@ services: build: context: cobalt/docker/linux cache_from: - - ghcr.io/youtube/cobalt/linux:latest - image: ghcr.io/youtube/cobalt/linux:latest + - ghcr.io/youtube/cobalt_sandbox/linux:latest + image: ghcr.io/youtube/cobalt_sandbox/linux:latest platform: linux/amd64 environment: - DEPOT_TOOLS_UPDATE=0