xref: /aosp_15_r20/frameworks/wilhelm/src/android/android_StreamPlayer.cpp (revision bebae9c0e76121f8312ccb50385c080b3a0b023c)
1*bebae9c0SAndroid Build Coastguard Worker /*
2*bebae9c0SAndroid Build Coastguard Worker  * Copyright (C) 2010 The Android Open Source Project
3*bebae9c0SAndroid Build Coastguard Worker  *
4*bebae9c0SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*bebae9c0SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*bebae9c0SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*bebae9c0SAndroid Build Coastguard Worker  *
8*bebae9c0SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*bebae9c0SAndroid Build Coastguard Worker  *
10*bebae9c0SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*bebae9c0SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*bebae9c0SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*bebae9c0SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*bebae9c0SAndroid Build Coastguard Worker  * limitations under the License.
15*bebae9c0SAndroid Build Coastguard Worker  */
16*bebae9c0SAndroid Build Coastguard Worker 
17*bebae9c0SAndroid Build Coastguard Worker //#define USE_LOG SLAndroidLogLevel_Verbose
18*bebae9c0SAndroid Build Coastguard Worker 
19*bebae9c0SAndroid Build Coastguard Worker #include "sles_allinclusive.h"
20*bebae9c0SAndroid Build Coastguard Worker #include "android_StreamPlayer.h"
21*bebae9c0SAndroid Build Coastguard Worker 
22*bebae9c0SAndroid Build Coastguard Worker #include <media/IStreamSource.h>
23*bebae9c0SAndroid Build Coastguard Worker #include <media/IMediaPlayerService.h>
24*bebae9c0SAndroid Build Coastguard Worker #include <media/stagefright/foundation/ADebug.h>
25*bebae9c0SAndroid Build Coastguard Worker #include <media/stagefright/foundation/MediaKeys.h>
26*bebae9c0SAndroid Build Coastguard Worker #include <mpeg2ts/ATSParser.h>
27*bebae9c0SAndroid Build Coastguard Worker #include <binder/IPCThreadState.h>
28*bebae9c0SAndroid Build Coastguard Worker 
29*bebae9c0SAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
30*bebae9c0SAndroid Build Coastguard Worker namespace android {
31*bebae9c0SAndroid Build Coastguard Worker 
StreamSourceAppProxy(IAndroidBufferQueue * androidBufferQueue,const sp<CallbackProtector> & callbackProtector,StreamPlayer * player)32*bebae9c0SAndroid Build Coastguard Worker StreamSourceAppProxy::StreamSourceAppProxy(
33*bebae9c0SAndroid Build Coastguard Worker         IAndroidBufferQueue *androidBufferQueue,
34*bebae9c0SAndroid Build Coastguard Worker         const sp<CallbackProtector> &callbackProtector,
35*bebae9c0SAndroid Build Coastguard Worker         // sp<StreamPlayer> would cause StreamPlayer's destructor to run during it's own
36*bebae9c0SAndroid Build Coastguard Worker         // construction.   If you pass in a sp<> to 'this' inside a constructor, then first the
37*bebae9c0SAndroid Build Coastguard Worker         // refcount is increased from 0 to 1, then decreased from 1 to 0, which causes the object's
38*bebae9c0SAndroid Build Coastguard Worker         // destructor to run from inside it's own constructor.
39*bebae9c0SAndroid Build Coastguard Worker         StreamPlayer * /* const sp<StreamPlayer> & */ player) :
40*bebae9c0SAndroid Build Coastguard Worker     mBuffersHasBeenSet(false),
41*bebae9c0SAndroid Build Coastguard Worker     mAndroidBufferQueue(androidBufferQueue),
42*bebae9c0SAndroid Build Coastguard Worker     mCallbackProtector(callbackProtector),
43*bebae9c0SAndroid Build Coastguard Worker     mPlayer(player)
44*bebae9c0SAndroid Build Coastguard Worker {
45*bebae9c0SAndroid Build Coastguard Worker     SL_LOGV("StreamSourceAppProxy::StreamSourceAppProxy()");
46*bebae9c0SAndroid Build Coastguard Worker }
47*bebae9c0SAndroid Build Coastguard Worker 
~StreamSourceAppProxy()48*bebae9c0SAndroid Build Coastguard Worker StreamSourceAppProxy::~StreamSourceAppProxy() {
49*bebae9c0SAndroid Build Coastguard Worker     SL_LOGV("StreamSourceAppProxy::~StreamSourceAppProxy()");
50*bebae9c0SAndroid Build Coastguard Worker     disconnect();
51*bebae9c0SAndroid Build Coastguard Worker }
52*bebae9c0SAndroid Build Coastguard Worker 
53*bebae9c0SAndroid Build Coastguard Worker const SLuint32 StreamSourceAppProxy::kItemProcessed[NB_BUFFEREVENT_ITEM_FIELDS] = {
54*bebae9c0SAndroid Build Coastguard Worker         SL_ANDROID_ITEMKEY_BUFFERQUEUEEVENT, // item key
55*bebae9c0SAndroid Build Coastguard Worker         sizeof(SLuint32),                    // item size
56*bebae9c0SAndroid Build Coastguard Worker         SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED // item data
57*bebae9c0SAndroid Build Coastguard Worker };
58*bebae9c0SAndroid Build Coastguard Worker 
59*bebae9c0SAndroid Build Coastguard Worker //--------------------------------------------------
60*bebae9c0SAndroid Build Coastguard Worker // IStreamSource implementation
setListener(const sp<IStreamListener> & listener)61*bebae9c0SAndroid Build Coastguard Worker void StreamSourceAppProxy::setListener(const sp<IStreamListener> &listener) {
62*bebae9c0SAndroid Build Coastguard Worker     assert(listener != NULL);
63*bebae9c0SAndroid Build Coastguard Worker     Mutex::Autolock _l(mLock);
64*bebae9c0SAndroid Build Coastguard Worker     assert(mListener == NULL);
65*bebae9c0SAndroid Build Coastguard Worker     mListener = listener;
66*bebae9c0SAndroid Build Coastguard Worker }
67*bebae9c0SAndroid Build Coastguard Worker 
setBuffers(const Vector<sp<IMemory>> & buffers)68*bebae9c0SAndroid Build Coastguard Worker void StreamSourceAppProxy::setBuffers(const Vector<sp<IMemory> > &buffers) {
69*bebae9c0SAndroid Build Coastguard Worker     Mutex::Autolock _l(mLock);
70*bebae9c0SAndroid Build Coastguard Worker     assert(!mBuffersHasBeenSet);
71*bebae9c0SAndroid Build Coastguard Worker     mBuffers = buffers;
72*bebae9c0SAndroid Build Coastguard Worker     mBuffersHasBeenSet = true;
73*bebae9c0SAndroid Build Coastguard Worker }
74*bebae9c0SAndroid Build Coastguard Worker 
onBufferAvailable(size_t index)75*bebae9c0SAndroid Build Coastguard Worker void StreamSourceAppProxy::onBufferAvailable(size_t index) {
76*bebae9c0SAndroid Build Coastguard Worker     //SL_LOGD("StreamSourceAppProxy::onBufferAvailable(%d)", index);
77*bebae9c0SAndroid Build Coastguard Worker 
78*bebae9c0SAndroid Build Coastguard Worker     {
79*bebae9c0SAndroid Build Coastguard Worker         Mutex::Autolock _l(mLock);
80*bebae9c0SAndroid Build Coastguard Worker         if (!mBuffersHasBeenSet) {
81*bebae9c0SAndroid Build Coastguard Worker             // no buffers available to push data to from the buffer queue, bail
82*bebae9c0SAndroid Build Coastguard Worker             return;
83*bebae9c0SAndroid Build Coastguard Worker         }
84*bebae9c0SAndroid Build Coastguard Worker         CHECK_LT(index, mBuffers.size());
85*bebae9c0SAndroid Build Coastguard Worker #if 0   // enable if needed for debugging
86*bebae9c0SAndroid Build Coastguard Worker         sp<IMemory> mem = mBuffers.itemAt(index);
87*bebae9c0SAndroid Build Coastguard Worker         SLAint64 length = (SLAint64) mem->size();
88*bebae9c0SAndroid Build Coastguard Worker #endif
89*bebae9c0SAndroid Build Coastguard Worker         mAvailableBuffers.push_back(index);
90*bebae9c0SAndroid Build Coastguard Worker         //SL_LOGD("onBufferAvailable() now %d buffers available in queue",
91*bebae9c0SAndroid Build Coastguard Worker         //         mAvailableBuffers.size());
92*bebae9c0SAndroid Build Coastguard Worker     }
93*bebae9c0SAndroid Build Coastguard Worker 
94*bebae9c0SAndroid Build Coastguard Worker     // a new shared mem buffer is available: let's try to fill immediately
95*bebae9c0SAndroid Build Coastguard Worker     pullFromBuffQueue();
96*bebae9c0SAndroid Build Coastguard Worker }
97*bebae9c0SAndroid Build Coastguard Worker 
receivedCmd_l(IStreamListener::Command cmd,const sp<AMessage> & msg)98*bebae9c0SAndroid Build Coastguard Worker void StreamSourceAppProxy::receivedCmd_l(IStreamListener::Command cmd, const sp<AMessage> &msg) {
99*bebae9c0SAndroid Build Coastguard Worker     if (mListener != 0) {
100*bebae9c0SAndroid Build Coastguard Worker         mListener->issueCommand(cmd, false /* synchronous */, msg);
101*bebae9c0SAndroid Build Coastguard Worker     }
102*bebae9c0SAndroid Build Coastguard Worker }
103*bebae9c0SAndroid Build Coastguard Worker 
receivedBuffer_l(size_t buffIndex,size_t buffLength)104*bebae9c0SAndroid Build Coastguard Worker void StreamSourceAppProxy::receivedBuffer_l(size_t buffIndex, size_t buffLength) {
105*bebae9c0SAndroid Build Coastguard Worker     if (mListener != 0) {
106*bebae9c0SAndroid Build Coastguard Worker         mListener->queueBuffer(buffIndex, buffLength);
107*bebae9c0SAndroid Build Coastguard Worker     }
108*bebae9c0SAndroid Build Coastguard Worker }
109*bebae9c0SAndroid Build Coastguard Worker 
disconnect()110*bebae9c0SAndroid Build Coastguard Worker void StreamSourceAppProxy::disconnect() {
111*bebae9c0SAndroid Build Coastguard Worker     Mutex::Autolock _l(mLock);
112*bebae9c0SAndroid Build Coastguard Worker     mListener.clear();
113*bebae9c0SAndroid Build Coastguard Worker     // Force binder to push the decremented reference count for sp<IStreamListener>.
114*bebae9c0SAndroid Build Coastguard Worker     // mediaserver and client both have sp<> to the other. When you decrement an sp<>
115*bebae9c0SAndroid Build Coastguard Worker     // reference count, binder doesn't push that to the other process immediately.
116*bebae9c0SAndroid Build Coastguard Worker     IPCThreadState::self()->flushCommands();
117*bebae9c0SAndroid Build Coastguard Worker     mBuffers.clear();
118*bebae9c0SAndroid Build Coastguard Worker     mBuffersHasBeenSet = false;
119*bebae9c0SAndroid Build Coastguard Worker     mAvailableBuffers.clear();
120*bebae9c0SAndroid Build Coastguard Worker }
121*bebae9c0SAndroid Build Coastguard Worker 
122*bebae9c0SAndroid Build Coastguard Worker //--------------------------------------------------
123*bebae9c0SAndroid Build Coastguard Worker // consumption from ABQ: pull from the ABQ, and push to shared memory (media server)
pullFromBuffQueue()124*bebae9c0SAndroid Build Coastguard Worker void StreamSourceAppProxy::pullFromBuffQueue() {
125*bebae9c0SAndroid Build Coastguard Worker 
126*bebae9c0SAndroid Build Coastguard Worker   if (android::CallbackProtector::enterCbIfOk(mCallbackProtector)) {
127*bebae9c0SAndroid Build Coastguard Worker 
128*bebae9c0SAndroid Build Coastguard Worker     size_t bufferId;
129*bebae9c0SAndroid Build Coastguard Worker     void* bufferLoc;
130*bebae9c0SAndroid Build Coastguard Worker     size_t buffSize;
131*bebae9c0SAndroid Build Coastguard Worker 
132*bebae9c0SAndroid Build Coastguard Worker     slAndroidBufferQueueCallback callback = NULL;
133*bebae9c0SAndroid Build Coastguard Worker     void* pBufferContext, *pBufferData, *callbackPContext = NULL;
134*bebae9c0SAndroid Build Coastguard Worker     AdvancedBufferHeader *oldFront = NULL;
135*bebae9c0SAndroid Build Coastguard Worker     uint32_t dataSize /* , dataUsed */;
136*bebae9c0SAndroid Build Coastguard Worker 
137*bebae9c0SAndroid Build Coastguard Worker     // retrieve data from the buffer queue
138*bebae9c0SAndroid Build Coastguard Worker     interface_lock_exclusive(mAndroidBufferQueue);
139*bebae9c0SAndroid Build Coastguard Worker 
140*bebae9c0SAndroid Build Coastguard Worker     // can this read operation cause us to call the buffer queue callback
141*bebae9c0SAndroid Build Coastguard Worker     // (either because there was a command with no data, or all the data has been consumed)
142*bebae9c0SAndroid Build Coastguard Worker     bool queueCallbackCandidate = false;
143*bebae9c0SAndroid Build Coastguard Worker 
144*bebae9c0SAndroid Build Coastguard Worker     if (mAndroidBufferQueue->mState.count != 0) {
145*bebae9c0SAndroid Build Coastguard Worker         // SL_LOGD("nbBuffers in ABQ = %u, buffSize=%u",abq->mState.count, buffSize);
146*bebae9c0SAndroid Build Coastguard Worker         assert(mAndroidBufferQueue->mFront != mAndroidBufferQueue->mRear);
147*bebae9c0SAndroid Build Coastguard Worker 
148*bebae9c0SAndroid Build Coastguard Worker         oldFront = mAndroidBufferQueue->mFront;
149*bebae9c0SAndroid Build Coastguard Worker         AdvancedBufferHeader *newFront = &oldFront[1];
150*bebae9c0SAndroid Build Coastguard Worker 
151*bebae9c0SAndroid Build Coastguard Worker         // consume events when starting to read data from a buffer for the first time
152*bebae9c0SAndroid Build Coastguard Worker         if (oldFront->mDataSizeConsumed == 0) {
153*bebae9c0SAndroid Build Coastguard Worker             // note this code assumes at most one event per buffer; see IAndroidBufferQueue_Enqueue
154*bebae9c0SAndroid Build Coastguard Worker             if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_EOS) {
155*bebae9c0SAndroid Build Coastguard Worker                 receivedCmd_l(IStreamListener::EOS);
156*bebae9c0SAndroid Build Coastguard Worker                 // EOS has no associated data
157*bebae9c0SAndroid Build Coastguard Worker                 queueCallbackCandidate = true;
158*bebae9c0SAndroid Build Coastguard Worker             } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCONTINUITY) {
159*bebae9c0SAndroid Build Coastguard Worker                 receivedCmd_l(IStreamListener::DISCONTINUITY);
160*bebae9c0SAndroid Build Coastguard Worker             } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCON_NEWPTS) {
161*bebae9c0SAndroid Build Coastguard Worker                 sp<AMessage> msg = new AMessage();
162*bebae9c0SAndroid Build Coastguard Worker                 msg->setInt64(kATSParserKeyResumeAtPTS,
163*bebae9c0SAndroid Build Coastguard Worker                         (int64_t)oldFront->mItems.mTsCmdData.mPts);
164*bebae9c0SAndroid Build Coastguard Worker                 receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
165*bebae9c0SAndroid Build Coastguard Worker             } else if (oldFront->mItems.mTsCmdData.mTsCmdCode
166*bebae9c0SAndroid Build Coastguard Worker                     & ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL) {
167*bebae9c0SAndroid Build Coastguard Worker                 sp<AMessage> msg = new AMessage();
168*bebae9c0SAndroid Build Coastguard Worker                 msg->setInt32(
169*bebae9c0SAndroid Build Coastguard Worker                         kIStreamListenerKeyDiscontinuityMask,
170*bebae9c0SAndroid Build Coastguard Worker                         ATSParser::DISCONTINUITY_FORMATCHANGE);
171*bebae9c0SAndroid Build Coastguard Worker                 receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
172*bebae9c0SAndroid Build Coastguard Worker             } else if (oldFront->mItems.mTsCmdData.mTsCmdCode
173*bebae9c0SAndroid Build Coastguard Worker                     & ANDROID_MP2TSEVENT_FORMAT_CHANGE_VIDEO) {
174*bebae9c0SAndroid Build Coastguard Worker                 sp<AMessage> msg = new AMessage();
175*bebae9c0SAndroid Build Coastguard Worker                 msg->setInt32(
176*bebae9c0SAndroid Build Coastguard Worker                         kIStreamListenerKeyDiscontinuityMask,
177*bebae9c0SAndroid Build Coastguard Worker                         ATSParser::DISCONTINUITY_VIDEO_FORMAT);
178*bebae9c0SAndroid Build Coastguard Worker                 receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
179*bebae9c0SAndroid Build Coastguard Worker             }
180*bebae9c0SAndroid Build Coastguard Worker             // note that here we are intentionally only supporting
181*bebae9c0SAndroid Build Coastguard Worker             //   ANDROID_MP2TSEVENT_FORMAT_CHANGE_VIDEO, see IAndroidBufferQueue.c
182*bebae9c0SAndroid Build Coastguard Worker 
183*bebae9c0SAndroid Build Coastguard Worker             // some commands may introduce a time discontinuity, reevaluate position if needed
184*bebae9c0SAndroid Build Coastguard Worker             if (oldFront->mItems.mTsCmdData.mTsCmdCode & (ANDROID_MP2TSEVENT_DISCONTINUITY |
185*bebae9c0SAndroid Build Coastguard Worker                     ANDROID_MP2TSEVENT_DISCON_NEWPTS | ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL)) {
186*bebae9c0SAndroid Build Coastguard Worker                 const sp<StreamPlayer> player(mPlayer.promote());
187*bebae9c0SAndroid Build Coastguard Worker                 if (player != NULL) {
188*bebae9c0SAndroid Build Coastguard Worker                     // FIXME see note at onSeek
189*bebae9c0SAndroid Build Coastguard Worker                     player->seek(ANDROID_UNKNOWN_TIME);
190*bebae9c0SAndroid Build Coastguard Worker                 }
191*bebae9c0SAndroid Build Coastguard Worker             }
192*bebae9c0SAndroid Build Coastguard Worker             oldFront->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
193*bebae9c0SAndroid Build Coastguard Worker         }
194*bebae9c0SAndroid Build Coastguard Worker 
195*bebae9c0SAndroid Build Coastguard Worker         {
196*bebae9c0SAndroid Build Coastguard Worker             // we're going to change the shared mem buffer queue, so lock it
197*bebae9c0SAndroid Build Coastguard Worker             Mutex::Autolock _l(mLock);
198*bebae9c0SAndroid Build Coastguard Worker             if (!mAvailableBuffers.empty()) {
199*bebae9c0SAndroid Build Coastguard Worker                 bufferId = *mAvailableBuffers.begin();
200*bebae9c0SAndroid Build Coastguard Worker                 CHECK_LT(bufferId, mBuffers.size());
201*bebae9c0SAndroid Build Coastguard Worker                 sp<IMemory> mem = mBuffers.itemAt(bufferId);
202*bebae9c0SAndroid Build Coastguard Worker                 bufferLoc = mem->unsecurePointer();
203*bebae9c0SAndroid Build Coastguard Worker                 buffSize = mem->size();
204*bebae9c0SAndroid Build Coastguard Worker 
205*bebae9c0SAndroid Build Coastguard Worker                 char *pSrc = ((char*)oldFront->mDataBuffer) + oldFront->mDataSizeConsumed;
206*bebae9c0SAndroid Build Coastguard Worker                 if (oldFront->mDataSizeConsumed + buffSize < oldFront->mDataSize) {
207*bebae9c0SAndroid Build Coastguard Worker                     // more available than requested, copy as much as requested
208*bebae9c0SAndroid Build Coastguard Worker                     // consume data: 1/ copy to given destination
209*bebae9c0SAndroid Build Coastguard Worker                     memcpy(bufferLoc, pSrc, buffSize);
210*bebae9c0SAndroid Build Coastguard Worker                     //               2/ keep track of how much has been consumed
211*bebae9c0SAndroid Build Coastguard Worker                     oldFront->mDataSizeConsumed += buffSize;
212*bebae9c0SAndroid Build Coastguard Worker                     //               3/ notify shared mem listener that new data is available
213*bebae9c0SAndroid Build Coastguard Worker                     receivedBuffer_l(bufferId, buffSize);
214*bebae9c0SAndroid Build Coastguard Worker                     mAvailableBuffers.erase(mAvailableBuffers.begin());
215*bebae9c0SAndroid Build Coastguard Worker                 } else {
216*bebae9c0SAndroid Build Coastguard Worker                     // requested as much available or more: consume the whole of the current
217*bebae9c0SAndroid Build Coastguard Worker                     //   buffer and move to the next
218*bebae9c0SAndroid Build Coastguard Worker                     size_t consumed = oldFront->mDataSize - oldFront->mDataSizeConsumed;
219*bebae9c0SAndroid Build Coastguard Worker                     //SL_LOGD("consuming rest of buffer: enqueueing=%u", consumed);
220*bebae9c0SAndroid Build Coastguard Worker                     oldFront->mDataSizeConsumed = oldFront->mDataSize;
221*bebae9c0SAndroid Build Coastguard Worker 
222*bebae9c0SAndroid Build Coastguard Worker                     // move queue to next
223*bebae9c0SAndroid Build Coastguard Worker                     if (newFront == &mAndroidBufferQueue->
224*bebae9c0SAndroid Build Coastguard Worker                             mBufferArray[mAndroidBufferQueue->mNumBuffers + 1]) {
225*bebae9c0SAndroid Build Coastguard Worker                         // reached the end, circle back
226*bebae9c0SAndroid Build Coastguard Worker                         newFront = mAndroidBufferQueue->mBufferArray;
227*bebae9c0SAndroid Build Coastguard Worker                     }
228*bebae9c0SAndroid Build Coastguard Worker                     mAndroidBufferQueue->mFront = newFront;
229*bebae9c0SAndroid Build Coastguard Worker                     mAndroidBufferQueue->mState.count--;
230*bebae9c0SAndroid Build Coastguard Worker                     mAndroidBufferQueue->mState.index++;
231*bebae9c0SAndroid Build Coastguard Worker 
232*bebae9c0SAndroid Build Coastguard Worker                     if (consumed > 0) {
233*bebae9c0SAndroid Build Coastguard Worker                         // consume data: 1/ copy to given destination
234*bebae9c0SAndroid Build Coastguard Worker                         memcpy(bufferLoc, pSrc, consumed);
235*bebae9c0SAndroid Build Coastguard Worker                         //               2/ keep track of how much has been consumed
236*bebae9c0SAndroid Build Coastguard Worker                         // here nothing to do because we are done with this buffer
237*bebae9c0SAndroid Build Coastguard Worker                         //               3/ notify StreamPlayer that new data is available
238*bebae9c0SAndroid Build Coastguard Worker                         receivedBuffer_l(bufferId, consumed);
239*bebae9c0SAndroid Build Coastguard Worker                         mAvailableBuffers.erase(mAvailableBuffers.begin());
240*bebae9c0SAndroid Build Coastguard Worker                     }
241*bebae9c0SAndroid Build Coastguard Worker 
242*bebae9c0SAndroid Build Coastguard Worker                     // data has been consumed, and the buffer queue state has been updated
243*bebae9c0SAndroid Build Coastguard Worker                     // we will notify the client if applicable
244*bebae9c0SAndroid Build Coastguard Worker                     queueCallbackCandidate = true;
245*bebae9c0SAndroid Build Coastguard Worker                 }
246*bebae9c0SAndroid Build Coastguard Worker             }
247*bebae9c0SAndroid Build Coastguard Worker 
248*bebae9c0SAndroid Build Coastguard Worker             if (queueCallbackCandidate) {
249*bebae9c0SAndroid Build Coastguard Worker                 if (mAndroidBufferQueue->mCallbackEventsMask &
250*bebae9c0SAndroid Build Coastguard Worker                         SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED) {
251*bebae9c0SAndroid Build Coastguard Worker                     callback = mAndroidBufferQueue->mCallback;
252*bebae9c0SAndroid Build Coastguard Worker                     // save callback data while under lock
253*bebae9c0SAndroid Build Coastguard Worker                     callbackPContext = mAndroidBufferQueue->mContext;
254*bebae9c0SAndroid Build Coastguard Worker                     pBufferContext = (void *)oldFront->mBufferContext;
255*bebae9c0SAndroid Build Coastguard Worker                     pBufferData    = (void *)oldFront->mDataBuffer;
256*bebae9c0SAndroid Build Coastguard Worker                     dataSize       = oldFront->mDataSize;
257*bebae9c0SAndroid Build Coastguard Worker                     // here a buffer is only dequeued when fully consumed
258*bebae9c0SAndroid Build Coastguard Worker                     //dataUsed     = oldFront->mDataSizeConsumed;
259*bebae9c0SAndroid Build Coastguard Worker                 }
260*bebae9c0SAndroid Build Coastguard Worker             }
261*bebae9c0SAndroid Build Coastguard Worker             //SL_LOGD("%d buffers available after reading from queue", mAvailableBuffers.size());
262*bebae9c0SAndroid Build Coastguard Worker             if (!mAvailableBuffers.empty()) {
263*bebae9c0SAndroid Build Coastguard Worker                 // there is still room in the shared memory, recheck later if we can pull
264*bebae9c0SAndroid Build Coastguard Worker                 // data from the buffer queue and write it to shared memory
265*bebae9c0SAndroid Build Coastguard Worker                 const sp<StreamPlayer> player(mPlayer.promote());
266*bebae9c0SAndroid Build Coastguard Worker                 if (player != NULL) {
267*bebae9c0SAndroid Build Coastguard Worker                     player->queueRefilled();
268*bebae9c0SAndroid Build Coastguard Worker                 }
269*bebae9c0SAndroid Build Coastguard Worker             }
270*bebae9c0SAndroid Build Coastguard Worker         }
271*bebae9c0SAndroid Build Coastguard Worker 
272*bebae9c0SAndroid Build Coastguard Worker     } else { // empty queue
273*bebae9c0SAndroid Build Coastguard Worker         SL_LOGD("ABQ empty, starving!");
274*bebae9c0SAndroid Build Coastguard Worker     }
275*bebae9c0SAndroid Build Coastguard Worker 
276*bebae9c0SAndroid Build Coastguard Worker     interface_unlock_exclusive(mAndroidBufferQueue);
277*bebae9c0SAndroid Build Coastguard Worker 
278*bebae9c0SAndroid Build Coastguard Worker     // notify client of buffer processed
279*bebae9c0SAndroid Build Coastguard Worker     if (NULL != callback) {
280*bebae9c0SAndroid Build Coastguard Worker         SLresult result = (*callback)(&mAndroidBufferQueue->mItf, callbackPContext,
281*bebae9c0SAndroid Build Coastguard Worker                 pBufferContext, pBufferData, dataSize,
282*bebae9c0SAndroid Build Coastguard Worker                 dataSize, /* dataUsed  */
283*bebae9c0SAndroid Build Coastguard Worker                 // no messages during playback other than marking the buffer as processed
284*bebae9c0SAndroid Build Coastguard Worker                 (const SLAndroidBufferItem*)(&kItemProcessed) /* pItems */,
285*bebae9c0SAndroid Build Coastguard Worker                 NB_BUFFEREVENT_ITEM_FIELDS *sizeof(SLuint32) /* itemsLength */ );
286*bebae9c0SAndroid Build Coastguard Worker         if (SL_RESULT_SUCCESS != result) {
287*bebae9c0SAndroid Build Coastguard Worker             // Reserved for future use
288*bebae9c0SAndroid Build Coastguard Worker             SL_LOGW("Unsuccessful result %d returned from AndroidBufferQueueCallback", result);
289*bebae9c0SAndroid Build Coastguard Worker         }
290*bebae9c0SAndroid Build Coastguard Worker     }
291*bebae9c0SAndroid Build Coastguard Worker 
292*bebae9c0SAndroid Build Coastguard Worker     mCallbackProtector->exitCb();
293*bebae9c0SAndroid Build Coastguard Worker   } // enterCbIfOk
294*bebae9c0SAndroid Build Coastguard Worker }
295*bebae9c0SAndroid Build Coastguard Worker 
296*bebae9c0SAndroid Build Coastguard Worker 
297*bebae9c0SAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
StreamPlayer(const AudioPlayback_Parameters * params,bool hasVideo,IAndroidBufferQueue * androidBufferQueue,const sp<CallbackProtector> & callbackProtector)298*bebae9c0SAndroid Build Coastguard Worker StreamPlayer::StreamPlayer(const AudioPlayback_Parameters* params, bool hasVideo,
299*bebae9c0SAndroid Build Coastguard Worker         IAndroidBufferQueue *androidBufferQueue, const sp<CallbackProtector> &callbackProtector) :
300*bebae9c0SAndroid Build Coastguard Worker         GenericMediaPlayer(params, hasVideo),
301*bebae9c0SAndroid Build Coastguard Worker         mAppProxy(new StreamSourceAppProxy(androidBufferQueue, callbackProtector, this)),
302*bebae9c0SAndroid Build Coastguard Worker         mStopForDestroyCompleted(false)
303*bebae9c0SAndroid Build Coastguard Worker {
304*bebae9c0SAndroid Build Coastguard Worker     SL_LOGD("StreamPlayer::StreamPlayer()");
305*bebae9c0SAndroid Build Coastguard Worker }
306*bebae9c0SAndroid Build Coastguard Worker 
~StreamPlayer()307*bebae9c0SAndroid Build Coastguard Worker StreamPlayer::~StreamPlayer() {
308*bebae9c0SAndroid Build Coastguard Worker     SL_LOGD("StreamPlayer::~StreamPlayer()");
309*bebae9c0SAndroid Build Coastguard Worker     mAppProxy->disconnect();
310*bebae9c0SAndroid Build Coastguard Worker }
311*bebae9c0SAndroid Build Coastguard Worker 
312*bebae9c0SAndroid Build Coastguard Worker 
onMessageReceived(const sp<AMessage> & msg)313*bebae9c0SAndroid Build Coastguard Worker void StreamPlayer::onMessageReceived(const sp<AMessage> &msg) {
314*bebae9c0SAndroid Build Coastguard Worker     switch (msg->what()) {
315*bebae9c0SAndroid Build Coastguard Worker         case kWhatPullFromAbq:
316*bebae9c0SAndroid Build Coastguard Worker             onPullFromAndroidBufferQueue();
317*bebae9c0SAndroid Build Coastguard Worker             break;
318*bebae9c0SAndroid Build Coastguard Worker 
319*bebae9c0SAndroid Build Coastguard Worker         case kWhatStopForDestroy:
320*bebae9c0SAndroid Build Coastguard Worker             onStopForDestroy();
321*bebae9c0SAndroid Build Coastguard Worker             break;
322*bebae9c0SAndroid Build Coastguard Worker 
323*bebae9c0SAndroid Build Coastguard Worker         default:
324*bebae9c0SAndroid Build Coastguard Worker             GenericMediaPlayer::onMessageReceived(msg);
325*bebae9c0SAndroid Build Coastguard Worker             break;
326*bebae9c0SAndroid Build Coastguard Worker     }
327*bebae9c0SAndroid Build Coastguard Worker }
328*bebae9c0SAndroid Build Coastguard Worker 
329*bebae9c0SAndroid Build Coastguard Worker 
preDestroy()330*bebae9c0SAndroid Build Coastguard Worker void StreamPlayer::preDestroy() {
331*bebae9c0SAndroid Build Coastguard Worker     // FIXME NuPlayerDriver is currently not thread-safe, so stop() must be called by looper
332*bebae9c0SAndroid Build Coastguard Worker     (new AMessage(kWhatStopForDestroy, this))->post();
333*bebae9c0SAndroid Build Coastguard Worker     {
334*bebae9c0SAndroid Build Coastguard Worker         Mutex::Autolock _l(mStopForDestroyLock);
335*bebae9c0SAndroid Build Coastguard Worker         while (!mStopForDestroyCompleted) {
336*bebae9c0SAndroid Build Coastguard Worker             mStopForDestroyCondition.wait(mStopForDestroyLock);
337*bebae9c0SAndroid Build Coastguard Worker         }
338*bebae9c0SAndroid Build Coastguard Worker     }
339*bebae9c0SAndroid Build Coastguard Worker     // GenericMediaPlayer::preDestroy will repeat some of what we've done, but that's benign
340*bebae9c0SAndroid Build Coastguard Worker     GenericMediaPlayer::preDestroy();
341*bebae9c0SAndroid Build Coastguard Worker }
342*bebae9c0SAndroid Build Coastguard Worker 
343*bebae9c0SAndroid Build Coastguard Worker 
onStopForDestroy()344*bebae9c0SAndroid Build Coastguard Worker void StreamPlayer::onStopForDestroy() {
345*bebae9c0SAndroid Build Coastguard Worker     if (mPlayer != 0) {
346*bebae9c0SAndroid Build Coastguard Worker         mPlayer->stop();
347*bebae9c0SAndroid Build Coastguard Worker         // causes CHECK failure in Nuplayer
348*bebae9c0SAndroid Build Coastguard Worker         //mPlayer->setDataSource(NULL);
349*bebae9c0SAndroid Build Coastguard Worker         mPlayer->setVideoSurfaceTexture(NULL);
350*bebae9c0SAndroid Build Coastguard Worker         mPlayer->disconnect();
351*bebae9c0SAndroid Build Coastguard Worker         mPlayer.clear();
352*bebae9c0SAndroid Build Coastguard Worker         {
353*bebae9c0SAndroid Build Coastguard Worker             // FIXME ugh make this a method
354*bebae9c0SAndroid Build Coastguard Worker             Mutex::Autolock _l(mPreparedPlayerLock);
355*bebae9c0SAndroid Build Coastguard Worker             mPreparedPlayer.clear();
356*bebae9c0SAndroid Build Coastguard Worker         }
357*bebae9c0SAndroid Build Coastguard Worker     }
358*bebae9c0SAndroid Build Coastguard Worker     {
359*bebae9c0SAndroid Build Coastguard Worker         Mutex::Autolock _l(mStopForDestroyLock);
360*bebae9c0SAndroid Build Coastguard Worker         mStopForDestroyCompleted = true;
361*bebae9c0SAndroid Build Coastguard Worker     }
362*bebae9c0SAndroid Build Coastguard Worker     mStopForDestroyCondition.signal();
363*bebae9c0SAndroid Build Coastguard Worker }
364*bebae9c0SAndroid Build Coastguard Worker 
365*bebae9c0SAndroid Build Coastguard Worker 
366*bebae9c0SAndroid Build Coastguard Worker /**
367*bebae9c0SAndroid Build Coastguard Worker  * Asynchronously notify the player that the queue is ready to be pulled from.
368*bebae9c0SAndroid Build Coastguard Worker  */
queueRefilled()369*bebae9c0SAndroid Build Coastguard Worker void StreamPlayer::queueRefilled() {
370*bebae9c0SAndroid Build Coastguard Worker     // async notification that the ABQ was refilled: the player should pull from the ABQ, and
371*bebae9c0SAndroid Build Coastguard Worker     //    and push to shared memory (to the media server)
372*bebae9c0SAndroid Build Coastguard Worker     (new AMessage(kWhatPullFromAbq, this))->post();
373*bebae9c0SAndroid Build Coastguard Worker }
374*bebae9c0SAndroid Build Coastguard Worker 
375*bebae9c0SAndroid Build Coastguard Worker 
appClear_l()376*bebae9c0SAndroid Build Coastguard Worker void StreamPlayer::appClear_l() {
377*bebae9c0SAndroid Build Coastguard Worker     // the user of StreamPlayer has cleared its AndroidBufferQueue:
378*bebae9c0SAndroid Build Coastguard Worker     // there's no clear() for the shared memory queue, so this is a no-op
379*bebae9c0SAndroid Build Coastguard Worker }
380*bebae9c0SAndroid Build Coastguard Worker 
381*bebae9c0SAndroid Build Coastguard Worker 
382*bebae9c0SAndroid Build Coastguard Worker //--------------------------------------------------
383*bebae9c0SAndroid Build Coastguard Worker // Event handlers
onPrepare()384*bebae9c0SAndroid Build Coastguard Worker void StreamPlayer::onPrepare() {
385*bebae9c0SAndroid Build Coastguard Worker     SL_LOGD("StreamPlayer::onPrepare()");
386*bebae9c0SAndroid Build Coastguard Worker         sp<IMediaPlayerService> mediaPlayerService(getMediaPlayerService());
387*bebae9c0SAndroid Build Coastguard Worker         if (mediaPlayerService != NULL) {
388*bebae9c0SAndroid Build Coastguard Worker             mPlayer = mediaPlayerService->create(mPlayerClient /*IMediaPlayerClient*/,
389*bebae9c0SAndroid Build Coastguard Worker                     mPlaybackParams.sessionId);
390*bebae9c0SAndroid Build Coastguard Worker             if (mPlayer == NULL) {
391*bebae9c0SAndroid Build Coastguard Worker                 SL_LOGE("media player service failed to create player by app proxy");
392*bebae9c0SAndroid Build Coastguard Worker             } else if (mPlayer->setDataSource(static_cast<sp<IStreamSource>>(mAppProxy)) !=
393*bebae9c0SAndroid Build Coastguard Worker                     NO_ERROR) {
394*bebae9c0SAndroid Build Coastguard Worker                 SL_LOGE("setDataSource failed");
395*bebae9c0SAndroid Build Coastguard Worker                 mPlayer.clear();
396*bebae9c0SAndroid Build Coastguard Worker             }
397*bebae9c0SAndroid Build Coastguard Worker         }
398*bebae9c0SAndroid Build Coastguard Worker     if (mPlayer == NULL) {
399*bebae9c0SAndroid Build Coastguard Worker         mStateFlags |= kFlagPreparedUnsuccessfully;
400*bebae9c0SAndroid Build Coastguard Worker     }
401*bebae9c0SAndroid Build Coastguard Worker     GenericMediaPlayer::onPrepare();
402*bebae9c0SAndroid Build Coastguard Worker     SL_LOGD("StreamPlayer::onPrepare() done");
403*bebae9c0SAndroid Build Coastguard Worker }
404*bebae9c0SAndroid Build Coastguard Worker 
405*bebae9c0SAndroid Build Coastguard Worker 
onPlay()406*bebae9c0SAndroid Build Coastguard Worker void StreamPlayer::onPlay() {
407*bebae9c0SAndroid Build Coastguard Worker     SL_LOGD("StreamPlayer::onPlay()");
408*bebae9c0SAndroid Build Coastguard Worker     // enqueue a message that will cause StreamAppProxy to consume from the queue (again if the
409*bebae9c0SAndroid Build Coastguard Worker     // player had starved the shared memory)
410*bebae9c0SAndroid Build Coastguard Worker     queueRefilled();
411*bebae9c0SAndroid Build Coastguard Worker 
412*bebae9c0SAndroid Build Coastguard Worker     GenericMediaPlayer::onPlay();
413*bebae9c0SAndroid Build Coastguard Worker }
414*bebae9c0SAndroid Build Coastguard Worker 
415*bebae9c0SAndroid Build Coastguard Worker 
onPullFromAndroidBufferQueue()416*bebae9c0SAndroid Build Coastguard Worker void StreamPlayer::onPullFromAndroidBufferQueue() {
417*bebae9c0SAndroid Build Coastguard Worker     SL_LOGD("StreamPlayer::onPullFromAndroidBufferQueue()");
418*bebae9c0SAndroid Build Coastguard Worker     mAppProxy->pullFromBuffQueue();
419*bebae9c0SAndroid Build Coastguard Worker }
420*bebae9c0SAndroid Build Coastguard Worker 
421*bebae9c0SAndroid Build Coastguard Worker } // namespace android
422