1b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten/* 2b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * Copyright (C) 2010 The Android Open Source Project 3b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * 4b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * you may not use this file except in compliance with the License. 6b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * You may obtain a copy of the License at 7b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * 8b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * 10b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * Unless required by applicable law or agreed to in writing, software 11b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * See the License for the specific language governing permissions and 14b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * limitations under the License. 15b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten */ 16b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 17369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief libsndfile integration */ 18b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 19b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#include "sles_allinclusive.h" 20b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 21343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten 228c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten/** \brief Called by SndFile.c:audioPlayerTransportUpdate after a play state change or seek, 238c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten * and by IOutputMixExt::FillBuffer after each buffer is consumed. 248c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten */ 25369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten 266a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kastenvoid SndFile_Callback(SLBufferQueueItf caller, void *pContext) 27b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 28276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten CAudioPlayer *thisAP = (CAudioPlayer *) pContext; 29e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten object_lock_peek(&thisAP->mObject); 30e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLuint32 state = thisAP->mPlay.mState; 31e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten object_unlock_peek(&thisAP->mObject); 328c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (SL_PLAYSTATE_PLAYING != state) { 33276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten return; 348c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 35bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten struct SndFile *thiz = &thisAP->mSndFile; 36b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLresult result; 37bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten pthread_mutex_lock(&thiz->mMutex); 38bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (thiz->mEOF) { 39bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten pthread_mutex_unlock(&thiz->mMutex); 40e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten return; 41e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 42bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten short *pBuffer = &thiz->mBuffer[thiz->mWhich * SndFile_BUFSIZE]; 43bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (++thiz->mWhich >= SndFile_NUMBUFS) { 44bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mWhich = 0; 458c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 46b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten sf_count_t count; 47bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten count = sf_read_short(thiz->mSNDFILE, pBuffer, (sf_count_t) SndFile_BUFSIZE); 48bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten pthread_mutex_unlock(&thiz->mMutex); 498c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten bool headAtNewPos = false; 508c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten object_lock_exclusive(&thisAP->mObject); 518c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten slPlayCallback callback = thisAP->mPlay.mCallback; 528c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten void *context = thisAP->mPlay.mContext; 538c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // make a copy of sample rate so we are absolutely sure we will not divide by zero 548c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten SLuint32 sampleRateMilliHz = thisAP->mSampleRateMilliHz; 551a9c2615d0933d183fcb1b9e34ec8f0da2a85153Glenn Kasten if (UNKNOWN_SAMPLERATE != sampleRateMilliHz) { 568c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // this will overflow after 49 days, but no fix possible as it's part of the API 578c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten thisAP->mPlay.mPosition = (SLuint32) (((long long) thisAP->mPlay.mFramesSinceLastSeek * 588c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten 1000000LL) / sampleRateMilliHz) + thisAP->mPlay.mLastSeekPosition; 598c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // make a good faith effort for the mean time between "head at new position" callbacks to 608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // occur at the requested update period, but there will be jitter 618c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten SLuint32 frameUpdatePeriod = thisAP->mPlay.mFrameUpdatePeriod; 628c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if ((0 != frameUpdatePeriod) && 638c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten (thisAP->mPlay.mFramesSincePositionUpdate >= frameUpdatePeriod) && 648c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten (SL_PLAYEVENT_HEADATNEWPOS & thisAP->mPlay.mEventFlags)) { 658c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // if we overrun a requested update period, then reset the clock modulo the 668c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // update period so that it appears to the application as one or more lost callbacks, 678c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // but no additional jitter 688c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if ((thisAP->mPlay.mFramesSincePositionUpdate -= thisAP->mPlay.mFrameUpdatePeriod) >= 698c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten frameUpdatePeriod) { 708c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten thisAP->mPlay.mFramesSincePositionUpdate %= frameUpdatePeriod; 718c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 728c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten headAtNewPos = true; 738c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 748c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 75b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (0 < count) { 768c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten object_unlock_exclusive(&thisAP->mObject); 777324a5ab12cc734e2feb4cef8baeda26566d3c92Glenn Kasten SLuint32 size = (SLuint32) (count * sizeof(short)); 78e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten result = IBufferQueue_Enqueue(caller, pBuffer, size); 798c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // not much we can do if the Enqueue fails, so we'll just drop the decoded data 808c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (SL_RESULT_SUCCESS != result) { 8171139e6bc1f077d285fb04629925d99383d1114fGlenn Kasten SL_LOGE("enqueue failed 0x%x", result); 82b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 83276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten } else { 84276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten thisAP->mPlay.mState = SL_PLAYSTATE_PAUSED; 85bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mEOF = SL_BOOLEAN_TRUE; 868c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // this would result in a non-monotonically increasing position, so don't do it 878c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // thisAP->mPlay.mPosition = thisAP->mPlay.mDuration; 88e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten object_unlock_exclusive_attributes(&thisAP->mObject, ATTR_TRANSPORT); 89b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 908c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // callbacks are called with mutex unlocked 918c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (NULL != callback) { 928c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (headAtNewPos) { 938c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten (*callback)(&thisAP->mPlay.mItf, context, SL_PLAYEVENT_HEADATNEWPOS); 948c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 958c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 96b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 97b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 98369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten 99369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Check whether the supplied libsndfile format is supported by us */ 100369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten 101b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn KastenSLboolean SndFile_IsSupported(const SF_INFO *sfinfo) 102b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 103b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten switch (sfinfo->format & SF_FORMAT_TYPEMASK) { 104b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten case SF_FORMAT_WAV: 105b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 106b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten default: 107b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_FALSE; 108b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 109b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten switch (sfinfo->format & SF_FORMAT_SUBMASK) { 110276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten case SF_FORMAT_PCM_U8: 111b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten case SF_FORMAT_PCM_16: 112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten default: 114b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_FALSE; 115b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 116b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten switch (sfinfo->samplerate) { 117276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten case 11025: 118276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten case 22050: 119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten case 44100: 120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 121b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten default: 122b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_FALSE; 123b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten switch (sfinfo->channels) { 125276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten case 1: 126b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten case 2: 127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten default: 129b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_FALSE; 130b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 131b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_TRUE; 132b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 133b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 134369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten 135369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Check whether the partially-constructed AudioPlayer is compatible with libsndfile */ 136369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten 137bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn KastenSLresult SndFile_checkAudioPlayerSourceSink(CAudioPlayer *thiz) 138daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{ 139bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const SLDataSource *pAudioSrc = &thiz->mDataSource.u.mSource; 140daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten SLuint32 locatorType = *(SLuint32 *)pAudioSrc->pLocator; 141daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten SLuint32 formatType = *(SLuint32 *)pAudioSrc->pFormat; 142daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten switch (locatorType) { 143daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten case SL_DATALOCATOR_BUFFERQUEUE: 14401e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten#ifdef ANDROID 14501e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: 14601e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten#endif 147daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 148daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten case SL_DATALOCATOR_URI: 149daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten { 150daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten SLDataLocator_URI *dl_uri = (SLDataLocator_URI *) pAudioSrc->pLocator; 151daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten SLchar *uri = dl_uri->URI; 1528c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (NULL == uri) { 153daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_PARAMETER_INVALID; 1548c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 1558c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (!strncmp((const char *) uri, "file:///", 8)) { 15627f8dfaea17ab7831a1bd34a02f85d55bacf67b7Glenn Kasten uri += 8; 1578c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 158daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten switch (formatType) { 159a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten case SL_DATAFORMAT_NULL: // OK to omit the data format 160a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten case SL_DATAFORMAT_MIME: // we ignore a MIME type if specified 161daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 16294a37e8117fb72790882dfb815f99e2365754c74Glenn Kasten case SL_DATAFORMAT_PCM: 16394a37e8117fb72790882dfb815f99e2365754c74Glenn Kasten case XA_DATAFORMAT_RAWIMAGE: 164daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 16594a37e8117fb72790882dfb815f99e2365754c74Glenn Kasten default: 16694a37e8117fb72790882dfb815f99e2365754c74Glenn Kasten // an invalid data format is detected earlier during the deep copy 16794a37e8117fb72790882dfb815f99e2365754c74Glenn Kasten assert(false); 16894a37e8117fb72790882dfb815f99e2365754c74Glenn Kasten return SL_RESULT_INTERNAL_ERROR; 169daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 170bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mSndFile.mPathname = uri; 171bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mBufferQueue.mNumBuffers = SndFile_NUMBUFS; 172daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 173daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 174daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten default: 175daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 176daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 177bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mSndFile.mWhich = 0; 178bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mSndFile.mSNDFILE = NULL; 179bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten // thiz->mSndFile.mMutex is initialized only when there is a valid mSNDFILE 180bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mSndFile.mEOF = SL_BOOLEAN_FALSE; 1813d81b8ca5d3cee893672beb76e00849d4f3fa8b8Glenn Kasten 182daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_SUCCESS; 183daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten} 184daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 185343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten 186369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Called with mutex unlocked for marker and position updates, and play state change */ 1874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 188e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenvoid audioPlayerTransportUpdate(CAudioPlayer *audioPlayer) 189e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{ 1904b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (NULL != audioPlayer->mSndFile.mSNDFILE) { 1924b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1934b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_lock_exclusive(&audioPlayer->mObject); 1944b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten SLboolean empty = 0 == audioPlayer->mBufferQueue.mState.count; 1953d81b8ca5d3cee893672beb76e00849d4f3fa8b8Glenn Kasten // FIXME a made-up number that should depend on player state and prefetch status 1963d81b8ca5d3cee893672beb76e00849d4f3fa8b8Glenn Kasten audioPlayer->mPrefetchStatus.mLevel = 1000; 1978c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten SLmillisecond pos = audioPlayer->mSeek.mPos; 1988c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (SL_TIME_UNKNOWN != pos) { 1998c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN; 2008c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // trim seek position to the current known duration 2018c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (pos > audioPlayer->mPlay.mDuration) { 2028c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten pos = audioPlayer->mPlay.mDuration; 2038c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 2048c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mPlay.mLastSeekPosition = pos; 2058c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mPlay.mFramesSinceLastSeek = 0; 2068c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // seek postpones the next head at new position callback 2078c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mPlay.mFramesSincePositionUpdate = 0; 2088c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 2094b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_unlock_exclusive(&audioPlayer->mObject); 2104b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 2114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (SL_TIME_UNKNOWN != pos) { 2124b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 2134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // discard any enqueued buffers for the old position 214e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten IBufferQueue_Clear(&audioPlayer->mBufferQueue.mItf); 2154b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten empty = SL_BOOLEAN_TRUE; 2164b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 2174b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten pthread_mutex_lock(&audioPlayer->mSndFile.mMutex); 2188c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // FIXME why void? 2194b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten (void) sf_seek(audioPlayer->mSndFile.mSNDFILE, (sf_count_t) (((long long) pos * 2204b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mSndFile.mSfInfo.samplerate) / 1000LL), SEEK_SET); 2214b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mSndFile.mEOF = SL_BOOLEAN_FALSE; 2224b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mSndFile.mWhich = 0; 2234b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten pthread_mutex_unlock(&audioPlayer->mSndFile.mMutex); 2244b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 2254b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 2264b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 2274b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // FIXME only on seek or play state change (STOPPED, PAUSED) -> PLAYING 2284b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (empty) { 2294b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten SndFile_Callback(&audioPlayer->mBufferQueue.mItf, audioPlayer); 2304b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 2314b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 232e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 233e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 234e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten} 235e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 236a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten 237a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten/** \brief Called by CAudioPlayer_Realize */ 238a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten 239bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn KastenSLresult SndFile_Realize(CAudioPlayer *thiz) 240a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten{ 241a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten SLresult result = SL_RESULT_SUCCESS; 242bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (NULL != thiz->mSndFile.mPathname) { 243bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mSndFile.mSfInfo.format = 0; 244bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mSndFile.mSNDFILE = sf_open( 245bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten (const char *) thiz->mSndFile.mPathname, SFM_READ, &thiz->mSndFile.mSfInfo); 246bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (NULL == thiz->mSndFile.mSNDFILE) { 247a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten result = SL_RESULT_CONTENT_NOT_FOUND; 248bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten } else if (!SndFile_IsSupported(&thiz->mSndFile.mSfInfo)) { 249bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten sf_close(thiz->mSndFile.mSNDFILE); 250bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mSndFile.mSNDFILE = NULL; 251a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten result = SL_RESULT_CONTENT_UNSUPPORTED; 252a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten } else { 253a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten int ok; 254bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten ok = pthread_mutex_init(&thiz->mSndFile.mMutex, (const pthread_mutexattr_t *) NULL); 255a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten assert(0 == ok); 256bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten SLBufferQueueItf bufferQueue = &thiz->mBufferQueue.mItf; 257a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten IBufferQueue *thisBQ = (IBufferQueue *) bufferQueue; 258bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IBufferQueue_RegisterCallback(&thisBQ->mItf, SndFile_Callback, thiz); 259bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_SUFFICIENTDATA; 260a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten // this is the initial duration; will update when a new maximum position is detected 261bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mPlay.mDuration = (SLmillisecond) (((long long) thiz->mSndFile.mSfInfo.frames * 262bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten 1000LL) / thiz->mSndFile.mSfInfo.samplerate); 263bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mNumChannels = thiz->mSndFile.mSfInfo.channels; 264bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mSampleRateMilliHz = thiz->mSndFile.mSfInfo.samplerate * 1000; 265a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#ifdef USE_OUTPUTMIXEXT 266bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mPlay.mFrameUpdatePeriod = ((long long) thiz->mPlay.mPositionUpdatePeriod * 267bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten (long long) thiz->mSampleRateMilliHz) / 1000000LL; 268a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#endif 269a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten } 270a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten } 271a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten return result; 272a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten} 273a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten 274a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten 275a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten/** \brief Called by CAudioPlayer_Destroy */ 276a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten 277bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid SndFile_Destroy(CAudioPlayer *thiz) 278a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten{ 279bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (NULL != thiz->mSndFile.mSNDFILE) { 280bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten sf_close(thiz->mSndFile.mSNDFILE); 281bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mSndFile.mSNDFILE = NULL; 282a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten int ok; 283bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten ok = pthread_mutex_destroy(&thiz->mSndFile.mMutex); 284a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten assert(0 == ok); 285a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten } 286a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten} 287