BufferQueueSource.cpp revision 4efb2aa0d563b86b3c95d418d6d61d97f51c0bbb
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define USE_LOG SLAndroidLogLevel_Verbose
18
19#include "sles_allinclusive.h"
20#include "android/BufferQueueSource.h"
21
22#include <media/stagefright/MediaDebug.h>
23#include <sys/types.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28
29namespace android {
30
31
32const SLuint32 BufferQueueSource::kItemProcessed[NB_BUFFEREVENT_ITEM_FIELDS] = {
33        SL_ANDROID_ITEMKEY_BUFFERQUEUEEVENT, // item key
34        sizeof(SLuint32),                    // item size
35        SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED // item data
36};
37
38
39BufferQueueSource::BufferQueueSource(const void* user, void *context,  const void *caller) :
40          mAndroidBufferQueueSource(NULL),
41          mStreamToBqOffset(0),
42          mEosReached(false)
43{
44    if (NULL != user) {
45        mAndroidBufferQueueSource = &((CAudioPlayer*)user)->mAndroidBufferQueue;
46    } else {
47        SL_LOGE("Can't create BufferQueueSource with NULL user");
48    }
49
50}
51
52
53BufferQueueSource::~BufferQueueSource() {
54    SL_LOGD("BufferQueueSource::~BufferQueueSource");
55}
56
57
58//--------------------------------------------------------------------------
59status_t BufferQueueSource::initCheck() const {
60    return mAndroidBufferQueueSource != NULL ? OK : NO_INIT;
61}
62
63ssize_t BufferQueueSource::readAt(off64_t offset, void *data, size_t size) {
64    SL_LOGD("BufferQueueSource::readAt(offset=%lld, data=%p, size=%d)", offset, data, size);
65
66    if (mEosReached) {
67        // once EOS has been received from the buffer queue, you can't read anymore
68        return 0;
69    }
70
71    ssize_t readSize;
72    slAndroidBufferQueueCallback callback = NULL;
73    void* pBufferContext, *pBufferData, *callbackPContext;
74    uint32_t dataSize, dataUsed;
75
76    interface_lock_exclusive(mAndroidBufferQueueSource);
77
78    if (mAndroidBufferQueueSource->mState.count == 0) {
79        readSize = 0;
80    } else {
81        assert(mAndroidBufferQueueSource->mFront != mAndroidBufferQueueSource->mRear);
82
83        AdvancedBufferHeader *oldFront = mAndroidBufferQueueSource->mFront;
84        AdvancedBufferHeader *newFront = &oldFront[1];
85
86        // where to read from
87        char *pSrc = NULL;
88        // can this read operation cause us to call the buffer queue callback
89        // (either because there was a command with no data, or all the data has been consumed)
90        bool queueCallbackCandidate = false;
91
92        // consume events when starting to read data from a buffer for the first time
93        if (oldFront->mDataSizeConsumed == 0) {
94            if (oldFront->mItems.mAdtsCmdData.mAdtsCmdCode & ANDROID_ADTSEVENT_EOS) {
95                mEosReached = true;
96                // EOS has no associated data
97                queueCallbackCandidate = true;
98            }
99            oldFront->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
100        }
101
102        //assert(mStreamToBqOffset <= offset);
103        CHECK(mStreamToBqOffset <= offset);
104
105        if (offset + size <= mStreamToBqOffset + oldFront->mDataSize) {
106            pSrc = ((char*)oldFront->mDataBuffer) + (offset - mStreamToBqOffset);
107
108            if (offset - mStreamToBqOffset + size == oldFront->mDataSize) {
109                // consumed buffer entirely
110                oldFront->mDataSizeConsumed = oldFront->mDataSize;
111                mStreamToBqOffset += oldFront->mDataSize;
112                queueCallbackCandidate = true;
113
114                // move queue to next buffer
115                if (newFront == &mAndroidBufferQueueSource->
116                        mBufferArray[mAndroidBufferQueueSource->mNumBuffers + 1]) {
117                    // reached the end, circle back
118                    newFront = mAndroidBufferQueueSource->mBufferArray;
119                }
120                mAndroidBufferQueueSource->mFront = newFront;
121                // update the queue state
122                mAndroidBufferQueueSource->mState.count--;
123                mAndroidBufferQueueSource->mState.index++;
124                SL_LOGV("BufferQueueSource moving to next buffer");
125            }
126        }
127
128        // consume data: copy to given destination
129        if (NULL != pSrc) {
130            memcpy(data, pSrc, size);
131            readSize = size;
132        } else {
133            readSize = 0;
134        }
135
136        if (queueCallbackCandidate) {
137            // data has been consumed, and the buffer queue state has been updated
138            // we will notify the client if applicable
139            if (mAndroidBufferQueueSource->mCallbackEventsMask &
140                    SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED) {
141                callback = mAndroidBufferQueueSource->mCallback;
142                // save callback data while under lock
143                callbackPContext = mAndroidBufferQueueSource->mContext;
144                pBufferContext = (void *)oldFront->mBufferContext;
145                pBufferData    = (void *)oldFront->mDataBuffer;
146                dataSize       = oldFront->mDataSize;
147                dataUsed       = oldFront->mDataSizeConsumed;
148            }
149        }
150    }
151
152    interface_unlock_exclusive(mAndroidBufferQueueSource);
153
154    // notify client
155    if (NULL != callback) {
156        SLresult result = (*callback)(&mAndroidBufferQueueSource->mItf, callbackPContext,
157                pBufferContext, pBufferData, dataSize, dataUsed,
158                // no messages during playback other than marking the buffer as processed
159                (const SLAndroidBufferItem*)(&kItemProcessed) /* pItems */,
160                NB_BUFFEREVENT_ITEM_FIELDS * sizeof(SLuint32) /* itemsLength */ );
161        if (SL_RESULT_SUCCESS != result) {
162            // Reserved for future use
163            SL_LOGW("Unsuccessful result %d returned from AndroidBufferQueueCallback", result);
164        }
165    }
166
167    return readSize;
168}
169
170
171status_t BufferQueueSource::getSize(off64_t *size) {
172    SL_LOGD("BufferQueueSource::getSize()");
173    // we're streaming, we don't know how much there is
174    *size = 0;
175    return ERROR_UNSUPPORTED;
176}
177
178}  // namespace android
179