SndFile.c revision 4b65ef9efdf5aba01bea89d8cdd64f500560a28d
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 17b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten/* libsndfile integration */ 18b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 19b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#include "sles_allinclusive.h" 20b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 21b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#ifdef USE_SNDFILE 22b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 236a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kastenvoid SndFile_Callback(SLBufferQueueItf caller, void *pContext) 24b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 25276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten CAudioPlayer *thisAP = (CAudioPlayer *) pContext; 26e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten object_lock_peek(&thisAP->mObject); 27e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLuint32 state = thisAP->mPlay.mState; 28e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten object_unlock_peek(&thisAP->mObject); 294b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // FIXME should not muck around directly at this low level 30e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (SL_PLAYSTATE_PLAYING != state) 31276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten return; 32276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten struct SndFile *this = &thisAP->mSndFile; 33b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLresult result; 344b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten pthread_mutex_lock(&this->mMutex); 354b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if ((NULL != this->mRetryBuffer) && (0 < this->mRetrySize)) { 3627f8dfaea17ab7831a1bd34a02f85d55bacf67b7Glenn Kasten result = (*caller)->Enqueue(caller, this->mRetryBuffer, this->mRetrySize); 374b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (SL_RESULT_BUFFER_INSUFFICIENT == result) { 384b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten pthread_mutex_unlock(&this->mMutex); 39b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return; // what, again? 404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 41b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(SL_RESULT_SUCCESS == result); 42b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mRetryBuffer = NULL; 43b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mRetrySize = 0; 444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten pthread_mutex_unlock(&this->mMutex); 45b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return; 46b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 47e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (this->mEOF) { 48e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten pthread_mutex_unlock(&this->mMutex); 49e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten return; 50e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 516a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten short *pBuffer = &this->mBuffer[this->mWhich * SndFile_BUFSIZE]; 526a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten if (++this->mWhich >= SndFile_NUMBUFS) 536a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten this->mWhich = 0; 54b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten sf_count_t count; 556a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten count = sf_read_short(this->mSNDFILE, pBuffer, (sf_count_t) SndFile_BUFSIZE); 56e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (0 >= count) 57e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten this->mEOF = SL_BOOLEAN_TRUE; 58e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten pthread_mutex_unlock(&this->mMutex); 59b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (0 < count) { 607324a5ab12cc734e2feb4cef8baeda26566d3c92Glenn Kasten SLuint32 size = (SLuint32) (count * sizeof(short)); 61b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten result = (*caller)->Enqueue(caller, pBuffer, size); 624b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // this should not happen, but if it does, who will call us to kick off again? 63b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (SL_RESULT_BUFFER_INSUFFICIENT == result) { 64b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mRetryBuffer = pBuffer; 65b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mRetrySize = size; 66b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return; 67b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 68b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(SL_RESULT_SUCCESS == result); 69276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten } else { 70e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten object_lock_exclusive(&thisAP->mObject); 714b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // FIXME This is really hosed, you can't do this anymore! 724b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // FIXME Need a state PAUSE_WHEN_EMPTY 737a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten // Should not pause yet - we just ran out of new data to enqueue, 74e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten // but there may still be (partially) full buffers in the queue. 75276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten thisAP->mPlay.mState = SL_PLAYSTATE_PAUSED; 76e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten thisAP->mPlay.mPosition = thisAP->mPlay.mDuration; 77e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten object_unlock_exclusive_attributes(&thisAP->mObject, ATTR_TRANSPORT); 78b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 79b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 80b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 81b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn KastenSLboolean SndFile_IsSupported(const SF_INFO *sfinfo) 82b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 83b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten switch (sfinfo->format & SF_FORMAT_TYPEMASK) { 84b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten case SF_FORMAT_WAV: 85b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 86b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten default: 87b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_FALSE; 88b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 89b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten switch (sfinfo->format & SF_FORMAT_SUBMASK) { 90276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten case SF_FORMAT_PCM_U8: 91b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten case SF_FORMAT_PCM_16: 92b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 93b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten default: 94b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_FALSE; 95b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 96b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten switch (sfinfo->samplerate) { 97276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten case 11025: 98276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten case 22050: 99b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten case 44100: 100b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 101b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten default: 102b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_FALSE; 103b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 104b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten switch (sfinfo->channels) { 105276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten case 1: 106b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten case 2: 107b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 108b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten default: 109b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_FALSE; 110b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 111b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten return SL_BOOLEAN_TRUE; 112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 114acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult SndFile_checkAudioPlayerSourceSink(CAudioPlayer *this) 115daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{ 116acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten const SLDataSource *pAudioSrc = &this->mDataSource.u.mSource; 117daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten SLuint32 locatorType = *(SLuint32 *)pAudioSrc->pLocator; 118daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten SLuint32 formatType = *(SLuint32 *)pAudioSrc->pFormat; 119daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten switch (locatorType) { 120daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten case SL_DATALOCATOR_BUFFERQUEUE: 121daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 122daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten case SL_DATALOCATOR_URI: 123daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten { 124daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten SLDataLocator_URI *dl_uri = (SLDataLocator_URI *) pAudioSrc->pLocator; 125daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten SLchar *uri = dl_uri->URI; 126daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten if (NULL == uri) 127daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_PARAMETER_INVALID; 12827f8dfaea17ab7831a1bd34a02f85d55bacf67b7Glenn Kasten if (!strncmp((const char *) uri, "file:///", 8)) 12927f8dfaea17ab7831a1bd34a02f85d55bacf67b7Glenn Kasten uri += 8; 130daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten switch (formatType) { 131a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten case SL_DATAFORMAT_NULL: // OK to omit the data format 132a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten case SL_DATAFORMAT_MIME: // we ignore a MIME type if specified 133daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 134daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten default: 135daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 136daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 13727f8dfaea17ab7831a1bd34a02f85d55bacf67b7Glenn Kasten this->mSndFile.mPathname = uri; 13840d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten this->mBufferQueue.mNumBuffers = SndFile_NUMBUFS; 139daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 140daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 141daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten default: 142daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 143daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 1446a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten this->mSndFile.mWhich = 0; 145acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten this->mSndFile.mSNDFILE = NULL; 146e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten // this->mSndFile.mMutex is initialized only when there is a valid mSNDFILE 147e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten this->mSndFile.mEOF = SL_BOOLEAN_FALSE; 148acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten this->mSndFile.mRetryBuffer = NULL; 149acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten this->mSndFile.mRetrySize = 0; 150daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_SUCCESS; 151daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten} 152daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 1534b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten// called with mutex unlocked for marker and position updates, and play state change 1544b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten// FIXME should use two separate hooks since we have separate attributes TRANSPORT and POSITION 1554b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 156e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenvoid audioPlayerTransportUpdate(CAudioPlayer *audioPlayer) 157e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{ 1584b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (NULL != audioPlayer->mSndFile.mSNDFILE) { 1604b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1614b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_lock_exclusive(&audioPlayer->mObject); 1624b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten SLmillisecond pos = audioPlayer->mSeek.mPos; 1634b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN; 1644b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten SLboolean empty = 0 == audioPlayer->mBufferQueue.mState.count; 1654b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_unlock_exclusive(&audioPlayer->mObject); 1664b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1674b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (SL_TIME_UNKNOWN != pos) { 1684b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1694b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // discard any enqueued buffers for the old position 1704b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten (*&audioPlayer->mBufferQueue.mItf)->Clear(&audioPlayer->mBufferQueue.mItf); 1714b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten empty = SL_BOOLEAN_TRUE; 1724b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1734b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten pthread_mutex_lock(&audioPlayer->mSndFile.mMutex); 1744b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten (void) sf_seek(audioPlayer->mSndFile.mSNDFILE, (sf_count_t) (((long long) pos * 1754b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mSndFile.mSfInfo.samplerate) / 1000LL), SEEK_SET); 1764b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mSndFile.mEOF = SL_BOOLEAN_FALSE; 1774b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mSndFile.mRetryBuffer = NULL; 1784b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mSndFile.mRetrySize = 0; 1794b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mSndFile.mWhich = 0; 1804b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten pthread_mutex_unlock(&audioPlayer->mSndFile.mMutex); 1814b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1824b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 1834b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1844b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // FIXME only on seek or play state change (STOPPED, PAUSED) -> PLAYING 1854b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (empty) { 1864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten SndFile_Callback(&audioPlayer->mBufferQueue.mItf, audioPlayer); 1874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 1884b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 189e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 190e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 191e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten} 192e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 193b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_SNDFILE 194