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