Example #1
0
status_t WifiDisplaySource::onSetParameterRequest(
        int32_t sessionID,
        int32_t cseq,
        const sp<ParsedMessage> &data) {
    int32_t playbackSessionID;
    sp<PlaybackSession> playbackSession =
        findPlaybackSession(data, &playbackSessionID);

    if (playbackSession == NULL) {
        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
        return ERROR_MALFORMED;
    }

    if (strstr(data->getContent(), "wfd_idr_request\r\n")) {
        playbackSession->requestIDRFrame();
    }

    playbackSession->updateLiveness();

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

    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
    return err;
}
Example #2
0
status_t WifiDisplaySource::onReceiveM3Response(
        int32_t sessionID, const sp<ParsedMessage> &msg) {
    int32_t statusCode;
    if (!msg->getStatusCode(&statusCode)) {
        return ERROR_MALFORMED;
    }

    if (statusCode != 200) {
        return ERROR_UNSUPPORTED;
    }

    sp<Parameters> params =
        Parameters::Parse(msg->getContent(), strlen(msg->getContent()));

    if (params == NULL) {
        return ERROR_MALFORMED;
    }

    AString value;
    if (!params->findParameter("wfd_client_rtp_ports", &value)) {
        ALOGE("Sink doesn't report its choice of wfd_client_rtp_ports.");
        return ERROR_MALFORMED;
    }

    unsigned port0 = 0, port1 = 0;
    if (sscanf(value.c_str(),
               "RTP/AVP/UDP;unicast %u %u mode=play",
               &port0,
               &port1) == 2
        || sscanf(value.c_str(),
               "RTP/AVP/TCP;unicast %u %u mode=play",
               &port0,
               &port1) == 2) {
            if (port0 == 0 || port0 > 65535 || port1 != 0) {
                ALOGE("Sink chose its wfd_client_rtp_ports poorly (%s)",
                      value.c_str());

                return ERROR_MALFORMED;
            }
    } else if (strcmp(value.c_str(), "RTP/AVP/TCP;interleaved mode=play")) {
        ALOGE("Unsupported value for wfd_client_rtp_ports (%s)",
              value.c_str());

        return ERROR_UNSUPPORTED;
    }

    mWfdClientRtpPorts = value;
    mChosenRTPPort = port0;

    if (!params->findParameter("wfd_video_formats", &value)) {
        ALOGE("Sink doesn't report its choice of wfd_video_formats.");
        return ERROR_MALFORMED;
    }

    mSinkSupportsVideo = false;

    if  (!(value == "none")) {
        mSinkSupportsVideo = true;
        if (!mSupportedSinkVideoFormats.parseFormatSpec(value.c_str())) {
            ALOGE("Failed to parse sink provided wfd_video_formats (%s)",
                  value.c_str());

            return ERROR_MALFORMED;
        }

        if (!VideoFormats::PickBestFormat(
                    mSupportedSinkVideoFormats,
                    mSupportedSourceVideoFormats,
                    &mChosenVideoResolutionType,
                    &mChosenVideoResolutionIndex,
                    &mChosenVideoProfile,
                    &mChosenVideoLevel)) {
            ALOGE("Sink and source share no commonly supported video "
                  "formats.");

            return ERROR_UNSUPPORTED;
        }

        size_t width, height, framesPerSecond;
        bool interlaced;
        CHECK(VideoFormats::GetConfiguration(
                    mChosenVideoResolutionType,
                    mChosenVideoResolutionIndex,
                    &width,
                    &height,
                    &framesPerSecond,
                    &interlaced));

        ALOGI("Picked video resolution %zu x %zu %c%zu",
              width, height, interlaced ? 'i' : 'p', framesPerSecond);

        ALOGI("Picked AVC profile %d, level %d",
              mChosenVideoProfile, mChosenVideoLevel);
    } else {
        ALOGI("Sink doesn't support video at all.");
    }

    if (!params->findParameter("wfd_audio_codecs", &value)) {
        ALOGE("Sink doesn't report its choice of wfd_audio_codecs.");
        return ERROR_MALFORMED;
    }

    mSinkSupportsAudio = false;

    if  (!(value == "none")) {
        mSinkSupportsAudio = true;

        uint32_t modes;
        GetAudioModes(value.c_str(), "AAC", &modes);

        bool supportsAAC = (modes & 1) != 0;  // AAC 2ch 48kHz

        GetAudioModes(value.c_str(), "LPCM", &modes);

        bool supportsPCM = (modes & 2) != 0;  // LPCM 2ch 48kHz

        if (supportsPCM
                && property_get_bool("media.wfd.use-pcm-audio", false)) {
            ALOGI("Using PCM audio.");
            mUsingPCMAudio = true;
        } else if (supportsAAC) {
            ALOGI("Using AAC audio.");
            mUsingPCMAudio = false;
        } else if (supportsPCM) {
            ALOGI("Using PCM audio.");
            mUsingPCMAudio = true;
        } else {
            ALOGI("Sink doesn't support an audio format we do.");
            return ERROR_UNSUPPORTED;
        }
    } else {
        ALOGI("Sink doesn't support audio at all.");
    }

    if (!mSinkSupportsVideo && !mSinkSupportsAudio) {
        ALOGE("Sink supports neither video nor audio...");
        return ERROR_UNSUPPORTED;
    }

    mUsingHDCP = false;
    if (!params->findParameter("wfd_content_protection", &value)) {
        ALOGI("Sink doesn't appear to support content protection.");
    } else if (value == "none") {
        ALOGI("Sink does not support content protection.");
    } else {
        mUsingHDCP = true;

        bool isHDCP2_0 = false;
        if (value.startsWith("HDCP2.0 ")) {
            isHDCP2_0 = true;
        } else if (!value.startsWith("HDCP2.1 ")) {
            ALOGE("malformed wfd_content_protection: '%s'", value.c_str());

            return ERROR_MALFORMED;
        }

        int32_t hdcpPort;
        if (!ParsedMessage::GetInt32Attribute(
                    value.c_str() + 8, "port", &hdcpPort)
                || hdcpPort < 1 || hdcpPort > 65535) {
            return ERROR_MALFORMED;
        }

        mIsHDCP2_0 = isHDCP2_0;
        mHDCPPort = hdcpPort;

        status_t err = makeHDCP();
        if (err != OK) {
            ALOGE("Unable to instantiate HDCP component. "
                  "Not using HDCP after all.");

            mUsingHDCP = false;
        }
    }

    return sendM4(sessionID);
}
status_t WifiDisplaySource::onReceiveM3Response(
        int32_t sessionID, const sp<ParsedMessage> &msg) {
    int32_t statusCode;
    if (!msg->getStatusCode(&statusCode)) {
        return ERROR_MALFORMED;
    }

    if (statusCode != 200) {
        return ERROR_UNSUPPORTED;
    }

    sp<Parameters> params =
        Parameters::Parse(msg->getContent(), strlen(msg->getContent()));

    if (params == NULL) {
        return ERROR_MALFORMED;
    }

    AString value;
    if (!params->findParameter("wfd_client_rtp_ports", &value)) {
        ALOGE("Sink doesn't report its choice of wfd_client_rtp_ports.");
        return ERROR_MALFORMED;
    }

    unsigned port0, port1;
    if (sscanf(value.c_str(),
               "RTP/AVP/UDP;unicast %u %u mode=play",
               &port0,
               &port1) != 2
        || port0 == 0 || port0 > 65535 || port1 != 0) {
        ALOGE("Sink chose its wfd_client_rtp_ports poorly (%s)",
              value.c_str());

        ALOGE("onReceiveM3Response() SKIP!! port check.");
        port0 = 19000;
        port1 = 0;
        //return ERROR_MALFORMED;
    }

    mChosenRTPPort = port0;

    if (!params->findParameter("wfd_audio_codecs", &value)) {
        ALOGE("Sink doesn't report its choice of wfd_audio_codecs.");
        return ERROR_MALFORMED;
    }

    if  (value == "none") {
        ALOGE("Sink doesn't support audio at all.");
        return ERROR_UNSUPPORTED;
    }

    if (value == "xxx") {
        ALOGE("onReceiveM3Response() Force Apply wfd_audio_codecs to AAC");
        value.clear();
        value.append("LPCM 00000003 00, AAC 0000000F 00");
    }

    uint32_t modes;
    GetAudioModes(value.c_str(), "AAC", &modes);

    bool supportsAAC = (modes & 1) != 0;  // AAC 2ch 48kHz

    GetAudioModes(value.c_str(), "LPCM", &modes);

    bool supportsPCM = (modes & 2) != 0;  // LPCM 2ch 48kHz

    char val[PROPERTY_VALUE_MAX];
    if (supportsPCM
            && property_get("media.wfd.use-pcm-audio", val, NULL)
            && (!strcasecmp("true", val) || !strcmp("1", val))) {
        ALOGI("Using PCM audio.");
        mUsingPCMAudio = true;
    } else if (supportsAAC) {
        ALOGI("Using AAC audio.");
        mUsingPCMAudio = false;
    } else if (supportsPCM) {
        ALOGI("Using PCM audio.");
        mUsingPCMAudio = true;
    } else {
        ALOGI("Sink doesn't support an audio format we do.");
        return ERROR_UNSUPPORTED;
    }

    mUsingHDCP = false;
    if (!params->findParameter("wfd_content_protection", &value)) {
        ALOGI("Sink doesn't appear to support content protection.");
    } else if (value == "none") {
        ALOGI("Sink does not support content protection.");
    } else {
        mUsingHDCP = true;

        bool isHDCP2_0 = false;
        if (value.startsWith("HDCP2.0 ")) {
            isHDCP2_0 = true;
        } else if (!value.startsWith("HDCP2.1 ")) {
            ALOGE("malformed wfd_content_protection: '%s'", value.c_str());

            return ERROR_MALFORMED;
        }

        int32_t hdcpPort;
        if (!ParsedMessage::GetInt32Attribute(
                    value.c_str() + 8, "port", &hdcpPort)
                || hdcpPort < 1 || hdcpPort > 65535) {
            return ERROR_MALFORMED;
        }

        mIsHDCP2_0 = isHDCP2_0;
        mHDCPPort = hdcpPort;

        status_t err = makeHDCP();
        if (err != OK) {
            ALOGE("Unable to instantiate HDCP component. "
                  "Not using HDCP after all.");

            mUsingHDCP = false;
        }
    }

    return sendM4(sessionID);
}