MediaCodec.cpp revision 317bb9163befccd87348c11bdfc0044e629b362b
1/*
2 * Copyright 2012, 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 LOG_NDEBUG 0
18#define LOG_TAG "MediaCodec"
19#include <inttypes.h>
20
21#include "include/avc_utils.h"
22#include "include/SoftwareRenderer.h"
23
24#include <binder/IBatteryStats.h>
25#include <binder/IServiceManager.h>
26#include <gui/Surface.h>
27#include <media/ICrypto.h>
28#include <media/stagefright/foundation/ABuffer.h>
29#include <media/stagefright/foundation/ADebug.h>
30#include <media/stagefright/foundation/AMessage.h>
31#include <media/stagefright/foundation/AString.h>
32#include <media/stagefright/foundation/hexdump.h>
33#include <media/stagefright/ACodec.h>
34#include <media/stagefright/BufferProducerWrapper.h>
35#include <media/stagefright/MediaCodec.h>
36#include <media/stagefright/MediaCodecList.h>
37#include <media/stagefright/MediaDefs.h>
38#include <media/stagefright/MediaErrors.h>
39#include <media/stagefright/MetaData.h>
40#include <media/stagefright/NativeWindowWrapper.h>
41#include <private/android_filesystem_config.h>
42#include <utils/Log.h>
43#include <utils/Singleton.h>
44
45namespace android {
46
47struct MediaCodec::BatteryNotifier : public Singleton<BatteryNotifier> {
48    BatteryNotifier();
49
50    void noteStartVideo();
51    void noteStopVideo();
52    void noteStartAudio();
53    void noteStopAudio();
54
55private:
56    int32_t mVideoRefCount;
57    int32_t mAudioRefCount;
58    sp<IBatteryStats> mBatteryStatService;
59};
60
61ANDROID_SINGLETON_STATIC_INSTANCE(MediaCodec::BatteryNotifier)
62
63MediaCodec::BatteryNotifier::BatteryNotifier() :
64    mVideoRefCount(0),
65    mAudioRefCount(0) {
66    // get battery service
67    const sp<IServiceManager> sm(defaultServiceManager());
68    if (sm != NULL) {
69        const String16 name("batterystats");
70        mBatteryStatService = interface_cast<IBatteryStats>(sm->getService(name));
71        if (mBatteryStatService == NULL) {
72            ALOGE("batterystats service unavailable!");
73        }
74    }
75}
76
77void MediaCodec::BatteryNotifier::noteStartVideo() {
78    if (mVideoRefCount == 0 && mBatteryStatService != NULL) {
79        mBatteryStatService->noteStartVideo(AID_MEDIA);
80    }
81    mVideoRefCount++;
82}
83
84void MediaCodec::BatteryNotifier::noteStopVideo() {
85    if (mVideoRefCount == 0) {
86        ALOGW("BatteryNotifier::noteStop(): video refcount is broken!");
87        return;
88    }
89
90    mVideoRefCount--;
91    if (mVideoRefCount == 0 && mBatteryStatService != NULL) {
92        mBatteryStatService->noteStopVideo(AID_MEDIA);
93    }
94}
95
96void MediaCodec::BatteryNotifier::noteStartAudio() {
97    if (mAudioRefCount == 0 && mBatteryStatService != NULL) {
98        mBatteryStatService->noteStartAudio(AID_MEDIA);
99    }
100    mAudioRefCount++;
101}
102
103void MediaCodec::BatteryNotifier::noteStopAudio() {
104    if (mAudioRefCount == 0) {
105        ALOGW("BatteryNotifier::noteStop(): audio refcount is broken!");
106        return;
107    }
108
109    mAudioRefCount--;
110    if (mAudioRefCount == 0 && mBatteryStatService != NULL) {
111        mBatteryStatService->noteStopAudio(AID_MEDIA);
112    }
113}
114// static
115sp<MediaCodec> MediaCodec::CreateByType(
116        const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err) {
117    sp<MediaCodec> codec = new MediaCodec(looper);
118
119    const status_t ret = codec->init(mime, true /* nameIsType */, encoder);
120    if (err != NULL) {
121        *err = ret;
122    }
123    return ret == OK ? codec : NULL; // NULL deallocates codec.
124}
125
126// static
127sp<MediaCodec> MediaCodec::CreateByComponentName(
128        const sp<ALooper> &looper, const char *name, status_t *err) {
129    sp<MediaCodec> codec = new MediaCodec(looper);
130
131    const status_t ret = codec->init(name, false /* nameIsType */, false /* encoder */);
132    if (err != NULL) {
133        *err = ret;
134    }
135    return ret == OK ? codec : NULL; // NULL deallocates codec.
136}
137
138MediaCodec::MediaCodec(const sp<ALooper> &looper)
139    : mState(UNINITIALIZED),
140      mLooper(looper),
141      mCodec(NULL),
142      mReplyID(0),
143      mFlags(0),
144      mStickyError(OK),
145      mSoftRenderer(NULL),
146      mBatteryStatNotified(false),
147      mIsVideo(false),
148      mDequeueInputTimeoutGeneration(0),
149      mDequeueInputReplyID(0),
150      mDequeueOutputTimeoutGeneration(0),
151      mDequeueOutputReplyID(0),
152      mHaveInputSurface(false) {
153}
154
155MediaCodec::~MediaCodec() {
156    CHECK_EQ(mState, UNINITIALIZED);
157}
158
159// static
160status_t MediaCodec::PostAndAwaitResponse(
161        const sp<AMessage> &msg, sp<AMessage> *response) {
162    status_t err = msg->postAndAwaitResponse(response);
163
164    if (err != OK) {
165        return err;
166    }
167
168    if (!(*response)->findInt32("err", &err)) {
169        err = OK;
170    }
171
172    return err;
173}
174
175// static
176void MediaCodec::PostReplyWithError(int32_t replyID, int32_t err) {
177    sp<AMessage> response = new AMessage;
178    response->setInt32("err", err);
179    response->postReply(replyID);
180}
181
182status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) {
183    // save init parameters for reset
184    mInitName = name;
185    mInitNameIsType = nameIsType;
186    mInitIsEncoder = encoder;
187
188    // Current video decoders do not return from OMX_FillThisBuffer
189    // quickly, violating the OpenMAX specs, until that is remedied
190    // we need to invest in an extra looper to free the main event
191    // queue.
192    mCodec = new ACodec;
193    bool needDedicatedLooper = false;
194    if (nameIsType && !strncasecmp(name, "video/", 6)) {
195        needDedicatedLooper = true;
196    } else {
197        AString tmp = name;
198        if (tmp.endsWith(".secure")) {
199            tmp.erase(tmp.size() - 7, 7);
200        }
201        const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
202        ssize_t codecIdx = mcl->findCodecByName(tmp.c_str());
203        if (codecIdx >= 0) {
204            const sp<MediaCodecInfo> info = mcl->getCodecInfo(codecIdx);
205            Vector<AString> mimes;
206            info->getSupportedMimes(&mimes);
207            for (size_t i = 0; i < mimes.size(); i++) {
208                if (mimes[i].startsWith("video/")) {
209                    needDedicatedLooper = true;
210                    break;
211                }
212            }
213        }
214    }
215
216    if (needDedicatedLooper) {
217        if (mCodecLooper == NULL) {
218            mCodecLooper = new ALooper;
219            mCodecLooper->setName("CodecLooper");
220            mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
221        }
222
223        mCodecLooper->registerHandler(mCodec);
224    } else {
225        mLooper->registerHandler(mCodec);
226    }
227
228    mLooper->registerHandler(this);
229
230    mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, id()));
231
232    sp<AMessage> msg = new AMessage(kWhatInit, id());
233    msg->setString("name", name);
234    msg->setInt32("nameIsType", nameIsType);
235
236    if (nameIsType) {
237        msg->setInt32("encoder", encoder);
238    }
239
240    sp<AMessage> response;
241    return PostAndAwaitResponse(msg, &response);
242}
243
244status_t MediaCodec::setCallback(const sp<AMessage> &callback) {
245    sp<AMessage> msg = new AMessage(kWhatSetCallback, id());
246    msg->setMessage("callback", callback);
247
248    sp<AMessage> response;
249    return PostAndAwaitResponse(msg, &response);
250}
251
252status_t MediaCodec::configure(
253        const sp<AMessage> &format,
254        const sp<Surface> &nativeWindow,
255        const sp<ICrypto> &crypto,
256        uint32_t flags) {
257    sp<AMessage> msg = new AMessage(kWhatConfigure, id());
258
259    msg->setMessage("format", format);
260    msg->setInt32("flags", flags);
261
262    if (nativeWindow != NULL) {
263        msg->setObject(
264                "native-window",
265                new NativeWindowWrapper(nativeWindow));
266    }
267
268    if (crypto != NULL) {
269        msg->setPointer("crypto", crypto.get());
270    }
271
272    sp<AMessage> response;
273    return PostAndAwaitResponse(msg, &response);
274}
275
276status_t MediaCodec::createInputSurface(
277        sp<IGraphicBufferProducer>* bufferProducer) {
278    sp<AMessage> msg = new AMessage(kWhatCreateInputSurface, id());
279
280    sp<AMessage> response;
281    status_t err = PostAndAwaitResponse(msg, &response);
282    if (err == NO_ERROR) {
283        // unwrap the sp<IGraphicBufferProducer>
284        sp<RefBase> obj;
285        bool found = response->findObject("input-surface", &obj);
286        CHECK(found);
287        sp<BufferProducerWrapper> wrapper(
288                static_cast<BufferProducerWrapper*>(obj.get()));
289        *bufferProducer = wrapper->getBufferProducer();
290    } else {
291        ALOGW("createInputSurface failed, err=%d", err);
292    }
293    return err;
294}
295
296status_t MediaCodec::start() {
297    sp<AMessage> msg = new AMessage(kWhatStart, id());
298
299    sp<AMessage> response;
300    return PostAndAwaitResponse(msg, &response);
301}
302
303status_t MediaCodec::stop() {
304    sp<AMessage> msg = new AMessage(kWhatStop, id());
305
306    sp<AMessage> response;
307    return PostAndAwaitResponse(msg, &response);
308}
309
310status_t MediaCodec::release() {
311    sp<AMessage> msg = new AMessage(kWhatRelease, id());
312
313    sp<AMessage> response;
314    return PostAndAwaitResponse(msg, &response);
315}
316
317status_t MediaCodec::reset() {
318    /* When external-facing MediaCodec object is created,
319       it is already initialized.  Thus, reset is essentially
320       release() followed by init(), plus clearing the state */
321
322    status_t err = release();
323
324    // unregister handlers
325    if (mCodec != NULL) {
326        if (mCodecLooper != NULL) {
327            mCodecLooper->unregisterHandler(mCodec->id());
328        } else {
329            mLooper->unregisterHandler(mCodec->id());
330        }
331        mCodec = NULL;
332    }
333    mLooper->unregisterHandler(id());
334
335    mFlags = 0;    // clear all flags
336    mStickyError = OK;
337
338    // reset state not reset by setState(UNINITIALIZED)
339    mReplyID = 0;
340    mDequeueInputReplyID = 0;
341    mDequeueOutputReplyID = 0;
342    mDequeueInputTimeoutGeneration = 0;
343    mDequeueOutputTimeoutGeneration = 0;
344    mHaveInputSurface = false;
345
346    if (err == OK) {
347        err = init(mInitName.c_str(), mInitNameIsType, mInitIsEncoder);
348    }
349    return err;
350}
351
352status_t MediaCodec::queueInputBuffer(
353        size_t index,
354        size_t offset,
355        size_t size,
356        int64_t presentationTimeUs,
357        uint32_t flags,
358        AString *errorDetailMsg) {
359    if (errorDetailMsg != NULL) {
360        errorDetailMsg->clear();
361    }
362
363    sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
364    msg->setSize("index", index);
365    msg->setSize("offset", offset);
366    msg->setSize("size", size);
367    msg->setInt64("timeUs", presentationTimeUs);
368    msg->setInt32("flags", flags);
369    msg->setPointer("errorDetailMsg", errorDetailMsg);
370
371    sp<AMessage> response;
372    return PostAndAwaitResponse(msg, &response);
373}
374
375status_t MediaCodec::queueSecureInputBuffer(
376        size_t index,
377        size_t offset,
378        const CryptoPlugin::SubSample *subSamples,
379        size_t numSubSamples,
380        const uint8_t key[16],
381        const uint8_t iv[16],
382        CryptoPlugin::Mode mode,
383        int64_t presentationTimeUs,
384        uint32_t flags,
385        AString *errorDetailMsg) {
386    if (errorDetailMsg != NULL) {
387        errorDetailMsg->clear();
388    }
389
390    sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
391    msg->setSize("index", index);
392    msg->setSize("offset", offset);
393    msg->setPointer("subSamples", (void *)subSamples);
394    msg->setSize("numSubSamples", numSubSamples);
395    msg->setPointer("key", (void *)key);
396    msg->setPointer("iv", (void *)iv);
397    msg->setInt32("mode", mode);
398    msg->setInt64("timeUs", presentationTimeUs);
399    msg->setInt32("flags", flags);
400    msg->setPointer("errorDetailMsg", errorDetailMsg);
401
402    sp<AMessage> response;
403    status_t err = PostAndAwaitResponse(msg, &response);
404
405    return err;
406}
407
408status_t MediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
409    sp<AMessage> msg = new AMessage(kWhatDequeueInputBuffer, id());
410    msg->setInt64("timeoutUs", timeoutUs);
411
412    sp<AMessage> response;
413    status_t err;
414    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
415        return err;
416    }
417
418    CHECK(response->findSize("index", index));
419
420    return OK;
421}
422
423status_t MediaCodec::dequeueOutputBuffer(
424        size_t *index,
425        size_t *offset,
426        size_t *size,
427        int64_t *presentationTimeUs,
428        uint32_t *flags,
429        int64_t timeoutUs) {
430    sp<AMessage> msg = new AMessage(kWhatDequeueOutputBuffer, id());
431    msg->setInt64("timeoutUs", timeoutUs);
432
433    sp<AMessage> response;
434    status_t err;
435    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
436        return err;
437    }
438
439    CHECK(response->findSize("index", index));
440    CHECK(response->findSize("offset", offset));
441    CHECK(response->findSize("size", size));
442    CHECK(response->findInt64("timeUs", presentationTimeUs));
443    CHECK(response->findInt32("flags", (int32_t *)flags));
444
445    return OK;
446}
447
448status_t MediaCodec::renderOutputBufferAndRelease(size_t index) {
449    sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
450    msg->setSize("index", index);
451    msg->setInt32("render", true);
452
453    sp<AMessage> response;
454    return PostAndAwaitResponse(msg, &response);
455}
456
457status_t MediaCodec::renderOutputBufferAndRelease(size_t index, int64_t timestampNs) {
458    sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
459    msg->setSize("index", index);
460    msg->setInt32("render", true);
461    msg->setInt64("timestampNs", timestampNs);
462
463    sp<AMessage> response;
464    return PostAndAwaitResponse(msg, &response);
465}
466
467status_t MediaCodec::releaseOutputBuffer(size_t index) {
468    sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
469    msg->setSize("index", index);
470
471    sp<AMessage> response;
472    return PostAndAwaitResponse(msg, &response);
473}
474
475status_t MediaCodec::signalEndOfInputStream() {
476    sp<AMessage> msg = new AMessage(kWhatSignalEndOfInputStream, id());
477
478    sp<AMessage> response;
479    return PostAndAwaitResponse(msg, &response);
480}
481
482status_t MediaCodec::getOutputFormat(sp<AMessage> *format) const {
483    sp<AMessage> msg = new AMessage(kWhatGetOutputFormat, id());
484
485    sp<AMessage> response;
486    status_t err;
487    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
488        return err;
489    }
490
491    CHECK(response->findMessage("format", format));
492
493    return OK;
494}
495
496status_t MediaCodec::getInputFormat(sp<AMessage> *format) const {
497    sp<AMessage> msg = new AMessage(kWhatGetInputFormat, id());
498
499    sp<AMessage> response;
500    status_t err;
501    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
502        return err;
503    }
504
505    CHECK(response->findMessage("format", format));
506
507    return OK;
508}
509
510status_t MediaCodec::getName(AString *name) const {
511    sp<AMessage> msg = new AMessage(kWhatGetName, id());
512
513    sp<AMessage> response;
514    status_t err;
515    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
516        return err;
517    }
518
519    CHECK(response->findString("name", name));
520
521    return OK;
522}
523
524status_t MediaCodec::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
525    sp<AMessage> msg = new AMessage(kWhatGetBuffers, id());
526    msg->setInt32("portIndex", kPortIndexInput);
527    msg->setPointer("buffers", buffers);
528
529    sp<AMessage> response;
530    return PostAndAwaitResponse(msg, &response);
531}
532
533status_t MediaCodec::getOutputBuffers(Vector<sp<ABuffer> > *buffers) const {
534    sp<AMessage> msg = new AMessage(kWhatGetBuffers, id());
535    msg->setInt32("portIndex", kPortIndexOutput);
536    msg->setPointer("buffers", buffers);
537
538    sp<AMessage> response;
539    return PostAndAwaitResponse(msg, &response);
540}
541
542status_t MediaCodec::getOutputBuffer(size_t index, sp<ABuffer> *buffer) {
543    sp<AMessage> format;
544    return getBufferAndFormat(kPortIndexOutput, index, buffer, &format);
545}
546
547status_t MediaCodec::getOutputFormat(size_t index, sp<AMessage> *format) {
548    sp<ABuffer> buffer;
549    return getBufferAndFormat(kPortIndexOutput, index, &buffer, format);
550}
551
552status_t MediaCodec::getInputBuffer(size_t index, sp<ABuffer> *buffer) {
553    sp<AMessage> format;
554    return getBufferAndFormat(kPortIndexInput, index, buffer, &format);
555}
556
557bool MediaCodec::isExecuting() const {
558    return mState == STARTED || mState == FLUSHED;
559}
560
561status_t MediaCodec::getBufferAndFormat(
562        size_t portIndex, size_t index,
563        sp<ABuffer> *buffer, sp<AMessage> *format) {
564    // use mutex instead of a context switch
565
566    buffer->clear();
567    format->clear();
568    if (!isExecuting()) {
569        return INVALID_OPERATION;
570    }
571
572    // we do not want mPortBuffers to change during this section
573    // we also don't want mOwnedByClient to change during this
574    Mutex::Autolock al(mBufferLock);
575    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
576    if (index < buffers->size()) {
577        const BufferInfo &info = buffers->itemAt(index);
578        if (info.mOwnedByClient) {
579            *buffer = info.mData;
580            *format = info.mFormat;
581        }
582    }
583    return OK;
584}
585
586status_t MediaCodec::flush() {
587    sp<AMessage> msg = new AMessage(kWhatFlush, id());
588
589    sp<AMessage> response;
590    return PostAndAwaitResponse(msg, &response);
591}
592
593status_t MediaCodec::requestIDRFrame() {
594    (new AMessage(kWhatRequestIDRFrame, id()))->post();
595
596    return OK;
597}
598
599void MediaCodec::requestActivityNotification(const sp<AMessage> &notify) {
600    sp<AMessage> msg = new AMessage(kWhatRequestActivityNotification, id());
601    msg->setMessage("notify", notify);
602    msg->post();
603}
604
605////////////////////////////////////////////////////////////////////////////////
606
607void MediaCodec::cancelPendingDequeueOperations() {
608    if (mFlags & kFlagDequeueInputPending) {
609        PostReplyWithError(mDequeueInputReplyID, INVALID_OPERATION);
610
611        ++mDequeueInputTimeoutGeneration;
612        mDequeueInputReplyID = 0;
613        mFlags &= ~kFlagDequeueInputPending;
614    }
615
616    if (mFlags & kFlagDequeueOutputPending) {
617        PostReplyWithError(mDequeueOutputReplyID, INVALID_OPERATION);
618
619        ++mDequeueOutputTimeoutGeneration;
620        mDequeueOutputReplyID = 0;
621        mFlags &= ~kFlagDequeueOutputPending;
622    }
623}
624
625bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) {
626    if (!isExecuting() || (mFlags & kFlagIsAsync)
627            || (newRequest && (mFlags & kFlagDequeueInputPending))) {
628        PostReplyWithError(replyID, INVALID_OPERATION);
629        return true;
630    } else if (mFlags & kFlagStickyError) {
631        PostReplyWithError(replyID, getStickyError());
632        return true;
633    }
634
635    ssize_t index = dequeuePortBuffer(kPortIndexInput);
636
637    if (index < 0) {
638        CHECK_EQ(index, -EAGAIN);
639        return false;
640    }
641
642    sp<AMessage> response = new AMessage;
643    response->setSize("index", index);
644    response->postReply(replyID);
645
646    return true;
647}
648
649bool MediaCodec::handleDequeueOutputBuffer(uint32_t replyID, bool newRequest) {
650    sp<AMessage> response = new AMessage;
651
652    if (!isExecuting() || (mFlags & kFlagIsAsync)
653            || (newRequest && (mFlags & kFlagDequeueOutputPending))) {
654        response->setInt32("err", INVALID_OPERATION);
655    } else if (mFlags & kFlagStickyError) {
656        response->setInt32("err", getStickyError());
657    } else if (mFlags & kFlagOutputBuffersChanged) {
658        response->setInt32("err", INFO_OUTPUT_BUFFERS_CHANGED);
659        mFlags &= ~kFlagOutputBuffersChanged;
660    } else if (mFlags & kFlagOutputFormatChanged) {
661        response->setInt32("err", INFO_FORMAT_CHANGED);
662        mFlags &= ~kFlagOutputFormatChanged;
663    } else {
664        ssize_t index = dequeuePortBuffer(kPortIndexOutput);
665
666        if (index < 0) {
667            CHECK_EQ(index, -EAGAIN);
668            return false;
669        }
670
671        const sp<ABuffer> &buffer =
672            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
673
674        response->setSize("index", index);
675        response->setSize("offset", buffer->offset());
676        response->setSize("size", buffer->size());
677
678        int64_t timeUs;
679        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
680
681        response->setInt64("timeUs", timeUs);
682
683        int32_t omxFlags;
684        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
685
686        uint32_t flags = 0;
687        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
688            flags |= BUFFER_FLAG_SYNCFRAME;
689        }
690        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
691            flags |= BUFFER_FLAG_CODECCONFIG;
692        }
693        if (omxFlags & OMX_BUFFERFLAG_EOS) {
694            flags |= BUFFER_FLAG_EOS;
695        }
696
697        response->setInt32("flags", flags);
698    }
699
700    response->postReply(replyID);
701
702    return true;
703}
704
705void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
706    switch (msg->what()) {
707        case kWhatCodecNotify:
708        {
709            int32_t what;
710            CHECK(msg->findInt32("what", &what));
711
712            switch (what) {
713                case CodecBase::kWhatError:
714                {
715                    int32_t err, actionCode;
716                    CHECK(msg->findInt32("err", &err));
717                    CHECK(msg->findInt32("actionCode", &actionCode));
718
719                    ALOGE("Codec reported err %#x, actionCode %d", err, actionCode);
720                    if (err == DEAD_OBJECT) {
721                        mFlags |= kFlagSawMediaServerDie;
722                    }
723
724                    bool sendErrorReponse = true;
725
726                    switch (mState) {
727                        case INITIALIZING:
728                        {
729                            setState(UNINITIALIZED);
730                            break;
731                        }
732
733                        case CONFIGURING:
734                        {
735                            setState(INITIALIZED);
736                            break;
737                        }
738
739                        case STARTING:
740                        {
741                            setState(CONFIGURED);
742                            break;
743                        }
744
745                        case STOPPING:
746                        case RELEASING:
747                        {
748                            // Ignore the error, assuming we'll still get
749                            // the shutdown complete notification.
750
751                            sendErrorReponse = false;
752
753                            if (mFlags & kFlagSawMediaServerDie) {
754                                // MediaServer died, there definitely won't
755                                // be a shutdown complete notification after
756                                // all.
757
758                                // note that we're directly going from
759                                // STOPPING->UNINITIALIZED, instead of the
760                                // usual STOPPING->INITIALIZED state.
761                                setState(UNINITIALIZED);
762
763                                (new AMessage)->postReply(mReplyID);
764                            }
765                            break;
766                        }
767
768                        case FLUSHING:
769                        {
770                            setState(
771                                    (mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
772                            break;
773                        }
774
775                        case FLUSHED:
776                        case STARTED:
777                        {
778                            sendErrorReponse = false;
779
780                            setStickyError(err);
781                            postActivityNotificationIfPossible();
782
783                            cancelPendingDequeueOperations();
784
785                            if (mFlags & kFlagIsAsync) {
786                                onError(err, actionCode);
787                            }
788                            switch (actionCode) {
789                            case ACTION_CODE_TRANSIENT:
790                                break;
791                            case ACTION_CODE_RECOVERABLE:
792                                setState(INITIALIZED);
793                                break;
794                            default:
795                                setState(UNINITIALIZED);
796                                break;
797                            }
798                            break;
799                        }
800
801                        default:
802                        {
803                            sendErrorReponse = false;
804
805                            setStickyError(err);
806                            postActivityNotificationIfPossible();
807
808                            // actionCode in an uninitialized state is always fatal.
809                            if (mState == UNINITIALIZED) {
810                                actionCode = ACTION_CODE_FATAL;
811                            }
812                            if (mFlags & kFlagIsAsync) {
813                                onError(err, actionCode);
814                            }
815                            switch (actionCode) {
816                            case ACTION_CODE_TRANSIENT:
817                                break;
818                            case ACTION_CODE_RECOVERABLE:
819                                setState(INITIALIZED);
820                                break;
821                            default:
822                                setState(UNINITIALIZED);
823                                break;
824                            }
825                            break;
826                        }
827                    }
828
829                    if (sendErrorReponse) {
830                        PostReplyWithError(mReplyID, err);
831                    }
832                    break;
833                }
834
835                case CodecBase::kWhatComponentAllocated:
836                {
837                    CHECK_EQ(mState, INITIALIZING);
838                    setState(INITIALIZED);
839
840                    CHECK(msg->findString("componentName", &mComponentName));
841
842                    if (mComponentName.startsWith("OMX.google.")) {
843                        mFlags |= kFlagIsSoftwareCodec;
844                    } else {
845                        mFlags &= ~kFlagIsSoftwareCodec;
846                    }
847
848                    if (mComponentName.endsWith(".secure")) {
849                        mFlags |= kFlagIsSecure;
850                    } else {
851                        mFlags &= ~kFlagIsSecure;
852                    }
853
854                    (new AMessage)->postReply(mReplyID);
855                    break;
856                }
857
858                case CodecBase::kWhatComponentConfigured:
859                {
860                    CHECK_EQ(mState, CONFIGURING);
861
862                    // reset input surface flag
863                    mHaveInputSurface = false;
864
865                    CHECK(msg->findMessage("input-format", &mInputFormat));
866                    CHECK(msg->findMessage("output-format", &mOutputFormat));
867
868                    setState(CONFIGURED);
869                    (new AMessage)->postReply(mReplyID);
870                    break;
871                }
872
873                case CodecBase::kWhatInputSurfaceCreated:
874                {
875                    // response to initiateCreateInputSurface()
876                    status_t err = NO_ERROR;
877                    sp<AMessage> response = new AMessage();
878                    if (!msg->findInt32("err", &err)) {
879                        sp<RefBase> obj;
880                        msg->findObject("input-surface", &obj);
881                        CHECK(obj != NULL);
882                        response->setObject("input-surface", obj);
883                        mHaveInputSurface = true;
884                    } else {
885                        response->setInt32("err", err);
886                    }
887                    response->postReply(mReplyID);
888                    break;
889                }
890
891                case CodecBase::kWhatSignaledInputEOS:
892                {
893                    // response to signalEndOfInputStream()
894                    sp<AMessage> response = new AMessage();
895                    status_t err;
896                    if (msg->findInt32("err", &err)) {
897                        response->setInt32("err", err);
898                    }
899                    response->postReply(mReplyID);
900                    break;
901                }
902
903
904                case CodecBase::kWhatBuffersAllocated:
905                {
906                    Mutex::Autolock al(mBufferLock);
907                    int32_t portIndex;
908                    CHECK(msg->findInt32("portIndex", &portIndex));
909
910                    ALOGV("%s buffers allocated",
911                          portIndex == kPortIndexInput ? "input" : "output");
912
913                    CHECK(portIndex == kPortIndexInput
914                            || portIndex == kPortIndexOutput);
915
916                    mPortBuffers[portIndex].clear();
917
918                    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
919
920                    sp<RefBase> obj;
921                    CHECK(msg->findObject("portDesc", &obj));
922
923                    sp<CodecBase::PortDescription> portDesc =
924                        static_cast<CodecBase::PortDescription *>(obj.get());
925
926                    size_t numBuffers = portDesc->countBuffers();
927
928                    for (size_t i = 0; i < numBuffers; ++i) {
929                        BufferInfo info;
930                        info.mBufferID = portDesc->bufferIDAt(i);
931                        info.mOwnedByClient = false;
932                        info.mData = portDesc->bufferAt(i);
933
934                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
935                            info.mEncryptedData =
936                                new ABuffer(info.mData->capacity());
937                        }
938
939                        buffers->push_back(info);
940                    }
941
942                    if (portIndex == kPortIndexOutput) {
943                        if (mState == STARTING) {
944                            // We're always allocating output buffers after
945                            // allocating input buffers, so this is a good
946                            // indication that now all buffers are allocated.
947                            setState(STARTED);
948                            (new AMessage)->postReply(mReplyID);
949                        } else {
950                            mFlags |= kFlagOutputBuffersChanged;
951                            postActivityNotificationIfPossible();
952                        }
953                    }
954                    break;
955                }
956
957                case CodecBase::kWhatOutputFormatChanged:
958                {
959                    ALOGV("codec output format changed");
960
961                    if ((mFlags & kFlagIsSoftwareCodec)
962                            && mNativeWindow != NULL) {
963                        AString mime;
964                        CHECK(msg->findString("mime", &mime));
965
966                        if (!strncasecmp("video/", mime.c_str(), 6)) {
967                            delete mSoftRenderer;
968                            mSoftRenderer = NULL;
969
970                            int32_t width, height;
971                            CHECK(msg->findInt32("width", &width));
972                            CHECK(msg->findInt32("height", &height));
973
974                            int32_t cropLeft, cropTop, cropRight, cropBottom;
975                            CHECK(msg->findRect("crop",
976                                &cropLeft, &cropTop, &cropRight, &cropBottom));
977
978                            int32_t colorFormat;
979                            CHECK(msg->findInt32(
980                                        "color-format", &colorFormat));
981
982                            sp<MetaData> meta = new MetaData;
983                            meta->setInt32(kKeyWidth, width);
984                            meta->setInt32(kKeyHeight, height);
985                            meta->setRect(kKeyCropRect,
986                                cropLeft, cropTop, cropRight, cropBottom);
987                            meta->setInt32(kKeyColorFormat, colorFormat);
988
989                            mSoftRenderer =
990                                new SoftwareRenderer(mNativeWindow, meta);
991                        }
992                    }
993
994                    mOutputFormat = msg;
995
996                    if (mFlags & kFlagIsEncoder) {
997                        // Before we announce the format change we should
998                        // collect codec specific data and amend the output
999                        // format as necessary.
1000                        mFlags |= kFlagGatherCodecSpecificData;
1001                    } else if (mFlags & kFlagIsAsync) {
1002                        onOutputFormatChanged();
1003                    } else {
1004                        mFlags |= kFlagOutputFormatChanged;
1005                        postActivityNotificationIfPossible();
1006                    }
1007                    break;
1008                }
1009
1010                case CodecBase::kWhatFillThisBuffer:
1011                {
1012                    /* size_t index = */updateBuffers(kPortIndexInput, msg);
1013
1014                    if (mState == FLUSHING
1015                            || mState == STOPPING
1016                            || mState == RELEASING) {
1017                        returnBuffersToCodecOnPort(kPortIndexInput);
1018                        break;
1019                    }
1020
1021                    if (!mCSD.empty()) {
1022                        ssize_t index = dequeuePortBuffer(kPortIndexInput);
1023                        CHECK_GE(index, 0);
1024
1025                        // If codec specific data had been specified as
1026                        // part of the format in the call to configure and
1027                        // if there's more csd left, we submit it here
1028                        // clients only get access to input buffers once
1029                        // this data has been exhausted.
1030
1031                        status_t err = queueCSDInputBuffer(index);
1032
1033                        if (err != OK) {
1034                            ALOGE("queueCSDInputBuffer failed w/ error %d",
1035                                  err);
1036
1037                            setStickyError(err);
1038                            postActivityNotificationIfPossible();
1039
1040                            cancelPendingDequeueOperations();
1041                        }
1042                        break;
1043                    }
1044
1045                    if (mFlags & kFlagIsAsync) {
1046                        onInputBufferAvailable();
1047                    } else if (mFlags & kFlagDequeueInputPending) {
1048                        CHECK(handleDequeueInputBuffer(mDequeueInputReplyID));
1049
1050                        ++mDequeueInputTimeoutGeneration;
1051                        mFlags &= ~kFlagDequeueInputPending;
1052                        mDequeueInputReplyID = 0;
1053                    } else {
1054                        postActivityNotificationIfPossible();
1055                    }
1056                    break;
1057                }
1058
1059                case CodecBase::kWhatDrainThisBuffer:
1060                {
1061                    /* size_t index = */updateBuffers(kPortIndexOutput, msg);
1062
1063                    if (mState == FLUSHING
1064                            || mState == STOPPING
1065                            || mState == RELEASING) {
1066                        returnBuffersToCodecOnPort(kPortIndexOutput);
1067                        break;
1068                    }
1069
1070                    sp<ABuffer> buffer;
1071                    CHECK(msg->findBuffer("buffer", &buffer));
1072
1073                    int32_t omxFlags;
1074                    CHECK(msg->findInt32("flags", &omxFlags));
1075
1076                    buffer->meta()->setInt32("omxFlags", omxFlags);
1077
1078                    if (mFlags & kFlagGatherCodecSpecificData) {
1079                        // This is the very first output buffer after a
1080                        // format change was signalled, it'll either contain
1081                        // the one piece of codec specific data we can expect
1082                        // or there won't be codec specific data.
1083                        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
1084                            status_t err =
1085                                amendOutputFormatWithCodecSpecificData(buffer);
1086
1087                            if (err != OK) {
1088                                ALOGE("Codec spit out malformed codec "
1089                                      "specific data!");
1090                            }
1091                        }
1092
1093                        mFlags &= ~kFlagGatherCodecSpecificData;
1094                        if (mFlags & kFlagIsAsync) {
1095                            onOutputFormatChanged();
1096                        } else {
1097                            mFlags |= kFlagOutputFormatChanged;
1098                        }
1099                    }
1100
1101                    if (mFlags & kFlagIsAsync) {
1102                        onOutputBufferAvailable();
1103                    } else if (mFlags & kFlagDequeueOutputPending) {
1104                        CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID));
1105
1106                        ++mDequeueOutputTimeoutGeneration;
1107                        mFlags &= ~kFlagDequeueOutputPending;
1108                        mDequeueOutputReplyID = 0;
1109                    } else {
1110                        postActivityNotificationIfPossible();
1111                    }
1112
1113                    break;
1114                }
1115
1116                case CodecBase::kWhatEOS:
1117                {
1118                    // We already notify the client of this by using the
1119                    // corresponding flag in "onOutputBufferReady".
1120                    break;
1121                }
1122
1123                case CodecBase::kWhatShutdownCompleted:
1124                {
1125                    if (mState == STOPPING) {
1126                        setState(INITIALIZED);
1127                    } else {
1128                        CHECK_EQ(mState, RELEASING);
1129                        setState(UNINITIALIZED);
1130                    }
1131
1132                    (new AMessage)->postReply(mReplyID);
1133                    break;
1134                }
1135
1136                case CodecBase::kWhatFlushCompleted:
1137                {
1138                    CHECK_EQ(mState, FLUSHING);
1139
1140                    if (mFlags & kFlagIsAsync) {
1141                        setState(FLUSHED);
1142                    } else {
1143                        setState(STARTED);
1144                        mCodec->signalResume();
1145                    }
1146
1147                    (new AMessage)->postReply(mReplyID);
1148                    break;
1149                }
1150
1151                default:
1152                    TRESPASS();
1153            }
1154            break;
1155        }
1156
1157        case kWhatInit:
1158        {
1159            uint32_t replyID;
1160            CHECK(msg->senderAwaitsResponse(&replyID));
1161
1162            if (mState != UNINITIALIZED) {
1163                PostReplyWithError(replyID, INVALID_OPERATION);
1164                break;
1165            }
1166
1167            mReplyID = replyID;
1168            setState(INITIALIZING);
1169
1170            AString name;
1171            CHECK(msg->findString("name", &name));
1172
1173            int32_t nameIsType;
1174            int32_t encoder = false;
1175            CHECK(msg->findInt32("nameIsType", &nameIsType));
1176            if (nameIsType) {
1177                CHECK(msg->findInt32("encoder", &encoder));
1178            }
1179
1180            sp<AMessage> format = new AMessage;
1181
1182            if (nameIsType) {
1183                format->setString("mime", name.c_str());
1184                format->setInt32("encoder", encoder);
1185            } else {
1186                format->setString("componentName", name.c_str());
1187            }
1188
1189            mCodec->initiateAllocateComponent(format);
1190            break;
1191        }
1192
1193        case kWhatSetCallback:
1194        {
1195            uint32_t replyID;
1196            CHECK(msg->senderAwaitsResponse(&replyID));
1197
1198            if (mState == UNINITIALIZED
1199                    || mState == INITIALIZING
1200                    || isExecuting()) {
1201                // callback can't be set after codec is executing,
1202                // or before it's initialized (as the callback
1203                // will be cleared when it goes to INITIALIZED)
1204                PostReplyWithError(replyID, INVALID_OPERATION);
1205                break;
1206            }
1207
1208            sp<AMessage> callback;
1209            CHECK(msg->findMessage("callback", &callback));
1210
1211            mCallback = callback;
1212
1213            if (mCallback != NULL) {
1214                ALOGI("MediaCodec will operate in async mode");
1215                mFlags |= kFlagIsAsync;
1216            } else {
1217                mFlags &= ~kFlagIsAsync;
1218            }
1219
1220            sp<AMessage> response = new AMessage;
1221            response->postReply(replyID);
1222            break;
1223        }
1224
1225        case kWhatConfigure:
1226        {
1227            uint32_t replyID;
1228            CHECK(msg->senderAwaitsResponse(&replyID));
1229
1230            if (mState != INITIALIZED) {
1231                PostReplyWithError(replyID, INVALID_OPERATION);
1232                break;
1233            }
1234
1235            sp<RefBase> obj;
1236            if (!msg->findObject("native-window", &obj)) {
1237                obj.clear();
1238            }
1239
1240            sp<AMessage> format;
1241            CHECK(msg->findMessage("format", &format));
1242
1243            if (obj != NULL) {
1244                format->setObject("native-window", obj);
1245
1246                status_t err = setNativeWindow(
1247                    static_cast<NativeWindowWrapper *>(obj.get())
1248                        ->getSurfaceTextureClient());
1249
1250                if (err != OK) {
1251                    PostReplyWithError(replyID, err);
1252                    break;
1253                }
1254            } else {
1255                setNativeWindow(NULL);
1256            }
1257
1258            mReplyID = replyID;
1259            setState(CONFIGURING);
1260
1261            void *crypto;
1262            if (!msg->findPointer("crypto", &crypto)) {
1263                crypto = NULL;
1264            }
1265
1266            mCrypto = static_cast<ICrypto *>(crypto);
1267
1268            uint32_t flags;
1269            CHECK(msg->findInt32("flags", (int32_t *)&flags));
1270
1271            if (flags & CONFIGURE_FLAG_ENCODE) {
1272                format->setInt32("encoder", true);
1273                mFlags |= kFlagIsEncoder;
1274            }
1275
1276            extractCSD(format);
1277
1278            mCodec->initiateConfigureComponent(format);
1279            break;
1280        }
1281
1282        case kWhatCreateInputSurface:
1283        {
1284            uint32_t replyID;
1285            CHECK(msg->senderAwaitsResponse(&replyID));
1286
1287            // Must be configured, but can't have been started yet.
1288            if (mState != CONFIGURED) {
1289                PostReplyWithError(replyID, INVALID_OPERATION);
1290                break;
1291            }
1292
1293            mReplyID = replyID;
1294            mCodec->initiateCreateInputSurface();
1295            break;
1296        }
1297
1298        case kWhatStart:
1299        {
1300            uint32_t replyID;
1301            CHECK(msg->senderAwaitsResponse(&replyID));
1302
1303            if (mState == FLUSHED) {
1304                mCodec->signalResume();
1305                PostReplyWithError(replyID, OK);
1306            } else if (mState != CONFIGURED) {
1307                PostReplyWithError(replyID, INVALID_OPERATION);
1308                break;
1309            }
1310
1311            mReplyID = replyID;
1312            setState(STARTING);
1313
1314            mCodec->initiateStart();
1315            break;
1316        }
1317
1318        case kWhatStop:
1319        case kWhatRelease:
1320        {
1321            State targetState =
1322                (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;
1323
1324            uint32_t replyID;
1325            CHECK(msg->senderAwaitsResponse(&replyID));
1326
1327            if (mState != INITIALIZED
1328                    && mState != CONFIGURED && !isExecuting()) {
1329                // We may be in "UNINITIALIZED" state already without the
1330                // client being aware of this if media server died while
1331                // we were being stopped. The client would assume that
1332                // after stop() returned, it would be safe to call release()
1333                // and it should be in this case, no harm to allow a release()
1334                // if we're already uninitialized.
1335                // Similarly stopping a stopped MediaCodec should be benign.
1336                sp<AMessage> response = new AMessage;
1337                response->setInt32(
1338                        "err",
1339                        mState == targetState ? OK : INVALID_OPERATION);
1340
1341                response->postReply(replyID);
1342                break;
1343            }
1344
1345            if (mFlags & kFlagSawMediaServerDie) {
1346                // It's dead, Jim. Don't expect initiateShutdown to yield
1347                // any useful results now...
1348                setState(UNINITIALIZED);
1349                (new AMessage)->postReply(replyID);
1350                break;
1351            }
1352
1353            mReplyID = replyID;
1354            setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
1355
1356            mCodec->initiateShutdown(
1357                    msg->what() == kWhatStop /* keepComponentAllocated */);
1358
1359            returnBuffersToCodec();
1360            break;
1361        }
1362
1363        case kWhatDequeueInputBuffer:
1364        {
1365            uint32_t replyID;
1366            CHECK(msg->senderAwaitsResponse(&replyID));
1367
1368            if (mFlags & kFlagIsAsync) {
1369                ALOGE("dequeueOutputBuffer can't be used in async mode");
1370                PostReplyWithError(replyID, INVALID_OPERATION);
1371                break;
1372            }
1373
1374            if (mHaveInputSurface) {
1375                ALOGE("dequeueInputBuffer can't be used with input surface");
1376                PostReplyWithError(replyID, INVALID_OPERATION);
1377                break;
1378            }
1379
1380            if (handleDequeueInputBuffer(replyID, true /* new request */)) {
1381                break;
1382            }
1383
1384            int64_t timeoutUs;
1385            CHECK(msg->findInt64("timeoutUs", &timeoutUs));
1386
1387            if (timeoutUs == 0ll) {
1388                PostReplyWithError(replyID, -EAGAIN);
1389                break;
1390            }
1391
1392            mFlags |= kFlagDequeueInputPending;
1393            mDequeueInputReplyID = replyID;
1394
1395            if (timeoutUs > 0ll) {
1396                sp<AMessage> timeoutMsg =
1397                    new AMessage(kWhatDequeueInputTimedOut, id());
1398                timeoutMsg->setInt32(
1399                        "generation", ++mDequeueInputTimeoutGeneration);
1400                timeoutMsg->post(timeoutUs);
1401            }
1402            break;
1403        }
1404
1405        case kWhatDequeueInputTimedOut:
1406        {
1407            int32_t generation;
1408            CHECK(msg->findInt32("generation", &generation));
1409
1410            if (generation != mDequeueInputTimeoutGeneration) {
1411                // Obsolete
1412                break;
1413            }
1414
1415            CHECK(mFlags & kFlagDequeueInputPending);
1416
1417            PostReplyWithError(mDequeueInputReplyID, -EAGAIN);
1418
1419            mFlags &= ~kFlagDequeueInputPending;
1420            mDequeueInputReplyID = 0;
1421            break;
1422        }
1423
1424        case kWhatQueueInputBuffer:
1425        {
1426            uint32_t replyID;
1427            CHECK(msg->senderAwaitsResponse(&replyID));
1428
1429            if (!isExecuting()) {
1430                PostReplyWithError(replyID, INVALID_OPERATION);
1431                break;
1432            } else if (mFlags & kFlagStickyError) {
1433                PostReplyWithError(replyID, getStickyError());
1434                break;
1435            }
1436
1437            status_t err = onQueueInputBuffer(msg);
1438
1439            PostReplyWithError(replyID, err);
1440            break;
1441        }
1442
1443        case kWhatDequeueOutputBuffer:
1444        {
1445            uint32_t replyID;
1446            CHECK(msg->senderAwaitsResponse(&replyID));
1447
1448            if (mFlags & kFlagIsAsync) {
1449                ALOGE("dequeueOutputBuffer can't be used in async mode");
1450                PostReplyWithError(replyID, INVALID_OPERATION);
1451                break;
1452            }
1453
1454            if (handleDequeueOutputBuffer(replyID, true /* new request */)) {
1455                break;
1456            }
1457
1458            int64_t timeoutUs;
1459            CHECK(msg->findInt64("timeoutUs", &timeoutUs));
1460
1461            if (timeoutUs == 0ll) {
1462                PostReplyWithError(replyID, -EAGAIN);
1463                break;
1464            }
1465
1466            mFlags |= kFlagDequeueOutputPending;
1467            mDequeueOutputReplyID = replyID;
1468
1469            if (timeoutUs > 0ll) {
1470                sp<AMessage> timeoutMsg =
1471                    new AMessage(kWhatDequeueOutputTimedOut, id());
1472                timeoutMsg->setInt32(
1473                        "generation", ++mDequeueOutputTimeoutGeneration);
1474                timeoutMsg->post(timeoutUs);
1475            }
1476            break;
1477        }
1478
1479        case kWhatDequeueOutputTimedOut:
1480        {
1481            int32_t generation;
1482            CHECK(msg->findInt32("generation", &generation));
1483
1484            if (generation != mDequeueOutputTimeoutGeneration) {
1485                // Obsolete
1486                break;
1487            }
1488
1489            CHECK(mFlags & kFlagDequeueOutputPending);
1490
1491            PostReplyWithError(mDequeueOutputReplyID, -EAGAIN);
1492
1493            mFlags &= ~kFlagDequeueOutputPending;
1494            mDequeueOutputReplyID = 0;
1495            break;
1496        }
1497
1498        case kWhatReleaseOutputBuffer:
1499        {
1500            uint32_t replyID;
1501            CHECK(msg->senderAwaitsResponse(&replyID));
1502
1503            if (!isExecuting()) {
1504                PostReplyWithError(replyID, INVALID_OPERATION);
1505                break;
1506            } else if (mFlags & kFlagStickyError) {
1507                PostReplyWithError(replyID, getStickyError());
1508                break;
1509            }
1510
1511            status_t err = onReleaseOutputBuffer(msg);
1512
1513            PostReplyWithError(replyID, err);
1514            break;
1515        }
1516
1517        case kWhatSignalEndOfInputStream:
1518        {
1519            uint32_t replyID;
1520            CHECK(msg->senderAwaitsResponse(&replyID));
1521
1522            if (!isExecuting()) {
1523                PostReplyWithError(replyID, INVALID_OPERATION);
1524                break;
1525            } else if (mFlags & kFlagStickyError) {
1526                PostReplyWithError(replyID, getStickyError());
1527                break;
1528            }
1529
1530            mReplyID = replyID;
1531            mCodec->signalEndOfInputStream();
1532            break;
1533        }
1534
1535        case kWhatGetBuffers:
1536        {
1537            uint32_t replyID;
1538            CHECK(msg->senderAwaitsResponse(&replyID));
1539
1540            if (!isExecuting() || (mFlags & kFlagIsAsync)) {
1541                PostReplyWithError(replyID, INVALID_OPERATION);
1542                break;
1543            } else if (mFlags & kFlagStickyError) {
1544                PostReplyWithError(replyID, getStickyError());
1545                break;
1546            }
1547
1548            int32_t portIndex;
1549            CHECK(msg->findInt32("portIndex", &portIndex));
1550
1551            Vector<sp<ABuffer> > *dstBuffers;
1552            CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
1553
1554            dstBuffers->clear();
1555            const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
1556
1557            for (size_t i = 0; i < srcBuffers.size(); ++i) {
1558                const BufferInfo &info = srcBuffers.itemAt(i);
1559
1560                dstBuffers->push_back(
1561                        (portIndex == kPortIndexInput && mCrypto != NULL)
1562                                ? info.mEncryptedData : info.mData);
1563            }
1564
1565            (new AMessage)->postReply(replyID);
1566            break;
1567        }
1568
1569        case kWhatFlush:
1570        {
1571            uint32_t replyID;
1572            CHECK(msg->senderAwaitsResponse(&replyID));
1573
1574            if (!isExecuting()) {
1575                PostReplyWithError(replyID, INVALID_OPERATION);
1576                break;
1577            } else if (mFlags & kFlagStickyError) {
1578                PostReplyWithError(replyID, getStickyError());
1579                break;
1580            }
1581
1582            mReplyID = replyID;
1583            // TODO: skip flushing if already FLUSHED
1584            setState(FLUSHING);
1585
1586            mCodec->signalFlush();
1587            returnBuffersToCodec();
1588            break;
1589        }
1590
1591        case kWhatGetInputFormat:
1592        case kWhatGetOutputFormat:
1593        {
1594            sp<AMessage> format =
1595                (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat);
1596
1597            uint32_t replyID;
1598            CHECK(msg->senderAwaitsResponse(&replyID));
1599
1600            if ((mState != CONFIGURED && mState != STARTING &&
1601                 mState != STARTED && mState != FLUSHING &&
1602                 mState != FLUSHED)
1603                    || format == NULL) {
1604                PostReplyWithError(replyID, INVALID_OPERATION);
1605                break;
1606            } else if (mFlags & kFlagStickyError) {
1607                PostReplyWithError(replyID, getStickyError());
1608                break;
1609            }
1610
1611            sp<AMessage> response = new AMessage;
1612            response->setMessage("format", format);
1613            response->postReply(replyID);
1614            break;
1615        }
1616
1617        case kWhatRequestIDRFrame:
1618        {
1619            mCodec->signalRequestIDRFrame();
1620            break;
1621        }
1622
1623        case kWhatRequestActivityNotification:
1624        {
1625            CHECK(mActivityNotify == NULL);
1626            CHECK(msg->findMessage("notify", &mActivityNotify));
1627
1628            postActivityNotificationIfPossible();
1629            break;
1630        }
1631
1632        case kWhatGetName:
1633        {
1634            uint32_t replyID;
1635            CHECK(msg->senderAwaitsResponse(&replyID));
1636
1637            if (mComponentName.empty()) {
1638                PostReplyWithError(replyID, INVALID_OPERATION);
1639                break;
1640            }
1641
1642            sp<AMessage> response = new AMessage;
1643            response->setString("name", mComponentName.c_str());
1644            response->postReply(replyID);
1645            break;
1646        }
1647
1648        case kWhatSetParameters:
1649        {
1650            uint32_t replyID;
1651            CHECK(msg->senderAwaitsResponse(&replyID));
1652
1653            sp<AMessage> params;
1654            CHECK(msg->findMessage("params", &params));
1655
1656            status_t err = onSetParameters(params);
1657
1658            PostReplyWithError(replyID, err);
1659            break;
1660        }
1661
1662        default:
1663            TRESPASS();
1664    }
1665}
1666
1667void MediaCodec::extractCSD(const sp<AMessage> &format) {
1668    mCSD.clear();
1669
1670    size_t i = 0;
1671    for (;;) {
1672        sp<ABuffer> csd;
1673        if (!format->findBuffer(StringPrintf("csd-%u", i).c_str(), &csd)) {
1674            break;
1675        }
1676
1677        mCSD.push_back(csd);
1678        ++i;
1679    }
1680
1681    ALOGV("Found %zu pieces of codec specific data.", mCSD.size());
1682}
1683
1684status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) {
1685    CHECK(!mCSD.empty());
1686
1687    const BufferInfo *info =
1688        &mPortBuffers[kPortIndexInput].itemAt(bufferIndex);
1689
1690    sp<ABuffer> csd = *mCSD.begin();
1691    mCSD.erase(mCSD.begin());
1692
1693    const sp<ABuffer> &codecInputData =
1694        (mCrypto != NULL) ? info->mEncryptedData : info->mData;
1695
1696    if (csd->size() > codecInputData->capacity()) {
1697        return -EINVAL;
1698    }
1699
1700    memcpy(codecInputData->data(), csd->data(), csd->size());
1701
1702    AString errorDetailMsg;
1703
1704    sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
1705    msg->setSize("index", bufferIndex);
1706    msg->setSize("offset", 0);
1707    msg->setSize("size", csd->size());
1708    msg->setInt64("timeUs", 0ll);
1709    msg->setInt32("flags", BUFFER_FLAG_CODECCONFIG);
1710    msg->setPointer("errorDetailMsg", &errorDetailMsg);
1711
1712    return onQueueInputBuffer(msg);
1713}
1714
1715void MediaCodec::setState(State newState) {
1716    if (newState == INITIALIZED || newState == UNINITIALIZED) {
1717        delete mSoftRenderer;
1718        mSoftRenderer = NULL;
1719
1720        mCrypto.clear();
1721        setNativeWindow(NULL);
1722
1723        mInputFormat.clear();
1724        mOutputFormat.clear();
1725        mFlags &= ~kFlagOutputFormatChanged;
1726        mFlags &= ~kFlagOutputBuffersChanged;
1727        mFlags &= ~kFlagStickyError;
1728        mFlags &= ~kFlagIsEncoder;
1729        mFlags &= ~kFlagGatherCodecSpecificData;
1730        mFlags &= ~kFlagIsAsync;
1731        mStickyError = OK;
1732
1733        mActivityNotify.clear();
1734        mCallback.clear();
1735    }
1736
1737    if (newState == UNINITIALIZED) {
1738        // return any straggling buffers, e.g. if we got here on an error
1739        returnBuffersToCodec();
1740
1741        mComponentName.clear();
1742
1743        // The component is gone, mediaserver's probably back up already
1744        // but should definitely be back up should we try to instantiate
1745        // another component.. and the cycle continues.
1746        mFlags &= ~kFlagSawMediaServerDie;
1747    }
1748
1749    mState = newState;
1750
1751    cancelPendingDequeueOperations();
1752
1753    updateBatteryStat();
1754}
1755
1756void MediaCodec::returnBuffersToCodec() {
1757    returnBuffersToCodecOnPort(kPortIndexInput);
1758    returnBuffersToCodecOnPort(kPortIndexOutput);
1759}
1760
1761void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex) {
1762    CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
1763    Mutex::Autolock al(mBufferLock);
1764
1765    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1766
1767    for (size_t i = 0; i < buffers->size(); ++i) {
1768        BufferInfo *info = &buffers->editItemAt(i);
1769
1770        if (info->mNotify != NULL) {
1771            sp<AMessage> msg = info->mNotify;
1772            info->mNotify = NULL;
1773            info->mOwnedByClient = false;
1774
1775            if (portIndex == kPortIndexInput) {
1776                /* no error, just returning buffers */
1777                msg->setInt32("err", OK);
1778            }
1779            msg->post();
1780        }
1781    }
1782
1783    mAvailPortBuffers[portIndex].clear();
1784}
1785
1786size_t MediaCodec::updateBuffers(
1787        int32_t portIndex, const sp<AMessage> &msg) {
1788    CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
1789
1790    uint32_t bufferID;
1791    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
1792
1793    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1794
1795    for (size_t i = 0; i < buffers->size(); ++i) {
1796        BufferInfo *info = &buffers->editItemAt(i);
1797
1798        if (info->mBufferID == bufferID) {
1799            CHECK(info->mNotify == NULL);
1800            CHECK(msg->findMessage("reply", &info->mNotify));
1801
1802            mAvailPortBuffers[portIndex].push_back(i);
1803
1804            return i;
1805        }
1806    }
1807
1808    TRESPASS();
1809
1810    return 0;
1811}
1812
1813status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) {
1814    size_t index;
1815    size_t offset;
1816    size_t size;
1817    int64_t timeUs;
1818    uint32_t flags;
1819    CHECK(msg->findSize("index", &index));
1820    CHECK(msg->findSize("offset", &offset));
1821    CHECK(msg->findInt64("timeUs", &timeUs));
1822    CHECK(msg->findInt32("flags", (int32_t *)&flags));
1823
1824    const CryptoPlugin::SubSample *subSamples;
1825    size_t numSubSamples;
1826    const uint8_t *key;
1827    const uint8_t *iv;
1828    CryptoPlugin::Mode mode = CryptoPlugin::kMode_Unencrypted;
1829
1830    // We allow the simpler queueInputBuffer API to be used even in
1831    // secure mode, by fabricating a single unencrypted subSample.
1832    CryptoPlugin::SubSample ss;
1833
1834    if (msg->findSize("size", &size)) {
1835        if (mCrypto != NULL) {
1836            ss.mNumBytesOfClearData = size;
1837            ss.mNumBytesOfEncryptedData = 0;
1838
1839            subSamples = &ss;
1840            numSubSamples = 1;
1841            key = NULL;
1842            iv = NULL;
1843        }
1844    } else {
1845        if (mCrypto == NULL) {
1846            return -EINVAL;
1847        }
1848
1849        CHECK(msg->findPointer("subSamples", (void **)&subSamples));
1850        CHECK(msg->findSize("numSubSamples", &numSubSamples));
1851        CHECK(msg->findPointer("key", (void **)&key));
1852        CHECK(msg->findPointer("iv", (void **)&iv));
1853
1854        int32_t tmp;
1855        CHECK(msg->findInt32("mode", &tmp));
1856
1857        mode = (CryptoPlugin::Mode)tmp;
1858
1859        size = 0;
1860        for (size_t i = 0; i < numSubSamples; ++i) {
1861            size += subSamples[i].mNumBytesOfClearData;
1862            size += subSamples[i].mNumBytesOfEncryptedData;
1863        }
1864    }
1865
1866    if (index >= mPortBuffers[kPortIndexInput].size()) {
1867        return -ERANGE;
1868    }
1869
1870    BufferInfo *info = &mPortBuffers[kPortIndexInput].editItemAt(index);
1871
1872    if (info->mNotify == NULL || !info->mOwnedByClient) {
1873        return -EACCES;
1874    }
1875
1876    if (offset + size > info->mData->capacity()) {
1877        return -EINVAL;
1878    }
1879
1880    sp<AMessage> reply = info->mNotify;
1881    info->mData->setRange(offset, size);
1882    info->mData->meta()->setInt64("timeUs", timeUs);
1883
1884    if (flags & BUFFER_FLAG_EOS) {
1885        info->mData->meta()->setInt32("eos", true);
1886    }
1887
1888    if (flags & BUFFER_FLAG_CODECCONFIG) {
1889        info->mData->meta()->setInt32("csd", true);
1890    }
1891
1892    if (mCrypto != NULL) {
1893        if (size > info->mEncryptedData->capacity()) {
1894            return -ERANGE;
1895        }
1896
1897        AString *errorDetailMsg;
1898        CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
1899
1900        ssize_t result = mCrypto->decrypt(
1901                (mFlags & kFlagIsSecure) != 0,
1902                key,
1903                iv,
1904                mode,
1905                info->mEncryptedData->base() + offset,
1906                subSamples,
1907                numSubSamples,
1908                info->mData->base(),
1909                errorDetailMsg);
1910
1911        if (result < 0) {
1912            return result;
1913        }
1914
1915        info->mData->setRange(0, result);
1916    }
1917
1918    // synchronization boundary for getBufferAndFormat
1919    {
1920        Mutex::Autolock al(mBufferLock);
1921        info->mOwnedByClient = false;
1922    }
1923    reply->setBuffer("buffer", info->mData);
1924    reply->post();
1925
1926    info->mNotify = NULL;
1927
1928    return OK;
1929}
1930
1931status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) {
1932    size_t index;
1933    CHECK(msg->findSize("index", &index));
1934
1935    int32_t render;
1936    if (!msg->findInt32("render", &render)) {
1937        render = 0;
1938    }
1939
1940    if (!isExecuting()) {
1941        return -EINVAL;
1942    }
1943
1944    if (index >= mPortBuffers[kPortIndexOutput].size()) {
1945        return -ERANGE;
1946    }
1947
1948    BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
1949
1950    if (info->mNotify == NULL || !info->mOwnedByClient) {
1951        return -EACCES;
1952    }
1953
1954    // synchronization boundary for getBufferAndFormat
1955    {
1956        Mutex::Autolock al(mBufferLock);
1957        info->mOwnedByClient = false;
1958    }
1959
1960    if (render && info->mData != NULL && info->mData->size() != 0) {
1961        info->mNotify->setInt32("render", true);
1962
1963        int64_t timestampNs = 0;
1964        if (msg->findInt64("timestampNs", &timestampNs)) {
1965            info->mNotify->setInt64("timestampNs", timestampNs);
1966        } else {
1967            // TODO: it seems like we should use the timestamp
1968            // in the (media)buffer as it potentially came from
1969            // an input surface, but we did not propagate it prior to
1970            // API 20.  Perhaps check for target SDK version.
1971#if 0
1972            if (info->mData->meta()->findInt64("timeUs", &timestampNs)) {
1973                ALOGV("using buffer PTS of %" PRId64, timestampNs);
1974                timestampNs *= 1000;
1975            }
1976#endif
1977        }
1978
1979        if (mSoftRenderer != NULL) {
1980            mSoftRenderer->render(
1981                    info->mData->data(), info->mData->size(), timestampNs, NULL);
1982        }
1983    }
1984
1985    info->mNotify->post();
1986    info->mNotify = NULL;
1987
1988    return OK;
1989}
1990
1991ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) {
1992    CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
1993
1994    List<size_t> *availBuffers = &mAvailPortBuffers[portIndex];
1995
1996    if (availBuffers->empty()) {
1997        return -EAGAIN;
1998    }
1999
2000    size_t index = *availBuffers->begin();
2001    availBuffers->erase(availBuffers->begin());
2002
2003    BufferInfo *info = &mPortBuffers[portIndex].editItemAt(index);
2004    CHECK(!info->mOwnedByClient);
2005    {
2006        Mutex::Autolock al(mBufferLock);
2007        info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat;
2008        info->mOwnedByClient = true;
2009
2010        // set image-data
2011        if (info->mFormat != NULL) {
2012            sp<ABuffer> imageData;
2013            if (info->mFormat->findBuffer("image-data", &imageData)) {
2014                info->mData->meta()->setBuffer("image-data", imageData);
2015            }
2016            int32_t left, top, right, bottom;
2017            if (info->mFormat->findRect("crop", &left, &top, &right, &bottom)) {
2018                info->mData->meta()->setRect("crop-rect", left, top, right, bottom);
2019            }
2020        }
2021    }
2022
2023    return index;
2024}
2025
2026status_t MediaCodec::setNativeWindow(
2027        const sp<Surface> &surfaceTextureClient) {
2028    status_t err;
2029
2030    if (mNativeWindow != NULL) {
2031        err = native_window_api_disconnect(
2032                mNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
2033
2034        if (err != OK) {
2035            ALOGW("native_window_api_disconnect returned an error: %s (%d)",
2036                    strerror(-err), err);
2037        }
2038
2039        mNativeWindow.clear();
2040    }
2041
2042    if (surfaceTextureClient != NULL) {
2043        err = native_window_api_connect(
2044                surfaceTextureClient.get(), NATIVE_WINDOW_API_MEDIA);
2045
2046        if (err != OK) {
2047            ALOGE("native_window_api_connect returned an error: %s (%d)",
2048                    strerror(-err), err);
2049
2050            return err;
2051        }
2052
2053        mNativeWindow = surfaceTextureClient;
2054    }
2055
2056    return OK;
2057}
2058
2059void MediaCodec::onInputBufferAvailable() {
2060    int32_t index;
2061    while ((index = dequeuePortBuffer(kPortIndexInput)) >= 0) {
2062        sp<AMessage> msg = mCallback->dup();
2063        msg->setInt32("callbackID", CB_INPUT_AVAILABLE);
2064        msg->setInt32("index", index);
2065        msg->post();
2066    }
2067}
2068
2069void MediaCodec::onOutputBufferAvailable() {
2070    int32_t index;
2071    while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
2072        const sp<ABuffer> &buffer =
2073            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
2074        sp<AMessage> msg = mCallback->dup();
2075        msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
2076        msg->setInt32("index", index);
2077        msg->setSize("offset", buffer->offset());
2078        msg->setSize("size", buffer->size());
2079
2080        int64_t timeUs;
2081        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
2082
2083        msg->setInt64("timeUs", timeUs);
2084
2085        int32_t omxFlags;
2086        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
2087
2088        uint32_t flags = 0;
2089        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
2090            flags |= BUFFER_FLAG_SYNCFRAME;
2091        }
2092        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
2093            flags |= BUFFER_FLAG_CODECCONFIG;
2094        }
2095        if (omxFlags & OMX_BUFFERFLAG_EOS) {
2096            flags |= BUFFER_FLAG_EOS;
2097        }
2098
2099        msg->setInt32("flags", flags);
2100
2101        msg->post();
2102    }
2103}
2104
2105void MediaCodec::onError(status_t err, int32_t actionCode, const char *detail) {
2106    if (mCallback != NULL) {
2107        sp<AMessage> msg = mCallback->dup();
2108        msg->setInt32("callbackID", CB_ERROR);
2109        msg->setInt32("err", err);
2110        msg->setInt32("actionCode", actionCode);
2111
2112        if (detail != NULL) {
2113            msg->setString("detail", detail);
2114        }
2115
2116        msg->post();
2117    }
2118}
2119
2120void MediaCodec::onOutputFormatChanged() {
2121    if (mCallback != NULL) {
2122        sp<AMessage> msg = mCallback->dup();
2123        msg->setInt32("callbackID", CB_OUTPUT_FORMAT_CHANGED);
2124        msg->setMessage("format", mOutputFormat);
2125        msg->post();
2126    }
2127}
2128
2129
2130void MediaCodec::postActivityNotificationIfPossible() {
2131    if (mActivityNotify == NULL) {
2132        return;
2133    }
2134
2135    if ((mFlags & (kFlagStickyError
2136                    | kFlagOutputBuffersChanged
2137                    | kFlagOutputFormatChanged))
2138            || !mAvailPortBuffers[kPortIndexInput].empty()
2139            || !mAvailPortBuffers[kPortIndexOutput].empty()) {
2140        mActivityNotify->post();
2141        mActivityNotify.clear();
2142    }
2143}
2144
2145status_t MediaCodec::setParameters(const sp<AMessage> &params) {
2146    sp<AMessage> msg = new AMessage(kWhatSetParameters, id());
2147    msg->setMessage("params", params);
2148
2149    sp<AMessage> response;
2150    return PostAndAwaitResponse(msg, &response);
2151}
2152
2153status_t MediaCodec::onSetParameters(const sp<AMessage> &params) {
2154    mCodec->signalSetParameters(params);
2155
2156    return OK;
2157}
2158
2159status_t MediaCodec::amendOutputFormatWithCodecSpecificData(
2160        const sp<ABuffer> &buffer) {
2161    AString mime;
2162    CHECK(mOutputFormat->findString("mime", &mime));
2163
2164    if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
2165        // Codec specific data should be SPS and PPS in a single buffer,
2166        // each prefixed by a startcode (0x00 0x00 0x00 0x01).
2167        // We separate the two and put them into the output format
2168        // under the keys "csd-0" and "csd-1".
2169
2170        unsigned csdIndex = 0;
2171
2172        const uint8_t *data = buffer->data();
2173        size_t size = buffer->size();
2174
2175        const uint8_t *nalStart;
2176        size_t nalSize;
2177        while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
2178            sp<ABuffer> csd = new ABuffer(nalSize + 4);
2179            memcpy(csd->data(), "\x00\x00\x00\x01", 4);
2180            memcpy(csd->data() + 4, nalStart, nalSize);
2181
2182            mOutputFormat->setBuffer(
2183                    StringPrintf("csd-%u", csdIndex).c_str(), csd);
2184
2185            ++csdIndex;
2186        }
2187
2188        if (csdIndex != 2) {
2189            return ERROR_MALFORMED;
2190        }
2191    } else {
2192        // For everything else we just stash the codec specific data into
2193        // the output format as a single piece of csd under "csd-0".
2194        mOutputFormat->setBuffer("csd-0", buffer);
2195    }
2196
2197    return OK;
2198}
2199
2200void MediaCodec::updateBatteryStat() {
2201    if (mState == CONFIGURED && !mBatteryStatNotified) {
2202        AString mime;
2203        CHECK(mOutputFormat != NULL &&
2204                mOutputFormat->findString("mime", &mime));
2205
2206        mIsVideo = mime.startsWithIgnoreCase("video/");
2207
2208        BatteryNotifier& notifier(BatteryNotifier::getInstance());
2209
2210        if (mIsVideo) {
2211            notifier.noteStartVideo();
2212        } else {
2213            notifier.noteStartAudio();
2214        }
2215
2216        mBatteryStatNotified = true;
2217    } else if (mState == UNINITIALIZED && mBatteryStatNotified) {
2218        BatteryNotifier& notifier(BatteryNotifier::getInstance());
2219
2220        if (mIsVideo) {
2221            notifier.noteStopVideo();
2222        } else {
2223            notifier.noteStopAudio();
2224        }
2225
2226        mBatteryStatNotified = false;
2227    }
2228}
2229
2230}  // namespace android
2231