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 BnMediaPlayerService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case CREATE: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder()); int audioSessionId = data.readInt32(); sp<IMediaPlayer> player = create(client, audioSessionId); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; case DECODE_URL: { CHECK_INTERFACE(IMediaPlayerService, data, reply); const char* url = data.readCString(); uint32_t sampleRate; int numChannels; audio_format_t format; sp<IMemory> player = decode(url, &sampleRate, &numChannels, &format); reply->writeInt32(sampleRate); reply->writeInt32(numChannels); reply->writeInt32((int32_t) format); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; case DECODE_FD: { CHECK_INTERFACE(IMediaPlayerService, data, reply); int fd = dup(data.readFileDescriptor()); int64_t offset = data.readInt64(); int64_t length = data.readInt64(); uint32_t sampleRate; int numChannels; audio_format_t format; sp<IMemory> player = decode(fd, offset, length, &sampleRate, &numChannels, &format); reply->writeInt32(sampleRate); reply->writeInt32(numChannels); reply->writeInt32((int32_t) format); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; case CREATE_MEDIA_RECORDER: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IMediaRecorder> recorder = createMediaRecorder(); reply->writeStrongBinder(recorder->asBinder()); return NO_ERROR; } break; case CREATE_METADATA_RETRIEVER: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IMediaMetadataRetriever> retriever = createMetadataRetriever(); reply->writeStrongBinder(retriever->asBinder()); return NO_ERROR; } break; case GET_OMX: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IOMX> omx = getOMX(); reply->writeStrongBinder(omx->asBinder()); return NO_ERROR; } break; case MAKE_CRYPTO: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<ICrypto> crypto = makeCrypto(); reply->writeStrongBinder(crypto->asBinder()); return NO_ERROR; } break; case MAKE_DRM: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IDrm> drm = makeDrm(); reply->writeStrongBinder(drm->asBinder()); return NO_ERROR; } break; case MAKE_HDCP: { CHECK_INTERFACE(IMediaPlayerService, data, reply); bool createEncryptionModule = data.readInt32(); sp<IHDCP> hdcp = makeHDCP(createEncryptionModule); reply->writeStrongBinder(hdcp->asBinder()); return NO_ERROR; } break; case ADD_BATTERY_DATA: { CHECK_INTERFACE(IMediaPlayerService, data, reply); uint32_t params = data.readInt32(); addBatteryData(params); return NO_ERROR; } break; case PULL_BATTERY_DATA: { CHECK_INTERFACE(IMediaPlayerService, data, reply); pullBatteryData(reply); return NO_ERROR; } break; case LISTEN_FOR_REMOTE_DISPLAY: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IRemoteDisplayClient> client( interface_cast<IRemoteDisplayClient>(data.readStrongBinder())); String8 iface(data.readString8()); sp<IRemoteDisplay> display(listenForRemoteDisplay(client, iface)); reply->writeStrongBinder(display->asBinder()); return NO_ERROR; } break; case UPDATE_PROXY_CONFIG: { CHECK_INTERFACE(IMediaPlayerService, data, reply); const char *host = NULL; int32_t port = 0; const char *exclusionList = NULL; if (data.readInt32()) { host = data.readCString(); port = data.readInt32(); exclusionList = data.readCString(); } reply->writeInt32(updateProxyConfig(host, port, exclusionList)); return OK; } default: return BBinder::onTransact(code, data, reply, flags); } }
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); }