1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chromecast/media/cma/backend/proxy/cma_backend_proxy.h"
6 
7 #include <algorithm>
8 
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/notreached.h"
13 #include "chromecast/media/cma/backend/proxy/multizone_audio_decoder_proxy_impl.h"
14 #include "chromecast/public/media/decoder_config.h"
15 
16 namespace chromecast {
17 namespace media {
18 namespace {
19 
20 // The maximum allowed difference between the audio and video decoders used for
21 // the CmaBackendProxy.
22 // TODO(b/168748626): Determine the correct value for this variable
23 // experimentally.
24 int64_t kMaxAllowedPtsDrift = 500;
25 
26 }  // namespace
27 
CmaBackendProxy(std::unique_ptr<CmaBackend> delegated_video_pipeline)28 CmaBackendProxy::CmaBackendProxy(
29     std::unique_ptr<CmaBackend> delegated_video_pipeline)
30     : CmaBackendProxy(
31           std::move(delegated_video_pipeline),
32           base::BindOnce([]() -> std::unique_ptr<MultizoneAudioDecoderProxy> {
33             return std::make_unique<MultizoneAudioDecoderProxyImpl>();
34           })) {}
35 
CmaBackendProxy(std::unique_ptr<CmaBackend> delegated_video_pipeline,CmaBackendProxy::AudioDecoderFactoryCB audio_decoder_factory)36 CmaBackendProxy::CmaBackendProxy(
37     std::unique_ptr<CmaBackend> delegated_video_pipeline,
38     CmaBackendProxy::AudioDecoderFactoryCB audio_decoder_factory)
39     : delegated_video_pipeline_(std::move(delegated_video_pipeline)),
40       audio_decoder_factory_(std::move(audio_decoder_factory)) {
41   DCHECK(delegated_video_pipeline_);
42   DCHECK(audio_decoder_factory_);
43 }
44 
45 CmaBackendProxy::~CmaBackendProxy() = default;
46 
CreateAudioDecoder()47 CmaBackend::AudioDecoder* CmaBackendProxy::CreateAudioDecoder() {
48   DCHECK(!audio_decoder_);
49   DCHECK(audio_decoder_factory_);
50   audio_decoder_ = std::move(audio_decoder_factory_).Run();
51   return audio_decoder_.get();
52 }
53 
CreateVideoDecoder()54 CmaBackend::VideoDecoder* CmaBackendProxy::CreateVideoDecoder() {
55   has_video_decoder_ = true;
56   return delegated_video_pipeline_->CreateVideoDecoder();
57 }
58 
Initialize()59 bool CmaBackendProxy::Initialize() {
60   if (has_video_decoder_ && !delegated_video_pipeline_->Initialize()) {
61     return false;
62   }
63 
64   return !audio_decoder_ || audio_decoder_->Initialize();
65 }
66 
Start(int64_t start_pts)67 bool CmaBackendProxy::Start(int64_t start_pts) {
68   if (has_video_decoder_ && !delegated_video_pipeline_->Start(start_pts)) {
69     return false;
70   }
71 
72   return !audio_decoder_ || audio_decoder_->Start(start_pts);
73 }
74 
Stop()75 void CmaBackendProxy::Stop() {
76   if (has_video_decoder_) {
77     delegated_video_pipeline_->Stop();
78   }
79 
80   if (audio_decoder_) {
81     audio_decoder_->Stop();
82   }
83 }
84 
Pause()85 bool CmaBackendProxy::Pause() {
86   bool result = true;
87 
88   if (has_video_decoder_) {
89     result &= delegated_video_pipeline_->Pause();
90   }
91 
92   if (audio_decoder_) {
93     result &= audio_decoder_->Pause();
94   }
95 
96   return result;
97 }
98 
Resume()99 bool CmaBackendProxy::Resume() {
100   if (has_video_decoder_ && !delegated_video_pipeline_->Resume()) {
101     return false;
102   }
103 
104   return !audio_decoder_ || audio_decoder_->Resume();
105 }
106 
GetCurrentPts()107 int64_t CmaBackendProxy::GetCurrentPts() {
108   if (audio_decoder_ && has_video_decoder_) {
109     const int64_t audio_pts = audio_decoder_->GetCurrentPts();
110     const int64_t video_pts = delegated_video_pipeline_->GetCurrentPts();
111     const int64_t min = std::min(audio_pts, video_pts);
112     LOG_IF(WARNING, std::max(audio_pts, video_pts) - min > kMaxAllowedPtsDrift);
113     return min;
114   } else if (audio_decoder_) {
115     return audio_decoder_->GetCurrentPts();
116   } else if (has_video_decoder_) {
117     return delegated_video_pipeline_->GetCurrentPts();
118   } else {
119     return std::numeric_limits<int64_t>::min();
120   }
121 }
122 
SetPlaybackRate(float rate)123 bool CmaBackendProxy::SetPlaybackRate(float rate) {
124   bool result = true;
125 
126   if (has_video_decoder_) {
127     result &= delegated_video_pipeline_->SetPlaybackRate(rate);
128   }
129 
130   if (audio_decoder_) {
131     result &= audio_decoder_->SetPlaybackRate(rate);
132   }
133 
134   return result;
135 }
136 
LogicalPause()137 void CmaBackendProxy::LogicalPause() {
138   if (has_video_decoder_) {
139     delegated_video_pipeline_->LogicalPause();
140   }
141 
142   if (audio_decoder_) {
143     audio_decoder_->LogicalPause();
144   }
145 }
146 
LogicalResume()147 void CmaBackendProxy::LogicalResume() {
148   if (has_video_decoder_) {
149     delegated_video_pipeline_->LogicalResume();
150   }
151 
152   if (audio_decoder_) {
153     audio_decoder_->LogicalResume();
154   }
155 }
156 
157 }  // namespace media
158 }  // namespace chromecast
159