Home | History | Annotate | Download | only in desktop
      1 /*
      2  * Copyright (C) 2010 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 /** \brief libsndfile integration */
     18 
     19 #include "sles_allinclusive.h"
     20 
     21 
     22 /** \brief Called by SndFile.c:audioPlayerTransportUpdate after a play state change or seek,
     23  *  and by IOutputMixExt::FillBuffer after each buffer is consumed.
     24  */
     25 
     26 void SndFile_Callback(SLBufferQueueItf caller, void *pContext)
     27 {
     28     CAudioPlayer *thisAP = (CAudioPlayer *) pContext;
     29     object_lock_peek(&thisAP->mObject);
     30     SLuint32 state = thisAP->mPlay.mState;
     31     object_unlock_peek(&thisAP->mObject);
     32     if (SL_PLAYSTATE_PLAYING != state) {
     33         return;
     34     }
     35     struct SndFile *thiz = &thisAP->mSndFile;
     36     SLresult result;
     37     pthread_mutex_lock(&thiz->mMutex);
     38     if (thiz->mEOF) {
     39         pthread_mutex_unlock(&thiz->mMutex);
     40         return;
     41     }
     42     short *pBuffer = &thiz->mBuffer[thiz->mWhich * SndFile_BUFSIZE];
     43     if (++thiz->mWhich >= SndFile_NUMBUFS) {
     44         thiz->mWhich = 0;
     45     }
     46     sf_count_t count;
     47     count = sf_read_short(thiz->mSNDFILE, pBuffer, (sf_count_t) SndFile_BUFSIZE);
     48     pthread_mutex_unlock(&thiz->mMutex);
     49     bool headAtNewPos = false;
     50     object_lock_exclusive(&thisAP->mObject);
     51     slPlayCallback callback = thisAP->mPlay.mCallback;
     52     void *context = thisAP->mPlay.mContext;
     53     // make a copy of sample rate so we are absolutely sure we will not divide by zero
     54     SLuint32 sampleRateMilliHz = thisAP->mSampleRateMilliHz;
     55     if (UNKNOWN_SAMPLERATE != sampleRateMilliHz) {
     56         // this will overflow after 49 days, but no fix possible as it's part of the API
     57         thisAP->mPlay.mPosition = (SLuint32) (((long long) thisAP->mPlay.mFramesSinceLastSeek *
     58             1000000LL) / sampleRateMilliHz) + thisAP->mPlay.mLastSeekPosition;
     59         // make a good faith effort for the mean time between "head at new position" callbacks to
     60         // occur at the requested update period, but there will be jitter
     61         SLuint32 frameUpdatePeriod = thisAP->mPlay.mFrameUpdatePeriod;
     62         if ((0 != frameUpdatePeriod) &&
     63             (thisAP->mPlay.mFramesSincePositionUpdate >= frameUpdatePeriod) &&
     64             (SL_PLAYEVENT_HEADATNEWPOS & thisAP->mPlay.mEventFlags)) {
     65             // if we overrun a requested update period, then reset the clock modulo the
     66             // update period so that it appears to the application as one or more lost callbacks,
     67             // but no additional jitter
     68             if ((thisAP->mPlay.mFramesSincePositionUpdate -= thisAP->mPlay.mFrameUpdatePeriod) >=
     69                     frameUpdatePeriod) {
     70                 thisAP->mPlay.mFramesSincePositionUpdate %= frameUpdatePeriod;
     71             }
     72             headAtNewPos = true;
     73         }
     74     }
     75     if (0 < count) {
     76         object_unlock_exclusive(&thisAP->mObject);
     77         SLuint32 size = (SLuint32) (count * sizeof(short));
     78         result = IBufferQueue_Enqueue(caller, pBuffer, size);
     79         // not much we can do if the Enqueue fails, so we'll just drop the decoded data
     80         if (SL_RESULT_SUCCESS != result) {
     81             SL_LOGE("enqueue failed 0x%x", result);
     82         }
     83     } else {
     84         thisAP->mPlay.mState = SL_PLAYSTATE_PAUSED;
     85         thiz->mEOF = SL_BOOLEAN_TRUE;
     86         // this would result in a non-monotonically increasing position, so don't do it
     87         // thisAP->mPlay.mPosition = thisAP->mPlay.mDuration;
     88         object_unlock_exclusive_attributes(&thisAP->mObject, ATTR_TRANSPORT);
     89     }
     90     // callbacks are called with mutex unlocked
     91     if (NULL != callback) {
     92         if (headAtNewPos) {
     93             (*callback)(&thisAP->mPlay.mItf, context, SL_PLAYEVENT_HEADATNEWPOS);
     94         }
     95     }
     96 }
     97 
     98 
     99 /** \brief Check whether the supplied libsndfile format is supported by us */
    100 
    101 SLboolean SndFile_IsSupported(const SF_INFO *sfinfo)
    102 {
    103     switch (sfinfo->format & SF_FORMAT_TYPEMASK) {
    104     case SF_FORMAT_WAV:
    105         break;
    106     default:
    107         return SL_BOOLEAN_FALSE;
    108     }
    109     switch (sfinfo->format & SF_FORMAT_SUBMASK) {
    110     case SF_FORMAT_PCM_U8:
    111     case SF_FORMAT_PCM_16:
    112         break;
    113     default:
    114         return SL_BOOLEAN_FALSE;
    115     }
    116     switch (sfinfo->samplerate) {
    117     case 11025:
    118     case 22050:
    119     case 44100:
    120         break;
    121     default:
    122         return SL_BOOLEAN_FALSE;
    123     }
    124     switch (sfinfo->channels) {
    125     case 1:
    126     case 2:
    127         break;
    128     default:
    129         return SL_BOOLEAN_FALSE;
    130     }
    131     return SL_BOOLEAN_TRUE;
    132 }
    133 
    134 
    135 /** \brief Check whether the partially-constructed AudioPlayer is compatible with libsndfile */
    136 
    137 SLresult SndFile_checkAudioPlayerSourceSink(CAudioPlayer *thiz)
    138 {
    139     const SLDataSource *pAudioSrc = &thiz->mDataSource.u.mSource;
    140     SLuint32 locatorType = *(SLuint32 *)pAudioSrc->pLocator;
    141     SLuint32 formatType = *(SLuint32 *)pAudioSrc->pFormat;
    142     switch (locatorType) {
    143     case SL_DATALOCATOR_BUFFERQUEUE:
    144 #ifdef ANDROID
    145     case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
    146 #endif
    147         break;
    148     case SL_DATALOCATOR_URI:
    149         {
    150         SLDataLocator_URI *dl_uri = (SLDataLocator_URI *) pAudioSrc->pLocator;
    151         SLchar *uri = dl_uri->URI;
    152         if (NULL == uri) {
    153             return SL_RESULT_PARAMETER_INVALID;
    154         }
    155         if (!strncmp((const char *) uri, "file:///", 8)) {
    156             uri += 8;
    157         }
    158         switch (formatType) {
    159         case SL_DATAFORMAT_NULL:    // OK to omit the data format
    160         case SL_DATAFORMAT_MIME:    // we ignore a MIME type if specified
    161             break;
    162         case SL_DATAFORMAT_PCM:
    163         case XA_DATAFORMAT_RAWIMAGE:
    164             return SL_RESULT_CONTENT_UNSUPPORTED;
    165         default:
    166             // an invalid data format is detected earlier during the deep copy
    167             assert(false);
    168             return SL_RESULT_INTERNAL_ERROR;
    169         }
    170         thiz->mSndFile.mPathname = uri;
    171         thiz->mBufferQueue.mNumBuffers = SndFile_NUMBUFS;
    172         }
    173         break;
    174     default:
    175         return SL_RESULT_CONTENT_UNSUPPORTED;
    176     }
    177     thiz->mSndFile.mWhich = 0;
    178     thiz->mSndFile.mSNDFILE = NULL;
    179     // thiz->mSndFile.mMutex is initialized only when there is a valid mSNDFILE
    180     thiz->mSndFile.mEOF = SL_BOOLEAN_FALSE;
    181 
    182     return SL_RESULT_SUCCESS;
    183 }
    184 
    185 
    186 /** \brief Called with mutex unlocked for marker and position updates, and play state change */
    187 
    188 void audioPlayerTransportUpdate(CAudioPlayer *audioPlayer)
    189 {
    190 
    191     if (NULL != audioPlayer->mSndFile.mSNDFILE) {
    192 
    193         object_lock_exclusive(&audioPlayer->mObject);
    194         SLboolean empty = 0 == audioPlayer->mBufferQueue.mState.count;
    195         // FIXME a made-up number that should depend on player state and prefetch status
    196         audioPlayer->mPrefetchStatus.mLevel = 1000;
    197         SLmillisecond pos = audioPlayer->mSeek.mPos;
    198         if (SL_TIME_UNKNOWN != pos) {
    199             audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN;
    200             // trim seek position to the current known duration
    201             if (pos > audioPlayer->mPlay.mDuration) {
    202                 pos = audioPlayer->mPlay.mDuration;
    203             }
    204             audioPlayer->mPlay.mLastSeekPosition = pos;
    205             audioPlayer->mPlay.mFramesSinceLastSeek = 0;
    206             // seek postpones the next head at new position callback
    207             audioPlayer->mPlay.mFramesSincePositionUpdate = 0;
    208         }
    209         object_unlock_exclusive(&audioPlayer->mObject);
    210 
    211         if (SL_TIME_UNKNOWN != pos) {
    212 
    213             // discard any enqueued buffers for the old position
    214             IBufferQueue_Clear(&audioPlayer->mBufferQueue.mItf);
    215             empty = SL_BOOLEAN_TRUE;
    216 
    217             pthread_mutex_lock(&audioPlayer->mSndFile.mMutex);
    218             // FIXME why void?
    219             (void) sf_seek(audioPlayer->mSndFile.mSNDFILE, (sf_count_t) (((long long) pos *
    220                 audioPlayer->mSndFile.mSfInfo.samplerate) / 1000LL), SEEK_SET);
    221             audioPlayer->mSndFile.mEOF = SL_BOOLEAN_FALSE;
    222             audioPlayer->mSndFile.mWhich = 0;
    223             pthread_mutex_unlock(&audioPlayer->mSndFile.mMutex);
    224 
    225         }
    226 
    227         // FIXME only on seek or play state change (STOPPED, PAUSED) -> PLAYING
    228         if (empty) {
    229             SndFile_Callback(&audioPlayer->mBufferQueue.mItf, audioPlayer);
    230         }
    231 
    232     }
    233 
    234 }
    235 
    236 
    237 /** \brief Called by CAudioPlayer_Realize */
    238 
    239 SLresult SndFile_Realize(CAudioPlayer *thiz)
    240 {
    241     SLresult result = SL_RESULT_SUCCESS;
    242     if (NULL != thiz->mSndFile.mPathname) {
    243         thiz->mSndFile.mSfInfo.format = 0;
    244         thiz->mSndFile.mSNDFILE = sf_open(
    245             (const char *) thiz->mSndFile.mPathname, SFM_READ, &thiz->mSndFile.mSfInfo);
    246         if (NULL == thiz->mSndFile.mSNDFILE) {
    247             result = SL_RESULT_CONTENT_NOT_FOUND;
    248         } else if (!SndFile_IsSupported(&thiz->mSndFile.mSfInfo)) {
    249             sf_close(thiz->mSndFile.mSNDFILE);
    250             thiz->mSndFile.mSNDFILE = NULL;
    251             result = SL_RESULT_CONTENT_UNSUPPORTED;
    252         } else {
    253             int ok;
    254             ok = pthread_mutex_init(&thiz->mSndFile.mMutex, (const pthread_mutexattr_t *) NULL);
    255             assert(0 == ok);
    256             SLBufferQueueItf bufferQueue = &thiz->mBufferQueue.mItf;
    257             IBufferQueue *thisBQ = (IBufferQueue *) bufferQueue;
    258             IBufferQueue_RegisterCallback(&thisBQ->mItf, SndFile_Callback, thiz);
    259             thiz->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_SUFFICIENTDATA;
    260             // this is the initial duration; will update when a new maximum position is detected
    261             thiz->mPlay.mDuration = (SLmillisecond) (((long long) thiz->mSndFile.mSfInfo.frames *
    262                 1000LL) / thiz->mSndFile.mSfInfo.samplerate);
    263             thiz->mNumChannels = thiz->mSndFile.mSfInfo.channels;
    264             thiz->mSampleRateMilliHz = thiz->mSndFile.mSfInfo.samplerate * 1000;
    265 #ifdef USE_OUTPUTMIXEXT
    266             thiz->mPlay.mFrameUpdatePeriod = ((long long) thiz->mPlay.mPositionUpdatePeriod *
    267                 (long long) thiz->mSampleRateMilliHz) / 1000000LL;
    268 #endif
    269         }
    270     }
    271     return result;
    272 }
    273 
    274 
    275 /** \brief Called by CAudioPlayer_Destroy */
    276 
    277 void SndFile_Destroy(CAudioPlayer *thiz)
    278 {
    279     if (NULL != thiz->mSndFile.mSNDFILE) {
    280         sf_close(thiz->mSndFile.mSNDFILE);
    281         thiz->mSndFile.mSNDFILE = NULL;
    282         int ok;
    283         ok = pthread_mutex_destroy(&thiz->mSndFile.mMutex);
    284         assert(0 == ok);
    285     }
    286 }
    287