1188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten/* 2188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Copyright (C) 2010 The Android Open Source Project 3188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * 4188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * you may not use this file except in compliance with the License. 6188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * You may obtain a copy of the License at 7188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * 8188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * 10188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Unless required by applicable law or agreed to in writing, software 11188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * See the License for the specific language governing permissions and 14188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * limitations under the License. 15188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten */ 16188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 1710ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief libsndfile integration */ 18188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 19188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten#include "sles_allinclusive.h" 20188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 216aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten 2266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten/** \brief Called by SndFile.c:audioPlayerTransportUpdate after a play state change or seek, 2366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten * and by IOutputMixExt::FillBuffer after each buffer is consumed. 2466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten */ 2510ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten 26ffeb2e16c2886eefa88d6eaf4c7be78c2eced82bGlenn Kastenvoid SndFile_Callback(SLBufferQueueItf caller, void *pContext) 27188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten{ 283cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten CAudioPlayer *thisAP = (CAudioPlayer *) pContext; 2915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten object_lock_peek(&thisAP->mObject); 3015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten SLuint32 state = thisAP->mPlay.mState; 3115f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten object_unlock_peek(&thisAP->mObject); 3266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (SL_PLAYSTATE_PLAYING != state) { 333cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten return; 3466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 3550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten struct SndFile *thiz = &thisAP->mSndFile; 36188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten SLresult result; 3750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten pthread_mutex_lock(&thiz->mMutex); 3850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten if (thiz->mEOF) { 3950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten pthread_mutex_unlock(&thiz->mMutex); 4015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten return; 4115f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten } 4250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten short *pBuffer = &thiz->mBuffer[thiz->mWhich * SndFile_BUFSIZE]; 4350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten if (++thiz->mWhich >= SndFile_NUMBUFS) { 4450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mWhich = 0; 4566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 46188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten sf_count_t count; 4750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten count = sf_read_short(thiz->mSNDFILE, pBuffer, (sf_count_t) SndFile_BUFSIZE); 4850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten pthread_mutex_unlock(&thiz->mMutex); 4966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten bool headAtNewPos = false; 5066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten object_lock_exclusive(&thisAP->mObject); 5166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten slPlayCallback callback = thisAP->mPlay.mCallback; 5266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten void *context = thisAP->mPlay.mContext; 5366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // make a copy of sample rate so we are absolutely sure we will not divide by zero 5466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten SLuint32 sampleRateMilliHz = thisAP->mSampleRateMilliHz; 55463a7641944e4a3613f5d76aa8450070ef56b9ffGlenn Kasten if (UNKNOWN_SAMPLERATE != sampleRateMilliHz) { 5666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // this will overflow after 49 days, but no fix possible as it's part of the API 5766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten thisAP->mPlay.mPosition = (SLuint32) (((long long) thisAP->mPlay.mFramesSinceLastSeek * 5866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten 1000000LL) / sampleRateMilliHz) + thisAP->mPlay.mLastSeekPosition; 5966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // make a good faith effort for the mean time between "head at new position" callbacks to 6066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // occur at the requested update period, but there will be jitter 6166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten SLuint32 frameUpdatePeriod = thisAP->mPlay.mFrameUpdatePeriod; 6266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if ((0 != frameUpdatePeriod) && 6366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten (thisAP->mPlay.mFramesSincePositionUpdate >= frameUpdatePeriod) && 6466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten (SL_PLAYEVENT_HEADATNEWPOS & thisAP->mPlay.mEventFlags)) { 6566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // if we overrun a requested update period, then reset the clock modulo the 6666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // update period so that it appears to the application as one or more lost callbacks, 6766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // but no additional jitter 6866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if ((thisAP->mPlay.mFramesSincePositionUpdate -= thisAP->mPlay.mFrameUpdatePeriod) >= 6966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten frameUpdatePeriod) { 7066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten thisAP->mPlay.mFramesSincePositionUpdate %= frameUpdatePeriod; 7166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 7266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten headAtNewPos = true; 7366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 7466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 75188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten if (0 < count) { 7666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten object_unlock_exclusive(&thisAP->mObject); 77aee4409e59584f8e8d0ddaf7e44dc80ec5b80444Glenn Kasten SLuint32 size = (SLuint32) (count * sizeof(short)); 789c03f04a9c6cc2a821182c8be8f2efe964a27efeGlenn Kasten result = IBufferQueue_Enqueue(caller, pBuffer, size); 7966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // not much we can do if the Enqueue fails, so we'll just drop the decoded data 8066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (SL_RESULT_SUCCESS != result) { 81156db48484793c2ce24f9ccd3cefe6e5f9f0b3feGlenn Kasten SL_LOGE("enqueue failed 0x%x", result); 82188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 833cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten } else { 843cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten thisAP->mPlay.mState = SL_PLAYSTATE_PAUSED; 8550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mEOF = SL_BOOLEAN_TRUE; 8666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // this would result in a non-monotonically increasing position, so don't do it 8766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // thisAP->mPlay.mPosition = thisAP->mPlay.mDuration; 8815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten object_unlock_exclusive_attributes(&thisAP->mObject, ATTR_TRANSPORT); 89188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 9066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // callbacks are called with mutex unlocked 9166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (NULL != callback) { 9266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (headAtNewPos) { 9366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten (*callback)(&thisAP->mPlay.mItf, context, SL_PLAYEVENT_HEADATNEWPOS); 9466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 9566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 96188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten} 97188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 9810ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten 9910ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief Check whether the supplied libsndfile format is supported by us */ 10010ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten 101188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn KastenSLboolean SndFile_IsSupported(const SF_INFO *sfinfo) 102188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten{ 103188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten switch (sfinfo->format & SF_FORMAT_TYPEMASK) { 104188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten case SF_FORMAT_WAV: 105188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten break; 106188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten default: 107188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten return SL_BOOLEAN_FALSE; 108188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 109188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten switch (sfinfo->format & SF_FORMAT_SUBMASK) { 1103cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten case SF_FORMAT_PCM_U8: 111188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten case SF_FORMAT_PCM_16: 112188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten break; 113188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten default: 114188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten return SL_BOOLEAN_FALSE; 115188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 116188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten switch (sfinfo->samplerate) { 1173cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten case 11025: 1183cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten case 22050: 119188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten case 44100: 120188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten break; 121188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten default: 122188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten return SL_BOOLEAN_FALSE; 123188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 124188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten switch (sfinfo->channels) { 1253cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten case 1: 126188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten case 2: 127188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten break; 128188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten default: 129188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten return SL_BOOLEAN_FALSE; 130188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 131188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten return SL_BOOLEAN_TRUE; 132188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten} 133188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 13410ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten 13510ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief Check whether the partially-constructed AudioPlayer is compatible with libsndfile */ 13610ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten 13750bccde01980ae803b8656e8b08ecacb65540f50Glenn KastenSLresult SndFile_checkAudioPlayerSourceSink(CAudioPlayer *thiz) 138f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten{ 13950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten const SLDataSource *pAudioSrc = &thiz->mDataSource.u.mSource; 140f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten SLuint32 locatorType = *(SLuint32 *)pAudioSrc->pLocator; 141f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten SLuint32 formatType = *(SLuint32 *)pAudioSrc->pFormat; 142f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten switch (locatorType) { 143f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten case SL_DATALOCATOR_BUFFERQUEUE: 1441a6bb4f8e738c9387dc9629db294ea5de618a53cGlenn Kasten#ifdef ANDROID 1451a6bb4f8e738c9387dc9629db294ea5de618a53cGlenn Kasten case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: 1461a6bb4f8e738c9387dc9629db294ea5de618a53cGlenn Kasten#endif 147f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten break; 148f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten case SL_DATALOCATOR_URI: 149f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten { 150f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten SLDataLocator_URI *dl_uri = (SLDataLocator_URI *) pAudioSrc->pLocator; 151f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten SLchar *uri = dl_uri->URI; 15266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (NULL == uri) { 153f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten return SL_RESULT_PARAMETER_INVALID; 15466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 15566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (!strncmp((const char *) uri, "file:///", 8)) { 15695364617b16ca2e322a4e0faeda93a2750d29fd6Glenn Kasten uri += 8; 15766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 158f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten switch (formatType) { 159c37c934e00a96afe18aaadd9f9a1863c721bf8eaGlenn Kasten case SL_DATAFORMAT_NULL: // OK to omit the data format 160c37c934e00a96afe18aaadd9f9a1863c721bf8eaGlenn Kasten case SL_DATAFORMAT_MIME: // we ignore a MIME type if specified 161f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten break; 162da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten case SL_DATAFORMAT_PCM: 163da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten case XA_DATAFORMAT_RAWIMAGE: 164f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 165da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten default: 166da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten // an invalid data format is detected earlier during the deep copy 167da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten assert(false); 168da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten return SL_RESULT_INTERNAL_ERROR; 169f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten } 17050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mSndFile.mPathname = uri; 17150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mBufferQueue.mNumBuffers = SndFile_NUMBUFS; 172f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten } 173f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten break; 174f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten default: 175f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 176f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten } 17750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mSndFile.mWhich = 0; 17850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mSndFile.mSNDFILE = NULL; 17950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten // thiz->mSndFile.mMutex is initialized only when there is a valid mSNDFILE 18050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mSndFile.mEOF = SL_BOOLEAN_FALSE; 181ec2cf4f7de22b97946cfb0c9c58d6db7f111b926Glenn Kasten 182f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten return SL_RESULT_SUCCESS; 183f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten} 184f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten 1856aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten 18610ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief Called with mutex unlocked for marker and position updates, and play state change */ 18723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 18815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kastenvoid audioPlayerTransportUpdate(CAudioPlayer *audioPlayer) 18915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten{ 19023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 19123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (NULL != audioPlayer->mSndFile.mSNDFILE) { 19223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 19323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten object_lock_exclusive(&audioPlayer->mObject); 19423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten SLboolean empty = 0 == audioPlayer->mBufferQueue.mState.count; 195ec2cf4f7de22b97946cfb0c9c58d6db7f111b926Glenn Kasten // FIXME a made-up number that should depend on player state and prefetch status 196ec2cf4f7de22b97946cfb0c9c58d6db7f111b926Glenn Kasten audioPlayer->mPrefetchStatus.mLevel = 1000; 19766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten SLmillisecond pos = audioPlayer->mSeek.mPos; 19866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (SL_TIME_UNKNOWN != pos) { 19966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN; 20066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // trim seek position to the current known duration 20166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (pos > audioPlayer->mPlay.mDuration) { 20266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten pos = audioPlayer->mPlay.mDuration; 20366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 20466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mPlay.mLastSeekPosition = pos; 20566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mPlay.mFramesSinceLastSeek = 0; 20666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // seek postpones the next head at new position callback 20766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mPlay.mFramesSincePositionUpdate = 0; 20866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 20923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten object_unlock_exclusive(&audioPlayer->mObject); 21023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 21123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (SL_TIME_UNKNOWN != pos) { 21223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 21323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // discard any enqueued buffers for the old position 2149c03f04a9c6cc2a821182c8be8f2efe964a27efeGlenn Kasten IBufferQueue_Clear(&audioPlayer->mBufferQueue.mItf); 21523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten empty = SL_BOOLEAN_TRUE; 21623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 21723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten pthread_mutex_lock(&audioPlayer->mSndFile.mMutex); 21866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // FIXME why void? 21923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten (void) sf_seek(audioPlayer->mSndFile.mSNDFILE, (sf_count_t) (((long long) pos * 22023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mSndFile.mSfInfo.samplerate) / 1000LL), SEEK_SET); 22123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mSndFile.mEOF = SL_BOOLEAN_FALSE; 22223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mSndFile.mWhich = 0; 22323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten pthread_mutex_unlock(&audioPlayer->mSndFile.mMutex); 22423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 22523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } 22623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 22723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // FIXME only on seek or play state change (STOPPED, PAUSED) -> PLAYING 22823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (empty) { 22923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten SndFile_Callback(&audioPlayer->mBufferQueue.mItf, audioPlayer); 23023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } 23123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 23215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten } 23315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten 23415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten} 23515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten 23651cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten 23751cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten/** \brief Called by CAudioPlayer_Realize */ 23851cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten 23950bccde01980ae803b8656e8b08ecacb65540f50Glenn KastenSLresult SndFile_Realize(CAudioPlayer *thiz) 24051cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten{ 24151cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten SLresult result = SL_RESULT_SUCCESS; 24250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten if (NULL != thiz->mSndFile.mPathname) { 24350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mSndFile.mSfInfo.format = 0; 24450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mSndFile.mSNDFILE = sf_open( 24550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten (const char *) thiz->mSndFile.mPathname, SFM_READ, &thiz->mSndFile.mSfInfo); 24650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten if (NULL == thiz->mSndFile.mSNDFILE) { 24751cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten result = SL_RESULT_CONTENT_NOT_FOUND; 24850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten } else if (!SndFile_IsSupported(&thiz->mSndFile.mSfInfo)) { 24950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten sf_close(thiz->mSndFile.mSNDFILE); 25050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mSndFile.mSNDFILE = NULL; 25151cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten result = SL_RESULT_CONTENT_UNSUPPORTED; 25251cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten } else { 25351cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten int ok; 25450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten ok = pthread_mutex_init(&thiz->mSndFile.mMutex, (const pthread_mutexattr_t *) NULL); 25551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten assert(0 == ok); 25650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten SLBufferQueueItf bufferQueue = &thiz->mBufferQueue.mItf; 25751cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten IBufferQueue *thisBQ = (IBufferQueue *) bufferQueue; 25850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten IBufferQueue_RegisterCallback(&thisBQ->mItf, SndFile_Callback, thiz); 25950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_SUFFICIENTDATA; 26051cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten // this is the initial duration; will update when a new maximum position is detected 26150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mPlay.mDuration = (SLmillisecond) (((long long) thiz->mSndFile.mSfInfo.frames * 26250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten 1000LL) / thiz->mSndFile.mSfInfo.samplerate); 26350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mNumChannels = thiz->mSndFile.mSfInfo.channels; 26450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mSampleRateMilliHz = thiz->mSndFile.mSfInfo.samplerate * 1000; 26551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten#ifdef USE_OUTPUTMIXEXT 26650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mPlay.mFrameUpdatePeriod = ((long long) thiz->mPlay.mPositionUpdatePeriod * 26750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten (long long) thiz->mSampleRateMilliHz) / 1000000LL; 26851cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten#endif 26951cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten } 27051cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten } 27151cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten return result; 27251cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten} 27351cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten 27451cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten 27551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten/** \brief Called by CAudioPlayer_Destroy */ 27651cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten 27750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kastenvoid SndFile_Destroy(CAudioPlayer *thiz) 27851cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten{ 27950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten if (NULL != thiz->mSndFile.mSNDFILE) { 28050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten sf_close(thiz->mSndFile.mSNDFILE); 28150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mSndFile.mSNDFILE = NULL; 28251cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten int ok; 28350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten ok = pthread_mutex_destroy(&thiz->mSndFile.mMutex); 28451cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten assert(0 == ok); 28551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten } 28651cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten} 287