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