1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "WAVExtractor"
19 #include <utils/Log.h>
20 
21 #include "WAVExtractor.h"
22 
23 #include <android-base/properties.h>
24 #include <android/binder_ibinder.h> // for AIBinder_getCallingUid
25 #include <audio_utils/primitives.h>
26 #include <media/stagefright/foundation/ADebug.h>
27 #include <media/stagefright/MediaDefs.h>
28 #include <media/stagefright/MediaErrors.h>
29 #include <media/stagefright/MetaData.h>
30 #include <private/android_filesystem_config.h> // for AID_MEDIA
31 #include <system/audio.h>
32 #include <utils/String8.h>
33 #include <cutils/bitops.h>
34 
35 #define CHANNEL_MASK_USE_CHANNEL_ORDER 0
36 
37 // NOTE: This code assumes the device processor is little endian.
38 
39 namespace android {
40 
41 // MediaServer is capable of handling float extractor output, but general processes
42 // may not be able to do so.
43 // TODO: Improve API to set extractor float output.
44 // (Note: duplicated with FLACExtractor.cpp)
shouldExtractorOutputFloat(int bitsPerSample)45 static inline bool shouldExtractorOutputFloat(int bitsPerSample)
46 {
47     return bitsPerSample > 16 && AIBinder_getCallingUid() == AID_MEDIA
48                               && android::base::GetBoolProperty("media.extractor.float", true);
49 }
50 
51 enum {
52     WAVE_FORMAT_PCM        = 0x0001,
53     WAVE_FORMAT_IEEE_FLOAT = 0x0003,
54     WAVE_FORMAT_ALAW       = 0x0006,
55     WAVE_FORMAT_MULAW      = 0x0007,
56     WAVE_FORMAT_MSGSM      = 0x0031,
57     WAVE_FORMAT_EXTENSIBLE = 0xFFFE
58 };
59 
60 static const char* WAVEEXT_SUBFORMAT = "\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71";
61 static const char* AMBISONIC_SUBFORMAT = "\x00\x00\x21\x07\xD3\x11\x86\x44\xC8\xC1\xCA\x00\x00\x00";
62 
U32_LE_AT(const uint8_t * ptr)63 static uint32_t U32_LE_AT(const uint8_t *ptr) {
64     return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0];
65 }
66 
U16_LE_AT(const uint8_t * ptr)67 static uint16_t U16_LE_AT(const uint8_t *ptr) {
68     return ptr[1] << 8 | ptr[0];
69 }
70 
71 struct WAVSource : public MediaTrackHelper {
72     WAVSource(
73             DataSourceHelper *dataSource,
74             AMediaFormat *meta,
75             uint16_t waveFormat,
76             bool outputFloat,
77             off64_t offset, size_t size);
78 
79     virtual media_status_t start();
80     virtual media_status_t stop();
81     virtual media_status_t getFormat(AMediaFormat *meta);
82 
83     virtual media_status_t read(
84             MediaBufferHelper **buffer, const ReadOptions *options = NULL);
85 
supportsNonBlockingReadandroid::WAVSource86     bool supportsNonBlockingRead() override { return false; }
87 
88 protected:
89     virtual ~WAVSource();
90 
91 private:
92     static const size_t kMaxFrameSize;
93 
94     DataSourceHelper *mDataSource;
95     AMediaFormat *mMeta;
96     uint16_t mWaveFormat;
97     const bool mOutputFloat;
98     int32_t mSampleRate;
99     int32_t mNumChannels;
100     int32_t mBitsPerSample;
101     off64_t mOffset;
102     size_t mSize;
103     bool mStarted;
104     off64_t mCurrentPos;
105 
106     WAVSource(const WAVSource &);
107     WAVSource &operator=(const WAVSource &);
108 };
109 
WAVExtractor(DataSourceHelper * source)110 WAVExtractor::WAVExtractor(DataSourceHelper *source)
111     : mDataSource(source),
112       mValidFormat(false),
113       mChannelMask(CHANNEL_MASK_USE_CHANNEL_ORDER) {
114     mTrackMeta = AMediaFormat_new();
115     mInitCheck = init();
116 }
117 
~WAVExtractor()118 WAVExtractor::~WAVExtractor() {
119     delete mDataSource;
120     AMediaFormat_delete(mTrackMeta);
121 }
122 
getMetaData(AMediaFormat * meta)123 media_status_t WAVExtractor::getMetaData(AMediaFormat *meta) {
124     AMediaFormat_clear(meta);
125     if (mInitCheck == OK) {
126         AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_WAV);
127     }
128 
129     return AMEDIA_OK;
130 }
131 
countTracks()132 size_t WAVExtractor::countTracks() {
133     return mInitCheck == OK ? 1 : 0;
134 }
135 
getTrack(size_t index)136 MediaTrackHelper *WAVExtractor::getTrack(size_t index) {
137     if (mInitCheck != OK || index > 0) {
138         return NULL;
139     }
140 
141     return new WAVSource(
142             mDataSource, mTrackMeta,
143             mWaveFormat, shouldExtractorOutputFloat(mBitsPerSample), mDataOffset, mDataSize);
144 }
145 
getTrackMetaData(AMediaFormat * meta,size_t index,uint32_t)146 media_status_t WAVExtractor::getTrackMetaData(
147         AMediaFormat *meta,
148         size_t index, uint32_t /* flags */) {
149     if (mInitCheck != OK || index > 0) {
150         return AMEDIA_ERROR_UNKNOWN;
151     }
152 
153     const media_status_t status = AMediaFormat_copy(meta, mTrackMeta);
154     if (status == OK) {
155         AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_PCM_ENCODING,
156                 shouldExtractorOutputFloat(mBitsPerSample)
157                         ? kAudioEncodingPcmFloat : kAudioEncodingPcm16bit);
158     }
159     return status;
160 }
161 
init()162 status_t WAVExtractor::init() {
163     uint8_t header[12];
164     if (mDataSource->readAt(
165                 0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
166         return NO_INIT;
167     }
168 
169     if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
170         return NO_INIT;
171     }
172 
173     size_t totalSize = U32_LE_AT(&header[4]);
174 
175     off64_t offset = 12;
176     size_t remainingSize = totalSize;
177     while (remainingSize >= 8) {
178         uint8_t chunkHeader[8];
179         if (mDataSource->readAt(offset, chunkHeader, 8) < 8) {
180             return NO_INIT;
181         }
182 
183         remainingSize -= 8;
184         offset += 8;
185 
186         uint32_t chunkSize = U32_LE_AT(&chunkHeader[4]);
187 
188         if (chunkSize > remainingSize) {
189             return NO_INIT;
190         }
191 
192         if (!memcmp(chunkHeader, "fmt ", 4)) {
193             if (chunkSize < 16) {
194                 return NO_INIT;
195             }
196 
197             uint8_t formatSpec[40];
198             if (mDataSource->readAt(offset, formatSpec, 2) < 2) {
199                 return NO_INIT;
200             }
201 
202             mWaveFormat = U16_LE_AT(formatSpec);
203             if (mWaveFormat != WAVE_FORMAT_PCM
204                     && mWaveFormat != WAVE_FORMAT_IEEE_FLOAT
205                     && mWaveFormat != WAVE_FORMAT_ALAW
206                     && mWaveFormat != WAVE_FORMAT_MULAW
207                     && mWaveFormat != WAVE_FORMAT_MSGSM
208                     && mWaveFormat != WAVE_FORMAT_EXTENSIBLE) {
209                 return AMEDIA_ERROR_UNSUPPORTED;
210             }
211 
212             uint8_t fmtSize = 16;
213             if (mWaveFormat == WAVE_FORMAT_EXTENSIBLE) {
214                 fmtSize = 40;
215             }
216             if (mDataSource->readAt(offset, formatSpec, fmtSize) < fmtSize) {
217                 return NO_INIT;
218             }
219 
220             mNumChannels = U16_LE_AT(&formatSpec[2]);
221 
222             if (mNumChannels < 1 || mNumChannels > FCC_8) {
223                 ALOGE("Unsupported number of channels (%d)", mNumChannels);
224                 return AMEDIA_ERROR_UNSUPPORTED;
225             }
226 
227             if (mWaveFormat != WAVE_FORMAT_EXTENSIBLE) {
228                 if (mNumChannels != 1 && mNumChannels != FCC_2) {
229                     ALOGW("More than 2 channels (%d) in non-WAVE_EXT, unknown channel mask",
230                             mNumChannels);
231                 }
232             }
233 
234             mSampleRate = U32_LE_AT(&formatSpec[4]);
235 
236             if (mSampleRate == 0) {
237                 return ERROR_MALFORMED;
238             }
239 
240             mBitsPerSample = U16_LE_AT(&formatSpec[14]);
241 
242             if (mWaveFormat == WAVE_FORMAT_EXTENSIBLE) {
243                 uint16_t validBitsPerSample = U16_LE_AT(&formatSpec[18]);
244                 if (validBitsPerSample != mBitsPerSample) {
245                     if (validBitsPerSample != 0) {
246                         ALOGE("validBits(%d) != bitsPerSample(%d) are not supported",
247                                 validBitsPerSample, mBitsPerSample);
248                         return AMEDIA_ERROR_UNSUPPORTED;
249                     } else {
250                         // we only support valitBitsPerSample == bitsPerSample but some WAV_EXT
251                         // writers don't correctly set the valid bits value, and leave it at 0.
252                         ALOGW("WAVE_EXT has 0 valid bits per sample, ignoring");
253                     }
254                 }
255 
256                 mChannelMask = U32_LE_AT(&formatSpec[20]);
257                 ALOGV("numChannels=%d channelMask=0x%x", mNumChannels, mChannelMask);
258                 if ((mChannelMask >> 18) != 0) {
259                     ALOGE("invalid channel mask 0x%x", mChannelMask);
260                     return ERROR_MALFORMED;
261                 }
262 
263                 if ((mChannelMask != CHANNEL_MASK_USE_CHANNEL_ORDER)
264                         && (popcount(mChannelMask) != mNumChannels)) {
265                     ALOGE("invalid number of channels (%d) in channel mask (0x%x)",
266                             popcount(mChannelMask), mChannelMask);
267                     return ERROR_MALFORMED;
268                 }
269 
270                 // In a WAVE_EXT header, the first two bytes of the GUID stored at byte 24 contain
271                 // the sample format, using the same definitions as a regular WAV header
272                 mWaveFormat = U16_LE_AT(&formatSpec[24]);
273                 if (memcmp(&formatSpec[26], WAVEEXT_SUBFORMAT, 14) &&
274                     memcmp(&formatSpec[26], AMBISONIC_SUBFORMAT, 14)) {
275                     ALOGE("unsupported GUID");
276                     return ERROR_UNSUPPORTED;
277                 }
278             }
279 
280             if (mWaveFormat == WAVE_FORMAT_PCM) {
281                 if (mBitsPerSample != 8 && mBitsPerSample != 16
282                     && mBitsPerSample != 24 && mBitsPerSample != 32) {
283                     return ERROR_UNSUPPORTED;
284                 }
285             } else if (mWaveFormat == WAVE_FORMAT_IEEE_FLOAT) {
286                 if (mBitsPerSample != 32) {  // TODO we don't support double
287                     return ERROR_UNSUPPORTED;
288                 }
289             }
290             else if (mWaveFormat == WAVE_FORMAT_MSGSM) {
291                 if (mBitsPerSample != 0) {
292                     return ERROR_UNSUPPORTED;
293                 }
294             } else if (mWaveFormat == WAVE_FORMAT_MULAW || mWaveFormat == WAVE_FORMAT_ALAW) {
295                 if (mBitsPerSample != 8) {
296                     return ERROR_UNSUPPORTED;
297                 }
298             } else {
299                 return ERROR_UNSUPPORTED;
300             }
301 
302             mValidFormat = true;
303         } else if (!memcmp(chunkHeader, "data", 4)) {
304             if (mValidFormat) {
305                 mDataOffset = offset;
306                 mDataSize = chunkSize;
307 
308                 AMediaFormat_clear(mTrackMeta);
309 
310                 switch (mWaveFormat) {
311                     case WAVE_FORMAT_PCM:
312                     case WAVE_FORMAT_IEEE_FLOAT:
313                         AMediaFormat_setString(mTrackMeta,
314                                 AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
315                         break;
316                     case WAVE_FORMAT_ALAW:
317                         AMediaFormat_setString(mTrackMeta,
318                                 AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
319                         break;
320                     case WAVE_FORMAT_MSGSM:
321                         AMediaFormat_setString(mTrackMeta,
322                                 AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MSGSM);
323                         break;
324                     default:
325                         CHECK_EQ(mWaveFormat, (uint16_t)WAVE_FORMAT_MULAW);
326                         AMediaFormat_setString(mTrackMeta,
327                                 AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
328                         break;
329                 }
330 
331                 AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mNumChannels);
332                 AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, mChannelMask);
333                 AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mSampleRate);
334                 AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, mBitsPerSample);
335                 int64_t durationUs = 0;
336                 if (mWaveFormat == WAVE_FORMAT_MSGSM) {
337                     // 65 bytes decode to 320 8kHz samples
338                     durationUs =
339                         1000000LL * (mDataSize / 65 * 320) / 8000;
340                 } else {
341                     size_t bytesPerSample = mBitsPerSample >> 3;
342 
343                     if (!bytesPerSample || !mNumChannels)
344                         return AMEDIA_ERROR_MALFORMED;
345 
346                     size_t num_samples = mDataSize / (mNumChannels * bytesPerSample);
347 
348                     if (!mSampleRate)
349                         return AMEDIA_ERROR_MALFORMED;
350 
351                     durationUs =
352                         1000000LL * num_samples / mSampleRate;
353                 }
354 
355                 AMediaFormat_setInt64(mTrackMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
356 
357                 return OK;
358             }
359         }
360 
361         offset += chunkSize;
362     }
363 
364     return NO_INIT;
365 }
366 
367 const size_t WAVSource::kMaxFrameSize = 32768;
368 
WAVSource(DataSourceHelper * dataSource,AMediaFormat * meta,uint16_t waveFormat,bool outputFloat,off64_t offset,size_t size)369 WAVSource::WAVSource(
370         DataSourceHelper *dataSource,
371         AMediaFormat *meta,
372         uint16_t waveFormat,
373         bool outputFloat,
374         off64_t offset, size_t size)
375     : mDataSource(dataSource),
376       mMeta(meta),
377       mWaveFormat(waveFormat),
378       mOutputFloat(outputFloat),
379       mOffset(offset),
380       mSize(size),
381       mStarted(false) {
382     CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate));
383     CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mNumChannels));
384     CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, &mBitsPerSample));
385 }
386 
~WAVSource()387 WAVSource::~WAVSource() {
388     if (mStarted) {
389         stop();
390     }
391 }
392 
start()393 media_status_t WAVSource::start() {
394     ALOGV("WAVSource::start");
395 
396     CHECK(!mStarted);
397 
398     // some WAV files may have large audio buffers that use shared memory transfer.
399     if (!mBufferGroup->init(4 /* buffers */, kMaxFrameSize)) {
400         return AMEDIA_ERROR_UNKNOWN;
401     }
402 
403     mCurrentPos = mOffset;
404 
405     mStarted = true;
406 
407     return AMEDIA_OK;
408 }
409 
stop()410 media_status_t WAVSource::stop() {
411     ALOGV("WAVSource::stop");
412 
413     CHECK(mStarted);
414 
415     mStarted = false;
416 
417     return AMEDIA_OK;
418 }
419 
getFormat(AMediaFormat * meta)420 media_status_t WAVSource::getFormat(AMediaFormat *meta) {
421     ALOGV("WAVSource::getFormat");
422 
423     const media_status_t status = AMediaFormat_copy(meta, mMeta);
424     if (status == OK) {
425         AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, kMaxFrameSize);
426         AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_PCM_ENCODING,
427                 mOutputFloat ? kAudioEncodingPcmFloat : kAudioEncodingPcm16bit);
428     }
429     return status;
430 }
431 
read(MediaBufferHelper ** out,const ReadOptions * options)432 media_status_t WAVSource::read(
433         MediaBufferHelper **out, const ReadOptions *options) {
434     *out = NULL;
435 
436     if (options != nullptr && options->getNonBlocking() && !mBufferGroup->has_buffers()) {
437         return AMEDIA_ERROR_WOULD_BLOCK;
438     }
439 
440     int64_t seekTimeUs;
441     ReadOptions::SeekMode mode;
442     if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
443         int64_t pos = 0;
444 
445         if (mWaveFormat == WAVE_FORMAT_MSGSM) {
446             // 65 bytes decode to 320 8kHz samples
447             int64_t samplenumber = (seekTimeUs * mSampleRate) / 1000000;
448             int64_t framenumber = samplenumber / 320;
449             pos = framenumber * 65;
450         } else {
451             pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * (mBitsPerSample >> 3);
452         }
453         if (pos > (off64_t)mSize) {
454             pos = mSize;
455         }
456         mCurrentPos = pos + mOffset;
457     }
458 
459     MediaBufferHelper *buffer;
460     media_status_t err = mBufferGroup->acquire_buffer(&buffer);
461     if (err != OK) {
462         return err;
463     }
464 
465     // maxBytesToRead may be reduced so that in-place data conversion will fit in buffer size.
466     const size_t bufferSize = std::min(buffer->size(), kMaxFrameSize);
467     size_t maxBytesToRead;
468     if (mOutputFloat) { // destination is float at 4 bytes per sample, source may be less.
469         maxBytesToRead = (mBitsPerSample / 8) * (bufferSize / 4);
470     } else { // destination is int16_t at 2 bytes per sample, only source of 8 bits is less.
471         maxBytesToRead = mBitsPerSample == 8 ? bufferSize / 2 : bufferSize;
472     }
473 
474     const size_t maxBytesAvailable =
475         (mCurrentPos - mOffset >= (off64_t)mSize)
476             ? 0 : mSize - (mCurrentPos - mOffset);
477 
478     if (maxBytesToRead > maxBytesAvailable) {
479         maxBytesToRead = maxBytesAvailable;
480     }
481 
482     if (mWaveFormat == WAVE_FORMAT_MSGSM) {
483         // Microsoft packs 2 frames into 65 bytes, rather than using separate 33-byte frames,
484         // so read multiples of 65, and use smaller buffers to account for ~10:1 expansion ratio
485         if (maxBytesToRead > 1024) {
486             maxBytesToRead = 1024;
487         }
488         maxBytesToRead = (maxBytesToRead / 65) * 65;
489     } else {
490         // read only integral amounts of audio unit frames.
491         const size_t inputUnitFrameSize = mNumChannels * mBitsPerSample / 8;
492         maxBytesToRead -= maxBytesToRead % inputUnitFrameSize;
493     }
494 
495     ssize_t n = mDataSource->readAt(
496             mCurrentPos, buffer->data(),
497             maxBytesToRead);
498 
499     if (n <= 0) {
500         buffer->release();
501         buffer = NULL;
502 
503         return AMEDIA_ERROR_END_OF_STREAM;
504     }
505 
506     buffer->set_range(0, n);
507 
508     // TODO: add capability to return data as float PCM instead of 16 bit PCM.
509     if (mWaveFormat == WAVE_FORMAT_PCM) {
510         const size_t bytesPerFrame = (mBitsPerSample >> 3) * mNumChannels;
511         const size_t numFrames = n / bytesPerFrame;
512         const size_t numSamples = numFrames * mNumChannels;
513         if (mOutputFloat) {
514             float *fdest = (float *)buffer->data();
515             buffer->set_range(0, 4 * numSamples);
516             switch (mBitsPerSample) {
517             case 8: {
518                 memcpy_to_float_from_u8(fdest, (const uint8_t *)buffer->data(), numSamples);
519             } break;
520             case 16: {
521                 memcpy_to_float_from_i16(fdest, (const int16_t *)buffer->data(), numSamples);
522             } break;
523             case 24: {
524                 memcpy_to_float_from_p24(fdest, (const uint8_t *)buffer->data(), numSamples);
525             } break;
526             case 32: { // buffer range is correct
527                 memcpy_to_float_from_i32(fdest, (const int32_t *)buffer->data(), numSamples);
528             } break;
529             }
530         } else {
531             int16_t *idest = (int16_t *)buffer->data();
532             buffer->set_range(0, 2 * numSamples);
533             switch (mBitsPerSample) {
534             case 8: {
535                 memcpy_to_i16_from_u8(idest, (const uint8_t *)buffer->data(), numSamples);
536             } break;
537             case 16:
538                 // no conversion needed
539                 break;
540             case 24: {
541                 memcpy_to_i16_from_p24(idest, (const uint8_t *)buffer->data(), numSamples);
542             } break;
543             case 32: {
544                 memcpy_to_i16_from_i32(idest, (const int32_t *)buffer->data(), numSamples);
545             } break;
546             }
547         }
548     } else if (mWaveFormat == WAVE_FORMAT_IEEE_FLOAT) {
549         if (!mOutputFloat) { // mBitsPerSample == 32
550             int16_t *idest = (int16_t *)buffer->data();
551             const size_t numSamples = n / 4;
552             memcpy_to_i16_from_float(idest, (const float *)buffer->data(), numSamples);
553             buffer->set_range(0, 2 * numSamples);
554         }
555         // Note: if output encoding is float, no need to convert if source is float.
556     }
557 
558     int64_t timeStampUs = 0;
559 
560     if (mWaveFormat == WAVE_FORMAT_MSGSM) {
561         timeStampUs = 1000000LL * (mCurrentPos - mOffset) * 320 / 65 / mSampleRate;
562     } else {
563         size_t bytesPerSample = mBitsPerSample >> 3;
564         timeStampUs = 1000000LL * (mCurrentPos - mOffset)
565                 / (mNumChannels * bytesPerSample) / mSampleRate;
566     }
567 
568     AMediaFormat *meta = buffer->meta_data();
569     AMediaFormat_setInt64(meta, AMEDIAFORMAT_KEY_TIME_US, timeStampUs);
570     AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, 1);
571 
572     mCurrentPos += n;
573 
574     *out = buffer;
575 
576     return AMEDIA_OK;
577 }
578 
579 ////////////////////////////////////////////////////////////////////////////////
580 
CreateExtractor(CDataSource * source,void *)581 static CMediaExtractor* CreateExtractor(
582         CDataSource *source,
583         void *) {
584     return wrap(new WAVExtractor(new DataSourceHelper(source)));
585 }
586 
Sniff(CDataSource * source,float * confidence,void **,FreeMetaFunc *)587 static CreatorFunc Sniff(
588         CDataSource *source,
589         float *confidence,
590         void **,
591         FreeMetaFunc *) {
592     DataSourceHelper *helper = new DataSourceHelper(source);
593     char header[12];
594     if (helper->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
595         delete helper;
596         return NULL;
597     }
598 
599     if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
600         delete helper;
601         return NULL;
602     }
603 
604     WAVExtractor *extractor = new WAVExtractor(helper); // extractor owns the helper
605     int numTracks = extractor->countTracks();
606     delete extractor;
607     if (numTracks == 0) {
608         return NULL;
609     }
610 
611     *confidence = 0.3f;
612 
613     return CreateExtractor;
614 }
615 
616 static const char *extensions[] = {
617     "wav",
618     NULL
619 };
620 
621 extern "C" {
622 // This is the only symbol that needs to be exported
623 __attribute__ ((visibility ("default")))
GETEXTRACTORDEF()624 ExtractorDef GETEXTRACTORDEF() {
625     return {
626         EXTRACTORDEF_VERSION,
627         UUID("7d613858-5837-4a38-84c5-332d1cddee27"),
628         1, // version
629         "WAV Extractor",
630         { .v3 = {Sniff, extensions} },
631     };
632 }
633 
634 } // extern "C"
635 
636 } // namespace android
637