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