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); }