1// Copyright (c) 2012 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 "media/filters/audio_decoder_selector.h"
6
7#include "base/bind.h"
8#include "base/callback_helpers.h"
9#include "base/logging.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "media/base/audio_decoder_config.h"
12#include "media/base/bind_to_loop.h"
13#include "media/base/demuxer_stream.h"
14#include "media/base/pipeline.h"
15#include "media/filters/decrypting_audio_decoder.h"
16#include "media/filters/decrypting_demuxer_stream.h"
17
18namespace media {
19
20AudioDecoderSelector::AudioDecoderSelector(
21    const scoped_refptr<base::MessageLoopProxy>& message_loop,
22    ScopedVector<AudioDecoder> decoders,
23    const SetDecryptorReadyCB& set_decryptor_ready_cb)
24    : message_loop_(message_loop),
25      decoders_(decoders.Pass()),
26      set_decryptor_ready_cb_(set_decryptor_ready_cb),
27      input_stream_(NULL),
28      weak_ptr_factory_(this) {
29}
30
31AudioDecoderSelector::~AudioDecoderSelector() {
32  DVLOG(2) << __FUNCTION__;
33}
34
35void AudioDecoderSelector::SelectAudioDecoder(
36    DemuxerStream* stream,
37    const StatisticsCB& statistics_cb,
38    const SelectDecoderCB& select_decoder_cb) {
39  DVLOG(2) << __FUNCTION__;
40  DCHECK(message_loop_->BelongsToCurrentThread());
41  DCHECK(stream);
42
43  // Make sure |select_decoder_cb| runs on a different execution stack.
44  select_decoder_cb_ = BindToCurrentLoop(select_decoder_cb);
45
46  const AudioDecoderConfig& config = stream->audio_decoder_config();
47  if (!config.IsValidConfig()) {
48    DLOG(ERROR) << "Invalid audio stream config.";
49    ReturnNullDecoder();
50    return;
51  }
52
53  input_stream_ = stream;
54  statistics_cb_ = statistics_cb;
55
56  if (!config.is_encrypted()) {
57    InitializeDecoder();
58    return;
59  }
60
61  // This could happen if Encrypted Media Extension (EME) is not enabled.
62  if (set_decryptor_ready_cb_.is_null()) {
63    ReturnNullDecoder();
64    return;
65  }
66
67  audio_decoder_.reset(new DecryptingAudioDecoder(
68      message_loop_, set_decryptor_ready_cb_));
69
70  audio_decoder_->Initialize(
71      input_stream_,
72      base::Bind(&AudioDecoderSelector::DecryptingAudioDecoderInitDone,
73                 weak_ptr_factory_.GetWeakPtr()),
74      statistics_cb_);
75}
76
77void AudioDecoderSelector::Abort() {
78  DVLOG(2) << __FUNCTION__;
79  DCHECK(message_loop_->BelongsToCurrentThread());
80
81  // This could happen when SelectAudioDecoder() was not called or when
82  // |select_decoder_cb_| was already posted but not fired (e.g. in the
83  // message loop queue).
84  if (select_decoder_cb_.is_null())
85    return;
86
87  // We must be trying to initialize the |audio_decoder_| or the
88  // |decrypted_stream_|. Invalid all weak pointers so that all initialization
89  // callbacks won't fire.
90  weak_ptr_factory_.InvalidateWeakPtrs();
91
92  if (audio_decoder_) {
93    // AudioDecoder doesn't provide a Stop() method. Also, |decrypted_stream_|
94    // is either NULL or already initialized. We don't need to Stop()
95    // |decrypted_stream_| in either case.
96    ReturnNullDecoder();
97    return;
98  }
99
100  if (decrypted_stream_) {
101    decrypted_stream_->Stop(
102        base::Bind(&AudioDecoderSelector::ReturnNullDecoder,
103                   weak_ptr_factory_.GetWeakPtr()));
104    return;
105  }
106
107  NOTREACHED();
108}
109
110void AudioDecoderSelector::DecryptingAudioDecoderInitDone(
111    PipelineStatus status) {
112  DVLOG(2) << __FUNCTION__;
113  DCHECK(message_loop_->BelongsToCurrentThread());
114
115  if (status == PIPELINE_OK) {
116    base::ResetAndReturn(&select_decoder_cb_).Run(
117        audio_decoder_.Pass(), scoped_ptr<DecryptingDemuxerStream>());
118    return;
119  }
120
121  audio_decoder_.reset();
122
123  decrypted_stream_.reset(new DecryptingDemuxerStream(
124      message_loop_, set_decryptor_ready_cb_));
125
126  decrypted_stream_->Initialize(
127      input_stream_,
128      base::Bind(&AudioDecoderSelector::DecryptingDemuxerStreamInitDone,
129                 weak_ptr_factory_.GetWeakPtr()));
130}
131
132void AudioDecoderSelector::DecryptingDemuxerStreamInitDone(
133    PipelineStatus status) {
134  DVLOG(2) << __FUNCTION__;
135  DCHECK(message_loop_->BelongsToCurrentThread());
136
137  if (status != PIPELINE_OK) {
138    ReturnNullDecoder();
139    return;
140  }
141
142  DCHECK(!decrypted_stream_->audio_decoder_config().is_encrypted());
143  input_stream_ = decrypted_stream_.get();
144  InitializeDecoder();
145}
146
147void AudioDecoderSelector::InitializeDecoder() {
148  DVLOG(2) << __FUNCTION__;
149  DCHECK(message_loop_->BelongsToCurrentThread());
150  DCHECK(!audio_decoder_);
151
152  if (decoders_.empty()) {
153    ReturnNullDecoder();
154    return;
155  }
156
157  audio_decoder_.reset(decoders_.front());
158  decoders_.weak_erase(decoders_.begin());
159
160  audio_decoder_->Initialize(input_stream_,
161                             base::Bind(&AudioDecoderSelector::DecoderInitDone,
162                                        weak_ptr_factory_.GetWeakPtr()),
163                             statistics_cb_);
164}
165
166void AudioDecoderSelector::DecoderInitDone(PipelineStatus status) {
167  DVLOG(2) << __FUNCTION__;
168  DCHECK(message_loop_->BelongsToCurrentThread());
169
170  if (status != PIPELINE_OK) {
171    audio_decoder_.reset();
172    InitializeDecoder();
173    return;
174  }
175
176  base::ResetAndReturn(&select_decoder_cb_).Run(audio_decoder_.Pass(),
177                                                decrypted_stream_.Pass());
178}
179
180void AudioDecoderSelector::ReturnNullDecoder() {
181  DVLOG(2) << __FUNCTION__;
182  DCHECK(message_loop_->BelongsToCurrentThread());
183  base::ResetAndReturn(&select_decoder_cb_).Run(
184      scoped_ptr<AudioDecoder>(), scoped_ptr<DecryptingDemuxerStream>());
185}
186
187}  // namespace media
188