void TunnelRenderer::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatQueueBuffer:
        {
            sp<ABuffer> buffer;
            CHECK(msg->findBuffer("buffer", &buffer));

            queueBuffer(buffer);

            if (mStreamSource == NULL) {
                if (mTotalBytesQueued > 0ll) {
                    initPlayer();
                } else {
                    ALOGI("Have %lld bytes queued...", mTotalBytesQueued);
                }
            } else {
                mStreamSource->doSomeWork();
            }
            break;
        }

        default:
            TRESPASS();
    }
}
Example #2
0
void DirectRenderer::onDecoderNotify(const sp<AMessage> &msg) {
    size_t trackIndex;
    CHECK(msg->findSize("trackIndex", &trackIndex));

    int32_t what;
    CHECK(msg->findInt32("what", &what));

    switch (what) {
        case DecoderContext::kWhatOutputBufferReady:
        {
            size_t index;
            CHECK(msg->findSize("index", &index));

            int64_t timeUs;
            CHECK(msg->findInt64("timeUs", &timeUs));

            sp<ABuffer> buffer;
            CHECK(msg->findBuffer("buffer", &buffer));

            queueOutputBuffer(trackIndex, index, timeUs, buffer);
            break;
        }

        default:
            TRESPASS();
    }
}
bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
    if (targetFormat == NULL) {
        return true;
    }

    AString mime;
    if (!targetFormat->findString("mime", &mime)) {
        return false;
    }

    if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
        // field-by-field comparison
        const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
        for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
            int32_t oldVal, newVal;
            if (!mFormat->findInt32(keys[i], &oldVal) || !targetFormat->findInt32(keys[i], &newVal)
                    || oldVal != newVal) {
                return false;
            }
        }

        sp<ABuffer> oldBuf, newBuf;
        if (mFormat->findBuffer("csd-0", &oldBuf) && targetFormat->findBuffer("csd-0", &newBuf)) {
            if (oldBuf->size() != newBuf->size()) {
                return false;
            }
            return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
        }
    }
    return false;
}
Example #4
0
void NuPlayer::HTTPLiveSource::onSessionNotify_l(const sp<AMessage> &msg) {
    int32_t what;
    CHECK(msg->findInt32("what", &what));

    if(what == LiveSession::kWhatPicture) {
        sp<ABuffer> metabuffer;
        CHECK(msg->findBuffer("buffer", &metabuffer));
        
        AString mimeType;
        sp<ABuffer> buffer;
        if(((metabuffer)->meta()->findString("mime", &mimeType)) &&
                ((metabuffer)->meta()->findBuffer("pictureBuffer", &buffer))) {
            if (mMetaData == NULL) {
                mMetaData = new MetaData;
            }
            mMetaData->setCString(kKeyAlbumArtMIME, mimeType.c_str());
            mMetaData->setData(kKeyAlbumArt, MetaData::TYPE_NONE, buffer->data(), buffer->size());
            ALOGI("kKeyAlbumArt set Data :%s, datasize:%d", mimeType.c_str(), buffer->size());
            
            sp<AMessage> notify = dupNotify();
            notify->setInt32("what", NuPlayer::Source::kWhatPicture);
            notify->post();
        }
    }
    else if (what == LiveSession::kWhatBufferingStart) {
        sp<AMessage> notify = dupNotify();
        notify->setInt32("what", kWhatBufferingStart);
        notify->post();
    }
    else if (what == LiveSession::kWhatBufferingEnd) {
        sp<AMessage> notify = dupNotify();
        notify->setInt32("what", kWhatBufferingEnd);
        notify->post();
    }
}
void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
    CHECK(mCodec == NULL);

    AString mime;
    CHECK(format->findString("mime", &mime));

    sp<AMessage> notifyMsg =
        new AMessage(kWhatCodecNotify, id());

    mCSDIndex = 0;
    for (size_t i = 0;; ++i) {
        sp<ABuffer> csd;
        if (!format->findBuffer(StringPrintf("csd-%d", i).c_str(), &csd)) {
            break;
        }

        mCSD.push(csd);
    }

#ifdef QCOM_HARDWARE
    sp<ABuffer> extendedCSD = ExtendedCodec::getRawCodecSpecificData(format);
    if (extendedCSD != NULL) {
        ALOGV("pushing extended CSD of size %d", extendedCSD->size());
        mCSD.push(extendedCSD);
    }

    sp<ABuffer> aacCSD = ExtendedCodec::getAacCodecSpecificData(format);
    if (aacCSD != NULL) {
        ALOGV("pushing AAC CSD of size %d", aacCSD->size());
        mCSD.push(aacCSD);
    }
