• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SndFile_Callback(SLBufferQueueItf caller,void * pContext)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 
SndFile_IsSupported(const SF_INFO * sfinfo)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 
SndFile_checkAudioPlayerSourceSink(CAudioPlayer * thiz)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 
audioPlayerTransportUpdate(CAudioPlayer * audioPlayer)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 
SndFile_Realize(CAudioPlayer * thiz)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 
SndFile_Destroy(CAudioPlayer * thiz)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