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