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