SndFile.c revision 94a37e8117fb72790882dfb815f99e2365754c74
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    }
35276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    struct SndFile *this = &thisAP->mSndFile;
36b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    SLresult result;
374b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    pthread_mutex_lock(&this->mMutex);
38e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    if (this->mEOF) {
39e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        pthread_mutex_unlock(&this->mMutex);
40e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        return;
41e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
426a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    short *pBuffer = &this->mBuffer[this->mWhich * SndFile_BUFSIZE];
438c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (++this->mWhich >= SndFile_NUMBUFS) {
446a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        this->mWhich = 0;
458c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
46b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    sf_count_t count;
476a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    count = sf_read_short(this->mSNDFILE, pBuffer, (sf_count_t) SndFile_BUFSIZE);
48e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    pthread_mutex_unlock(&this->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;
558c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (0 != 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) {
81a7b79e766ec6d95e9236168c27461c2ebaef4659Glenn Kasten            SL_LOGE("enqueue failed 0x%lx", result);
82b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        }
83276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    } else {
84276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        thisAP->mPlay.mState = SL_PLAYSTATE_PAUSED;
858c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        this->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
137acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult SndFile_checkAudioPlayerSourceSink(CAudioPlayer *this)
138daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{
139acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    const SLDataSource *pAudioSrc = &this->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        }
17027f8dfaea17ab7831a1bd34a02f85d55bacf67b7Glenn Kasten        this->mSndFile.mPathname = uri;
17140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten        this->mBufferQueue.mNumBuffers = SndFile_NUMBUFS;
172daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
173daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        break;
174daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    default:
175daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        return SL_RESULT_CONTENT_UNSUPPORTED;
176daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    }
1776a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    this->mSndFile.mWhich = 0;
178acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    this->mSndFile.mSNDFILE = NULL;
179e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    // this->mSndFile.mMutex is initialized only when there is a valid mSNDFILE
180e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    this->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
239a3080daa505f91df51a808c85ddb37c48745bf7cGlenn KastenSLresult SndFile_Realize(CAudioPlayer *this)
240a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten{
241a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    SLresult result = SL_RESULT_SUCCESS;
242a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    if (NULL != this->mSndFile.mPathname) {
243a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        this->mSndFile.mSfInfo.format = 0;
244a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        this->mSndFile.mSNDFILE = sf_open(
245a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            (const char *) this->mSndFile.mPathname, SFM_READ, &this->mSndFile.mSfInfo);
246a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        if (NULL == this->mSndFile.mSNDFILE) {
247a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            result = SL_RESULT_CONTENT_NOT_FOUND;
248a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        } else if (!SndFile_IsSupported(&this->mSndFile.mSfInfo)) {
249a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            sf_close(this->mSndFile.mSNDFILE);
250a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mSndFile.mSNDFILE = NULL;
251a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            result = SL_RESULT_CONTENT_UNSUPPORTED;
252a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        } else {
253a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            int ok;
254a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            ok = pthread_mutex_init(&this->mSndFile.mMutex, (const pthread_mutexattr_t *) NULL);
255a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            assert(0 == ok);
256a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            SLBufferQueueItf bufferQueue = &this->mBufferQueue.mItf;
257a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            IBufferQueue *thisBQ = (IBufferQueue *) bufferQueue;
258a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            IBufferQueue_RegisterCallback(&thisBQ->mItf, SndFile_Callback, this);
259a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_SUFFICIENTDATA;
260a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            // this is the initial duration; will update when a new maximum position is detected
261a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mPlay.mDuration = (SLmillisecond) (((long long) this->mSndFile.mSfInfo.frames *
262a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                1000LL) / this->mSndFile.mSfInfo.samplerate);
263a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mNumChannels = this->mSndFile.mSfInfo.channels;
264a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mSampleRateMilliHz = this->mSndFile.mSfInfo.samplerate * 1000;
265a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#ifdef USE_OUTPUTMIXEXT
266a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mPlay.mFrameUpdatePeriod = ((long long) this->mPlay.mPositionUpdatePeriod *
267a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                (long long) this->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
277a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kastenvoid SndFile_Destroy(CAudioPlayer *this)
278a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten{
279a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    if (NULL != this->mSndFile.mSNDFILE) {
280a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        sf_close(this->mSndFile.mSNDFILE);
281a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        this->mSndFile.mSNDFILE = NULL;
282a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        int ok;
283a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        ok = pthread_mutex_destroy(&this->mSndFile.mMutex);
284a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        assert(0 == ok);
285a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    }
286a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten}
287