static AString codecResultsToXml(const KeyedVector<AString, CodecSettings> &results) {
    AString ret;
    for (size_t i = 0; i < results.size(); ++i) {
        AString name;
        AString mime;
        if (!splitString(results.keyAt(i), " ", &name, &mime)) {
            continue;
        }
        AString codec =
                AStringPrintf("        <MediaCodec name=\"%s\" type=\"%s\" update=\"true\" >\n",
                              name.c_str(),
                              mime.c_str());
        ret.append(codec);
        const CodecSettings &settings = results.valueAt(i);
        for (size_t i = 0; i < settings.size(); ++i) {
            // WARNING: we assume all the settings are "Limit". Currently we have only one type
            // of setting in this case, which is "max-supported-instances".
            AString setting = AStringPrintf(
                    "            <Limit name=\"%s\" value=\"%s\" />\n",
                    settings.keyAt(i).c_str(),
                    settings.valueAt(i).c_str());
            ret.append(setting);
        }
        ret.append("        </MediaCodec>\n");
    }
    return ret;
}
TEST_F(TimedTextSRTSourceTest, readAll) {
    for (int i = 1; i <= 5; i++) {
        err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
        EXPECT_EQ(OK, err);
        CheckStartTimeMs(parcel, i * kSecToMsec);
        subtitle = AStringPrintf("%d\n\n", i);
        CheckDataEquals(parcel, subtitle.c_str());
    }
    // read edge cases
    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
    EXPECT_EQ(OK, err);
    CheckStartTimeMs(parcel, 5500);
    subtitle = AStringPrintf("6\n\n");
    CheckDataEquals(parcel, subtitle.c_str());

    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
    EXPECT_EQ(OK, err);
    CheckStartTimeMs(parcel, 5800);
    subtitle = AStringPrintf("7\n\n");
    CheckDataEquals(parcel, subtitle.c_str());

    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
    EXPECT_EQ(OK, err);
    CheckStartTimeMs(parcel, 6000);
    subtitle = AStringPrintf("8\n\n");
    CheckDataEquals(parcel, subtitle.c_str());

    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
    EXPECT_EQ(ERROR_END_OF_STREAM, err);
}
Example #3
0
status_t WifiDisplaySource::sendM4(int32_t sessionID) {
    CHECK_EQ(sessionID, mClientSessionID);

    AString body;

    if (mSinkSupportsVideo) {
        body.append("wfd_video_formats: ");

        VideoFormats chosenVideoFormat;
        chosenVideoFormat.disableAll();
        chosenVideoFormat.setNativeResolution(
                mChosenVideoResolutionType, mChosenVideoResolutionIndex);
        chosenVideoFormat.setProfileLevel(
                mChosenVideoResolutionType, mChosenVideoResolutionIndex,
                mChosenVideoProfile, mChosenVideoLevel);

        body.append(chosenVideoFormat.getFormatSpec(true /* forM4Message */));
        body.append("\r\n");
    }

    if (mSinkSupportsAudio) {
        body.append(
                AStringPrintf("wfd_audio_codecs: %s\r\n",
                             (mUsingPCMAudio
                                ? "LPCM 00000002 00" // 2 ch PCM 48kHz
                                : "AAC 00000001 00")));  // 2 ch AAC 48kHz
    }

    body.append(
            AStringPrintf(
                "wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n",
                mClientInfo.mLocalIP.c_str()));

    body.append(
            AStringPrintf(
                "wfd_client_rtp_ports: %s\r\n", mWfdClientRtpPorts.c_str()));

    AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
    AppendCommonResponse(&request, mNextCSeq);

    request.append("Content-Type: text/parameters\r\n");
    request.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
    request.append("\r\n");
    request.append(body);

    status_t err =
        mNetSession->sendRequest(sessionID, request.c_str(), request.size());

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

    registerResponseHandler(
            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM4Response);

    ++mNextCSeq;

    return OK;
}
Example #4
0
status_t WifiDisplaySource::sendM16(int32_t sessionID) {
    AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
    AppendCommonResponse(&request, mNextCSeq);

    CHECK_EQ(sessionID, mClientSessionID);
    request.append(
            AStringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID));
    request.append("\r\n");  // Empty body

    status_t err =
        mNetSession->sendRequest(sessionID, request.c_str(), request.size());

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

    registerResponseHandler(
            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM16Response);

    ++mNextCSeq;

    scheduleKeepAlive(sessionID);

    return OK;
}
Example #5
0
status_t WifiDisplaySource::sendM3(int32_t sessionID) {
    AString body =
        "wfd_content_protection\r\n"
        "wfd_video_formats\r\n"
        "wfd_audio_codecs\r\n"
        "wfd_client_rtp_ports\r\n";

    AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
    AppendCommonResponse(&request, mNextCSeq);

    request.append("Content-Type: text/parameters\r\n");
    request.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
    request.append("\r\n");
    request.append(body);

    status_t err =
        mNetSession->sendRequest(sessionID, request.c_str(), request.size());

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

    registerResponseHandler(
            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM3Response);

    ++mNextCSeq;

    return OK;
}
AString getProfilingVersionString() {
    char val[PROPERTY_VALUE_MAX];
    if (property_get("ro.build.display.id", val, NULL) && (strlen(val) > 0)) {
        return AStringPrintf("<!-- Profiled-with: %s -->", val);
    }

    return "<!-- Profiled-with: UNKNOWN_BUILD_ID -->";
}
static AString globalResultsToXml(const CodecSettings &results) {
    AString ret;
    for (size_t i = 0; i < results.size(); ++i) {
        AString setting = AStringPrintf(
                "        <Setting name=\"%s\" value=\"%s\" />\n",
                results.keyAt(i).c_str(),
                results.valueAt(i).c_str());
        ret.append(setting);
    }
    return ret;
}
TEST_F(TimedTextSRTSourceTest, checkEdgeCase) {
    MediaSource::ReadOptions options;
    options.setSeekTo(5500 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
    EXPECT_EQ(OK, err);
    EXPECT_EQ(5500 * kMsecToUsec, startTimeUs);
    subtitle = AStringPrintf("6\n\n");
    CheckDataEquals(parcel, subtitle.c_str());

    options.setSeekTo(5800 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
    EXPECT_EQ(OK, err);
    EXPECT_EQ(5800 * kMsecToUsec, startTimeUs);
    subtitle = AStringPrintf("7\n\n");
    CheckDataEquals(parcel, subtitle.c_str());

    options.setSeekTo(6000 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
    EXPECT_EQ(OK, err);
    EXPECT_EQ(6000 * kMsecToUsec, startTimeUs);
    subtitle = AStringPrintf("8\n\n");
    CheckDataEquals(parcel, subtitle.c_str());
}
Example #9
0
// static
void WifiDisplaySource::AppendCommonResponse(
        AString *response, int32_t cseq, int32_t playbackSessionID) {
    time_t now = time(NULL);
    struct tm *now2 = gmtime(&now);
    char buf[128];
    strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2);

    response->append("Date: ");
    response->append(buf);
    response->append("\r\n");

    response->append(AStringPrintf("Server: %s\r\n", sUserAgent.c_str()));

    if (cseq >= 0) {
        response->append(AStringPrintf("CSeq: %d\r\n", cseq));
    }

    if (playbackSessionID >= 0ll) {
        response->append(
                AStringPrintf(
                    "Session: %d;timeout=%lld\r\n",
                    playbackSessionID, kPlaybackSessionTimeoutSecs));
    }
}
Example #10
0
status_t WifiDisplaySource::sendTrigger(
        int32_t sessionID, TriggerType triggerType) {
    AString body = "wfd_trigger_method: ";
    switch (triggerType) {
        case TRIGGER_SETUP:
            body.append("SETUP");
            break;
        case TRIGGER_TEARDOWN:
            ALOGI("Sending TEARDOWN trigger.");
            body.append("TEARDOWN");
            break;
        case TRIGGER_PAUSE:
            body.append("PAUSE");
            break;
        case TRIGGER_PLAY:
            body.append("PLAY");
            break;
        default:
            TRESPASS();
    }

    body.append("\r\n");

    AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
    AppendCommonResponse(&request, mNextCSeq);

    request.append("Content-Type: text/parameters\r\n");
    request.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
    request.append("\r\n");
    request.append(body);

    status_t err =
        mNetSession->sendRequest(sessionID, request.c_str(), request.size());

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

    registerResponseHandler(
            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM5Response);

    ++mNextCSeq;

    return OK;
}
Example #11
0
status_t WifiDisplaySource::onSetupRequest(
        int32_t sessionID,
        int32_t cseq,
        const sp<ParsedMessage> &data) {
    CHECK_EQ(sessionID, mClientSessionID);
    if (mClientInfo.mPlaybackSessionID != -1) {
        // We only support a single playback session per client.
        // This is due to the reversed keep-alive design in the wfd specs...
        sendErrorResponse(sessionID, "400 Bad Request", cseq);
        return ERROR_MALFORMED;
    }

    AString transport;
    if (!data->findString("transport", &transport)) {
        sendErrorResponse(sessionID, "400 Bad Request", cseq);
        return ERROR_MALFORMED;
    }

    RTPSender::TransportMode rtpMode = RTPSender::TRANSPORT_UDP;

    int clientRtp, clientRtcp;
    if (transport.startsWith("RTP/AVP/TCP;")) {
        AString interleaved;
        if (ParsedMessage::GetAttribute(
                    transport.c_str(), "interleaved", &interleaved)
                && sscanf(interleaved.c_str(), "%d-%d",
                          &clientRtp, &clientRtcp) == 2) {
            rtpMode = RTPSender::TRANSPORT_TCP_INTERLEAVED;
        } else {
            bool badRequest = false;

            AString clientPort;
            if (!ParsedMessage::GetAttribute(
                        transport.c_str(), "client_port", &clientPort)) {
                badRequest = true;
            } else if (sscanf(clientPort.c_str(), "%d-%d",
                              &clientRtp, &clientRtcp) == 2) {
            } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
                // No RTCP.
                clientRtcp = -1;
            } else {
                badRequest = true;
            }

            if (badRequest) {
                sendErrorResponse(sessionID, "400 Bad Request", cseq);
                return ERROR_MALFORMED;
            }

            rtpMode = RTPSender::TRANSPORT_TCP;
        }
    } else if (transport.startsWith("RTP/AVP;unicast;")
            || transport.startsWith("RTP/AVP/UDP;unicast;")) {
        bool badRequest = false;

        AString clientPort;
        if (!ParsedMessage::GetAttribute(
                    transport.c_str(), "client_port", &clientPort)) {
            badRequest = true;
        } else if (sscanf(clientPort.c_str(), "%d-%d",
                          &clientRtp, &clientRtcp) == 2) {
        } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
            // No RTCP.
            clientRtcp = -1;
        } else {
            badRequest = true;
        }

        if (badRequest) {
            sendErrorResponse(sessionID, "400 Bad Request", cseq);
            return ERROR_MALFORMED;
        }
#if 1
    // The older LG dongles doesn't specify client_port=xxx apparently.
    } else if (transport == "RTP/AVP/UDP;unicast") {
        clientRtp = 19000;
        clientRtcp = -1;
#endif
    } else {
        sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);
        return ERROR_UNSUPPORTED;
    }

    int32_t playbackSessionID = makeUniquePlaybackSessionID();

    sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, this);
    notify->setInt32("playbackSessionID", playbackSessionID);
    notify->setInt32("sessionID", sessionID);

    sp<PlaybackSession> playbackSession =
        new PlaybackSession(
                mOpPackageName, mNetSession, notify, mInterfaceAddr, mHDCP, mMediaPath.c_str());

    looper()->registerHandler(playbackSession);

    AString uri;
    data->getRequestField(1, &uri);

    if (strncasecmp("rtsp://", uri.c_str(), 7)) {
        sendErrorResponse(sessionID, "400 Bad Request", cseq);
        return ERROR_MALFORMED;
    }

    if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) {
        sendErrorResponse(sessionID, "404 Not found", cseq);
        return ERROR_MALFORMED;
    }

    RTPSender::TransportMode rtcpMode = RTPSender::TRANSPORT_UDP;
    if (clientRtcp < 0) {
        rtcpMode = RTPSender::TRANSPORT_NONE;
    }

    status_t err = playbackSession->init(
            mClientInfo.mRemoteIP.c_str(),
            clientRtp,
            rtpMode,
            clientRtcp,
            rtcpMode,
            mSinkSupportsAudio,
            mUsingPCMAudio,
            mSinkSupportsVideo,
            mChosenVideoResolutionType,
            mChosenVideoResolutionIndex,
            mChosenVideoProfile,
            mChosenVideoLevel);

    if (err != OK) {
        looper()->unregisterHandler(playbackSession->id());
        playbackSession.clear();
    }

    switch (err) {
        case OK:
            break;
        case -ENOENT:
            sendErrorResponse(sessionID, "404 Not Found", cseq);
            return err;
        default:
            sendErrorResponse(sessionID, "403 Forbidden", cseq);
            return err;
    }

    mClientInfo.mPlaybackSessionID = playbackSessionID;
    mClientInfo.mPlaybackSession = playbackSession;

    AString response = "RTSP/1.0 200 OK\r\n";
    AppendCommonResponse(&response, cseq, playbackSessionID);

    if (rtpMode == RTPSender::TRANSPORT_TCP_INTERLEAVED) {
        response.append(
                AStringPrintf(
                    "Transport: RTP/AVP/TCP;interleaved=%d-%d;",
                    clientRtp, clientRtcp));
    } else {
        int32_t serverRtp = playbackSession->getRTPPort();

        AString transportString = "UDP";
        if (rtpMode == RTPSender::TRANSPORT_TCP) {
            transportString = "TCP";
        }

        if (clientRtcp >= 0) {
            response.append(
                    AStringPrintf(
                        "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;"
                        "server_port=%d-%d\r\n",
                        transportString.c_str(),
                        clientRtp, clientRtcp, serverRtp, serverRtp + 1));
        } else {
            response.append(
                    AStringPrintf(
                        "Transport: RTP/AVP/%s;unicast;client_port=%d;"
                        "server_port=%d\r\n",
                        transportString.c_str(),
                        clientRtp, serverRtp));
        }
    }

    response.append("\r\n");

    err = mNetSession->sendRequest(sessionID, response.c_str());

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

    mState = AWAITING_CLIENT_PLAY;

    scheduleReaper();
    scheduleKeepAlive(sessionID);

    return OK;
}