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 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "AudioPlayer"
     19 #include <utils/Log.h>
     20 
     21 #include <binder/IPCThreadState.h>
     22 #include <media/AudioTrack.h>
     23 #include <media/stagefright/AudioPlayer.h>
     24 #include <media/stagefright/MediaDebug.h>
     25 #include <media/stagefright/MediaDefs.h>
     26 #include <media/stagefright/MediaSource.h>
     27 #include <media/stagefright/MetaData.h>
     28 
     29 namespace android {
     30 
     31 AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
     32     : mAudioTrack(NULL),
     33       mInputBuffer(NULL),
     34       mSampleRate(0),
     35       mLatencyUs(0),
     36       mFrameSize(0),
     37       mNumFramesPlayed(0),
     38       mPositionTimeMediaUs(-1),
     39       mPositionTimeRealUs(-1),
     40       mSeeking(false),
     41       mReachedEOS(false),
     42       mFinalStatus(OK),
     43       mStarted(false),
     44       mAudioSink(audioSink) {
     45 }
     46 
     47 AudioPlayer::~AudioPlayer() {
     48     if (mStarted) {
     49         stop();
     50     }
     51 }
     52 
     53 void AudioPlayer::setSource(const sp<MediaSource> &source) {
     54     CHECK_EQ(mSource, NULL);
     55     mSource = source;
     56 }
     57 
     58 status_t AudioPlayer::start(bool sourceAlreadyStarted) {
     59     CHECK(!mStarted);
     60     CHECK(mSource != NULL);
     61 
     62     status_t err;
     63     if (!sourceAlreadyStarted) {
     64         err = mSource->start();
     65 
     66         if (err != OK) {
     67             return err;
     68         }
     69     }
     70 
     71     sp<MetaData> format = mSource->getFormat();
     72     const char *mime;
     73     bool success = format->findCString(kKeyMIMEType, &mime);
     74     CHECK(success);
     75     CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
     76 
     77     success = format->findInt32(kKeySampleRate, &mSampleRate);
     78     CHECK(success);
     79 
     80     int32_t numChannels;
     81     success = format->findInt32(kKeyChannelCount, &numChannels);
     82     CHECK(success);
     83 
     84     if (mAudioSink.get() != NULL) {
     85         status_t err = mAudioSink->open(
     86                 mSampleRate, numChannels, AudioSystem::PCM_16_BIT,
     87                 DEFAULT_AUDIOSINK_BUFFERCOUNT,
     88                 &AudioPlayer::AudioSinkCallback, this);
     89         if (err != OK) {
     90             mSource->stop();
     91 
     92             return err;
     93         }
     94 
     95         mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
     96         mFrameSize = mAudioSink->frameSize();
     97 
     98         mAudioSink->start();
     99     } else {
    100         mAudioTrack = new AudioTrack(
    101                 AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
    102                 (numChannels == 2)
    103                     ? AudioSystem::CHANNEL_OUT_STEREO
    104                     : AudioSystem::CHANNEL_OUT_MONO,
    105                 0, 0, &AudioCallback, this, 0);
    106 
    107         if ((err = mAudioTrack->initCheck()) != OK) {
    108             delete mAudioTrack;
    109             mAudioTrack = NULL;
    110 
    111             mSource->stop();
    112 
    113             return err;
    114         }
    115 
    116         mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
    117         mFrameSize = mAudioTrack->frameSize();
    118 
    119         mAudioTrack->start();
    120     }
    121 
    122     mStarted = true;
    123 
    124     return OK;
    125 }
    126 
    127 void AudioPlayer::pause() {
    128     CHECK(mStarted);
    129 
    130     if (mAudioSink.get() != NULL) {
    131         mAudioSink->pause();
    132     } else {
    133         mAudioTrack->stop();
    134     }
    135 }
    136 
    137 void AudioPlayer::resume() {
    138     CHECK(mStarted);
    139 
    140     if (mAudioSink.get() != NULL) {
    141         mAudioSink->start();
    142     } else {
    143         mAudioTrack->start();
    144     }
    145 }
    146 
    147 void AudioPlayer::stop() {
    148     CHECK(mStarted);
    149 
    150     if (mAudioSink.get() != NULL) {
    151         mAudioSink->stop();
    152         mAudioSink->close();
    153     } else {
    154         mAudioTrack->stop();
    155 
    156         delete mAudioTrack;
    157         mAudioTrack = NULL;
    158     }
    159 
    160     // Make sure to release any buffer we hold onto so that the
    161     // source is able to stop().
    162     if (mInputBuffer != NULL) {
    163         LOGV("AudioPlayer releasing input buffer.");
    164 
    165         mInputBuffer->release();
    166         mInputBuffer = NULL;
    167     }
    168 
    169     mSource->stop();
    170 
    171     // The following hack is necessary to ensure that the OMX
    172     // component is completely released by the time we may try
    173     // to instantiate it again.
    174     wp<MediaSource> tmp = mSource;
    175     mSource.clear();
    176     while (tmp.promote() != NULL) {
    177         usleep(1000);
    178     }
    179     IPCThreadState::self()->flushCommands();
    180 
    181     mNumFramesPlayed = 0;
    182     mPositionTimeMediaUs = -1;
    183     mPositionTimeRealUs = -1;
    184     mSeeking = false;
    185     mReachedEOS = false;
    186     mFinalStatus = OK;
    187     mStarted = false;
    188 }
    189 
    190 // static
    191 void AudioPlayer::AudioCallback(int event, void *user, void *info) {
    192     static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
    193 }
    194 
    195 bool AudioPlayer::isSeeking() {
    196     Mutex::Autolock autoLock(mLock);
    197     return mSeeking;
    198 }
    199 
    200 bool AudioPlayer::reachedEOS(status_t *finalStatus) {
    201     *finalStatus = OK;
    202 
    203     Mutex::Autolock autoLock(mLock);
    204     *finalStatus = mFinalStatus;
    205     return mReachedEOS;
    206 }
    207 
    208 // static
    209 size_t AudioPlayer::AudioSinkCallback(
    210         MediaPlayerBase::AudioSink *audioSink,
    211         void *buffer, size_t size, void *cookie) {
    212     AudioPlayer *me = (AudioPlayer *)cookie;
    213 
    214     return me->fillBuffer(buffer, size);
    215 }
    216 
    217 void AudioPlayer::AudioCallback(int event, void *info) {
    218     if (event != AudioTrack::EVENT_MORE_DATA) {
    219         return;
    220     }
    221 
    222     AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
    223     size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
    224 
    225     buffer->size = numBytesWritten;
    226 }
    227 
    228 size_t AudioPlayer::fillBuffer(void *data, size_t size) {
    229     if (mNumFramesPlayed == 0) {
    230         LOGV("AudioCallback");
    231     }
    232 
    233     if (mReachedEOS) {
    234         return 0;
    235     }
    236 
    237     size_t size_done = 0;
    238     size_t size_remaining = size;
    239     while (size_remaining > 0) {
    240         MediaSource::ReadOptions options;
    241 
    242         {
    243             Mutex::Autolock autoLock(mLock);
    244 
    245             if (mSeeking) {
    246                 options.setSeekTo(mSeekTimeUs);
    247 
    248                 if (mInputBuffer != NULL) {
    249                     mInputBuffer->release();
    250                     mInputBuffer = NULL;
    251                 }
    252 
    253                 mSeeking = false;
    254             }
    255         }
    256 
    257         if (mInputBuffer == NULL) {
    258             status_t err = mSource->read(&mInputBuffer, &options);
    259 
    260             CHECK((err == OK && mInputBuffer != NULL)
    261                    || (err != OK && mInputBuffer == NULL));
    262 
    263             Mutex::Autolock autoLock(mLock);
    264 
    265             if (err != OK) {
    266                 mReachedEOS = true;
    267                 mFinalStatus = err;
    268                 break;
    269             }
    270 
    271             CHECK(mInputBuffer->meta_data()->findInt64(
    272                         kKeyTime, &mPositionTimeMediaUs));
    273 
    274             mPositionTimeRealUs =
    275                 ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
    276                     / mSampleRate;
    277 
    278             LOGV("buffer->size() = %d, "
    279                  "mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
    280                  mInputBuffer->range_length(),
    281                  mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
    282         }
    283 
    284         if (mInputBuffer->range_length() == 0) {
    285             mInputBuffer->release();
    286             mInputBuffer = NULL;
    287 
    288             continue;
    289         }
    290 
    291         size_t copy = size_remaining;
    292         if (copy > mInputBuffer->range_length()) {
    293             copy = mInputBuffer->range_length();
    294         }
    295 
    296         memcpy((char *)data + size_done,
    297                (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
    298                copy);
    299 
    300         mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
    301                                 mInputBuffer->range_length() - copy);
    302 
    303         size_done += copy;
    304         size_remaining -= copy;
    305     }
    306 
    307     Mutex::Autolock autoLock(mLock);
    308     mNumFramesPlayed += size_done / mFrameSize;
    309 
    310     return size_done;
    311 }
    312 
    313 int64_t AudioPlayer::getRealTimeUs() {
    314     Mutex::Autolock autoLock(mLock);
    315     return getRealTimeUsLocked();
    316 }
    317 
    318 int64_t AudioPlayer::getRealTimeUsLocked() const {
    319     return -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate;
    320 }
    321 
    322 int64_t AudioPlayer::getMediaTimeUs() {
    323     Mutex::Autolock autoLock(mLock);
    324 
    325     if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) {
    326         return 0;
    327     }
    328 
    329     int64_t realTimeOffset = getRealTimeUsLocked() - mPositionTimeRealUs;
    330     if (realTimeOffset < 0) {
    331         realTimeOffset = 0;
    332     }
    333 
    334     return mPositionTimeMediaUs + realTimeOffset;
    335 }
    336 
    337 bool AudioPlayer::getMediaTimeMapping(
    338         int64_t *realtime_us, int64_t *mediatime_us) {
    339     Mutex::Autolock autoLock(mLock);
    340 
    341     *realtime_us = mPositionTimeRealUs;
    342     *mediatime_us = mPositionTimeMediaUs;
    343 
    344     return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
    345 }
    346 
    347 status_t AudioPlayer::seekTo(int64_t time_us) {
    348     Mutex::Autolock autoLock(mLock);
    349 
    350     mSeeking = true;
    351     mReachedEOS = false;
    352     mSeekTimeUs = time_us;
    353 
    354     return OK;
    355 }
    356 
    357 }
    358