1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "RemoteAudioDecoder.h"
7
8 #include "RemoteDecoderManagerChild.h"
9 #include "OpusDecoder.h"
10 #include "VorbisDecoder.h"
11 #include "WAVDecoder.h"
12
13 #include "mozilla/PodOperations.h"
14
15 namespace mozilla {
16
RemoteAudioDecoderChild()17 RemoteAudioDecoderChild::RemoteAudioDecoderChild() : RemoteDecoderChild() {}
18
ProcessOutput(const DecodedOutputIPDL & aDecodedData)19 MediaResult RemoteAudioDecoderChild::ProcessOutput(
20 const DecodedOutputIPDL& aDecodedData) {
21 AssertOnManagerThread();
22 MOZ_ASSERT(aDecodedData.type() ==
23 DecodedOutputIPDL::TArrayOfRemoteAudioDataIPDL);
24 const nsTArray<RemoteAudioDataIPDL>& arrayData =
25 aDecodedData.get_ArrayOfRemoteAudioDataIPDL();
26
27 for (auto&& data : arrayData) {
28 AlignedAudioBuffer alignedAudioBuffer;
29 // Use std::min to make sure we can't overrun our buffer in case someone is
30 // fibbing about buffer sizes.
31 if (!alignedAudioBuffer.SetLength(
32 std::min((unsigned long)data.audioDataBufferSize(),
33 (unsigned long)data.buffer().Size<AudioDataValue>()))) {
34 // OOM
35 return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__);
36 }
37 PodCopy(alignedAudioBuffer.Data(), data.buffer().get<AudioDataValue>(),
38 alignedAudioBuffer.Length());
39
40 RefPtr<AudioData> audio = new AudioData(
41 data.base().offset(), data.base().time(), std::move(alignedAudioBuffer),
42 data.channels(), data.rate(), data.channelMap());
43
44 mDecodedData.AppendElement(std::move(audio));
45 }
46 return NS_OK;
47 }
48
InitIPDL(const AudioInfo & aAudioInfo,const CreateDecoderParams::OptionSet & aOptions)49 MediaResult RemoteAudioDecoderChild::InitIPDL(
50 const AudioInfo& aAudioInfo,
51 const CreateDecoderParams::OptionSet& aOptions) {
52 RefPtr<RemoteDecoderManagerChild> manager =
53 RemoteDecoderManagerChild::GetRDDProcessSingleton();
54
55 // The manager isn't available because RemoteDecoderManagerChild has been
56 // initialized with null end points and we don't want to decode video on RDD
57 // process anymore. Return false here so that we can fallback to other PDMs.
58 if (!manager) {
59 return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
60 RESULT_DETAIL("RemoteDecoderManager is not available."));
61 }
62
63 if (!manager->CanSend()) {
64 return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
65 RESULT_DETAIL("RemoteDecoderManager unable to send."));
66 }
67
68 mIPDLSelfRef = this;
69 bool success = false;
70 nsCString errorDescription;
71 Unused << manager->SendPRemoteDecoderConstructor(
72 this, aAudioInfo, aOptions, Nothing(), &success, &errorDescription);
73 return success ? MediaResult(NS_OK)
74 : MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, errorDescription);
75 }
76
RemoteAudioDecoderParent(RemoteDecoderManagerParent * aParent,const AudioInfo & aAudioInfo,const CreateDecoderParams::OptionSet & aOptions,TaskQueue * aManagerTaskQueue,TaskQueue * aDecodeTaskQueue,bool * aSuccess,nsCString * aErrorDescription)77 RemoteAudioDecoderParent::RemoteAudioDecoderParent(
78 RemoteDecoderManagerParent* aParent, const AudioInfo& aAudioInfo,
79 const CreateDecoderParams::OptionSet& aOptions,
80 TaskQueue* aManagerTaskQueue, TaskQueue* aDecodeTaskQueue, bool* aSuccess,
81 nsCString* aErrorDescription)
82 : RemoteDecoderParent(aParent, aManagerTaskQueue, aDecodeTaskQueue),
83 mAudioInfo(aAudioInfo) {
84 CreateDecoderParams params(mAudioInfo);
85 params.mTaskQueue = mDecodeTaskQueue;
86 params.mOptions = aOptions;
87 MediaResult error(NS_OK);
88 params.mError = &error;
89
90 if (VorbisDataDecoder::IsVorbis(params.mConfig.mMimeType)) {
91 mDecoder = new VorbisDataDecoder(params);
92 } else if (OpusDataDecoder::IsOpus(params.mConfig.mMimeType)) {
93 mDecoder = new OpusDataDecoder(params);
94 } else if (WaveDataDecoder::IsWave(params.mConfig.mMimeType)) {
95 mDecoder = new WaveDataDecoder(params);
96 }
97
98 if (NS_FAILED(error)) {
99 MOZ_ASSERT(aErrorDescription);
100 *aErrorDescription = error.Description();
101 }
102
103 *aSuccess = !!mDecoder;
104 }
105
ProcessDecodedData(const MediaDataDecoder::DecodedData & aData,DecodedOutputIPDL & aDecodedData)106 MediaResult RemoteAudioDecoderParent::ProcessDecodedData(
107 const MediaDataDecoder::DecodedData& aData,
108 DecodedOutputIPDL& aDecodedData) {
109 MOZ_ASSERT(OnManagerThread());
110
111 nsTArray<RemoteAudioDataIPDL> array;
112
113 for (const auto& data : aData) {
114 MOZ_ASSERT(data->mType == MediaData::Type::AUDIO_DATA,
115 "Can only decode audio using RemoteAudioDecoderParent!");
116 AudioData* audio = static_cast<AudioData*>(data.get());
117
118 MOZ_ASSERT(audio->Data().Elements(),
119 "Decoded audio must output an AlignedAudioBuffer "
120 "to be used with RemoteAudioDecoderParent");
121
122 ShmemBuffer buffer =
123 AllocateBuffer(audio->Data().Length() * sizeof(AudioDataValue));
124 if (!buffer.Valid()) {
125 return MediaResult(NS_ERROR_OUT_OF_MEMORY,
126 "ShmemBuffer::Get failed in "
127 "RemoteAudioDecoderParent::ProcessDecodedData");
128 }
129
130 PodCopy(buffer.Get().get<AudioDataValue>(), audio->Data().Elements(),
131 audio->Data().Length());
132
133 RemoteAudioDataIPDL output(
134 MediaDataIPDL(data->mOffset, data->mTime, data->mTimecode,
135 data->mDuration, data->mKeyframe),
136 audio->mChannels, audio->mRate, audio->mChannelMap,
137 audio->Data().Length(), std::move(buffer.Get()));
138 array.AppendElement(output);
139 }
140
141 // With the new possiblity of batch decodes, we can't always move the
142 // results directly into DecodedOutputIPDL. If there are already
143 // elements, we should append the new results.
144 if (aDecodedData.type() == DecodedOutputIPDL::TArrayOfRemoteAudioDataIPDL) {
145 aDecodedData.get_ArrayOfRemoteAudioDataIPDL().AppendElements(
146 std::move(array));
147 } else {
148 aDecodedData = std::move(array);
149 }
150
151 return NS_OK;
152 }
153
154 } // namespace mozilla
155