#endif

    if (mNativeWindow != NULL) {
        format->setObject("native-window", mNativeWindow);
    }

    // Current video decoders do not return from OMX_FillThisBuffer
    // quickly, violating the OpenMAX specs, until that is remedied
    // we need to invest in an extra looper to free the main event
    // queue.
    bool needDedicatedLooper = !strncasecmp(mime.c_str(), "video/", 6);

    mFormat = format;
    mCodec = new ACodec;

    if (needDedicatedLooper && mCodecLooper == NULL) {
        mCodecLooper = new ALooper;
        mCodecLooper->setName("NuPlayerDecoder");
        mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
    }

    (needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec);

    mCodec->setNotificationMessage(notifyMsg);
    mCodec->initiateSetup(format);
}
Example #6
0
sp<ABuffer> ExtendedCodec::getAacCodecSpecificData(
        const sp<AMessage> &msg) {
    sp<ABuffer> buffer;
    if (msg->findBuffer(getMsgKey(kKeyAacCodecSpecificData), &buffer)) {
        ALOGV("ACodec found kKeyAacCodecSpecificData of size %d\n", buffer->size());
        return buffer;
    }
    return NULL;
}
Example #7
0
void DirectRenderer::onQueueAccessUnit(const sp<AMessage> &msg) {
    size_t trackIndex;
    CHECK(msg->findSize("trackIndex", &trackIndex));

    sp<ABuffer> accessUnit;
    CHECK(msg->findBuffer("accessUnit", &accessUnit));

    CHECK_LT(trackIndex, 2u);
    CHECK(mDecoderContext[trackIndex] != NULL);

    mDecoderContext[trackIndex]->queueInputBuffer(accessUnit);
}
Example #8
0
// static
bool ColorUtils::getHDRStaticInfoFromFormat(const sp<AMessage> &format, HDRStaticInfo *info) {
    sp<ABuffer> buf;
    if (!format->findBuffer("hdr-static-info", &buf)) {
        return false;
    }

    // TODO: Make this more flexible when adding more members to HDRStaticInfo
    if (buf->size() != 25 /* static Metadata Type 1 size */) {
        ALOGW("Ignore invalid HDRStaticInfo with size: %zu", buf->size());
        return false;
    }

    const uint8_t *data = buf->data();
    if (*data != HDRStaticInfo::kType1) {
        ALOGW("Unsupported static Metadata Type %u", *data);
        return false;
    }

    info->mID = HDRStaticInfo::kType1;
    info->sType1.mR.x = U16LE_AT(&data[1]);
    info->sType1.mR.y = U16LE_AT(&data[3]);
    info->sType1.mG.x = U16LE_AT(&data[5]);
    info->sType1.mG.y = U16LE_AT(&data[7]);
    info->sType1.mB.x = U16LE_AT(&data[9]);
    info->sType1.mB.y = U16LE_AT(&data[11]);
    info->sType1.mW.x = U16LE_AT(&data[13]);
    info->sType1.mW.y = U16LE_AT(&data[15]);
    info->sType1.mMaxDisplayLuminance = U16LE_AT(&data[17]);
    info->sType1.mMinDisplayLuminance = U16LE_AT(&data[19]);
    info->sType1.mMaxContentLightLevel = U16LE_AT(&data[21]);
    info->sType1.mMaxFrameAverageLightLevel = U16LE_AT(&data[23]);

    ALOGV("Got HDRStaticInfo from config (R: %u %u, G: %u %u, B: %u, %u, W: %u, %u, "
            "MaxDispL: %u, MinDispL: %u, MaxContentL: %u, MaxFrameAvgL: %u)",
            info->sType1.mR.x, info->sType1.mR.y, info->sType1.mG.x, info->sType1.mG.y,
            info->sType1.mB.x, info->sType1.mB.y, info->sType1.mW.x, info->sType1.mW.y,
            info->sType1.mMaxDisplayLuminance, info->sType1.mMinDisplayLuminance,
            info->sType1.mMaxContentLightLevel, info->sType1.mMaxFrameAverageLightLevel);
    return true;
}
void DashPlayer::Decoder::onFillThisBuffer(const sp<AMessage> &msg) {
    sp<AMessage> reply;
    CHECK(msg->findMessage("reply", &reply));

#if 0
    sp<ABuffer> outBuffer;
    CHECK(msg->findBuffer("buffer", &outBuffer));
#else
    sp<ABuffer> outBuffer;
#endif

    if (mCSDIndex < mCSD.size()) {
        outBuffer = mCSD.editItemAt(mCSDIndex++);
        outBuffer->meta()->setInt64("timeUs", 0);

        reply->setBuffer("buffer", outBuffer);
        reply->post();
        return;
    }

    sp<AMessage> notify = mNotify->dup();
    notify->setMessage("codec-request", msg);
    notify->post();
}
void MediaFilter::onInputBufferFilled(const sp<AMessage> &msg) {
    IOMX::buffer_id bufferID;
    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
    BufferInfo *info = findBufferByID(kPortIndexInput, bufferID);

    if (mState != STARTED) {
        // we're not running, so we'll just keep that buffer...
        info->mStatus = BufferInfo::OWNED_BY_US;
        return;
    }

    if (info->mGeneration != mGeneration) {
        ALOGV("Caught a stale input buffer [ID %d]", bufferID);
        // buffer is stale (taken before a flush/shutdown) - repost it
        CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
        postFillThisBuffer(info);
        return;
    }

    CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
    info->mStatus = BufferInfo::OWNED_BY_US;

    sp<ABuffer> buffer;
    int32_t err = OK;
    bool eos = false;

    if (!msg->findBuffer("buffer", &buffer)) {
        // these are unfilled buffers returned by client
        CHECK(msg->findInt32("err", &err));

        if (err == OK) {
            // buffers with no errors are returned on MediaCodec.flush
            ALOGV("saw unfilled buffer (MediaCodec.flush)");
            postFillThisBuffer(info);
            return;
        } else {
            ALOGV("saw error %d instead of an input buffer", err);
            eos = true;
        }

        buffer.clear();
    }

    int32_t isCSD;
    if (buffer != NULL && buffer->meta()->findInt32("csd", &isCSD)
            && isCSD != 0) {
        // ignore codec-specific data buffers
        ALOGW("MediaFilter received a codec-specific data buffer");
        postFillThisBuffer(info);
        return;
    }

    int32_t tmp;
    if (buffer != NULL && buffer->meta()->findInt32("eos", &tmp) && tmp) {
        eos = true;
        err = ERROR_END_OF_STREAM;
    }

    mAvailableInputBuffers.push_back(info);
    processBuffers();

    if (eos) {
        mPortEOS[kPortIndexInput] = true;
        mInputEOSResult = err;
    }

    ALOGV("Handled kWhatInputBufferFilled. [ID %u]", bufferID);
}
status_t ConvertMessageToMap(
        JNIEnv *env, const sp<AMessage> &msg, jobject *map) {
    ScopedLocalRef<jclass> hashMapClazz(
            env, env->FindClass("java/util/HashMap"));

    if (hashMapClazz.get() == NULL) {
        return -EINVAL;
    }

    jmethodID hashMapConstructID =
        env->GetMethodID(hashMapClazz.get(), "<init>", "()V");

    if (hashMapConstructID == NULL) {
        return -EINVAL;
    }

    jmethodID hashMapPutID =
        env->GetMethodID(
                hashMapClazz.get(),
                "put",
                "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

    if (hashMapPutID == NULL) {
        return -EINVAL;
    }

    jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID);

    for (size_t i = 0; i < msg->countEntries(); ++i) {
        AMessage::Type valueType;
        const char *key = msg->getEntryNameAt(i, &valueType);

        jobject valueObj = NULL;

        switch (valueType) {
            case AMessage::kTypeInt32:
            {
                int32_t val;
                CHECK(msg->findInt32(key, &val));

                valueObj = makeIntegerObject(env, val);
                break;
            }

            case AMessage::kTypeInt64:
            {
                int64_t val;
                CHECK(msg->findInt64(key, &val));

                valueObj = makeLongObject(env, val);
                break;
            }

            case AMessage::kTypeFloat:
            {
                float val;
                CHECK(msg->findFloat(key, &val));

                valueObj = makeFloatObject(env, val);
                break;
            }

            case AMessage::kTypeString:
            {
                AString val;
                CHECK(msg->findString(key, &val));

                valueObj = env->NewStringUTF(val.c_str());
                break;
            }

            case AMessage::kTypeBuffer:
            {
                sp<ABuffer> buffer;
                CHECK(msg->findBuffer(key, &buffer));

                valueObj = makeByteBufferObject(
                        env, buffer->data(), buffer->size());
                break;
            }

            case AMessage::kTypeRect:
            {
                int32_t left, top, right, bottom;
                CHECK(msg->findRect(key, &left, &top, &right, &bottom));

                SetMapInt32(
                        env,
                        hashMap,
                        hashMapPutID,
                        StringPrintf("%s-left", key).c_str(),
                        left);

                SetMapInt32(
                        env,
                        hashMap,
                        hashMapPutID,
                        StringPrintf("%s-top", key).c_str(),
                        top);

                SetMapInt32(
                        env,
                        hashMap,
                        hashMapPutID,
                        StringPrintf("%s-right", key).c_str(),
                        right);

                SetMapInt32(
                        env,
                        hashMap,
                        hashMapPutID,
                        StringPrintf("%s-bottom", key).c_str(),
                        bottom);
                break;
            }

            default:
                break;
        }

        if (valueObj != NULL) {
            jstring keyObj = env->NewStringUTF(key);

            env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj);

            env->DeleteLocalRef(keyObj); keyObj = NULL;
            env->DeleteLocalRef(valueObj); valueObj = NULL;
        }
    }

    *map = hashMap;

    return OK;
}
void DashPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
    int32_t audio;
    CHECK(msg->findInt32("audio", &audio));

    if (audio) {
        mHasAudio = true;
    } else {
        mHasVideo = true;
    }

    if (dropBufferWhileFlushing(audio, msg)) {
        return;
    }

    sp<ABuffer> buffer;
    CHECK(msg->findBuffer("buffer", &buffer));

    sp<AMessage> notifyConsumed;
    CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));

    QueueEntry entry;
    entry.mBuffer = buffer;
    entry.mNotifyConsumed = notifyConsumed;
    entry.mOffset = 0;
    entry.mFinalResult = OK;

    if (audio) {
        mAudioQueue.push_back(entry);
        postDrainAudioQueue();
    } else {
        mVideoQueue.push_back(entry);
        postDrainVideoQueue();
    }

    if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
        return;
    }

    sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
    sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;

    if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
        // EOS signalled on either queue.
        syncQueuesDone();
        return;
    }

    int64_t firstAudioTimeUs;
    int64_t firstVideoTimeUs;
    CHECK(firstAudioBuffer->meta()
            ->findInt64("timeUs", &firstAudioTimeUs));
    CHECK(firstVideoBuffer->meta()
            ->findInt64("timeUs", &firstVideoTimeUs));

    int64_t diff = firstVideoTimeUs - firstAudioTimeUs;

    ALOGV("queueDiff = %.2f secs", diff / 1E6);

    if (diff > 100000ll) {
        // Audio data starts More than 0.1 secs before video.
        // Drop some audio.

        (*mAudioQueue.begin()).mNotifyConsumed->post();
        mAudioQueue.erase(mAudioQueue.begin());
        return;
    }

    syncQueuesDone();
}
Example #13
0
void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatStart:
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            AString iface;
            CHECK(msg->findString("iface", &iface));

            status_t err = OK;

            ssize_t colonPos = iface.find(":");

            unsigned long port;

            if (colonPos >= 0) {
                const char *s = iface.c_str() + colonPos + 1;

                char *end;
                port = strtoul(s, &end, 10);

                if (end == s || *end != '\0' || port > 65535) {
                    err = -EINVAL;
                } else {
                    iface.erase(colonPos, iface.size() - colonPos);
                }
            } else {
                port = kWifiDisplayDefaultPort;
            }

            if (err == OK) {
                if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) {
                    sp<AMessage> notify = new AMessage(kWhatRTSPNotify, this);

                    err = mNetSession->createRTSPServer(
                            mInterfaceAddr, port, notify, &mSessionID);
                } else {
                    err = -EINVAL;
                }
            }

            mState = AWAITING_CLIENT_CONNECTION;

            sp<AMessage> response = new AMessage;
            response->setInt32("err", err);
            response->postReply(replyID);
            break;
        }

        case kWhatRTSPNotify:
        {
            int32_t reason;
            CHECK(msg->findInt32("reason", &reason));

            switch (reason) {
                case ANetworkSession::kWhatError:
                {
                    int32_t sessionID;
                    CHECK(msg->findInt32("sessionID", &sessionID));

                    int32_t err;
                    CHECK(msg->findInt32("err", &err));

                    AString detail;
                    CHECK(msg->findString("detail", &detail));

                    ALOGE("An error occurred in session %d (%d, '%s/%s').",
                          sessionID,
                          err,
                          detail.c_str(),
                          strerror(-err));

                    mNetSession->destroySession(sessionID);

                    if (sessionID == mClientSessionID) {
                        mClientSessionID = 0;

                        mClient->onDisplayError(
                                IRemoteDisplayClient::kDisplayErrorUnknown);
                    }
                    break;
                }

                case ANetworkSession::kWhatClientConnected:
                {
                    int32_t sessionID;
                    CHECK(msg->findInt32("sessionID", &sessionID));

                    if (mClientSessionID > 0) {
                        ALOGW("A client tried to connect, but we already "
                              "have one.");

                        mNetSession->destroySession(sessionID);
                        break;
                    }

                    CHECK_EQ(mState, AWAITING_CLIENT_CONNECTION);

                    CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP));
                    CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP));

                    if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) {
                        // Disallow connections from the local interface
                        // for security reasons.
                        mNetSession->destroySession(sessionID);
                        break;
                    }

                    CHECK(msg->findInt32(
                                "server-port", &mClientInfo.mLocalPort));
                    mClientInfo.mPlaybackSessionID = -1;

                    mClientSessionID = sessionID;

                    ALOGI("We now have a client (%d) connected.", sessionID);

                    mState = AWAITING_CLIENT_SETUP;

                    status_t err = sendM1(sessionID);
                    CHECK_EQ(err, (status_t)OK);
                    break;
                }

                case ANetworkSession::kWhatData:
                {
                    status_t err = onReceiveClientData(msg);

                    if (err != OK) {
                        mClient->onDisplayError(
                                IRemoteDisplayClient::kDisplayErrorUnknown);
                    }

#if 0
                    // testing only.
                    char val[PROPERTY_VALUE_MAX];
                    if (property_get("media.wfd.trigger", val, NULL)) {
                        if (!strcasecmp(val, "pause") && mState == PLAYING) {
                            mState = PLAYING_TO_PAUSED;
                            sendTrigger(mClientSessionID, TRIGGER_PAUSE);
                        } else if (!strcasecmp(val, "play")
                                    && mState == PAUSED) {
                            mState = PAUSED_TO_PLAYING;
                            sendTrigger(mClientSessionID, TRIGGER_PLAY);
                        }
                    }
#endif
                    break;
                }

                case ANetworkSession::kWhatNetworkStall:
                {
                    break;
                }

                default:
                    TRESPASS();
            }
            break;
        }

        case kWhatStop:
        {
            CHECK(msg->senderAwaitsResponse(&mStopReplyID));

            CHECK_LT(mState, AWAITING_CLIENT_TEARDOWN);

            if (mState >= AWAITING_CLIENT_PLAY) {
                // We have a session, i.e. a previous SETUP succeeded.

                status_t err = sendTrigger(
                        mClientSessionID, TRIGGER_TEARDOWN);

                if (err == OK) {
                    mState = AWAITING_CLIENT_TEARDOWN;

                    (new AMessage(kWhatTeardownTriggerTimedOut, this))->post(
                            kTeardownTriggerTimeouSecs * 1000000ll);

                    break;
                }

                // fall through.
            }

            finishStop();
            break;
        }

        case kWhatPause:
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            status_t err = OK;

            if (mState != PLAYING) {
                err = INVALID_OPERATION;
            } else {
                mState = PLAYING_TO_PAUSED;
                sendTrigger(mClientSessionID, TRIGGER_PAUSE);
            }

            sp<AMessage> response = new AMessage;
            response->setInt32("err", err);
            response->postReply(replyID);
            break;
        }

        case kWhatResume:
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            status_t err = OK;

            if (mState != PAUSED) {
                err = INVALID_OPERATION;
            } else {
                mState = PAUSED_TO_PLAYING;
                sendTrigger(mClientSessionID, TRIGGER_PLAY);
            }

            sp<AMessage> response = new AMessage;
            response->setInt32("err", err);
            response->postReply(replyID);
            break;
        }

        case kWhatReapDeadClients:
        {
            mReaperPending = false;

            if (mClientSessionID == 0
                    || mClientInfo.mPlaybackSession == NULL) {
                break;
            }

            if (mClientInfo.mPlaybackSession->getLastLifesignUs()
                    + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) {
                ALOGI("playback session timed out, reaping.");

                mNetSession->destroySession(mClientSessionID);
                mClientSessionID = 0;

                mClient->onDisplayError(
                        IRemoteDisplayClient::kDisplayErrorUnknown);
            } else {
                scheduleReaper();
            }
            break;
        }

        case kWhatPlaybackSessionNotify:
        {
            int32_t playbackSessionID;
            CHECK(msg->findInt32("playbackSessionID", &playbackSessionID));

            int32_t what;
            CHECK(msg->findInt32("what", &what));

            if (what == PlaybackSession::kWhatSessionDead) {
                ALOGI("playback session wants to quit.");

                mClient->onDisplayError(
                        IRemoteDisplayClient::kDisplayErrorUnknown);
            } else if (what == PlaybackSession::kWhatSessionEstablished) {
                mPlaybackSessionEstablished = true;

                if (mClient != NULL) {
                    if (!mSinkSupportsVideo) {
                        mClient->onDisplayConnected(
                                NULL,  // SurfaceTexture
                                0, // width,
                                0, // height,
                                mUsingHDCP
                                    ? IRemoteDisplayClient::kDisplayFlagSecure
                                    : 0,
                                0);
                    } else {
                        size_t width, height;

                        CHECK(VideoFormats::GetConfiguration(
                                    mChosenVideoResolutionType,
                                    mChosenVideoResolutionIndex,
                                    &width,
                                    &height,
                                    NULL /* framesPerSecond */,
                                    NULL /* interlaced */));

                        mClient->onDisplayConnected(
                                mClientInfo.mPlaybackSession
                                    ->getSurfaceTexture(),
                                width,
                                height,
                                mUsingHDCP
                                    ? IRemoteDisplayClient::kDisplayFlagSecure
                                    : 0,
                                playbackSessionID);
                    }
                }

                finishPlay();

                if (mState == ABOUT_TO_PLAY) {
                    mState = PLAYING;
                }
            } else if (what == PlaybackSession::kWhatSessionDestroyed) {
                disconnectClient2();
            } else {
                CHECK_EQ(what, PlaybackSession::kWhatBinaryData);

                int32_t channel;
                CHECK(msg->findInt32("channel", &channel));

                sp<ABuffer> data;
                CHECK(msg->findBuffer("data", &data));

                CHECK_LE(channel, 0xff);
                CHECK_LE(data->size(), 0xffffu);

                int32_t sessionID;
                CHECK(msg->findInt32("sessionID", &sessionID));

                char header[4];
                header[0] = '$';
                header[1] = channel;
                header[2] = data->size() >> 8;
                header[3] = data->size() & 0xff;

                mNetSession->sendRequest(
                        sessionID, header, sizeof(header));

                mNetSession->sendRequest(
                        sessionID, data->data(), data->size());
            }
            break;
        }

        case kWhatKeepAlive:
        {
            int32_t sessionID;
            CHECK(msg->findInt32("sessionID", &sessionID));

            if (mClientSessionID != sessionID) {
                // Obsolete event, client is already gone.
                break;
            }

            sendM16(sessionID);
            break;
        }

        case kWhatTeardownTriggerTimedOut:
        {
            if (mState == AWAITING_CLIENT_TEARDOWN) {
                ALOGI("TEARDOWN trigger timed out, forcing disconnection.");

                CHECK(mStopReplyID != NULL);
                finishStop();
                break;
            }
            break;
        }

        case kWhatHDCPNotify:
        {
            int32_t msgCode, ext1, ext2;
            CHECK(msg->findInt32("msg", &msgCode));
            CHECK(msg->findInt32("ext1", &ext1));
            CHECK(msg->findInt32("ext2", &ext2));

            ALOGI("Saw HDCP notification code %d, ext1 %d, ext2 %d",
                    msgCode, ext1, ext2);

            switch (msgCode) {
                case HDCPModule::HDCP_INITIALIZATION_COMPLETE:
                {
                    mHDCPInitializationComplete = true;

                    if (mSetupTriggerDeferred) {
                        mSetupTriggerDeferred = false;

                        sendTrigger(mClientSessionID, TRIGGER_SETUP);
                    }
                    break;
                }

                case HDCPModule::HDCP_SHUTDOWN_COMPLETE:
                case HDCPModule::HDCP_SHUTDOWN_FAILED:
                {
                    // Ugly hack to make sure that the call to
                    // HDCPObserver::notify is completely handled before
                    // we clear the HDCP instance and unload the shared
                    // library :(
                    (new AMessage(kWhatFinishStop2, this))->post(300000ll);
                    break;
                }

                default:
                {
                    ALOGE("HDCP failure, shutting down.");

                    mClient->onDisplayError(
                            IRemoteDisplayClient::kDisplayErrorUnknown);
                    break;
                }
            }
            break;
        }

        case kWhatFinishStop2:
        {
            finishStop2();
            break;
        }

        default:
            TRESPASS();
    }
}
void DashPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
    int32_t audio;
    CHECK(msg->findInt32("audio", &audio));

    if (audio) {
        mHasAudio = true;
    } else {
        mHasVideo = true;
    }

    if (dropBufferWhileFlushing(audio, msg)) {
        return;
    }

    sp<ABuffer> buffer;
    CHECK(msg->findBuffer("buffer", &buffer));

    sp<AMessage> notifyConsumed;
    CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));

    QueueEntry entry;
    entry.mBuffer = buffer;
    entry.mNotifyConsumed = notifyConsumed;
    entry.mOffset = 0;
    entry.mFinalResult = OK;

    if (audio) {
        mAudioQueue.push_back(entry);
        int64_t audioTimeUs;
        (buffer->meta())->findInt64("timeUs", &audioTimeUs);
        if ((mHasVideo && mIsFirstVideoframeReceived)
            || !mHasVideo){
        postDrainAudioQueue();
            return;
        }
        else
        {
          mPendingPostAudioDrains = true;
          DPR_MSG_HIGH("Not rendering Audio Sample with TS: %lld  as Video frame is not decoded", audioTimeUs);
        }
    } else {
        mVideoQueue.push_back(entry);
        int64_t videoTimeUs;
        (buffer->meta())->findInt64("timeUs", &videoTimeUs);
        if (!mIsFirstVideoframeReceived) {
            mIsFirstVideoframeReceived = true;
            DPR_MSG_HIGH("Received first video Sample with TS: %lld", videoTimeUs);
            if (mPendingPostAudioDrains) {
                mPendingPostAudioDrains = false;
                postDrainAudioQueue();
            }
        }
        postDrainVideoQueue();
    }

    if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
        return;
    }

    sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
    sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;

    if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
        // EOS signalled on either queue.
        syncQueuesDone();
        return;
    }

    int64_t firstAudioTimeUs;
    int64_t firstVideoTimeUs;
    CHECK(firstAudioBuffer->meta()
            ->findInt64("timeUs", &firstAudioTimeUs));
    CHECK(firstVideoBuffer->meta()
            ->findInt64("timeUs", &firstVideoTimeUs));

    int64_t diff = firstVideoTimeUs - firstAudioTimeUs;

    DPR_MSG_LOW("queueDiff = %.2f secs", diff / 1E6);

    if (diff > 100000ll) {
        // Audio data starts More than 0.1 secs before video.
        // Drop some audio.

        (*mAudioQueue.begin()).mNotifyConsumed->post();
        mAudioQueue.erase(mAudioQueue.begin());
        return;
    }

    syncQueuesDone();
}
void Converter::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatMediaPullerNotify:
        {
            int32_t what;
            CHECK(msg->findInt32("what", &what));

            if (!mIsPCMAudio && mEncoder == NULL) {
                ALOGV("got msg '%s' after encoder shutdown.",
                      msg->debugString().c_str());

                if (what == MediaPuller::kWhatAccessUnit) {
                    sp<ABuffer> accessUnit;
                    CHECK(msg->findBuffer("accessUnit", &accessUnit));

                    accessUnit->setMediaBufferBase(NULL);
                }
                break;
            }

            if (what == MediaPuller::kWhatEOS) {
                mInputBufferQueue.push_back(NULL);

                feedEncoderInputBuffers();

                scheduleDoMoreWork();
            } else {
                CHECK_EQ(what, MediaPuller::kWhatAccessUnit);

                sp<ABuffer> accessUnit;
                CHECK(msg->findBuffer("accessUnit", &accessUnit));

                if (mNumFramesToDrop > 0 || mEncodingSuspended) {
                    if (mNumFramesToDrop > 0) {
                        --mNumFramesToDrop;
                        ALOGI("dropping frame.");
                    }

                    accessUnit->setMediaBufferBase(NULL);
                    break;
                }

#if 0
                MediaBuffer *mbuf =
                    (MediaBuffer *)(accessUnit->getMediaBufferBase());
                if (mbuf != NULL) {
                    ALOGI("queueing mbuf %p", mbuf);
                    mbuf->release();
                }
#endif

#if ENABLE_SILENCE_DETECTION
                if (!mIsVideo) {
                    if (IsSilence(accessUnit)) {
                        if (mInSilentMode) {
                            break;
                        }

                        int64_t nowUs = ALooper::GetNowUs();

                        if (mFirstSilentFrameUs < 0ll) {
                            mFirstSilentFrameUs = nowUs;
                        } else if (nowUs >= mFirstSilentFrameUs + 10000000ll) {
                            mInSilentMode = true;
                            ALOGI("audio in silent mode now.");
                            break;
                        }
                    } else {
                        if (mInSilentMode) {
                            ALOGI("audio no longer in silent mode.");
                        }
                        mInSilentMode = false;
                        mFirstSilentFrameUs = -1ll;
                    }
                }
#endif

                mInputBufferQueue.push_back(accessUnit);

                feedEncoderInputBuffers();

                scheduleDoMoreWork();
            }
            break;
        }

        case kWhatEncoderActivity:
        {
#if 0
            int64_t whenUs;
            if (msg->findInt64("whenUs", &whenUs)) {
                int64_t nowUs = ALooper::GetNowUs();
                ALOGI("[%s] kWhatEncoderActivity after %lld us",
                      mIsVideo ? "video" : "audio", nowUs - whenUs);
            }
#endif

            mDoMoreWorkPending = false;

            if (mEncoder == NULL) {
                break;
            }

            status_t err = doMoreWork();

            if (err != OK) {
                notifyError(err);
            } else {
                scheduleDoMoreWork();
            }
            break;
        }

        case kWhatRequestIDRFrame:
        {
            if (mEncoder == NULL) {
                break;
            }

            if (mIsVideo) {
                ALOGV("requesting IDR frame");
                mEncoder->requestIDRFrame();
            }
            break;
        }

        case kWhatShutdown:
        {
            ALOGI("shutting down %s encoder", mIsVideo ? "video" : "audio");

            releaseEncoder();

            AString mime;
            CHECK(mOutputFormat->findString("mime", &mime));
            ALOGI("encoder (%s) shut down.", mime.c_str());

            sp<AMessage> notify = mNotify->dup();
            notify->setInt32("what", kWhatShutdownCompleted);
            notify->post();
            break;
        }

        case kWhatDropAFrame:
        {
            ++mNumFramesToDrop;
            break;
        }

        case kWhatReleaseOutputBuffer:
        {
            if (mEncoder != NULL) {
                size_t bufferIndex;
                CHECK(msg->findInt32("bufferIndex", (int32_t*)&bufferIndex));
                CHECK(bufferIndex < mEncoderOutputBuffers.size());
                mEncoder->releaseOutputBuffer(bufferIndex);
            }
            break;
        }

        case kWhatSuspendEncoding:
        {
            int32_t suspend;
            CHECK(msg->findInt32("suspend", &suspend));

            mEncodingSuspended = suspend;

            if (mFlags & FLAG_USE_SURFACE_INPUT) {
                sp<AMessage> params = new AMessage;
                params->setInt32("drop-input-frames",suspend);
                mEncoder->setParameters(params);
            }
            break;
        }

        default:
            TRESPASS();
    }
}
Example #16
0
void TimeSyncer::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatStartClient:
        {
            AString remoteHost;
            CHECK(msg->findString("remoteHost", &remoteHost));

            int32_t remotePort;
            CHECK(msg->findInt32("remotePort", &remotePort));

            sp<AMessage> notify = new AMessage(kWhatUDPNotify, id());

            CHECK_EQ((status_t)OK,
                     mNetSession->createUDPSession(
                         0 /* localPort */,
                         remoteHost.c_str(),
                         remotePort,
                         notify,
                         &mUDPSession));

            postSendPacket();
            break;
        }

        case kWhatStartServer:
        {
            mIsServer = true;

            int32_t localPort;
            CHECK(msg->findInt32("localPort", &localPort));

            sp<AMessage> notify = new AMessage(kWhatUDPNotify, id());

            CHECK_EQ((status_t)OK,
                     mNetSession->createUDPSession(
                         localPort, notify, &mUDPSession));

            break;
        }

        case kWhatSendPacket:
        {
            if (mHistory.size() == 0) {
                ALOGI("starting batch");
            }

            TimeInfo ti;
            memset(&ti, 0, sizeof(ti));

            ti.mT1 = ALooper::GetNowUs();

            CHECK_EQ((status_t)OK,
                     mNetSession->sendRequest(
                         mUDPSession, &ti, sizeof(ti)));

            mPendingT1 = ti.mT1;
            postTimeout();
            break;
        }

        case kWhatTimedOut:
        {
            int32_t generation;
            CHECK(msg->findInt32("generation", &generation));

            if (generation != mTimeoutGeneration) {
                break;
            }

            ALOGI("timed out, sending another request");
            postSendPacket();
            break;
        }

        case kWhatUDPNotify:
        {
            int32_t reason;
            CHECK(msg->findInt32("reason", &reason));

            switch (reason) {
                case ANetworkSession::kWhatError:
                {
                    int32_t sessionID;
                    CHECK(msg->findInt32("sessionID", &sessionID));

                    int32_t err;
                    CHECK(msg->findInt32("err", &err));

                    AString detail;
                    CHECK(msg->findString("detail", &detail));

                    ALOGE("An error occurred in session %d (%d, '%s/%s').",
                          sessionID,
                          err,
                          detail.c_str(),
                          strerror(-err));

                    mNetSession->destroySession(sessionID);

                    cancelTimeout();

                    notifyError(err);
                    break;
                }

                case ANetworkSession::kWhatDatagram:
                {
                    int32_t sessionID;
                    CHECK(msg->findInt32("sessionID", &sessionID));

                    sp<ABuffer> packet;
                    CHECK(msg->findBuffer("data", &packet));

                    int64_t arrivalTimeUs;
                    CHECK(packet->meta()->findInt64(
                                "arrivalTimeUs", &arrivalTimeUs));

                    CHECK_EQ(packet->size(), sizeof(TimeInfo));

                    TimeInfo *ti = (TimeInfo *)packet->data();

                    if (mIsServer) {
                        if (!mConnected) {
                            AString fromAddr;
                            CHECK(msg->findString("fromAddr", &fromAddr));

                            int32_t fromPort;
                            CHECK(msg->findInt32("fromPort", &fromPort));

                            CHECK_EQ((status_t)OK,
                                     mNetSession->connectUDPSession(
                                         mUDPSession, fromAddr.c_str(), fromPort));

                            mConnected = true;
                        }

                        ti->mT2 = arrivalTimeUs;
                        ti->mT3 = ALooper::GetNowUs();

                        CHECK_EQ((status_t)OK,
                                 mNetSession->sendRequest(
                                     mUDPSession, ti, sizeof(*ti)));
                    } else {
                        if (ti->mT1 != mPendingT1) {
                            break;
                        }

                        cancelTimeout();
                        mPendingT1 = 0;

                        ti->mT4 = arrivalTimeUs;

                        // One way delay for a packet to travel from client
                        // to server or back (assumed to be the same either way).
                        int64_t delay =
                            (ti->mT2 - ti->mT1 + ti->mT4 - ti->mT3) / 2;

                        // Offset between the client clock (T1, T4) and the
                        // server clock (T2, T3) timestamps.
                        int64_t offset =
                            (ti->mT2 - ti->mT1 - ti->mT4 + ti->mT3) / 2;

                        mHistory.push_back(*ti);

                        ALOGV("delay = %lld us,\toffset %lld us",
                               delay,
                               offset);

                        if (mHistory.size() < kNumPacketsPerBatch) {
                            postSendPacket(1000000ll / 30);
                        } else {
                            notifyOffset();

                            ALOGI("batch done");

                            mHistory.clear();
                            postSendPacket(kBatchDelayUs);
                        }
                    }
                    break;
                }

                default:
                    TRESPASS();
            }

            break;
        }

        default:
            TRESPASS();
    }
}
void NuPlayer::DecoderPassThrough::onInputBufferFetched(
        const sp<AMessage> &msg) {
    if (mReachedEOS) {
        return;
    }

    sp<ABuffer> buffer;
    bool hasBuffer = msg->findBuffer("buffer", &buffer);
    if (buffer == NULL) {
        int32_t streamErr = ERROR_END_OF_STREAM;
        CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
        if (streamErr == OK) {
            return;
        }

        mReachedEOS = true;
        if (mRenderer != NULL) {
            mRenderer->queueEOS(true /* audio */, ERROR_END_OF_STREAM);
        }
        return;
    }

    sp<AMessage> extra;
    if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
        int64_t resumeAtMediaTimeUs;
        if (extra->findInt64(
                    "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
            ALOGI("[%s] suppressing rendering until %lld us",
                    mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
            mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
        }
    }

    int32_t bufferSize = buffer->size();
    mCachedBytes += bufferSize;

    if (mSkipRenderingUntilMediaTimeUs >= 0) {
        int64_t timeUs = 0;
        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));

        if (timeUs < mSkipRenderingUntilMediaTimeUs) {
            ALOGV("[%s] dropping buffer at time %lld as requested.",
                     mComponentName.c_str(), (long long)timeUs);

            onBufferConsumed(bufferSize);
            return;
        }

        mSkipRenderingUntilMediaTimeUs = -1;
    }

    if (mRenderer == NULL) {
        onBufferConsumed(bufferSize);
        return;
    }

    sp<AMessage> reply = new AMessage(kWhatBufferConsumed, this);
    reply->setInt32("generation", mBufferGeneration);
    reply->setInt32("size", bufferSize);

    mRenderer->queueBuffer(true /* audio */, buffer, reply);

    ++mPendingBuffersToDrain;
    ALOGV("onInputBufferFilled: #ToDrain = %zu, cachedBytes = %zu",
            mPendingBuffersToDrain, mCachedBytes);
}
void ARTPSession::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatAccessUnitComplete:
        {
            int32_t firstRTCP;
            if (msg->findInt32("first-rtcp", &firstRTCP)) {
                // There won't be an access unit here, it's just a notification
                // that the data communication worked since we got the first
                // rtcp packet.
                break;
            }

            size_t trackIndex;
            CHECK(msg->findSize("track-index", &trackIndex));

            int32_t eos;
            if (msg->findInt32("eos", &eos) && eos) {
                TrackInfo *info = &mTracks.editItemAt(trackIndex);
                info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
                break;
            }

            sp<ABuffer> accessUnit;
            CHECK(msg->findBuffer("access-unit", &accessUnit));

            uint64_t ntpTime;
            CHECK(accessUnit->meta()->findInt64(
                        "ntp-time", (int64_t *)&ntpTime));

#if 0
#if 0
            printf("access unit complete size=%d\tntp-time=0x%016llx\n",
                   accessUnit->size(), ntpTime);
#else
            ALOGI("access unit complete, size=%d, ntp-time=%llu",
                 accessUnit->size(), ntpTime);
            hexdump(accessUnit->data(), accessUnit->size());
#endif
#endif

#if 0
            CHECK_GE(accessUnit->size(), 5u);
            CHECK(!memcmp("\x00\x00\x00\x01", accessUnit->data(), 4));
            unsigned x = accessUnit->data()[4];

            ALOGI("access unit complete: nalType=0x%02x, nalRefIdc=0x%02x",
                 x & 0x1f, (x & 0x60) >> 5);
#endif

            accessUnit->meta()->setInt64("ntp-time", ntpTime);
            accessUnit->meta()->setInt64("timeUs", 0);

#if 0
            int32_t damaged;
            if (accessUnit->meta()->findInt32("damaged", &damaged)
                    && damaged != 0) {
                ALOGI("ignoring damaged AU");
            } else
#endif
            {
                TrackInfo *info = &mTracks.editItemAt(trackIndex);
                info->mPacketSource->queueAccessUnit(accessUnit);
            }
            break;
        }

        default:
            TRESPASS();
            break;
    }
}
void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    if (msg->what() == kWhatDisconnect) {
        sp<AReplyToken> replyID;
        CHECK(msg->senderAwaitsResponse(&replyID));

        mDisconnectReplyID = replyID;
        finishDisconnectIfPossible();
        return;
    } else if (msg->what() == kWhatPerformSeek) {
        int32_t generation;
        CHECK(msg->findInt32("generation", &generation));
        CHECK(msg->senderAwaitsResponse(&mSeekReplyID));

        if (generation != mSeekGeneration) {
            // obsolete.
            finishSeek(OK);
            return;
        }

        int64_t seekTimeUs;
        CHECK(msg->findInt64("timeUs", &seekTimeUs));

        performSeek(seekTimeUs);
        return;
    } else if (msg->what() == kWhatPollBuffering) {
        onPollBuffering();
        return;
    } else if (msg->what() == kWhatSignalEOS) {
        onSignalEOS(msg);
        return;
    }

    CHECK_EQ(msg->what(), (int)kWhatNotify);

    int32_t what;
    CHECK(msg->findInt32("what", &what));

    switch (what) {
        case MyHandler::kWhatConnected:
        {
            onConnected();

            notifyVideoSizeChanged();

            uint32_t flags = 0;

            if (mHandler->isSeekable()) {
                flags = FLAG_CAN_PAUSE
                        | FLAG_CAN_SEEK
                        | FLAG_CAN_SEEK_BACKWARD
                        | FLAG_CAN_SEEK_FORWARD;
            }

            notifyFlagsChanged(flags);
            schedulePollBuffering();
            break;
        }

        case MyHandler::kWhatDisconnected:
        {
            onDisconnected(msg);
            break;
        }

        case MyHandler::kWhatSeekDone:
        {
            mState = CONNECTED;
            // Unblock seekTo here in case we attempted to seek in a live stream
            finishSeek(OK);
            break;
        }

        case MyHandler::kWhatSeekPaused:
        {
            sp<AnotherPacketSource> source = getSource(true /* audio */);
            if (source != NULL) {
                source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
                        /* extra */ NULL,
                        /* discard */ true);
            }
            source = getSource(false /* video */);
            if (source != NULL) {
                source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
                        /* extra */ NULL,
                        /* discard */ true);
            };

            status_t err = OK;
            msg->findInt32("err", &err);

            if (err == OK) {
                int64_t timeUs;
                CHECK(msg->findInt64("time", &timeUs));
                mHandler->continueSeekAfterPause(timeUs);
            } else {
                finishSeek(err);
            }
            break;
        }

        case MyHandler::kWhatAccessUnit:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));

            if (mTSParser == NULL) {
                CHECK_LT(trackIndex, mTracks.size());
            } else {
                CHECK_EQ(trackIndex, 0u);
            }

            sp<ABuffer> accessUnit;
            CHECK(msg->findBuffer("accessUnit", &accessUnit));

            int32_t damaged;
            if (accessUnit->meta()->findInt32("damaged", &damaged)
                    && damaged) {
                ALOGI("dropping damaged access unit.");
                break;
            }

            if (mTSParser != NULL) {
                size_t offset = 0;
                status_t err = OK;
                while (offset + 188 <= accessUnit->size()) {
                    err = mTSParser->feedTSPacket(
                            accessUnit->data() + offset, 188);
                    if (err != OK) {
                        break;
                    }

                    offset += 188;
                }

                if (offset < accessUnit->size()) {
                    err = ERROR_MALFORMED;
                }

                if (err != OK) {
                    signalSourceEOS(err);
                }

                postSourceEOSIfNecessary();
                break;
            }

            TrackInfo *info = &mTracks.editItemAt(trackIndex);

            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                uint32_t rtpTime;
                CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));

                if (!info->mNPTMappingValid) {
                    // This is a live stream, we didn't receive any normal
                    // playtime mapping. We won't map to npt time.
                    source->queueAccessUnit(accessUnit);
                    break;
                }

                int64_t nptUs =
                    ((double)rtpTime - (double)info->mRTPTime)
                        / info->mTimeScale
                        * 1000000ll
                        + info->mNormalPlaytimeUs;

                accessUnit->meta()->setInt64("timeUs", nptUs);

                source->queueAccessUnit(accessUnit);
            }
            postSourceEOSIfNecessary();
            break;
        }

        case MyHandler::kWhatEOS:
        {
            int32_t finalResult;
            CHECK(msg->findInt32("finalResult", &finalResult));
            CHECK_NE(finalResult, (status_t)OK);

            if (mTSParser != NULL) {
                signalSourceEOS(finalResult);
            }

            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                source->signalEOS(finalResult);
            }

            break;
        }

        case MyHandler::kWhatSeekDiscontinuity:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            sp<AnotherPacketSource> source = info->mSource;
            if (source != NULL) {
                source->queueDiscontinuity(
                        ATSParser::DISCONTINUITY_TIME,
                        NULL,
                        true /* discard */);
            }

            break;
        }

        case MyHandler::kWhatNormalPlayTimeMapping:
        {
            size_t trackIndex;
            CHECK(msg->findSize("trackIndex", &trackIndex));
            CHECK_LT(trackIndex, mTracks.size());

            uint32_t rtpTime;
            CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));

            int64_t nptUs;
            CHECK(msg->findInt64("nptUs", &nptUs));

            TrackInfo *info = &mTracks.editItemAt(trackIndex);
            info->mRTPTime = rtpTime;
            info->mNormalPlaytimeUs = nptUs;
            info->mNPTMappingValid = true;
            break;
        }

        case SDPLoader::kWhatSDPLoaded:
        {
            onSDPLoaded(msg);
            break;
        }

        default:
            TRESPASS();
    }
}
Example #20
0
void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
    int32_t what;
    CHECK(msg->findInt32("what", &what));

    switch (what) {
        case LiveSession::kWhatPrepared:
        {
            // notify the current size here if we have it, otherwise report an initial size of (0,0)
            sp<AMessage> format = getFormat(false /* audio */);
            int32_t width;
            int32_t height;
            if (format != NULL &&
                    format->findInt32("width", &width) && format->findInt32("height", &height)) {
                notifyVideoSizeChanged(width, height);
            } else {
#ifdef ANDROID_DEFAULT_CODE
                notifyVideoSizeChanged(0, 0);
#endif                
            }
#ifdef ANDROID_DEFAULT_CODE
            uint32_t flags = FLAG_CAN_PAUSE;
#else            
            uint32_t flags = 0;
#endif
            if (mLiveSession->isSeekable()) {
#ifndef ANDROID_DEFAULT_CODE
                flags |= FLAG_CAN_PAUSE;
#endif                
                flags |= FLAG_CAN_SEEK;
                flags |= FLAG_CAN_SEEK_BACKWARD;
                flags |= FLAG_CAN_SEEK_FORWARD;
            }

            if (mLiveSession->hasDynamicDuration()) {
                flags |= FLAG_DYNAMIC_DURATION;
            }

            notifyFlagsChanged(flags);

            notifyPrepared();
            break;
        }

        case LiveSession::kWhatPreparationFailed:
        {
            status_t err;
            CHECK(msg->findInt32("err", &err));

            notifyPrepared(err);
            break;
        }

        case LiveSession::kWhatStreamsChanged:
        {
            uint32_t changedMask;
            CHECK(msg->findInt32(
                        "changedMask", (int32_t *)&changedMask));

            bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
            bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;

            sp<AMessage> reply;
            CHECK(msg->findMessage("reply", &reply));

            sp<AMessage> notify = dupNotify();
            notify->setInt32("what", kWhatQueueDecoderShutdown);
            notify->setInt32("audio", audio);
            notify->setInt32("video", video);
            notify->setMessage("reply", reply);
            notify->post();
            break;
        }

        case LiveSession::kWhatError:
        {
            break;
        }
#ifndef ANDROID_DEFAULT_CODE
        case LiveSession::kWhatPicture:
        {
         	  sp<ABuffer> metabuffer;
            CHECK(msg->findBuffer("buffer", &metabuffer));
           
            AString mimeType;
            sp<ABuffer> buffer;
            if(((metabuffer)->meta()->findString("mime", &mimeType)) &&
                   ((metabuffer)->meta()->findBuffer("pictureBuffer", &buffer)))
            {
                if (mMetaData == NULL)
                {
        	         mMetaData = new MetaData;
                }
                mMetaData->setCString(kKeyAlbumArtMIME, mimeType.c_str());
                mMetaData->setData(kKeyAlbumArt, MetaData::TYPE_NONE, buffer->data(), buffer->size());
                ALOGI("kKeyAlbumArt set Data :%s, datasize:%d", mimeType.c_str(), buffer->size());

                sp<AMessage> notify = dupNotify();
                notify->setInt32("what", NuPlayer::Source::kWhatPicture);
                notify->post();
            }
            break;
        }
        case LiveSession::kWhatBufferingStart:
        {
            sp<AMessage> notify = dupNotify();
            notify->setInt32("what", kWhatBufferingStart);
            notify->post();
            break;
        }
        case LiveSession::kWhatBufferingEnd:
        {
            sp<AMessage> notify = dupNotify();
            notify->setInt32("what", kWhatBufferingEnd);
            notify->post();
            break;
        }
#endif
        default:
            TRESPASS();
    }
}
void Converter::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatMediaPullerNotify:
        {
            int32_t what;
            CHECK(msg->findInt32("what", &what));

            if (!mIsPCMAudio && mEncoder == NULL) {
                ALOGV("got msg '%s' after encoder shutdown.",
                      msg->debugString().c_str());

                if (what == MediaPuller::kWhatAccessUnit) {
                    sp<ABuffer> accessUnit;
                    CHECK(msg->findBuffer("accessUnit", &accessUnit));

                    void *mbuf;
                    if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
                            && mbuf != NULL) {
                        ALOGV("releasing mbuf %p", mbuf);

                        accessUnit->meta()->setPointer("mediaBuffer", NULL);

                        static_cast<MediaBuffer *>(mbuf)->release();
                        mbuf = NULL;
                    }
                }
                break;
            }

            if (what == MediaPuller::kWhatEOS) {
                mInputBufferQueue.push_back(NULL);

                feedEncoderInputBuffers();

                scheduleDoMoreWork();
            } else {
                CHECK_EQ(what, MediaPuller::kWhatAccessUnit);

                sp<ABuffer> accessUnit;
                CHECK(msg->findBuffer("accessUnit", &accessUnit));

#if 0
                void *mbuf;
                if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
                        && mbuf != NULL) {
                    ALOGI("queueing mbuf %p", mbuf);
                }
