SndFile.c revision a3080daa505f91df51a808c85ddb37c48745bf7c
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);
324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    // FIXME should not muck around directly at this low level
338c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (SL_PLAYSTATE_PLAYING != state) {
34276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        return;
358c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
36276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    struct SndFile *this = &thisAP->mSndFile;
37b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    SLresult result;
384b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    pthread_mutex_lock(&this->mMutex);
39e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    if (this->mEOF) {
40e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        pthread_mutex_unlock(&this->mMutex);
41e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        return;
42e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
436a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    short *pBuffer = &this->mBuffer[this->mWhich * SndFile_BUFSIZE];
448c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (++this->mWhich >= SndFile_NUMBUFS) {
456a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        this->mWhich = 0;
468c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
47b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    sf_count_t count;
486a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    count = sf_read_short(this->mSNDFILE, pBuffer, (sf_count_t) SndFile_BUFSIZE);
49e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    pthread_mutex_unlock(&this->mMutex);
508c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    bool headAtNewPos = false;
518c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    object_lock_exclusive(&thisAP->mObject);
528c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    slPlayCallback callback = thisAP->mPlay.mCallback;
538c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    void *context = thisAP->mPlay.mContext;
548c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    // make a copy of sample rate so we are absolutely sure we will not divide by zero
558c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    SLuint32 sampleRateMilliHz = thisAP->mSampleRateMilliHz;
568c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (0 != sampleRateMilliHz) {
578c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // this will overflow after 49 days, but no fix possible as it's part of the API
588c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        thisAP->mPlay.mPosition = (SLuint32) (((long long) thisAP->mPlay.mFramesSinceLastSeek *
598c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            1000000LL) / sampleRateMilliHz) + thisAP->mPlay.mLastSeekPosition;
608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // make a good faith effort for the mean time between "head at new position" callbacks to
618c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // occur at the requested update period, but there will be jitter
628c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        SLuint32 frameUpdatePeriod = thisAP->mPlay.mFrameUpdatePeriod;
638c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if ((0 != frameUpdatePeriod) &&
648c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            (thisAP->mPlay.mFramesSincePositionUpdate >= frameUpdatePeriod) &&
658c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            (SL_PLAYEVENT_HEADATNEWPOS & thisAP->mPlay.mEventFlags)) {
668c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // if we overrun a requested update period, then reset the clock modulo the
678c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // update period so that it appears to the application as one or more lost callbacks,
688c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // but no additional jitter
698c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if ((thisAP->mPlay.mFramesSincePositionUpdate -= thisAP->mPlay.mFrameUpdatePeriod) >=
708c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    frameUpdatePeriod) {
718c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                thisAP->mPlay.mFramesSincePositionUpdate %= frameUpdatePeriod;
728c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
738c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            headAtNewPos = true;
748c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
758c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
76b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    if (0 < count) {
778c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        object_unlock_exclusive(&thisAP->mObject);
787324a5ab12cc734e2feb4cef8baeda26566d3c92Glenn Kasten        SLuint32 size = (SLuint32) (count * sizeof(short));
79e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten        result = IBufferQueue_Enqueue(caller, pBuffer, size);
808c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // not much we can do if the Enqueue fails, so we'll just drop the decoded data
818c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (SL_RESULT_SUCCESS != result) {
82a7b79e766ec6d95e9236168c27461c2ebaef4659Glenn Kasten            SL_LOGE("enqueue failed 0x%lx", result);
83b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        }
84276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    } else {
854b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // FIXME This is really hosed, you can't do this anymore!
864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // FIXME Need a state PAUSE_WHEN_EMPTY
877a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten        // Should not pause yet - we just ran out of new data to enqueue,
88e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        // but there may still be (partially) full buffers in the queue.
89276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        thisAP->mPlay.mState = SL_PLAYSTATE_PAUSED;
908c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        this->mEOF = SL_BOOLEAN_TRUE;
918c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // this would result in a non-monotonically increasing position, so don't do it
928c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // thisAP->mPlay.mPosition = thisAP->mPlay.mDuration;
93e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        object_unlock_exclusive_attributes(&thisAP->mObject, ATTR_TRANSPORT);
94b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
958c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    // callbacks are called with mutex unlocked
968c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (NULL != callback) {
978c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (headAtNewPos) {
988c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            (*callback)(&thisAP->mPlay.mItf, context, SL_PLAYEVENT_HEADATNEWPOS);
998c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
1008c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
101b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
102b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
103369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten
104369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Check whether the supplied libsndfile format is supported by us */
105369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten
106b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn KastenSLboolean SndFile_IsSupported(const SF_INFO *sfinfo)
107b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
108b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    switch (sfinfo->format & SF_FORMAT_TYPEMASK) {
109b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    case SF_FORMAT_WAV:
110b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        break;
111b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    default:
112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        return SL_BOOLEAN_FALSE;
113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
114b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    switch (sfinfo->format & SF_FORMAT_SUBMASK) {
115276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    case SF_FORMAT_PCM_U8:
116b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    case SF_FORMAT_PCM_16:
117b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        break;
118b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    default:
119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        return SL_BOOLEAN_FALSE;
120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
121b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    switch (sfinfo->samplerate) {
122276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    case 11025:
123276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    case 22050:
124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    case 44100:
125b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        break;
126b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    default:
127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        return SL_BOOLEAN_FALSE;
128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
129b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    switch (sfinfo->channels) {
130276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    case 1:
131b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    case 2:
132b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        break;
133b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    default:
134b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        return SL_BOOLEAN_FALSE;
135b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
136b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    return SL_BOOLEAN_TRUE;
137b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
138b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
139369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten
140369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Check whether the partially-constructed AudioPlayer is compatible with libsndfile */
141369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten
142acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult SndFile_checkAudioPlayerSourceSink(CAudioPlayer *this)
143daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{
144acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    const SLDataSource *pAudioSrc = &this->mDataSource.u.mSource;
145daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    SLuint32 locatorType = *(SLuint32 *)pAudioSrc->pLocator;
146daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    SLuint32 formatType = *(SLuint32 *)pAudioSrc->pFormat;
147daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    switch (locatorType) {
148daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    case SL_DATALOCATOR_BUFFERQUEUE:
14901e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten#ifdef ANDROID
15001e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
15101e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten#endif
152daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        break;
153daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    case SL_DATALOCATOR_URI:
154daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        {
155daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        SLDataLocator_URI *dl_uri = (SLDataLocator_URI *) pAudioSrc->pLocator;
156daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        SLchar *uri = dl_uri->URI;
1578c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (NULL == uri) {
158daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            return SL_RESULT_PARAMETER_INVALID;
1598c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
1608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (!strncmp((const char *) uri, "file:///", 8)) {
16127f8dfaea17ab7831a1bd34a02f85d55bacf67b7Glenn Kasten            uri += 8;
1628c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
163daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        switch (formatType) {
164a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten        case SL_DATAFORMAT_NULL:    // OK to omit the data format
165a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten        case SL_DATAFORMAT_MIME:    // we ignore a MIME type if specified
166daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            break;
167daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        default:
168daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            return SL_RESULT_CONTENT_UNSUPPORTED;
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{
190369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten    // FIXME should use two separate hooks since we have separate attributes TRANSPORT and POSITION
1914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1924b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    if (NULL != audioPlayer->mSndFile.mSNDFILE) {
1934b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1944b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        object_lock_exclusive(&audioPlayer->mObject);
1954b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        SLboolean empty = 0 == audioPlayer->mBufferQueue.mState.count;
1963d81b8ca5d3cee893672beb76e00849d4f3fa8b8Glenn Kasten        // FIXME a made-up number that should depend on player state and prefetch status
1973d81b8ca5d3cee893672beb76e00849d4f3fa8b8Glenn Kasten        audioPlayer->mPrefetchStatus.mLevel = 1000;
1988c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        SLmillisecond pos = audioPlayer->mSeek.mPos;
1998c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (SL_TIME_UNKNOWN != pos) {
2008c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN;
2018c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // trim seek position to the current known duration
2028c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (pos > audioPlayer->mPlay.mDuration) {
2038c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                pos = audioPlayer->mPlay.mDuration;
2048c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
2058c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mPlay.mLastSeekPosition = pos;
2068c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mPlay.mFramesSinceLastSeek = 0;
2078c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // seek postpones the next head at new position callback
2088c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mPlay.mFramesSincePositionUpdate = 0;
2098c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
2104b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        object_unlock_exclusive(&audioPlayer->mObject);
2114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
2124b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        if (SL_TIME_UNKNOWN != pos) {
2134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
2144b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // discard any enqueued buffers for the old position
215e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten            IBufferQueue_Clear(&audioPlayer->mBufferQueue.mItf);
2164b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            empty = SL_BOOLEAN_TRUE;
2174b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
2184b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            pthread_mutex_lock(&audioPlayer->mSndFile.mMutex);
2198c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // FIXME why void?
2204b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            (void) sf_seek(audioPlayer->mSndFile.mSNDFILE, (sf_count_t) (((long long) pos *
2214b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                audioPlayer->mSndFile.mSfInfo.samplerate) / 1000LL), SEEK_SET);
2224b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mSndFile.mEOF = SL_BOOLEAN_FALSE;
2234b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mSndFile.mWhich = 0;
2244b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            pthread_mutex_unlock(&audioPlayer->mSndFile.mMutex);
2254b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
2264b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
2274b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
2284b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // FIXME only on seek or play state change (STOPPED, PAUSED) -> PLAYING
2294b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        if (empty) {
2304b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            SndFile_Callback(&audioPlayer->mBufferQueue.mItf, audioPlayer);
2314b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
2324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
233e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
234e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
235e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten}
236e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
237a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
238a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten/** \brief Called by CAudioPlayer_Realize */
239a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
240a3080daa505f91df51a808c85ddb37c48745bf7cGlenn KastenSLresult SndFile_Realize(CAudioPlayer *this)
241a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten{
242a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    SLresult result = SL_RESULT_SUCCESS;
243a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    if (NULL != this->mSndFile.mPathname) {
244a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        this->mSndFile.mSfInfo.format = 0;
245a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        this->mSndFile.mSNDFILE = sf_open(
246a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            (const char *) this->mSndFile.mPathname, SFM_READ, &this->mSndFile.mSfInfo);
247a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        if (NULL == this->mSndFile.mSNDFILE) {
248a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            result = SL_RESULT_CONTENT_NOT_FOUND;
249a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        } else if (!SndFile_IsSupported(&this->mSndFile.mSfInfo)) {
250a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            sf_close(this->mSndFile.mSNDFILE);
251a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mSndFile.mSNDFILE = NULL;
252a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            result = SL_RESULT_CONTENT_UNSUPPORTED;
253a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        } else {
254a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            int ok;
255a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            ok = pthread_mutex_init(&this->mSndFile.mMutex, (const pthread_mutexattr_t *) NULL);
256a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            assert(0 == ok);
257a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            SLBufferQueueItf bufferQueue = &this->mBufferQueue.mItf;
258a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            IBufferQueue *thisBQ = (IBufferQueue *) bufferQueue;
259a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            IBufferQueue_RegisterCallback(&thisBQ->mItf, SndFile_Callback, this);
260a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_SUFFICIENTDATA;
261a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            // this is the initial duration; will update when a new maximum position is detected
262a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mPlay.mDuration = (SLmillisecond) (((long long) this->mSndFile.mSfInfo.frames *
263a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                1000LL) / this->mSndFile.mSfInfo.samplerate);
264a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mNumChannels = this->mSndFile.mSfInfo.channels;
265a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mSampleRateMilliHz = this->mSndFile.mSfInfo.samplerate * 1000;
266a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#ifdef USE_OUTPUTMIXEXT
267a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            this->mPlay.mFrameUpdatePeriod = ((long long) this->mPlay.mPositionUpdatePeriod *
268a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                (long long) this->mSampleRateMilliHz) / 1000000LL;
269a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#endif
270a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        }
271a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    }
272a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    return result;
273a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten}
274a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
275a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
276a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten/** \brief Called by CAudioPlayer_Destroy */
277a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
278a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kastenvoid SndFile_Destroy(CAudioPlayer *this)
279a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten{
280a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    if (NULL != this->mSndFile.mSNDFILE) {
281a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        sf_close(this->mSndFile.mSNDFILE);
282a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        this->mSndFile.mSNDFILE = NULL;
283a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        int ok;
284a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        ok = pthread_mutex_destroy(&this->mSndFile.mMutex);
285a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        assert(0 == ok);
286a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    }
287a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten}
288