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