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