1 // Copyright 2016 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/mojo/services/mojo_audio_decoder_service.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/logging.h"
12 #include "media/base/content_decryption_module.h"
13 #include "media/mojo/common/media_type_converters.h"
14 #include "media/mojo/common/mojo_decoder_buffer_converter.h"
15 #include "media/mojo/services/mojo_cdm_service_context.h"
16 
17 namespace media {
18 
MojoAudioDecoderService(MojoCdmServiceContext * mojo_cdm_service_context,std::unique_ptr<media::AudioDecoder> decoder)19 MojoAudioDecoderService::MojoAudioDecoderService(
20     MojoCdmServiceContext* mojo_cdm_service_context,
21     std::unique_ptr<media::AudioDecoder> decoder)
22     : mojo_cdm_service_context_(mojo_cdm_service_context),
23       decoder_(std::move(decoder)) {
24   DCHECK(mojo_cdm_service_context_);
25   weak_this_ = weak_factory_.GetWeakPtr();
26 }
27 
28 MojoAudioDecoderService::~MojoAudioDecoderService() = default;
29 
Construct(mojo::PendingAssociatedRemote<mojom::AudioDecoderClient> client)30 void MojoAudioDecoderService::Construct(
31     mojo::PendingAssociatedRemote<mojom::AudioDecoderClient> client) {
32   DVLOG(1) << __func__;
33   client_.Bind(std::move(client));
34 }
35 
Initialize(const AudioDecoderConfig & config,const base::Optional<base::UnguessableToken> & cdm_id,InitializeCallback callback)36 void MojoAudioDecoderService::Initialize(
37     const AudioDecoderConfig& config,
38     const base::Optional<base::UnguessableToken>& cdm_id,
39     InitializeCallback callback) {
40   DVLOG(1) << __func__ << " " << config.AsHumanReadableString();
41 
42   // |cdm_context_ref_| must be kept as long as |cdm_context| is used by the
43   // |decoder_|. We do NOT support resetting |cdm_context_ref_| because in
44   // general we don't support resetting CDM in the media pipeline.
45   if (cdm_id) {
46     if (!cdm_id_) {
47       DCHECK(!cdm_context_ref_);
48       cdm_id_ = cdm_id;
49       cdm_context_ref_ =
50           mojo_cdm_service_context_->GetCdmContextRef(cdm_id.value());
51     } else if (cdm_id != cdm_id_) {
52       // TODO(xhwang): Replace with mojo::ReportBadMessage().
53       NOTREACHED() << "The caller should not switch CDM";
54       OnInitialized(std::move(callback),
55                     StatusCode::kDecoderMissingCdmForEncryptedContent);
56       return;
57     }
58   }
59 
60   // Get CdmContext, which could be null.
61   CdmContext* cdm_context =
62       cdm_context_ref_ ? cdm_context_ref_->GetCdmContext() : nullptr;
63 
64   if (config.is_encrypted() && !cdm_context) {
65     DVLOG(1) << "CdmContext for "
66              << CdmContext::CdmIdToString(base::OptionalOrNullptr(cdm_id))
67              << " not found for encrypted audio";
68     OnInitialized(std::move(callback),
69                   StatusCode::kDecoderMissingCdmForEncryptedContent);
70     return;
71   }
72 
73   decoder_->Initialize(
74       config, cdm_context,
75       base::BindOnce(&MojoAudioDecoderService::OnInitialized, weak_this_,
76                      std::move(callback)),
77       base::Bind(&MojoAudioDecoderService::OnAudioBufferReady, weak_this_),
78       base::Bind(&MojoAudioDecoderService::OnWaiting, weak_this_));
79 }
80 
SetDataSource(mojo::ScopedDataPipeConsumerHandle receive_pipe)81 void MojoAudioDecoderService::SetDataSource(
82     mojo::ScopedDataPipeConsumerHandle receive_pipe) {
83   DVLOG(1) << __func__;
84 
85   mojo_decoder_buffer_reader_.reset(
86       new MojoDecoderBufferReader(std::move(receive_pipe)));
87 }
88 
Decode(mojom::DecoderBufferPtr buffer,DecodeCallback callback)89 void MojoAudioDecoderService::Decode(mojom::DecoderBufferPtr buffer,
90                                      DecodeCallback callback) {
91   DVLOG(3) << __func__;
92   mojo_decoder_buffer_reader_->ReadDecoderBuffer(
93       std::move(buffer), base::BindOnce(&MojoAudioDecoderService::OnReadDone,
94                                         weak_this_, std::move(callback)));
95 }
96 
Reset(ResetCallback callback)97 void MojoAudioDecoderService::Reset(ResetCallback callback) {
98   DVLOG(1) << __func__;
99 
100   // Reset the reader so that pending decodes will be dispatches first.
101   mojo_decoder_buffer_reader_->Flush(
102       base::BindOnce(&MojoAudioDecoderService::OnReaderFlushDone, weak_this_,
103                      std::move(callback)));
104 }
105 
OnInitialized(InitializeCallback callback,Status status)106 void MojoAudioDecoderService::OnInitialized(InitializeCallback callback,
107                                             Status status) {
108   DVLOG(1) << __func__ << " success:" << status.is_ok();
109 
110   if (!status.is_ok()) {
111     // Do not call decoder_->NeedsBitstreamConversion() if init failed.
112     std::move(callback).Run(std::move(status), false);
113     return;
114   }
115 
116   std::move(callback).Run(std::move(status),
117                           decoder_->NeedsBitstreamConversion());
118 }
119 
120 // The following methods are needed so that we can bind them with a weak pointer
121 // to avoid running the |callback| after connection error happens and |this| is
122 // deleted. It's not safe to run the |callback| after a connection error.
123 
OnReadDone(DecodeCallback callback,scoped_refptr<DecoderBuffer> buffer)124 void MojoAudioDecoderService::OnReadDone(DecodeCallback callback,
125                                          scoped_refptr<DecoderBuffer> buffer) {
126   DVLOG(3) << __func__ << " success:" << !!buffer;
127 
128   if (!buffer) {
129     std::move(callback).Run(DecodeStatus::DECODE_ERROR);
130     return;
131   }
132 
133   decoder_->Decode(buffer, base::Bind(&MojoAudioDecoderService::OnDecodeStatus,
134                                       weak_this_, base::Passed(&callback)));
135 }
136 
OnReaderFlushDone(ResetCallback callback)137 void MojoAudioDecoderService::OnReaderFlushDone(ResetCallback callback) {
138   decoder_->Reset(base::BindOnce(&MojoAudioDecoderService::OnResetDone,
139                                  weak_this_, std::move(callback)));
140 }
141 
OnDecodeStatus(DecodeCallback callback,const Status status)142 void MojoAudioDecoderService::OnDecodeStatus(DecodeCallback callback,
143                                              const Status status) {
144   DVLOG(3) << __func__ << " status:" << status.code();
145   std::move(callback).Run(std::move(status));
146 }
147 
OnResetDone(ResetCallback callback)148 void MojoAudioDecoderService::OnResetDone(ResetCallback callback) {
149   DVLOG(1) << __func__;
150   std::move(callback).Run();
151 }
152 
OnAudioBufferReady(scoped_refptr<AudioBuffer> audio_buffer)153 void MojoAudioDecoderService::OnAudioBufferReady(
154     scoped_refptr<AudioBuffer> audio_buffer) {
155   DVLOG(1) << __func__;
156 
157   // TODO(timav): Use DataPipe.
158   client_->OnBufferDecoded(mojom::AudioBuffer::From(*audio_buffer));
159 }
160 
OnWaiting(WaitingReason reason)161 void MojoAudioDecoderService::OnWaiting(WaitingReason reason) {
162   DVLOG(1) << __func__;
163   client_->OnWaiting(reason);
164 }
165 
166 }  // namespace media
167