1 // Copyright 2014 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.
5 #include "chromecast/media/cma/pipeline/audio_pipeline_impl.h"
8 #include "chromecast/media/cma/backend/audio_pipeline_device.h"
9 #include "chromecast/media/cma/base/buffering_defs.h"
10 #include "chromecast/media/cma/base/cma_logging.h"
11 #include "chromecast/media/cma/base/coded_frame_provider.h"
12 #include "chromecast/media/cma/base/decoder_config_adapter.h"
13 #include "chromecast/media/cma/pipeline/av_pipeline_impl.h"
14 #include "chromecast/public/media/decoder_config.h"
15 #include "media/base/audio_decoder_config.h"
17 namespace chromecast
{
21 const size_t kMaxAudioFrameSize
= 32 * 1024;
24 AudioPipelineImpl::AudioPipelineImpl(AudioPipelineDevice
* audio_device
)
25 : audio_device_(audio_device
),
27 av_pipeline_impl_
.reset(new AvPipelineImpl(
29 base::Bind(&AudioPipelineImpl::OnUpdateConfig
, base::Unretained(this))));
30 weak_this_
= weak_factory_
.GetWeakPtr();
33 AudioPipelineImpl::~AudioPipelineImpl() {
36 void AudioPipelineImpl::SetCodedFrameProvider(
37 scoped_ptr
<CodedFrameProvider
> frame_provider
) {
38 av_pipeline_impl_
->SetCodedFrameProvider(
39 frame_provider
.Pass(), kAppAudioBufferSize
, kMaxAudioFrameSize
);
42 void AudioPipelineImpl::SetClient(const AvPipelineClient
& client
) {
43 audio_client_
= client
;
44 av_pipeline_impl_
->SetClient(client
);
47 bool AudioPipelineImpl::StartPlayingFrom(
49 const scoped_refptr
<BufferingState
>& buffering_state
) {
50 CMALOG(kLogControl
) << "AudioPipelineImpl::StartPlayingFrom t0="
51 << time
.InMilliseconds();
53 // Reset the pipeline statistics.
54 previous_stats_
= ::media::PipelineStatistics();
57 if (av_pipeline_impl_
->GetState() == AvPipelineImpl::kError
)
59 DCHECK_EQ(av_pipeline_impl_
->GetState(), AvPipelineImpl::kFlushed
);
61 if (!av_pipeline_impl_
->StartPlayingFrom(time
, buffering_state
)) {
62 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kError
);
65 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kPlaying
);
70 void AudioPipelineImpl::Flush(const ::media::PipelineStatusCB
& status_cb
) {
71 CMALOG(kLogControl
) << "AudioPipelineImpl::Flush";
72 if (av_pipeline_impl_
->GetState() == AvPipelineImpl::kError
) {
73 status_cb
.Run(::media::PIPELINE_ERROR_ABORT
);
76 DCHECK_EQ(av_pipeline_impl_
->GetState(), AvPipelineImpl::kPlaying
);
77 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kFlushing
);
78 av_pipeline_impl_
->Flush(
79 base::Bind(&AudioPipelineImpl::OnFlushDone
, weak_this_
, status_cb
));
82 void AudioPipelineImpl::OnFlushDone(
83 const ::media::PipelineStatusCB
& status_cb
) {
84 CMALOG(kLogControl
) << "AudioPipelineImpl::OnFlushDone";
85 if (av_pipeline_impl_
->GetState() == AvPipelineImpl::kError
) {
86 status_cb
.Run(::media::PIPELINE_ERROR_ABORT
);
89 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kFlushed
);
90 status_cb
.Run(::media::PIPELINE_OK
);
93 void AudioPipelineImpl::Stop() {
94 CMALOG(kLogControl
) << "AudioPipelineImpl::Stop";
95 av_pipeline_impl_
->Stop();
96 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kStopped
);
99 void AudioPipelineImpl::SetCdm(BrowserCdmCast
* media_keys
) {
100 av_pipeline_impl_
->SetCdm(media_keys
);
103 void AudioPipelineImpl::Initialize(
104 const ::media::AudioDecoderConfig
& audio_config
,
105 scoped_ptr
<CodedFrameProvider
> frame_provider
,
106 const ::media::PipelineStatusCB
& status_cb
) {
107 CMALOG(kLogControl
) << "AudioPipelineImpl::Initialize "
108 << audio_config
.AsHumanReadableString();
110 SetCodedFrameProvider(frame_provider
.Pass());
112 DCHECK(audio_config
.IsValidConfig());
113 if (!audio_device_
->SetConfig(
114 DecoderConfigAdapter::ToCastAudioConfig(kPrimary
, audio_config
)) ||
115 !av_pipeline_impl_
->Initialize()) {
116 status_cb
.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED
);
119 av_pipeline_impl_
->TransitionToState(AvPipelineImpl::kFlushed
);
120 status_cb
.Run(::media::PIPELINE_OK
);
123 void AudioPipelineImpl::SetVolume(float volume
) {
124 audio_device_
->SetStreamVolumeMultiplier(volume
);
127 void AudioPipelineImpl::OnUpdateConfig(
129 const ::media::AudioDecoderConfig
& audio_config
,
130 const ::media::VideoDecoderConfig
& video_config
) {
131 if (audio_config
.IsValidConfig()) {
132 CMALOG(kLogControl
) << "AudioPipelineImpl::OnUpdateConfig id:" << id
<< " "
133 << audio_config
.AsHumanReadableString();
135 bool success
= audio_device_
->SetConfig(
136 DecoderConfigAdapter::ToCastAudioConfig(id
, audio_config
));
137 if (!success
&& !audio_client_
.playback_error_cb
.is_null())
138 audio_client_
.playback_error_cb
.Run(::media::PIPELINE_ERROR_DECODE
);
142 void AudioPipelineImpl::UpdateStatistics() {
143 if (audio_client_
.statistics_cb
.is_null())
146 MediaComponentDevice::Statistics device_stats
;
147 if (!audio_device_
->GetStatistics(&device_stats
))
150 ::media::PipelineStatistics current_stats
;
151 current_stats
.audio_bytes_decoded
= device_stats
.decoded_bytes
;
153 ::media::PipelineStatistics delta_stats
;
154 delta_stats
.audio_bytes_decoded
=
155 current_stats
.audio_bytes_decoded
- previous_stats_
.audio_bytes_decoded
;
157 previous_stats_
= current_stats
;
159 audio_client_
.statistics_cb
.Run(delta_stats
);
163 } // namespace chromecast