1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 
7 #include "AppleATDecoder.h"
8 #include "Adts.h"
9 #include "AppleUtils.h"
10 #include "MP4Decoder.h"
11 #include "MediaInfo.h"
12 #include "VideoUtils.h"
13 #include "mozilla/Logging.h"
14 #include "mozilla/SyncRunnable.h"
15 #include "mozilla/UniquePtr.h"
16 #include "nsTArray.h"
17 
18 #define LOG(...) DDMOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, __VA_ARGS__)
19 #define LOGEX(_this, ...) \
20   DDMOZ_LOGEX(_this, sPDMLog, mozilla::LogLevel::Debug, __VA_ARGS__)
21 #define FourCC2Str(n) \
22   ((char[5]){(char)(n >> 24), (char)(n >> 16), (char)(n >> 8), (char)(n), 0})
23 
24 namespace mozilla {
25 
AppleATDecoder(const AudioInfo & aConfig)26 AppleATDecoder::AppleATDecoder(const AudioInfo& aConfig)
27     : mConfig(aConfig),
28       mFileStreamError(false),
29       mConverter(nullptr),
30       mOutputFormat(),
31       mStream(nullptr),
32       mParsedFramesForAACMagicCookie(0),
33       mErrored(false) {
34   MOZ_COUNT_CTOR(AppleATDecoder);
35   LOG("Creating Apple AudioToolbox decoder");
36   LOG("Audio Decoder configuration: %s %d Hz %d channels %d bits per channel",
37       mConfig.mMimeType.get(), mConfig.mRate, mConfig.mChannels,
38       mConfig.mBitDepth);
39 
40   if (mConfig.mMimeType.EqualsLiteral("audio/mpeg")) {
41     mFormatID = kAudioFormatMPEGLayer3;
42   } else if (mConfig.mMimeType.EqualsLiteral("audio/mp4a-latm")) {
43     mFormatID = kAudioFormatMPEG4AAC;
44   } else {
45     mFormatID = 0;
46   }
47 }
48 
~AppleATDecoder()49 AppleATDecoder::~AppleATDecoder() {
50   MOZ_COUNT_DTOR(AppleATDecoder);
51   MOZ_ASSERT(!mConverter);
52 }
53 
Init()54 RefPtr<MediaDataDecoder::InitPromise> AppleATDecoder::Init() {
55   if (!mFormatID) {
56     return InitPromise::CreateAndReject(
57         MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
58                     RESULT_DETAIL("Non recognised format")),
59         __func__);
60   }
61   mThread = GetCurrentSerialEventTarget();
62 
63   return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__);
64 }
65 
Flush()66 RefPtr<MediaDataDecoder::FlushPromise> AppleATDecoder::Flush() {
67   MOZ_ASSERT(mThread->IsOnCurrentThread());
68   LOG("Flushing AudioToolbox AAC decoder");
69   mQueuedSamples.Clear();
70   mDecodedSamples.Clear();
71 
72   if (mConverter) {
73     OSStatus rv = AudioConverterReset(mConverter);
74     if (rv) {
75       LOG("Error %d resetting AudioConverter", static_cast<int>(rv));
76     }
77   }
78   if (mErrored) {
79     mParsedFramesForAACMagicCookie = 0;
80     mMagicCookie.Clear();
81     ProcessShutdown();
82     mErrored = false;
83   }
84   return FlushPromise::CreateAndResolve(true, __func__);
85 }
86 
Drain()87 RefPtr<MediaDataDecoder::DecodePromise> AppleATDecoder::Drain() {
88   MOZ_ASSERT(mThread->IsOnCurrentThread());
89   LOG("Draining AudioToolbox AAC decoder");
90   return DecodePromise::CreateAndResolve(DecodedData(), __func__);
91 }
92 
Shutdown()93 RefPtr<ShutdownPromise> AppleATDecoder::Shutdown() {
94   // mThread may not be set if Init hasn't been called first.
95   MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
96   ProcessShutdown();
97   return ShutdownPromise::CreateAndResolve(true, __func__);
98 }
99 
ProcessShutdown()100 void AppleATDecoder::ProcessShutdown() {
101   // mThread may not be set if Init hasn't been called first.
102   MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
103 
104   if (mStream) {
105     OSStatus rv = AudioFileStreamClose(mStream);
106     if (rv) {
107       LOG("error %d disposing of AudioFileStream", static_cast<int>(rv));
108       return;
109     }
110     mStream = nullptr;
111   }
112 
113   if (mConverter) {
114     LOG("Shutdown: Apple AudioToolbox AAC decoder");
115     OSStatus rv = AudioConverterDispose(mConverter);
116     if (rv) {
117       LOG("error %d disposing of AudioConverter", static_cast<int>(rv));
118     }
119     mConverter = nullptr;
120   }
121 }
122 
123 struct PassthroughUserData {
124   UInt32 mChannels;
125   UInt32 mDataSize;
126   const void* mData;
127   AudioStreamPacketDescription mPacket;
128 };
129 
130 // Error value we pass through the decoder to signal that nothing
131 // has gone wrong during decoding and we're done processing the packet.
132 const uint32_t kNoMoreDataErr = 'MOAR';
133 
_PassthroughInputDataCallback(AudioConverterRef aAudioConverter,UInt32 * aNumDataPackets,AudioBufferList * aData,AudioStreamPacketDescription ** aPacketDesc,void * aUserData)134 static OSStatus _PassthroughInputDataCallback(
135     AudioConverterRef aAudioConverter, UInt32* aNumDataPackets /* in/out */,
136     AudioBufferList* aData /* in/out */,
137     AudioStreamPacketDescription** aPacketDesc, void* aUserData) {
138   PassthroughUserData* userData = (PassthroughUserData*)aUserData;
139   if (!userData->mDataSize) {
140     *aNumDataPackets = 0;
141     return kNoMoreDataErr;
142   }
143 
144   if (aPacketDesc) {
145     userData->mPacket.mStartOffset = 0;
146     userData->mPacket.mVariableFramesInPacket = 0;
147     userData->mPacket.mDataByteSize = userData->mDataSize;
148     *aPacketDesc = &userData->mPacket;
149   }
150 
151   aData->mBuffers[0].mNumberChannels = userData->mChannels;
152   aData->mBuffers[0].mDataByteSize = userData->mDataSize;
153   aData->mBuffers[0].mData = const_cast<void*>(userData->mData);
154 
155   // No more data to provide following this run.
156   userData->mDataSize = 0;
157 
158   return noErr;
159 }
160 
Decode(MediaRawData * aSample)161 RefPtr<MediaDataDecoder::DecodePromise> AppleATDecoder::Decode(
162     MediaRawData* aSample) {
163   MOZ_ASSERT(mThread->IsOnCurrentThread());
164   LOG("mp4 input sample %p %lld us %lld pts%s %llu bytes audio", aSample,
165       aSample->mDuration.ToMicroseconds(), aSample->mTime.ToMicroseconds(),
166       aSample->mKeyframe ? " keyframe" : "",
167       (unsigned long long)aSample->Size());
168 
169   MediaResult rv = NS_OK;
170   if (!mConverter) {
171     rv = SetupDecoder(aSample);
172     if (rv != NS_OK && rv != NS_ERROR_NOT_INITIALIZED) {
173       return DecodePromise::CreateAndReject(rv, __func__);
174     }
175   }
176 
177   mQueuedSamples.AppendElement(aSample);
178 
179   if (rv == NS_OK) {
180     for (size_t i = 0; i < mQueuedSamples.Length(); i++) {
181       rv = DecodeSample(mQueuedSamples[i]);
182       if (NS_FAILED(rv)) {
183         mErrored = true;
184         return DecodePromise::CreateAndReject(rv, __func__);
185       }
186     }
187     mQueuedSamples.Clear();
188   }
189 
190   DecodedData results = std::move(mDecodedSamples);
191   mDecodedSamples = DecodedData();
192   return DecodePromise::CreateAndResolve(std::move(results), __func__);
193 }
194 
DecodeSample(MediaRawData * aSample)195 MediaResult AppleATDecoder::DecodeSample(MediaRawData* aSample) {
196   MOZ_ASSERT(mThread->IsOnCurrentThread());
197 
198   // Array containing the queued decoded audio frames, about to be output.
199   nsTArray<AudioDataValue> outputData;
200   UInt32 channels = mOutputFormat.mChannelsPerFrame;
201   // Pick a multiple of the frame size close to a power of two
202   // for efficient allocation.
203   const uint32_t MAX_AUDIO_FRAMES = 128;
204   const uint32_t maxDecodedSamples = MAX_AUDIO_FRAMES * channels;
205 
206   // Descriptions for _decompressed_ audio packets. ignored.
207   auto packets = MakeUnique<AudioStreamPacketDescription[]>(MAX_AUDIO_FRAMES);
208 
209   // This API insists on having packets spoon-fed to it from a callback.
210   // This structure exists only to pass our state.
211   PassthroughUserData userData = {channels, (UInt32)aSample->Size(),
212                                   aSample->Data()};
213 
214   // Decompressed audio buffer
215   AlignedAudioBuffer decoded(maxDecodedSamples);
216   if (!decoded) {
217     return NS_ERROR_OUT_OF_MEMORY;
218   }
219 
220   do {
221     AudioBufferList decBuffer;
222     decBuffer.mNumberBuffers = 1;
223     decBuffer.mBuffers[0].mNumberChannels = channels;
224     decBuffer.mBuffers[0].mDataByteSize =
225         maxDecodedSamples * sizeof(AudioDataValue);
226     decBuffer.mBuffers[0].mData = decoded.get();
227 
228     // in: the max number of packets we can handle from the decoder.
229     // out: the number of packets the decoder is actually returning.
230     UInt32 numFrames = MAX_AUDIO_FRAMES;
231 
232     OSStatus rv = AudioConverterFillComplexBuffer(
233         mConverter, _PassthroughInputDataCallback, &userData,
234         &numFrames /* in/out */, &decBuffer, packets.get());
235 
236     if (rv && rv != kNoMoreDataErr) {
237       LOG("Error decoding audio sample: %d\n", static_cast<int>(rv));
238       return MediaResult(
239           NS_ERROR_DOM_MEDIA_DECODE_ERR,
240           RESULT_DETAIL("Error decoding audio sample: %d @ %lld",
241                         static_cast<int>(rv), aSample->mTime.ToMicroseconds()));
242     }
243 
244     if (numFrames) {
245       outputData.AppendElements(decoded.get(), numFrames * channels);
246     }
247 
248     if (rv == kNoMoreDataErr) {
249       break;
250     }
251   } while (true);
252 
253   if (outputData.IsEmpty()) {
254     return NS_OK;
255   }
256 
257   size_t numFrames = outputData.Length() / channels;
258   int rate = mOutputFormat.mSampleRate;
259   media::TimeUnit duration = FramesToTimeUnit(numFrames, rate);
260   if (!duration.IsValid()) {
261     NS_WARNING("Invalid count of accumulated audio samples");
262     return MediaResult(
263         NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
264         RESULT_DETAIL(
265             "Invalid count of accumulated audio samples: num:%llu rate:%d",
266             uint64_t(numFrames), rate));
267   }
268 
269 #ifdef LOG_SAMPLE_DECODE
270   LOG("pushed audio at time %lfs; duration %lfs\n",
271       (double)aSample->mTime / USECS_PER_S, duration.ToSeconds());
272 #endif
273 
274   AudioSampleBuffer data(outputData.Elements(), outputData.Length());
275   if (!data.Data()) {
276     return NS_ERROR_OUT_OF_MEMORY;
277   }
278   if (mChannelLayout && !mAudioConverter) {
279     AudioConfig in(*mChannelLayout, channels, rate);
280     AudioConfig out(AudioConfig::ChannelLayout::SMPTEDefault(*mChannelLayout),
281                     channels, rate);
282     mAudioConverter = MakeUnique<AudioConverter>(in, out);
283   }
284   if (mAudioConverter && mChannelLayout && mChannelLayout->IsValid()) {
285     MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
286     data = mAudioConverter->Process(std::move(data));
287   }
288 
289   RefPtr<AudioData> audio = new AudioData(
290       aSample->mOffset, aSample->mTime, data.Forget(), channels, rate,
291       mChannelLayout && mChannelLayout->IsValid()
292           ? mChannelLayout->Map()
293           : AudioConfig::ChannelLayout::UNKNOWN_MAP);
294   MOZ_DIAGNOSTIC_ASSERT(duration == audio->mDuration, "must be equal");
295   mDecodedSamples.AppendElement(std::move(audio));
296   return NS_OK;
297 }
298 
GetInputAudioDescription(AudioStreamBasicDescription & aDesc,const nsTArray<uint8_t> & aExtraData)299 MediaResult AppleATDecoder::GetInputAudioDescription(
300     AudioStreamBasicDescription& aDesc, const nsTArray<uint8_t>& aExtraData) {
301   MOZ_ASSERT(mThread->IsOnCurrentThread());
302 
303   // Request the properties from CoreAudio using the codec magic cookie
304   AudioFormatInfo formatInfo;
305   PodZero(&formatInfo.mASBD);
306   formatInfo.mASBD.mFormatID = mFormatID;
307   if (mFormatID == kAudioFormatMPEG4AAC) {
308     formatInfo.mASBD.mFormatFlags = mConfig.mExtendedProfile;
309   }
310   formatInfo.mMagicCookieSize = aExtraData.Length();
311   formatInfo.mMagicCookie = aExtraData.Elements();
312 
313   UInt32 formatListSize;
314   // Attempt to retrieve the default format using
315   // kAudioFormatProperty_FormatInfo method.
316   // This method only retrieves the FramesPerPacket information required
317   // by the decoder, which depends on the codec type and profile.
318   aDesc.mFormatID = mFormatID;
319   aDesc.mChannelsPerFrame = mConfig.mChannels;
320   aDesc.mSampleRate = mConfig.mRate;
321   UInt32 inputFormatSize = sizeof(aDesc);
322   OSStatus rv = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL,
323                                        &inputFormatSize, &aDesc);
324   if (NS_WARN_IF(rv)) {
325     return MediaResult(
326         NS_ERROR_FAILURE,
327         RESULT_DETAIL("Unable to get format info:%d", int32_t(rv)));
328   }
329 
330   // If any of the methods below fail, we will return the default format as
331   // created using kAudioFormatProperty_FormatInfo above.
332   rv = AudioFormatGetPropertyInfo(kAudioFormatProperty_FormatList,
333                                   sizeof(formatInfo), &formatInfo,
334                                   &formatListSize);
335   if (rv || (formatListSize % sizeof(AudioFormatListItem))) {
336     return NS_OK;
337   }
338   size_t listCount = formatListSize / sizeof(AudioFormatListItem);
339   auto formatList = MakeUnique<AudioFormatListItem[]>(listCount);
340 
341   rv = AudioFormatGetProperty(kAudioFormatProperty_FormatList,
342                               sizeof(formatInfo), &formatInfo, &formatListSize,
343                               formatList.get());
344   if (rv) {
345     return NS_OK;
346   }
347   LOG("found %zu available audio stream(s)",
348       formatListSize / sizeof(AudioFormatListItem));
349   // Get the index number of the first playable format.
350   // This index number will be for the highest quality layer the platform
351   // is capable of playing.
352   UInt32 itemIndex;
353   UInt32 indexSize = sizeof(itemIndex);
354   rv = AudioFormatGetProperty(kAudioFormatProperty_FirstPlayableFormatFromList,
355                               formatListSize, formatList.get(), &indexSize,
356                               &itemIndex);
357   if (rv) {
358     return NS_OK;
359   }
360 
361   aDesc = formatList[itemIndex].mASBD;
362 
363   return NS_OK;
364 }
365 
ConvertChannelLabel(AudioChannelLabel id)366 AudioConfig::Channel ConvertChannelLabel(AudioChannelLabel id) {
367   switch (id) {
368     case kAudioChannelLabel_Left:
369       return AudioConfig::CHANNEL_FRONT_LEFT;
370     case kAudioChannelLabel_Right:
371       return AudioConfig::CHANNEL_FRONT_RIGHT;
372     case kAudioChannelLabel_Mono:
373     case kAudioChannelLabel_Center:
374       return AudioConfig::CHANNEL_FRONT_CENTER;
375     case kAudioChannelLabel_LFEScreen:
376       return AudioConfig::CHANNEL_LFE;
377     case kAudioChannelLabel_LeftSurround:
378       return AudioConfig::CHANNEL_SIDE_LEFT;
379     case kAudioChannelLabel_RightSurround:
380       return AudioConfig::CHANNEL_SIDE_RIGHT;
381     case kAudioChannelLabel_CenterSurround:
382       return AudioConfig::CHANNEL_BACK_CENTER;
383     case kAudioChannelLabel_RearSurroundLeft:
384       return AudioConfig::CHANNEL_BACK_LEFT;
385     case kAudioChannelLabel_RearSurroundRight:
386       return AudioConfig::CHANNEL_BACK_RIGHT;
387     default:
388       return AudioConfig::CHANNEL_INVALID;
389   }
390 }
391 
392 // Will set mChannelLayout if a channel layout could properly be identified
393 // and is supported.
SetupChannelLayout()394 nsresult AppleATDecoder::SetupChannelLayout() {
395   MOZ_ASSERT(mThread->IsOnCurrentThread());
396 
397   // Determine the channel layout.
398   UInt32 propertySize;
399   UInt32 size;
400   OSStatus status = AudioConverterGetPropertyInfo(
401       mConverter, kAudioConverterOutputChannelLayout, &propertySize, NULL);
402   if (status || !propertySize) {
403     LOG("Couldn't get channel layout property (%s)", FourCC2Str(status));
404     return NS_ERROR_FAILURE;
405   }
406 
407   auto data = MakeUnique<uint8_t[]>(propertySize);
408   size = propertySize;
409   status = AudioConverterGetProperty(
410       mConverter, kAudioConverterInputChannelLayout, &size, data.get());
411   if (status || size != propertySize) {
412     LOG("Couldn't get channel layout property (%s)", FourCC2Str(status));
413     return NS_ERROR_FAILURE;
414   }
415 
416   AudioChannelLayout* layout =
417       reinterpret_cast<AudioChannelLayout*>(data.get());
418   AudioChannelLayoutTag tag = layout->mChannelLayoutTag;
419 
420   // if tag is kAudioChannelLayoutTag_UseChannelDescriptions then the structure
421   // directly contains the the channel layout mapping.
422   // If tag is kAudioChannelLayoutTag_UseChannelBitmap then the layout will
423   // be defined via the bitmap and can be retrieved using
424   // kAudioFormatProperty_ChannelLayoutForBitmap property.
425   // Otherwise the tag itself describes the layout.
426   if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) {
427     AudioFormatPropertyID property =
428         tag == kAudioChannelLayoutTag_UseChannelBitmap
429             ? kAudioFormatProperty_ChannelLayoutForBitmap
430             : kAudioFormatProperty_ChannelLayoutForTag;
431 
432     if (property == kAudioFormatProperty_ChannelLayoutForBitmap) {
433       status = AudioFormatGetPropertyInfo(
434           property, sizeof(UInt32), &layout->mChannelBitmap, &propertySize);
435     } else {
436       status = AudioFormatGetPropertyInfo(
437           property, sizeof(AudioChannelLayoutTag), &tag, &propertySize);
438     }
439     if (status || !propertySize) {
440       LOG("Couldn't get channel layout property info (%s:%s)",
441           FourCC2Str(property), FourCC2Str(status));
442       return NS_ERROR_FAILURE;
443     }
444     data = MakeUnique<uint8_t[]>(propertySize);
445     layout = reinterpret_cast<AudioChannelLayout*>(data.get());
446     size = propertySize;
447 
448     if (property == kAudioFormatProperty_ChannelLayoutForBitmap) {
449       status = AudioFormatGetProperty(property, sizeof(UInt32),
450                                       &layout->mChannelBitmap, &size, layout);
451     } else {
452       status = AudioFormatGetProperty(property, sizeof(AudioChannelLayoutTag),
453                                       &tag, &size, layout);
454     }
455     if (status || size != propertySize) {
456       LOG("Couldn't get channel layout property (%s:%s)", FourCC2Str(property),
457           FourCC2Str(status));
458       return NS_ERROR_FAILURE;
459     }
460     // We have retrieved the channel layout from the tag or bitmap.
461     // We can now directly use the channel descriptions.
462     layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
463   }
464 
465   if (layout->mNumberChannelDescriptions != mOutputFormat.mChannelsPerFrame) {
466     LOG("Not matching the original channel number");
467     return NS_ERROR_FAILURE;
468   }
469 
470   AutoTArray<AudioConfig::Channel, 8> channels;
471   channels.SetLength(layout->mNumberChannelDescriptions);
472   for (uint32_t i = 0; i < layout->mNumberChannelDescriptions; i++) {
473     AudioChannelLabel id = layout->mChannelDescriptions[i].mChannelLabel;
474     AudioConfig::Channel channel = ConvertChannelLabel(id);
475     channels[i] = channel;
476   }
477   mChannelLayout = MakeUnique<AudioConfig::ChannelLayout>(
478       mOutputFormat.mChannelsPerFrame, channels.Elements());
479   return NS_OK;
480 }
481 
SetupDecoder(MediaRawData * aSample)482 MediaResult AppleATDecoder::SetupDecoder(MediaRawData* aSample) {
483   MOZ_ASSERT(mThread->IsOnCurrentThread());
484   static const uint32_t MAX_FRAMES = 2;
485 
486   if (mFormatID == kAudioFormatMPEG4AAC && mConfig.mExtendedProfile == 2 &&
487       mParsedFramesForAACMagicCookie < MAX_FRAMES) {
488     // Check for implicit SBR signalling if stream is AAC-LC
489     // This will provide us with an updated magic cookie for use with
490     // GetInputAudioDescription.
491     if (NS_SUCCEEDED(GetImplicitAACMagicCookie(aSample)) &&
492         !mMagicCookie.Length()) {
493       // nothing found yet, will try again later
494       mParsedFramesForAACMagicCookie++;
495       return NS_ERROR_NOT_INITIALIZED;
496     }
497     // An error occurred, fallback to using default stream description
498   }
499 
500   LOG("Initializing Apple AudioToolbox decoder");
501 
502   nsTArray<uint8_t>& magicCookie =
503       mMagicCookie.Length() ? mMagicCookie : *mConfig.mExtraData;
504   AudioStreamBasicDescription inputFormat;
505   PodZero(&inputFormat);
506 
507   MediaResult rv = GetInputAudioDescription(inputFormat, magicCookie);
508   if (NS_FAILED(rv)) {
509     return rv;
510   }
511   // Fill in the output format manually.
512   PodZero(&mOutputFormat);
513   mOutputFormat.mFormatID = kAudioFormatLinearPCM;
514   mOutputFormat.mSampleRate = inputFormat.mSampleRate;
515   mOutputFormat.mChannelsPerFrame = inputFormat.mChannelsPerFrame;
516 #if defined(MOZ_SAMPLE_TYPE_FLOAT32)
517   mOutputFormat.mBitsPerChannel = 32;
518   mOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat | 0;
519 #elif defined(MOZ_SAMPLE_TYPE_S16)
520   mOutputFormat.mBitsPerChannel = 16;
521   mOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | 0;
522 #else
523 #  error Unknown audio sample type
524 #endif
525   // Set up the decoder so it gives us one sample per frame
526   mOutputFormat.mFramesPerPacket = 1;
527   mOutputFormat.mBytesPerPacket = mOutputFormat.mBytesPerFrame =
528       mOutputFormat.mChannelsPerFrame * mOutputFormat.mBitsPerChannel / 8;
529 
530   OSStatus status =
531       AudioConverterNew(&inputFormat, &mOutputFormat, &mConverter);
532   if (status) {
533     LOG("Error %d constructing AudioConverter", int(status));
534     mConverter = nullptr;
535     return MediaResult(
536         NS_ERROR_FAILURE,
537         RESULT_DETAIL("Error constructing AudioConverter:%d", int32_t(status)));
538   }
539 
540   if (magicCookie.Length() && mFormatID == kAudioFormatMPEG4AAC) {
541     status = AudioConverterSetProperty(
542         mConverter, kAudioConverterDecompressionMagicCookie,
543         magicCookie.Length(), magicCookie.Elements());
544     if (status) {
545       LOG("Error setting AudioConverter AAC cookie:%d", int32_t(status));
546       ProcessShutdown();
547       return MediaResult(
548           NS_ERROR_FAILURE,
549           RESULT_DETAIL("Error setting AudioConverter AAC cookie:%d",
550                         int32_t(status)));
551     }
552   }
553 
554   if (NS_FAILED(SetupChannelLayout())) {
555     NS_WARNING("Couldn't retrieve channel layout, will use default layout");
556   }
557 
558   return NS_OK;
559 }
560 
_MetadataCallback(void * aAppleATDecoder,AudioFileStreamID aStream,AudioFileStreamPropertyID aProperty,UInt32 * aFlags)561 static void _MetadataCallback(void* aAppleATDecoder, AudioFileStreamID aStream,
562                               AudioFileStreamPropertyID aProperty,
563                               UInt32* aFlags) {
564   AppleATDecoder* decoder = static_cast<AppleATDecoder*>(aAppleATDecoder);
565   MOZ_RELEASE_ASSERT(decoder->mThread->IsOnCurrentThread());
566 
567   LOGEX(decoder, "MetadataCallback receiving: '%s'", FourCC2Str(aProperty));
568   if (aProperty == kAudioFileStreamProperty_MagicCookieData) {
569     UInt32 size;
570     Boolean writeable;
571     OSStatus rv =
572         AudioFileStreamGetPropertyInfo(aStream, aProperty, &size, &writeable);
573     if (rv) {
574       LOGEX(decoder, "Couldn't get property info for '%s' (%s)",
575             FourCC2Str(aProperty), FourCC2Str(rv));
576       decoder->mFileStreamError = true;
577       return;
578     }
579     auto data = MakeUnique<uint8_t[]>(size);
580     rv = AudioFileStreamGetProperty(aStream, aProperty, &size, data.get());
581     if (rv) {
582       LOGEX(decoder, "Couldn't get property '%s' (%s)", FourCC2Str(aProperty),
583             FourCC2Str(rv));
584       decoder->mFileStreamError = true;
585       return;
586     }
587     decoder->mMagicCookie.AppendElements(data.get(), size);
588   }
589 }
590 
_SampleCallback(void * aSBR,UInt32 aNumBytes,UInt32 aNumPackets,const void * aData,AudioStreamPacketDescription * aPackets)591 static void _SampleCallback(void* aSBR, UInt32 aNumBytes, UInt32 aNumPackets,
592                             const void* aData,
593                             AudioStreamPacketDescription* aPackets) {}
594 
GetImplicitAACMagicCookie(const MediaRawData * aSample)595 nsresult AppleATDecoder::GetImplicitAACMagicCookie(
596     const MediaRawData* aSample) {
597   MOZ_ASSERT(mThread->IsOnCurrentThread());
598 
599   // Prepend ADTS header to AAC audio.
600   RefPtr<MediaRawData> adtssample(aSample->Clone());
601   if (!adtssample) {
602     return NS_ERROR_OUT_OF_MEMORY;
603   }
604   int8_t frequency_index = Adts::GetFrequencyIndex(mConfig.mRate);
605 
606   bool rv = Adts::ConvertSample(mConfig.mChannels, frequency_index,
607                                 mConfig.mProfile, adtssample);
608   if (!rv) {
609     NS_WARNING("Failed to apply ADTS header");
610     return NS_ERROR_FAILURE;
611   }
612   if (!mStream) {
613     OSStatus rv = AudioFileStreamOpen(this, _MetadataCallback, _SampleCallback,
614                                       kAudioFileAAC_ADTSType, &mStream);
615     if (rv) {
616       NS_WARNING("Couldn't open AudioFileStream");
617       return NS_ERROR_FAILURE;
618     }
619   }
620 
621   OSStatus status = AudioFileStreamParseBytes(
622       mStream, adtssample->Size(), adtssample->Data(), 0 /* discontinuity */);
623   if (status) {
624     NS_WARNING("Couldn't parse sample");
625   }
626 
627   if (status || mFileStreamError || mMagicCookie.Length()) {
628     // We have decoded a magic cookie or an error occurred as such
629     // we won't need the stream any longer.
630     AudioFileStreamClose(mStream);
631     mStream = nullptr;
632   }
633 
634   return (mFileStreamError || status) ? NS_ERROR_FAILURE : NS_OK;
635 }
636 
637 }  // namespace mozilla
638 
639 #undef LOG
640 #undef LOGEX
641