Home | History | Annotate | Download | only in libstagefright
      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 #include <inttypes.h>
     18 
     19 //#define LOG_NDEBUG 0
     20 #define LOG_TAG "AudioPlayer"
     21 #include <utils/Log.h>
     22 #include <cutils/compiler.h>
     23 
     24 #include <binder/IPCThreadState.h>
     25 #include <media/AudioTrack.h>
     26 #include <media/MediaSource.h>
     27 #include <media/openmax/OMX_Audio.h>
     28 #include <media/stagefright/foundation/ADebug.h>
     29 #include <media/stagefright/foundation/ALookup.h>
     30 #include <media/stagefright/foundation/ALooper.h>
     31 #include <media/stagefright/AudioPlayer.h>
     32 #include <media/stagefright/MediaDefs.h>
     33 #include <media/stagefright/MediaErrors.h>
     34 #include <media/stagefright/MetaData.h>
     35 #include <media/stagefright/Utils.h>
     36 
     37 namespace android {
     38 
     39 AudioPlayer::AudioPlayer(
     40         const sp<MediaPlayerBase::AudioSink> &audioSink,
     41         uint32_t flags)
     42     : mInputBuffer(NULL),
     43       mSampleRate(0),
     44       mLatencyUs(0),
     45       mFrameSize(0),
     46       mNumFramesPlayed(0),
     47       mNumFramesPlayedSysTimeUs(ALooper::GetNowUs()),
     48       mPositionTimeMediaUs(-1),
     49       mPositionTimeRealUs(-1),
     50       mSeeking(false),
     51       mReachedEOS(false),
     52       mFinalStatus(OK),
     53       mSeekTimeUs(0),
     54       mStarted(false),
     55       mIsFirstBuffer(false),
     56       mFirstBufferResult(OK),
     57       mFirstBuffer(NULL),
     58       mAudioSink(audioSink),
     59       mPlaying(false),
     60       mStartPosUs(0),
     61       mCreateFlags(flags) {
     62 }
     63 
     64 AudioPlayer::~AudioPlayer() {
     65     if (mStarted) {
     66         reset();
     67     }
     68 }
     69 
     70 void AudioPlayer::setSource(const sp<MediaSource> &source) {
     71     CHECK(mSource == NULL);
     72     mSource = source;
     73 }
     74 
     75 ALookup<audio_format_t, int32_t> sAudioFormatToPcmEncoding {
     76     {
     77         { AUDIO_FORMAT_PCM_16_BIT, kAudioEncodingPcm16bit },
     78         { AUDIO_FORMAT_PCM_8_BIT,  kAudioEncodingPcm8bit  },
     79         { AUDIO_FORMAT_PCM_FLOAT,  kAudioEncodingPcmFloat },
     80     }
     81 };
     82 
     83 status_t AudioPlayer::start(bool sourceAlreadyStarted) {
     84     CHECK(!mStarted);
     85     CHECK(mSource != NULL);
     86 
     87     status_t err;
     88     if (!sourceAlreadyStarted) {
     89         err = mSource->start();
     90 
     91         if (err != OK) {
     92             return err;
     93         }
     94     }
     95 
     96     // We allow an optional INFO_FORMAT_CHANGED at the very beginning
     97     // of playback, if there is one, getFormat below will retrieve the
     98     // updated format, if there isn't, we'll stash away the valid buffer
     99     // of data to be used on the first audio callback.
    100 
    101     CHECK(mFirstBuffer == NULL);
    102 
    103     MediaSource::ReadOptions options;
    104     if (mSeeking) {
    105         options.setSeekTo(mSeekTimeUs);
    106         mSeeking = false;
    107     }
    108 
    109     mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
    110     if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
    111         ALOGV("INFO_FORMAT_CHANGED!!!");
    112 
    113         CHECK(mFirstBuffer == NULL);
    114         mFirstBufferResult = OK;
    115         mIsFirstBuffer = false;
    116     } else {
    117         mIsFirstBuffer = true;
    118     }
    119 
    120     sp<MetaData> format = mSource->getFormat();
    121     const char *mime;
    122     bool success = format->findCString(kKeyMIMEType, &mime);
    123     CHECK(success);
    124     CHECK(useOffload() || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
    125 
    126     success = format->findInt32(kKeySampleRate, &mSampleRate);
    127     CHECK(success);
    128 
    129     int32_t numChannels, channelMask;
    130     success = format->findInt32(kKeyChannelCount, &numChannels);
    131     CHECK(success);
    132 
    133     if(!format->findInt32(kKeyChannelMask, &channelMask)) {
    134         // log only when there's a risk of ambiguity of channel mask selection
    135         ALOGI_IF(numChannels > 2,
    136                 "source format didn't specify channel mask, using (%d) channel order", numChannels);
    137         channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
    138     }
    139 
    140     audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
    141     int32_t pcmEncoding;
    142     if (format->findInt32(kKeyPcmEncoding, &pcmEncoding)) {
    143         sAudioFormatToPcmEncoding.map(pcmEncoding, &audioFormat);
    144     }
    145 
    146     if (useOffload()) {
    147         if (mapMimeToAudioFormat(audioFormat, mime) != OK) {
    148             ALOGE("Couldn't map mime type \"%s\" to a valid AudioSystem::audio_format", mime);
    149             audioFormat = AUDIO_FORMAT_INVALID;
    150         } else {
    151             ALOGV("Mime type \"%s\" mapped to audio_format 0x%x", mime, audioFormat);
    152         }
    153 
    154         int32_t aacaot = -1;
    155         if ((audioFormat == AUDIO_FORMAT_AAC) && format->findInt32(kKeyAACAOT, &aacaot)) {
    156             // Redefine AAC format corrosponding to aac profile
    157             mapAACProfileToAudioFormat(audioFormat,(OMX_AUDIO_AACPROFILETYPE) aacaot);
    158         }
    159     }
    160 
    161     int avgBitRate = -1;
    162     format->findInt32(kKeyBitRate, &avgBitRate);
    163 
    164     if (mAudioSink.get() != NULL) {
    165 
    166         uint32_t flags = AUDIO_OUTPUT_FLAG_NONE;
    167         audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
    168 
    169         if (allowDeepBuffering()) {
    170             flags |= AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
    171         }
    172         if (useOffload()) {
    173             flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
    174 
    175             int64_t durationUs;
    176             if (format->findInt64(kKeyDuration, &durationUs)) {
    177                 offloadInfo.duration_us = durationUs;
    178             } else {
    179                 offloadInfo.duration_us = -1;
    180             }
    181 
    182             offloadInfo.sample_rate = mSampleRate;
    183             offloadInfo.channel_mask = channelMask;
    184             offloadInfo.format = audioFormat;
    185             offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
    186             offloadInfo.bit_rate = avgBitRate;
    187             offloadInfo.has_video = ((mCreateFlags & HAS_VIDEO) != 0);
    188             offloadInfo.is_streaming = ((mCreateFlags & IS_STREAMING) != 0);
    189         }
    190 
    191         status_t err = mAudioSink->open(
    192                 mSampleRate, numChannels, channelMask, audioFormat,
    193                 DEFAULT_AUDIOSINK_BUFFERCOUNT,
    194                 &AudioPlayer::AudioSinkCallback,
    195                 this,
    196                 (audio_output_flags_t)flags,
    197                 useOffload() ? &offloadInfo : NULL);
    198 
    199         if (err == OK) {
    200             mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
    201             mFrameSize = mAudioSink->frameSize();
    202 
    203             if (useOffload()) {
    204                 // If the playback is offloaded to h/w we pass the
    205                 // HAL some metadata information
    206                 // We don't want to do this for PCM because it will be going
    207                 // through the AudioFlinger mixer before reaching the hardware
    208                 sendMetaDataToHal(mAudioSink, format);
    209             }
    210 
    211             err = mAudioSink->start();
    212             // do not alter behavior for non offloaded tracks: ignore start status.
    213             if (!useOffload()) {
    214                 err = OK;
    215             }
    216         }
    217 
    218         if (err != OK) {
    219             if (mFirstBuffer != NULL) {
    220                 mFirstBuffer->release();
    221                 mFirstBuffer = NULL;
    222             }
    223 
    224             if (!sourceAlreadyStarted) {
    225                 mSource->stop();
    226             }
    227 
    228             return err;
    229         }
    230 
    231     } else {
    232         // playing to an AudioTrack, set up mask if necessary
    233         audio_channel_mask_t audioMask = channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER ?
    234                 audio_channel_out_mask_from_count(numChannels) : channelMask;
    235         if (0 == audioMask) {
    236             return BAD_VALUE;
    237         }
    238 
    239         mAudioTrack = new AudioTrack(
    240                 AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, audioMask,
    241                 0 /*frameCount*/, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this,
    242                 0 /*notificationFrames*/);
    243 
    244         if ((err = mAudioTrack->initCheck()) != OK) {
    245             mAudioTrack.clear();
    246 
    247             if (mFirstBuffer != NULL) {
    248                 mFirstBuffer->release();
    249                 mFirstBuffer = NULL;
    250             }
    251 
    252             if (!sourceAlreadyStarted) {
    253                 mSource->stop();
    254             }
    255 
    256             return err;
    257         }
    258 
    259         mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
    260         mFrameSize = mAudioTrack->frameSize();
    261 
    262         mAudioTrack->start();
    263     }
    264 
    265     mStarted = true;
    266     mPlaying = true;
    267 
    268     return OK;
    269 }
    270 
    271 void AudioPlayer::pause(bool playPendingSamples) {
    272     CHECK(mStarted);
    273 
    274     if (playPendingSamples) {
    275         if (mAudioSink.get() != NULL) {
    276             mAudioSink->stop();
    277         } else {
    278             mAudioTrack->stop();
    279         }
    280 
    281         mNumFramesPlayed = 0;
    282         mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
    283     } else {
    284         if (mAudioSink.get() != NULL) {
    285             mAudioSink->pause();
    286         } else {
    287             mAudioTrack->pause();
    288         }
    289     }
    290 
    291     mPlaying = false;
    292 }
    293 
    294 status_t AudioPlayer::resume() {
    295     CHECK(mStarted);
    296     status_t err;
    297 
    298     if (mAudioSink.get() != NULL) {
    299         err = mAudioSink->start();
    300     } else {
    301         err = mAudioTrack->start();
    302     }
    303 
    304     if (err == OK) {
    305         mPlaying = true;
    306     }
    307 
    308     return err;
    309 }
    310 
    311 void AudioPlayer::reset() {
    312     CHECK(mStarted);
    313 
    314     ALOGV("reset: mPlaying=%d mReachedEOS=%d useOffload=%d",
    315                                 mPlaying, mReachedEOS, useOffload() );
    316 
    317     if (mAudioSink.get() != NULL) {
    318         mAudioSink->stop();
    319         // If we're closing and have reached EOS, we don't want to flush
    320         // the track because if it is offloaded there could be a small
    321         // amount of residual data in the hardware buffer which we must
    322         // play to give gapless playback.
    323         // But if we're resetting when paused or before we've reached EOS
    324         // we can't be doing a gapless playback and there could be a large
    325         // amount of data queued in the hardware if the track is offloaded,
    326         // so we must flush to prevent a track switch being delayed playing
    327         // the buffered data that we don't want now
    328         if (!mPlaying || !mReachedEOS) {
    329             mAudioSink->flush();
    330         }
    331 
    332         mAudioSink->close();
    333     } else {
    334         mAudioTrack->stop();
    335 
    336         if (!mPlaying || !mReachedEOS) {
    337             mAudioTrack->flush();
    338         }
    339 
    340         mAudioTrack.clear();
    341     }
    342 
    343     // Make sure to release any buffer we hold onto so that the
    344     // source is able to stop().
    345 
    346     if (mFirstBuffer != NULL) {
    347         mFirstBuffer->release();
    348         mFirstBuffer = NULL;
    349     }
    350 
    351     if (mInputBuffer != NULL) {
    352         ALOGV("AudioPlayer releasing input buffer.");
    353 
    354         mInputBuffer->release();
    355         mInputBuffer = NULL;
    356     }
    357 
    358     mSource->stop();
    359 
    360     // The following hack is necessary to ensure that the OMX
    361     // component is completely released by the time we may try
    362     // to instantiate it again.
    363     // When offloading, the OMX component is not used so this hack
    364     // is not needed
    365     if (!useOffload()) {
    366         wp<MediaSource> tmp = mSource;
    367         mSource.clear();
    368         while (tmp.promote() != NULL) {
    369             usleep(1000);
    370         }
    371     } else {
    372         mSource.clear();
    373     }
    374     IPCThreadState::self()->flushCommands();
    375 
    376     mNumFramesPlayed = 0;
    377     mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
    378     mPositionTimeMediaUs = -1;
    379     mPositionTimeRealUs = -1;
    380     mSeeking = false;
    381     mSeekTimeUs = 0;
    382     mReachedEOS = false;
    383     mFinalStatus = OK;
    384     mStarted = false;
    385     mPlaying = false;
    386     mStartPosUs = 0;
    387 }
    388 
    389 // static
    390 void AudioPlayer::AudioCallback(int event, void *user, void *info) {
    391     static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
    392 }
    393 
    394 bool AudioPlayer::reachedEOS(status_t *finalStatus) {
    395     *finalStatus = OK;
    396 
    397     Mutex::Autolock autoLock(mLock);
    398     *finalStatus = mFinalStatus;
    399     return mReachedEOS;
    400 }
    401 
    402 status_t AudioPlayer::setPlaybackRate(const AudioPlaybackRate &rate) {
    403     if (mAudioSink.get() != NULL) {
    404         return mAudioSink->setPlaybackRate(rate);
    405     } else if (mAudioTrack != 0){
    406         return mAudioTrack->setPlaybackRate(rate);
    407     } else {
    408         return NO_INIT;
    409     }
    410 }
    411 
    412 status_t AudioPlayer::getPlaybackRate(AudioPlaybackRate *rate /* nonnull */) {
    413     if (mAudioSink.get() != NULL) {
    414         return mAudioSink->getPlaybackRate(rate);
    415     } else if (mAudioTrack != 0) {
    416         *rate = mAudioTrack->getPlaybackRate();
    417         return OK;
    418     } else {
    419         return NO_INIT;
    420     }
    421 }
    422 
    423 // static
    424 size_t AudioPlayer::AudioSinkCallback(
    425         MediaPlayerBase::AudioSink * /* audioSink */,
    426         void *buffer, size_t size, void *cookie,
    427         MediaPlayerBase::AudioSink::cb_event_t event) {
    428     AudioPlayer *me = (AudioPlayer *)cookie;
    429 
    430     switch(event) {
    431     case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
    432         return me->fillBuffer(buffer, size);
    433 
    434     case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
    435         ALOGV("AudioSinkCallback: stream end");
    436         me->mReachedEOS = true;
    437         break;
    438 
    439     case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
    440         ALOGV("AudioSinkCallback: Tear down event");
    441         break;
    442     }
    443 
    444     return 0;
    445 }
    446 
    447 void AudioPlayer::AudioCallback(int event, void *info) {
    448     switch (event) {
    449     case AudioTrack::EVENT_MORE_DATA:
    450         {
    451         AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
    452         size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
    453         buffer->size = numBytesWritten;
    454         }
    455         break;
    456 
    457     case AudioTrack::EVENT_STREAM_END:
    458         mReachedEOS = true;
    459         break;
    460     }
    461 }
    462 
    463 size_t AudioPlayer::fillBuffer(void *data, size_t size) {
    464     if (mNumFramesPlayed == 0) {
    465         ALOGV("AudioCallback");
    466     }
    467 
    468     if (mReachedEOS) {
    469         return 0;
    470     }
    471 
    472     size_t size_done = 0;
    473     size_t size_remaining = size;
    474     while (size_remaining > 0) {
    475         MediaSource::ReadOptions options;
    476         bool refreshSeekTime = false;
    477 
    478         {
    479             Mutex::Autolock autoLock(mLock);
    480 
    481             if (mSeeking) {
    482                 if (mIsFirstBuffer) {
    483                     if (mFirstBuffer != NULL) {
    484                         mFirstBuffer->release();
    485                         mFirstBuffer = NULL;
    486                     }
    487                     mIsFirstBuffer = false;
    488                 }
    489 
    490                 options.setSeekTo(mSeekTimeUs);
    491                 refreshSeekTime = true;
    492 
    493                 if (mInputBuffer != NULL) {
    494                     mInputBuffer->release();
    495                     mInputBuffer = NULL;
    496                 }
    497 
    498                 mSeeking = false;
    499             }
    500         }
    501 
    502         if (mInputBuffer == NULL) {
    503             status_t err;
    504 
    505             if (mIsFirstBuffer) {
    506                 mInputBuffer = mFirstBuffer;
    507                 mFirstBuffer = NULL;
    508                 err = mFirstBufferResult;
    509 
    510                 mIsFirstBuffer = false;
    511             } else {
    512                 err = mSource->read(&mInputBuffer, &options);
    513             }
    514 
    515             CHECK((err == OK && mInputBuffer != NULL)
    516                    || (err != OK && mInputBuffer == NULL));
    517 
    518             Mutex::Autolock autoLock(mLock);
    519 
    520             if (err != OK) {
    521                 if (!mReachedEOS) {
    522                     if (useOffload()) {
    523                         // no more buffers to push - stop() and wait for STREAM_END
    524                         // don't set mReachedEOS until stream end received
    525                         if (mAudioSink != NULL) {
    526                             mAudioSink->stop();
    527                         } else {
    528                             mAudioTrack->stop();
    529                         }
    530                     } else {
    531                         mReachedEOS = true;
    532                     }
    533                 }
    534 
    535                 mFinalStatus = err;
    536                 break;
    537             }
    538 
    539             if (mAudioSink != NULL) {
    540                 mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
    541             } else {
    542                 mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
    543             }
    544 
    545             if(mInputBuffer->range_length() != 0) {
    546                 CHECK(mInputBuffer->meta_data().findInt64(
    547                         kKeyTime, &mPositionTimeMediaUs));
    548             }
    549 
    550             // need to adjust the mStartPosUs for offload decoding since parser
    551             // might not be able to get the exact seek time requested.
    552             if (refreshSeekTime) {
    553                 if (useOffload()) {
    554                     mStartPosUs = mPositionTimeMediaUs;
    555                     ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
    556                 }
    557                 // clear seek time with mLock locked and once we have valid mPositionTimeMediaUs
    558                 // and mPositionTimeRealUs
    559                 // before clearing mSeekTimeUs check if a new seek request has been received while
    560                 // we were reading from the source with mLock released.
    561                 if (!mSeeking) {
    562                     mSeekTimeUs = 0;
    563                 }
    564             }
    565 
    566             if (!useOffload()) {
    567                 mPositionTimeRealUs =
    568                     ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
    569                         / mSampleRate;
    570                 ALOGV("buffer->size() = %zu, "
    571                      "mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
    572                      mInputBuffer->range_length(),
    573                      mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
    574             }
    575 
    576         }
    577 
    578         if (mInputBuffer->range_length() == 0) {
    579             mInputBuffer->release();
    580             mInputBuffer = NULL;
    581 
    582             continue;
    583         }
    584 
    585         size_t copy = size_remaining;
    586         if (copy > mInputBuffer->range_length()) {
    587             copy = mInputBuffer->range_length();
    588         }
    589 
    590         memcpy((char *)data + size_done,
    591                (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
    592                copy);
    593 
    594         mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
    595                                 mInputBuffer->range_length() - copy);
    596 
    597         size_done += copy;
    598         size_remaining -= copy;
    599     }
    600 
    601     if (useOffload()) {
    602         // We must ask the hardware what it has played
    603         mPositionTimeRealUs = getOutputPlayPositionUs_l();
    604         ALOGV("mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
    605              mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
    606     }
    607 
    608     {
    609         Mutex::Autolock autoLock(mLock);
    610         mNumFramesPlayed += size_done / mFrameSize;
    611         mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
    612     }
    613 
    614     return size_done;
    615 }
    616 
    617 int64_t AudioPlayer::getOutputPlayPositionUs_l()
    618 {
    619     uint32_t playedSamples = 0;
    620     uint32_t sampleRate;
    621     if (mAudioSink != NULL) {
    622         mAudioSink->getPosition(&playedSamples);
    623         sampleRate = mAudioSink->getSampleRate();
    624     } else {
    625         mAudioTrack->getPosition(&playedSamples);
    626         sampleRate = mAudioTrack->getSampleRate();
    627     }
    628     if (sampleRate != 0) {
    629         mSampleRate = sampleRate;
    630     }
    631 
    632     int64_t playedUs;
    633     if (mSampleRate != 0) {
    634         playedUs = (static_cast<int64_t>(playedSamples) * 1000000 ) / mSampleRate;
    635     } else {
    636         playedUs = 0;
    637     }
    638 
    639     // HAL position is relative to the first buffer we sent at mStartPosUs
    640     const int64_t renderedDuration = mStartPosUs + playedUs;
    641     ALOGV("getOutputPlayPositionUs_l %" PRId64, renderedDuration);
    642     return renderedDuration;
    643 }
    644 
    645 status_t AudioPlayer::seekTo(int64_t time_us) {
    646     Mutex::Autolock autoLock(mLock);
    647 
    648     ALOGV("seekTo( %" PRId64 " )", time_us);
    649 
    650     mSeeking = true;
    651     mPositionTimeRealUs = mPositionTimeMediaUs = -1;
    652     mReachedEOS = false;
    653     mSeekTimeUs = time_us;
    654     mStartPosUs = time_us;
    655 
    656     // Flush resets the number of played frames
    657     mNumFramesPlayed = 0;
    658     mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
    659 
    660     if (mAudioSink != NULL) {
    661         if (mPlaying) {
    662             mAudioSink->pause();
    663         }
    664         mAudioSink->flush();
    665         if (mPlaying) {
    666             mAudioSink->start();
    667         }
    668     } else {
    669         if (mPlaying) {
    670             mAudioTrack->pause();
    671         }
    672         mAudioTrack->flush();
    673         if (mPlaying) {
    674             mAudioTrack->start();
    675         }
    676     }
    677 
    678     return OK;
    679 }
    680 
    681 }
    682