1188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten/*
2188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Copyright (C) 2010 The Android Open Source Project
3188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten *
4188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * you may not use this file except in compliance with the License.
6188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * You may obtain a copy of the License at
7188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten *
8188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten *
10188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Unless required by applicable law or agreed to in writing, software
11188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * See the License for the specific language governing permissions and
14188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * limitations under the License.
15188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten */
16188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
1710ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief libsndfile integration */
18188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
19188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten#include "sles_allinclusive.h"
20188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
216aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten
2266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten/** \brief Called by SndFile.c:audioPlayerTransportUpdate after a play state change or seek,
2366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten *  and by IOutputMixExt::FillBuffer after each buffer is consumed.
2466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten */
2510ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten
26ffeb2e16c2886eefa88d6eaf4c7be78c2eced82bGlenn Kastenvoid SndFile_Callback(SLBufferQueueItf caller, void *pContext)
27188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten{
283cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten    CAudioPlayer *thisAP = (CAudioPlayer *) pContext;
2915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    object_lock_peek(&thisAP->mObject);
3015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    SLuint32 state = thisAP->mPlay.mState;
3115f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    object_unlock_peek(&thisAP->mObject);
3266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    if (SL_PLAYSTATE_PLAYING != state) {
333cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten        return;
3466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    }
3550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    struct SndFile *thiz = &thisAP->mSndFile;
36188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    SLresult result;
3750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    pthread_mutex_lock(&thiz->mMutex);
3850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    if (thiz->mEOF) {
3950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        pthread_mutex_unlock(&thiz->mMutex);
4015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        return;
4115f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    }
4250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    short *pBuffer = &thiz->mBuffer[thiz->mWhich * SndFile_BUFSIZE];
4350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    if (++thiz->mWhich >= SndFile_NUMBUFS) {
4450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mWhich = 0;
4566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    }
46188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    sf_count_t count;
4750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    count = sf_read_short(thiz->mSNDFILE, pBuffer, (sf_count_t) SndFile_BUFSIZE);
4850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    pthread_mutex_unlock(&thiz->mMutex);
4966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    bool headAtNewPos = false;
5066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    object_lock_exclusive(&thisAP->mObject);
5166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    slPlayCallback callback = thisAP->mPlay.mCallback;
5266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    void *context = thisAP->mPlay.mContext;
5366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    // make a copy of sample rate so we are absolutely sure we will not divide by zero
5466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    SLuint32 sampleRateMilliHz = thisAP->mSampleRateMilliHz;
55463a7641944e4a3613f5d76aa8450070ef56b9ffGlenn Kasten    if (UNKNOWN_SAMPLERATE != sampleRateMilliHz) {
5666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        // this will overflow after 49 days, but no fix possible as it's part of the API
5766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        thisAP->mPlay.mPosition = (SLuint32) (((long long) thisAP->mPlay.mFramesSinceLastSeek *
5866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            1000000LL) / sampleRateMilliHz) + thisAP->mPlay.mLastSeekPosition;
5966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        // make a good faith effort for the mean time between "head at new position" callbacks to
6066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        // occur at the requested update period, but there will be jitter
6166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        SLuint32 frameUpdatePeriod = thisAP->mPlay.mFrameUpdatePeriod;
6266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if ((0 != frameUpdatePeriod) &&
6366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            (thisAP->mPlay.mFramesSincePositionUpdate >= frameUpdatePeriod) &&
6466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            (SL_PLAYEVENT_HEADATNEWPOS & thisAP->mPlay.mEventFlags)) {
6566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            // if we overrun a requested update period, then reset the clock modulo the
6666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            // update period so that it appears to the application as one or more lost callbacks,
6766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            // but no additional jitter
6866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            if ((thisAP->mPlay.mFramesSincePositionUpdate -= thisAP->mPlay.mFrameUpdatePeriod) >=
6966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                    frameUpdatePeriod) {
7066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                thisAP->mPlay.mFramesSincePositionUpdate %= frameUpdatePeriod;
7166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            }
7266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            headAtNewPos = true;
7366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        }
7466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    }
75188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    if (0 < count) {
7666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        object_unlock_exclusive(&thisAP->mObject);
77aee4409e59584f8e8d0ddaf7e44dc80ec5b80444Glenn Kasten        SLuint32 size = (SLuint32) (count * sizeof(short));
789c03f04a9c6cc2a821182c8be8f2efe964a27efeGlenn Kasten        result = IBufferQueue_Enqueue(caller, pBuffer, size);
7966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        // not much we can do if the Enqueue fails, so we'll just drop the decoded data
8066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if (SL_RESULT_SUCCESS != result) {
81156db48484793c2ce24f9ccd3cefe6e5f9f0b3feGlenn Kasten            SL_LOGE("enqueue failed 0x%x", result);
82188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        }
833cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten    } else {
843cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten        thisAP->mPlay.mState = SL_PLAYSTATE_PAUSED;
8550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mEOF = SL_BOOLEAN_TRUE;
8666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        // this would result in a non-monotonically increasing position, so don't do it
8766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        // thisAP->mPlay.mPosition = thisAP->mPlay.mDuration;
8815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        object_unlock_exclusive_attributes(&thisAP->mObject, ATTR_TRANSPORT);
89188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    }
9066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    // callbacks are called with mutex unlocked
9166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    if (NULL != callback) {
9266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if (headAtNewPos) {
9366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            (*callback)(&thisAP->mPlay.mItf, context, SL_PLAYEVENT_HEADATNEWPOS);
9466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        }
9566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    }
96188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten}
97188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
9810ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten
9910ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief Check whether the supplied libsndfile format is supported by us */
10010ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten
101188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn KastenSLboolean SndFile_IsSupported(const SF_INFO *sfinfo)
102188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten{
103188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    switch (sfinfo->format & SF_FORMAT_TYPEMASK) {
104188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    case SF_FORMAT_WAV:
105188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        break;
106188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    default:
107188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        return SL_BOOLEAN_FALSE;
108188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    }
109188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    switch (sfinfo->format & SF_FORMAT_SUBMASK) {
1103cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten    case SF_FORMAT_PCM_U8:
111188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    case SF_FORMAT_PCM_16:
112188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        break;
113188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    default:
114188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        return SL_BOOLEAN_FALSE;
115188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    }
116188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    switch (sfinfo->samplerate) {
1173cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten    case 11025:
1183cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten    case 22050:
119188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    case 44100:
120188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        break;
121188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    default:
122188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        return SL_BOOLEAN_FALSE;
123188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    }
124188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    switch (sfinfo->channels) {
1253cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten    case 1:
126188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    case 2:
127188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        break;
128188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    default:
129188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        return SL_BOOLEAN_FALSE;
130188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    }
131188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    return SL_BOOLEAN_TRUE;
132188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten}
133188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
13410ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten
13510ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief Check whether the partially-constructed AudioPlayer is compatible with libsndfile */
13610ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten
13750bccde01980ae803b8656e8b08ecacb65540f50Glenn KastenSLresult SndFile_checkAudioPlayerSourceSink(CAudioPlayer *thiz)
138f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten{
13950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    const SLDataSource *pAudioSrc = &thiz->mDataSource.u.mSource;
140f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    SLuint32 locatorType = *(SLuint32 *)pAudioSrc->pLocator;
141f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    SLuint32 formatType = *(SLuint32 *)pAudioSrc->pFormat;
142f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    switch (locatorType) {
143f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    case SL_DATALOCATOR_BUFFERQUEUE:
1441a6bb4f8e738c9387dc9629db294ea5de618a53cGlenn Kasten#ifdef ANDROID
1451a6bb4f8e738c9387dc9629db294ea5de618a53cGlenn Kasten    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
1461a6bb4f8e738c9387dc9629db294ea5de618a53cGlenn Kasten#endif
147f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        break;
148f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    case SL_DATALOCATOR_URI:
149f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        {
150f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        SLDataLocator_URI *dl_uri = (SLDataLocator_URI *) pAudioSrc->pLocator;
151f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        SLchar *uri = dl_uri->URI;
15266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if (NULL == uri) {
153f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten            return SL_RESULT_PARAMETER_INVALID;
15466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        }
15566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if (!strncmp((const char *) uri, "file:///", 8)) {
15695364617b16ca2e322a4e0faeda93a2750d29fd6Glenn Kasten            uri += 8;
15766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        }
158f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        switch (formatType) {
159c37c934e00a96afe18aaadd9f9a1863c721bf8eaGlenn Kasten        case SL_DATAFORMAT_NULL:    // OK to omit the data format
160c37c934e00a96afe18aaadd9f9a1863c721bf8eaGlenn Kasten        case SL_DATAFORMAT_MIME:    // we ignore a MIME type if specified
161f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten            break;
162da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten        case SL_DATAFORMAT_PCM:
163da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten        case XA_DATAFORMAT_RAWIMAGE:
164f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten            return SL_RESULT_CONTENT_UNSUPPORTED;
165da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten        default:
166da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten            // an invalid data format is detected earlier during the deep copy
167da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten            assert(false);
168da97f083b47fa4442a40ad962ed86a922a537a64Glenn Kasten            return SL_RESULT_INTERNAL_ERROR;
169f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        }
17050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mSndFile.mPathname = uri;
17150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mBufferQueue.mNumBuffers = SndFile_NUMBUFS;
172f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        }
173f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        break;
174f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    default:
175f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        return SL_RESULT_CONTENT_UNSUPPORTED;
176f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    }
17750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    thiz->mSndFile.mWhich = 0;
17850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    thiz->mSndFile.mSNDFILE = NULL;
17950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    // thiz->mSndFile.mMutex is initialized only when there is a valid mSNDFILE
18050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    thiz->mSndFile.mEOF = SL_BOOLEAN_FALSE;
181ec2cf4f7de22b97946cfb0c9c58d6db7f111b926Glenn Kasten
182f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    return SL_RESULT_SUCCESS;
183f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten}
184f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten
1856aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten
18610ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief Called with mutex unlocked for marker and position updates, and play state change */
18723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
18815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kastenvoid audioPlayerTransportUpdate(CAudioPlayer *audioPlayer)
18915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten{
19023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
19123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten    if (NULL != audioPlayer->mSndFile.mSNDFILE) {
19223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
19323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        object_lock_exclusive(&audioPlayer->mObject);
19423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        SLboolean empty = 0 == audioPlayer->mBufferQueue.mState.count;
195ec2cf4f7de22b97946cfb0c9c58d6db7f111b926Glenn Kasten        // FIXME a made-up number that should depend on player state and prefetch status
196ec2cf4f7de22b97946cfb0c9c58d6db7f111b926Glenn Kasten        audioPlayer->mPrefetchStatus.mLevel = 1000;
19766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        SLmillisecond pos = audioPlayer->mSeek.mPos;
19866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if (SL_TIME_UNKNOWN != pos) {
19966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN;
20066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            // trim seek position to the current known duration
20166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            if (pos > audioPlayer->mPlay.mDuration) {
20266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                pos = audioPlayer->mPlay.mDuration;
20366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            }
20466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mPlay.mLastSeekPosition = pos;
20566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mPlay.mFramesSinceLastSeek = 0;
20666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            // seek postpones the next head at new position callback
20766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mPlay.mFramesSincePositionUpdate = 0;
20866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        }
20923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        object_unlock_exclusive(&audioPlayer->mObject);
21023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
21123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        if (SL_TIME_UNKNOWN != pos) {
21223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
21323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            // discard any enqueued buffers for the old position
2149c03f04a9c6cc2a821182c8be8f2efe964a27efeGlenn Kasten            IBufferQueue_Clear(&audioPlayer->mBufferQueue.mItf);
21523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            empty = SL_BOOLEAN_TRUE;
21623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
21723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            pthread_mutex_lock(&audioPlayer->mSndFile.mMutex);
21866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            // FIXME why void?
21923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            (void) sf_seek(audioPlayer->mSndFile.mSNDFILE, (sf_count_t) (((long long) pos *
22023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                audioPlayer->mSndFile.mSfInfo.samplerate) / 1000LL), SEEK_SET);
22123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            audioPlayer->mSndFile.mEOF = SL_BOOLEAN_FALSE;
22223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            audioPlayer->mSndFile.mWhich = 0;
22323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            pthread_mutex_unlock(&audioPlayer->mSndFile.mMutex);
22423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
22523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        }
22623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
22723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        // FIXME only on seek or play state change (STOPPED, PAUSED) -> PLAYING
22823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        if (empty) {
22923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            SndFile_Callback(&audioPlayer->mBufferQueue.mItf, audioPlayer);
23023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        }
23123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
23215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    }
23315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten
23415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten}
23515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten
23651cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten
23751cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten/** \brief Called by CAudioPlayer_Realize */
23851cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten
23950bccde01980ae803b8656e8b08ecacb65540f50Glenn KastenSLresult SndFile_Realize(CAudioPlayer *thiz)
24051cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten{
24151cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten    SLresult result = SL_RESULT_SUCCESS;
24250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    if (NULL != thiz->mSndFile.mPathname) {
24350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mSndFile.mSfInfo.format = 0;
24450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mSndFile.mSNDFILE = sf_open(
24550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            (const char *) thiz->mSndFile.mPathname, SFM_READ, &thiz->mSndFile.mSfInfo);
24650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        if (NULL == thiz->mSndFile.mSNDFILE) {
24751cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten            result = SL_RESULT_CONTENT_NOT_FOUND;
24850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        } else if (!SndFile_IsSupported(&thiz->mSndFile.mSfInfo)) {
24950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            sf_close(thiz->mSndFile.mSNDFILE);
25050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            thiz->mSndFile.mSNDFILE = NULL;
25151cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten            result = SL_RESULT_CONTENT_UNSUPPORTED;
25251cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten        } else {
25351cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten            int ok;
25450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            ok = pthread_mutex_init(&thiz->mSndFile.mMutex, (const pthread_mutexattr_t *) NULL);
25551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten            assert(0 == ok);
25650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            SLBufferQueueItf bufferQueue = &thiz->mBufferQueue.mItf;
25751cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten            IBufferQueue *thisBQ = (IBufferQueue *) bufferQueue;
25850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            IBufferQueue_RegisterCallback(&thisBQ->mItf, SndFile_Callback, thiz);
25950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            thiz->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_SUFFICIENTDATA;
26051cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten            // this is the initial duration; will update when a new maximum position is detected
26150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            thiz->mPlay.mDuration = (SLmillisecond) (((long long) thiz->mSndFile.mSfInfo.frames *
26250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten                1000LL) / thiz->mSndFile.mSfInfo.samplerate);
26350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            thiz->mNumChannels = thiz->mSndFile.mSfInfo.channels;
26450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            thiz->mSampleRateMilliHz = thiz->mSndFile.mSfInfo.samplerate * 1000;
26551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten#ifdef USE_OUTPUTMIXEXT
26650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            thiz->mPlay.mFrameUpdatePeriod = ((long long) thiz->mPlay.mPositionUpdatePeriod *
26750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten                (long long) thiz->mSampleRateMilliHz) / 1000000LL;
26851cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten#endif
26951cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten        }
27051cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten    }
27151cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten    return result;
27251cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten}
27351cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten
27451cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten
27551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten/** \brief Called by CAudioPlayer_Destroy */
27651cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten
27750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kastenvoid SndFile_Destroy(CAudioPlayer *thiz)
27851cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten{
27950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    if (NULL != thiz->mSndFile.mSNDFILE) {
28050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        sf_close(thiz->mSndFile.mSNDFILE);
28150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mSndFile.mSNDFILE = NULL;
28251cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten        int ok;
28350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        ok = pthread_mutex_destroy(&thiz->mSndFile.mMutex);
28451cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten        assert(0 == ok);
28551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten    }
28651cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten}
287