SndFile.c revision 8c065779232fdd89abace68d2fc7bea786a010d7
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
21b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#ifdef USE_SNDFILE
22b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
23343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
248c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten/** \brief Called by SndFile.c:audioPlayerTransportUpdate after a play state change or seek,
258c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten *  and by IOutputMixExt::FillBuffer after each buffer is consumed.
268c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten */
27369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten
286a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kastenvoid SndFile_Callback(SLBufferQueueItf caller, void *pContext)
29b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
30276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    CAudioPlayer *thisAP = (CAudioPlayer *) pContext;
31e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    object_lock_peek(&thisAP->mObject);
32e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLuint32 state = thisAP->mPlay.mState;
33e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    object_unlock_peek(&thisAP->mObject);
344b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    // FIXME should not muck around directly at this low level
358c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (SL_PLAYSTATE_PLAYING != state) {
36276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        return;
378c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
38276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    struct SndFile *this = &thisAP->mSndFile;
39b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    SLresult result;
404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    pthread_mutex_lock(&this->mMutex);
41e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    if (this->mEOF) {
42e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        pthread_mutex_unlock(&this->mMutex);
43e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        return;
44e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
456a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    short *pBuffer = &this->mBuffer[this->mWhich * SndFile_BUFSIZE];
468c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (++this->mWhich >= SndFile_NUMBUFS) {
476a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        this->mWhich = 0;
488c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
49b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    sf_count_t count;
506a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    count = sf_read_short(this->mSNDFILE, pBuffer, (sf_count_t) SndFile_BUFSIZE);
51e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    pthread_mutex_unlock(&this->mMutex);
528c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    bool headAtNewPos = false;
538c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    object_lock_exclusive(&thisAP->mObject);
548c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    slPlayCallback callback = thisAP->mPlay.mCallback;
558c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    void *context = thisAP->mPlay.mContext;
568c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    // make a copy of sample rate so we are absolutely sure we will not divide by zero
578c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    SLuint32 sampleRateMilliHz = thisAP->mSampleRateMilliHz;
588c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (0 != sampleRateMilliHz) {
598c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // this will overflow after 49 days, but no fix possible as it's part of the API
608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        thisAP->mPlay.mPosition = (SLuint32) (((long long) thisAP->mPlay.mFramesSinceLastSeek *
618c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            1000000LL) / sampleRateMilliHz) + thisAP->mPlay.mLastSeekPosition;
628c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // make a good faith effort for the mean time between "head at new position" callbacks to
638c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // occur at the requested update period, but there will be jitter
648c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        SLuint32 frameUpdatePeriod = thisAP->mPlay.mFrameUpdatePeriod;
658c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if ((0 != frameUpdatePeriod) &&
668c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            (thisAP->mPlay.mFramesSincePositionUpdate >= frameUpdatePeriod) &&
678c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            (SL_PLAYEVENT_HEADATNEWPOS & thisAP->mPlay.mEventFlags)) {
688c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // if we overrun a requested update period, then reset the clock modulo the
698c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // update period so that it appears to the application as one or more lost callbacks,
708c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // but no additional jitter
718c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if ((thisAP->mPlay.mFramesSincePositionUpdate -= thisAP->mPlay.mFrameUpdatePeriod) >=
728c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    frameUpdatePeriod) {
738c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                thisAP->mPlay.mFramesSincePositionUpdate %= frameUpdatePeriod;
748c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
758c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            headAtNewPos = true;
768c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
778c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
78b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    if (0 < count) {
798c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        object_unlock_exclusive(&thisAP->mObject);
807324a5ab12cc734e2feb4cef8baeda26566d3c92Glenn Kasten        SLuint32 size = (SLuint32) (count * sizeof(short));
81e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten        result = IBufferQueue_Enqueue(caller, pBuffer, size);
828c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // not much we can do if the Enqueue fails, so we'll just drop the decoded data
838c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (SL_RESULT_SUCCESS != result) {
848c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            SL_LOGE("enqueue failed 0x%x", (unsigned) result);
85b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        }
86276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    } else {
874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // FIXME This is really hosed, you can't do this anymore!
884b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // FIXME Need a state PAUSE_WHEN_EMPTY
897a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten        // Should not pause yet - we just ran out of new data to enqueue,
90e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        // but there may still be (partially) full buffers in the queue.
91276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        thisAP->mPlay.mState = SL_PLAYSTATE_PAUSED;
928c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        this->mEOF = SL_BOOLEAN_TRUE;
938c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // this would result in a non-monotonically increasing position, so don't do it
948c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // thisAP->mPlay.mPosition = thisAP->mPlay.mDuration;
95e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        object_unlock_exclusive_attributes(&thisAP->mObject, ATTR_TRANSPORT);
96b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
978c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    // callbacks are called with mutex unlocked
988c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (NULL != callback) {
998c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (headAtNewPos) {
1008c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            (*callback)(&thisAP->mPlay.mItf, context, SL_PLAYEVENT_HEADATNEWPOS);
1018c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
1028c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
103b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
104b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
105369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten
106369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Check whether the supplied libsndfile format is supported by us */
107369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten
108b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn KastenSLboolean SndFile_IsSupported(const SF_INFO *sfinfo)
109b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
110b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    switch (sfinfo->format & SF_FORMAT_TYPEMASK) {
111b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    case SF_FORMAT_WAV:
112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        break;
113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    default:
114b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        return SL_BOOLEAN_FALSE;
115b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
116b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    switch (sfinfo->format & SF_FORMAT_SUBMASK) {
117276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    case SF_FORMAT_PCM_U8:
118b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    case SF_FORMAT_PCM_16:
119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        break;
120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    default:
121b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        return SL_BOOLEAN_FALSE;
122b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
123b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    switch (sfinfo->samplerate) {
124276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    case 11025:
125276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    case 22050:
126b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    case 44100:
127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        break;
128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    default:
129b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        return SL_BOOLEAN_FALSE;
130b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
131b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    switch (sfinfo->channels) {
132276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    case 1:
133b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    case 2:
134b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        break;
135b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    default:
136b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        return SL_BOOLEAN_FALSE;
137b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
138b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    return SL_BOOLEAN_TRUE;
139b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
140b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
141369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten
142369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Check whether the partially-constructed AudioPlayer is compatible with libsndfile */
143369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten
144acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult SndFile_checkAudioPlayerSourceSink(CAudioPlayer *this)
145daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{
146acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    const SLDataSource *pAudioSrc = &this->mDataSource.u.mSource;
147daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    SLuint32 locatorType = *(SLuint32 *)pAudioSrc->pLocator;
148daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    SLuint32 formatType = *(SLuint32 *)pAudioSrc->pFormat;
149daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    switch (locatorType) {
150daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    case SL_DATALOCATOR_BUFFERQUEUE:
151daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        break;
152daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    case SL_DATALOCATOR_URI:
153daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        {
154daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        SLDataLocator_URI *dl_uri = (SLDataLocator_URI *) pAudioSrc->pLocator;
155daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        SLchar *uri = dl_uri->URI;
1568c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (NULL == uri) {
157daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            return SL_RESULT_PARAMETER_INVALID;
1588c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
1598c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (!strncmp((const char *) uri, "file:///", 8)) {
16027f8dfaea17ab7831a1bd34a02f85d55bacf67b7Glenn Kasten            uri += 8;
1618c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
162daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        switch (formatType) {
163a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten        case SL_DATAFORMAT_NULL:    // OK to omit the data format
164a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten        case SL_DATAFORMAT_MIME:    // we ignore a MIME type if specified
165daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            break;
166daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        default:
167daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            return SL_RESULT_CONTENT_UNSUPPORTED;
168daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
16927f8dfaea17ab7831a1bd34a02f85d55bacf67b7Glenn Kasten        this->mSndFile.mPathname = uri;
17040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten        this->mBufferQueue.mNumBuffers = SndFile_NUMBUFS;
171daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
172daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        break;
173daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    default:
174daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        return SL_RESULT_CONTENT_UNSUPPORTED;
175daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    }
1766a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    this->mSndFile.mWhich = 0;
177acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    this->mSndFile.mSNDFILE = NULL;
178e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    // this->mSndFile.mMutex is initialized only when there is a valid mSNDFILE
179e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    this->mSndFile.mEOF = SL_BOOLEAN_FALSE;
1803d81b8ca5d3cee893672beb76e00849d4f3fa8b8Glenn Kasten
181daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    return SL_RESULT_SUCCESS;
182daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten}
183daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten
184343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
185369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Called with mutex unlocked for marker and position updates, and play state change */
1864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
187e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenvoid audioPlayerTransportUpdate(CAudioPlayer *audioPlayer)
188e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{
189369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten    // FIXME should use two separate hooks since we have separate attributes TRANSPORT and POSITION
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
236b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_SNDFILE
237