android_StreamPlayer.cpp revision 37dc2fccf3f122b79ebd554de209d0a3c94ae161
1/*
2 * Copyright (C) 2010 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 <media/IMediaPlayerService.h>
21
22//--------------------------------------------------------------------------------------------------
23// FIXME abstract out the diff between CMediaPlayer and CAudioPlayer
24
25void android_StreamPlayer_realize_l(CAudioPlayer *ap, const notif_cbf_t cbf, void* notifUser) {
26    SL_LOGI("android_StreamPlayer_realize_l(%p)", ap);
27
28    AudioPlayback_Parameters ap_params;
29    ap_params.sessionId = ap->mSessionId;
30    ap_params.streamType = ap->mStreamType;
31    ap_params.trackcb = NULL;
32    ap_params.trackcbUser = NULL;
33    android::StreamPlayer* splr = new android::StreamPlayer(&ap_params, false /*hasVideo*/);
34    ap->mAPlayer = splr;
35    splr->init(cbf, notifUser);
36}
37
38
39//--------------------------------------------------------------------------------------------------
40namespace android {
41
42StreamSourceAppProxy::StreamSourceAppProxy(
43        const void* user, bool userIsAudioPlayer,
44        void *context, const void *caller) :
45    mUser(user),
46    mUserIsAudioPlayer(userIsAudioPlayer),
47    mAndroidBufferQueue(NULL),
48    mAppContext(context),
49    mCaller(caller)
50{
51    SL_LOGI("StreamSourceAppProxy::StreamSourceAppProxy()");
52
53    if (mUserIsAudioPlayer) {
54        mAndroidBufferQueue = &((CAudioPlayer*)mUser)->mAndroidBufferQueue;
55    } else {
56        mAndroidBufferQueue = &((CMediaPlayer*)mUser)->mAndroidBufferQueue;
57    }
58}
59
60StreamSourceAppProxy::~StreamSourceAppProxy() {
61    SL_LOGI("StreamSourceAppProxy::~StreamSourceAppProxy()");
62    mListener.clear();
63    mBuffers.clear();
64}
65
66//--------------------------------------------------
67// IStreamSource implementation
68void StreamSourceAppProxy::setListener(const sp<IStreamListener> &listener) {
69    Mutex::Autolock _l(mLock);
70    mListener = listener;
71}
72
73void StreamSourceAppProxy::setBuffers(const Vector<sp<IMemory> > &buffers) {
74    mBuffers = buffers;
75}
76
77void StreamSourceAppProxy::onBufferAvailable(size_t index) {
78    //SL_LOGD("StreamSourceAppProxy::onBufferAvailable(%d)", index);
79
80    CHECK_LT(index, mBuffers.size());
81    sp<IMemory> mem = mBuffers.itemAt(index);
82    SLAint64 length = (SLAint64) mem->size();
83
84    {
85        Mutex::Autolock _l(mLock);
86        mAvailableBuffers.push_back(index);
87    }
88//SL_LOGD("onBufferAvailable() now %d buffers available in queue", mAvailableBuffers.size());
89
90    // a new shared mem buffer is available: let's try to fill immediately
91    pullFromBuffQueue();
92}
93
94void StreamSourceAppProxy::receivedCmd_l(IStreamListener::Command cmd, const sp<AMessage> &msg) {
95    if (mListener != 0) {
96        mListener->issueCommand(cmd, false /* synchronous */, msg);
97    }
98}
99
100void StreamSourceAppProxy::receivedBuffer_l(size_t buffIndex, size_t buffLength) {
101    if (mListener != 0) {
102        mListener->queueBuffer(buffIndex, buffLength);
103    }
104}
105
106//--------------------------------------------------
107// consumption from ABQ
108void StreamSourceAppProxy::pullFromBuffQueue() {
109
110    size_t bufferId;
111    void* bufferLoc;
112    size_t buffSize;
113
114    slAndroidBufferQueueCallback callback = NULL;
115    void* callbackPContext = NULL;
116    AdvancedBufferHeader *oldFront = NULL;
117
118    // retrieve data from the buffer queue
119    interface_lock_exclusive(mAndroidBufferQueue);
120
121    if (mAndroidBufferQueue->mState.count != 0) {
122        // SL_LOGD("nbBuffers in ABQ = %lu, buffSize=%lu",abq->mState.count, buffSize);
123        assert(mAndroidBufferQueue->mFront != mAndroidBufferQueue->mRear);
124
125        oldFront = mAndroidBufferQueue->mFront;
126        AdvancedBufferHeader *newFront = &oldFront[1];
127
128        // consume events when starting to read data from a buffer for the first time
129        if (oldFront->mDataSizeConsumed == 0) {
130            if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_EOS) {
131                receivedCmd_l(IStreamListener::EOS);
132            } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCONTINUITY) {
133                receivedCmd_l(IStreamListener::DISCONTINUITY);
134            } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCON_NEWPTS) {
135                sp<AMessage> msg = new AMessage();
136                msg->setInt64(IStreamListener::kKeyResumeAtPTS,
137                        (int64_t)oldFront->mItems.mTsCmdData.mPts);
138                receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
139            }
140            oldFront->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
141        }
142
143        {
144            // we're going to change the shared mem buffer queue, so lock it
145            Mutex::Autolock _l(mLock);
146            if (!mAvailableBuffers.empty()) {
147                bufferId = *mAvailableBuffers.begin();
148                CHECK_LT(bufferId, mBuffers.size());
149                sp<IMemory> mem = mBuffers.itemAt(bufferId);
150                bufferLoc = mem->pointer();
151                buffSize = mem->size();
152
153                char *pSrc = ((char*)oldFront->mDataBuffer) + oldFront->mDataSizeConsumed;
154                if (oldFront->mDataSizeConsumed + buffSize < oldFront->mDataSize) {
155                    // more available than requested, copy as much as requested
156                    // consume data: 1/ copy to given destination
157                    memcpy(bufferLoc, pSrc, buffSize);
158                    //               2/ keep track of how much has been consumed
159                    oldFront->mDataSizeConsumed += buffSize;
160                    //               3/ notify shared mem listener that new data is available
161                    receivedBuffer_l(bufferId, buffSize);
162                    mAvailableBuffers.erase(mAvailableBuffers.begin());
163                } else {
164                    // requested as much available or more: consume the whole of the current
165                    //   buffer and move to the next
166                    size_t consumed = oldFront->mDataSize - oldFront->mDataSizeConsumed;
167                    //SL_LOGD("consuming rest of buffer: enqueueing=%ld", consumed);
168                    oldFront->mDataSizeConsumed = oldFront->mDataSize;
169
170                    // move queue to next
171                    if (newFront == &mAndroidBufferQueue->
172                            mBufferArray[mAndroidBufferQueue->mNumBuffers + 1]) {
173                        // reached the end, circle back
174                        newFront = mAndroidBufferQueue->mBufferArray;
175                    }
176                    mAndroidBufferQueue->mFront = newFront;
177                    mAndroidBufferQueue->mState.count--;
178                    mAndroidBufferQueue->mState.index++;
179
180                    if (consumed > 0) {
181                        // consume data: 1/ copy to given destination
182                        memcpy(bufferLoc, pSrc, consumed);
183                        //               2/ keep track of how much has been consumed
184                        // here nothing to do because we are done with this buffer
185                        //               3/ notify StreamPlayer that new data is available
186                        receivedBuffer_l(bufferId, consumed);
187                        mAvailableBuffers.erase(mAvailableBuffers.begin());
188                    }
189
190                    // data has been consumed, and the buffer queue state has been updated
191                    // we will notify the client if applicable
192                    callback = mAndroidBufferQueue->mCallback;
193                    // save callback data
194                    callbackPContext = mAndroidBufferQueue->mContext;
195                }
196                //SL_LOGD("onBufferAvailable() %d buffers available after enqueue",
197                //     mAvailableBuffers.size());
198            }
199        }
200
201
202    } else { // empty queue
203        SL_LOGD("ABQ empty, starving!");
204        // signal we're at the end of the content, but don't pause (see note in function)
205        if (mUserIsAudioPlayer) {
206            // FIXME declare this external
207            //audioPlayer_dispatch_headAtEnd_lockPlay((CAudioPlayer*)user,
208            //        false /*set state to paused?*/, false);
209        } else {
210            // FIXME implement headAtEnd dispatch for CMediaPlayer
211        }
212    }
213
214    interface_unlock_exclusive(mAndroidBufferQueue);
215
216    // notify client
217    if (NULL != callback) {
218        // oldFront was only initialized in the code path where callback is initialized
219        //    so no need to check if it's valid
220        (*callback)(&mAndroidBufferQueue->mItf, callbackPContext,
221                (void *)oldFront->mBufferContext, /* pBufferContext */
222                (void *)oldFront->mDataBuffer,/* pBufferData  */
223                oldFront->mDataSize, /* dataSize  */
224                // here a buffer is only dequeued when fully consumed
225                oldFront->mDataSize, /* dataUsed  */
226                // no messages during playback
227                0, /* itemsLength */
228                NULL /* pItems */);
229    }
230}
231
232
233//--------------------------------------------------------------------------------------------------
234StreamPlayer::StreamPlayer(AudioPlayback_Parameters* params, bool hasVideo) :
235        GenericMediaPlayer(params, hasVideo),
236        mAppProxy(0)
237{
238    SL_LOGI("StreamPlayer::StreamPlayer()");
239
240    mPlaybackParams = *params;
241
242}
243
244StreamPlayer::~StreamPlayer() {
245    SL_LOGI("StreamPlayer::~StreamPlayer()");
246
247    mAppProxy.clear();
248}
249
250
251void StreamPlayer::onMessageReceived(const sp<AMessage> &msg) {
252    switch (msg->what()) {
253        case kWhatQueueRefilled:
254            onQueueRefilled();
255            break;
256
257        default:
258            GenericMediaPlayer::onMessageReceived(msg);
259            break;
260    }
261}
262
263
264void StreamPlayer::registerQueueCallback(
265        const void* user, bool userIsAudioPlayer,
266        void *context,
267        const void *caller) {
268    SL_LOGI("StreamPlayer::registerQueueCallback");
269    Mutex::Autolock _l(mAppProxyLock);
270
271    mAppProxy = new StreamSourceAppProxy(
272            user, userIsAudioPlayer,
273            context, caller);
274
275    CHECK(mAppProxy != 0);
276    SL_LOGI("StreamPlayer::registerQueueCallback end");
277}
278
279
280/**
281 * Called with a lock on ABQ
282 */
283void StreamPlayer::queueRefilled_l() {
284    // async notification that the ABQ was refilled
285    (new AMessage(kWhatQueueRefilled, id()))->post();
286}
287
288
289void StreamPlayer::appClear_l() {
290    // the user of StreamPlayer has cleared its AndroidBufferQueue:
291    // there's no clear() for the shared memory queue, so this is a no-op
292}
293
294
295//--------------------------------------------------
296// Event handlers
297void StreamPlayer::onPrepare() {
298    SL_LOGI("StreamPlayer::onPrepare()");
299    Mutex::Autolock _l(mAppProxyLock);
300    if (mAppProxy != 0) {
301        mPlayer = mMediaPlayerService->create(getpid(), mPlayerClient /*IMediaPlayerClient*/,
302                mAppProxy /*IStreamSource*/, mPlaybackParams.sessionId);
303        // blocks until mPlayer is prepared
304        GenericMediaPlayer::onPrepare();
305        SL_LOGI("StreamPlayer::onPrepare() done");
306    } else {
307        SL_LOGE("Nothing to do here because there is no registered callback");
308    }
309}
310
311
312void StreamPlayer::onQueueRefilled() {
313    //SL_LOGD("StreamPlayer::onQueueRefilled()");
314    Mutex::Autolock _l(mAppProxyLock);
315    if (mAppProxy != 0) {
316        mAppProxy->pullFromBuffQueue();
317    }
318}
319
320} // namespace android
321