#endif

#if ENABLE_SILENCE_DETECTION
                if (!mIsVideo) {
                    if (IsSilence(accessUnit)) {
                        if (mInSilentMode) {
                            break;
                        }

                        int64_t nowUs = ALooper::GetNowUs();

                        if (mFirstSilentFrameUs < 0ll) {
                            mFirstSilentFrameUs = nowUs;
                        } else if (nowUs >= mFirstSilentFrameUs + 10000000ll) {
                            mInSilentMode = true;
                            ALOGI("audio in silent mode now.");
                            break;
                        }
                    } else {
                        if (mInSilentMode) {
                            ALOGI("audio no longer in silent mode.");
                        }
                        mInSilentMode = false;
                        mFirstSilentFrameUs = -1ll;
                    }
                }
#endif

                mInputBufferQueue.push_back(accessUnit);

                feedEncoderInputBuffers();

                scheduleDoMoreWork();
            }
            break;
        }

        case kWhatEncoderActivity:
        {
#if 0
            int64_t whenUs;
            if (msg->findInt64("whenUs", &whenUs)) {
                int64_t nowUs = ALooper::GetNowUs();
                ALOGI("[%s] kWhatEncoderActivity after %lld us",
                      mIsVideo ? "video" : "audio", nowUs - whenUs);
            }
#endif

            mDoMoreWorkPending = false;

            if (mEncoder == NULL) {
                break;
            }

            status_t err = doMoreWork();

            if (err != OK) {
                notifyError(err);
            } else {
                scheduleDoMoreWork();
            }
            break;
        }

        case kWhatRequestIDRFrame:
        {
            if (mEncoder == NULL) {
                break;
            }

            if (mIsVideo) {
                ALOGI("requesting IDR frame");
                mEncoder->requestIDRFrame();
            }
            break;
        }

        case kWhatShutdown:
        {
            ALOGI("shutting down encoder");

            /*bugfix: release queue buffer,it may fall into blackhold.
             *		when 4kplayer is floating in the dynamic desktop,
             *		and someone disable wifi in the quicksetting, this will lead to UI deadlock.
             *   It mainly let the source emit onDisplayDisconnect msg to framework.
             */
            while (!mInputBufferQueue.empty()) {
                sp<ABuffer> accessUnit = *mInputBufferQueue.begin();
                mInputBufferQueue.erase(mInputBufferQueue.begin());
                void *mbuf = NULL;
                if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
                        && mbuf != NULL) {
                    ALOGI(">>releasing mbuf %p", mbuf);
                    accessUnit->meta()->setPointer("mediaBuffer", NULL);
                    static_cast<MediaBuffer *>(mbuf)->release();
                    mbuf = NULL;
                }
            }

            if (mEncoder != NULL) {
                mEncoder->release();
                mEncoder.clear();
            }

            AString mime;
            CHECK(mInputFormat->findString("mime", &mime));
            ALOGI("encoder (%s) shut down.", mime.c_str());
            break;
        }

        default:
            TRESPASS();
    }
}