| /** |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <VideoStreamGraphRtpRx.h> |
| #include <ImsMediaTrace.h> |
| #include <ImsMediaNetworkUtil.h> |
| #include <VideoConfig.h> |
| #include <RtpDecoderNode.h> |
| #include <SocketReaderNode.h> |
| #include <VideoRtpPayloadDecoderNode.h> |
| #include <IVideoRendererNode.h> |
| |
| VideoStreamGraphRtpRx::VideoStreamGraphRtpRx(BaseSessionCallback* callback, int localFd) : |
| VideoStreamGraph(callback, localFd) |
| { |
| mSurface = nullptr; |
| } |
| |
| VideoStreamGraphRtpRx::~VideoStreamGraphRtpRx() {} |
| |
| ImsMediaResult VideoStreamGraphRtpRx::create(RtpConfig* config) |
| { |
| IMLOGI1("[create] state[%d]", mGraphState); |
| |
| if (config == nullptr) |
| { |
| return RESULT_INVALID_PARAM; |
| } |
| |
| mConfig = new VideoConfig(reinterpret_cast<VideoConfig*>(config)); |
| |
| char localIp[MAX_IP_LEN]; |
| uint32_t localPort = 0; |
| ImsMediaNetworkUtil::getLocalIpPortFromSocket(mLocalFd, localIp, MAX_IP_LEN, localPort); |
| RtpAddress localAddress(localIp, localPort); |
| |
| BaseNode* pNodeSocketReader = new SocketReaderNode(mCallback); |
| pNodeSocketReader->SetMediaType(IMS_MEDIA_VIDEO); |
| (static_cast<SocketReaderNode*>(pNodeSocketReader))->SetLocalFd(mLocalFd); |
| (static_cast<SocketReaderNode*>(pNodeSocketReader))->SetLocalAddress(localAddress); |
| (static_cast<SocketReaderNode*>(pNodeSocketReader))->SetProtocolType(kProtocolRtp); |
| pNodeSocketReader->SetConfig(config); |
| AddNode(pNodeSocketReader); |
| |
| BaseNode* pNodeRtpDecoder = new RtpDecoderNode(mCallback); |
| pNodeRtpDecoder->SetMediaType(IMS_MEDIA_VIDEO); |
| pNodeRtpDecoder->SetConfig(mConfig); |
| (static_cast<RtpDecoderNode*>(pNodeRtpDecoder))->SetLocalAddress(localAddress); |
| AddNode(pNodeRtpDecoder); |
| pNodeSocketReader->ConnectRearNode(pNodeRtpDecoder); |
| |
| BaseNode* pNodeRtpPayloadDecoder = new VideoRtpPayloadDecoderNode(mCallback); |
| pNodeRtpPayloadDecoder->SetMediaType(IMS_MEDIA_VIDEO); |
| pNodeRtpPayloadDecoder->SetConfig(mConfig); |
| AddNode(pNodeRtpPayloadDecoder); |
| pNodeRtpDecoder->ConnectRearNode(pNodeRtpPayloadDecoder); |
| |
| BaseNode* pNodeRenderer = new IVideoRendererNode(mCallback); |
| pNodeRenderer->SetMediaType(IMS_MEDIA_VIDEO); |
| pNodeRenderer->SetConfig(mConfig); |
| AddNode(pNodeRenderer); |
| pNodeRtpPayloadDecoder->ConnectRearNode(pNodeRenderer); |
| setState(StreamState::kStreamStateCreated); |
| return RESULT_SUCCESS; |
| } |
| |
| ImsMediaResult VideoStreamGraphRtpRx::update(RtpConfig* config) |
| { |
| IMLOGI1("[update] state[%d]", mGraphState); |
| |
| if (config == nullptr) |
| { |
| return RESULT_INVALID_PARAM; |
| } |
| |
| VideoConfig* pConfig = reinterpret_cast<VideoConfig*>(config); |
| |
| if (*reinterpret_cast<VideoConfig*>(mConfig) == *pConfig) |
| { |
| IMLOGD0("[update] no update"); |
| return RESULT_SUCCESS; |
| } |
| |
| if (mGraphState == kStreamStateWaitSurface) |
| { |
| setState(StreamState::kStreamStateCreated); |
| } |
| |
| if (mConfig != nullptr) |
| { |
| delete mConfig; |
| mConfig = nullptr; |
| } |
| |
| mConfig = new VideoConfig(pConfig); |
| |
| if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW || |
| mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY || |
| mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_INACTIVE) |
| { |
| IMLOGI0("[update] pause RX"); |
| return stop(); |
| } |
| |
| ImsMediaResult ret = RESULT_NOT_READY; |
| |
| if (mGraphState == kStreamStateRunning) |
| { |
| mScheduler->Stop(); |
| |
| for (auto& node : mListNodeStarted) |
| { |
| if (node != nullptr) |
| { |
| IMLOGD1("[update] update node[%s]", node->GetNodeName()); |
| ret = node->UpdateConfig(mConfig); |
| if (ret != RESULT_SUCCESS) |
| { |
| IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret); |
| } |
| } |
| } |
| |
| mScheduler->Start(); |
| } |
| else if (mGraphState == kStreamStateCreated) |
| { |
| for (auto& node : mListNodeToStart) |
| { |
| if (node != nullptr) |
| { |
| IMLOGD1("[update] update node[%s]", node->GetNodeName()); |
| ret = node->UpdateConfig(mConfig); |
| |
| if (ret != RESULT_SUCCESS) |
| { |
| IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret); |
| } |
| } |
| } |
| } |
| |
| if (mGraphState == kStreamStateCreated && |
| (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY || |
| pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE)) |
| { |
| IMLOGI0("[update] resume RX"); |
| return start(); |
| } |
| |
| return ret; |
| } |
| |
| ImsMediaResult VideoStreamGraphRtpRx::start() |
| { |
| IMLOGI1("[start] state[%d]", mGraphState); |
| |
| if (mConfig == nullptr) |
| { |
| return RESULT_INVALID_PARAM; |
| } |
| |
| VideoConfig* pConfig = reinterpret_cast<VideoConfig*>(mConfig); |
| |
| if (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW || |
| pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY || |
| mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_INACTIVE) |
| { |
| IMLOGI1("[start] direction[%d] no need to start", pConfig->getMediaDirection()); |
| return RESULT_SUCCESS; |
| } |
| |
| if (mSurface == nullptr) |
| { |
| IMLOGI2("[start] direction[%d], mode[%d], surface is not ready, wait", |
| pConfig->getMediaDirection(), pConfig->getVideoMode()); |
| setState(StreamState::kStreamStateWaitSurface); |
| return RESULT_SUCCESS; |
| } |
| |
| ImsMediaResult result = startNodes(); |
| |
| if (result != RESULT_SUCCESS) |
| { |
| setState(StreamState::kStreamStateCreated); |
| mCallback->SendEvent(kImsMediaEventNotifyError, result, kStreamModeRtpRx); |
| return result; |
| } |
| |
| setState(StreamState::kStreamStateRunning); |
| return RESULT_SUCCESS; |
| } |
| |
| bool VideoStreamGraphRtpRx::setMediaQualityThreshold(MediaQualityThreshold* threshold) |
| { |
| if (threshold != nullptr) |
| { |
| BaseNode* node = findNode(kNodeIdRtpDecoder); |
| |
| if (node != nullptr) |
| { |
| RtpDecoderNode* decoder = reinterpret_cast<RtpDecoderNode*>(node); |
| decoder->SetInactivityTimerSec(threshold->getRtpInactivityTimerMillis().empty() |
| ? 0 |
| : threshold->getRtpInactivityTimerMillis().front() / 1000); |
| return true; |
| } |
| |
| node = findNode(kNodeIdVideoRenderer); |
| |
| if (node != nullptr) |
| { |
| IVideoRendererNode* decoder = reinterpret_cast<IVideoRendererNode*>(node); |
| decoder->SetPacketLossParam(threshold->getRtpPacketLossDurationMillis(), |
| threshold->getRtpPacketLossRate().empty() |
| ? 0 |
| : threshold->getRtpPacketLossRate().front()); |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| void VideoStreamGraphRtpRx::setSurface(ANativeWindow* surface) |
| { |
| IMLOGD0("[setSurface]"); |
| |
| if (surface != nullptr) |
| { |
| mSurface = surface; |
| |
| BaseNode* node = findNode(kNodeIdVideoRenderer); |
| |
| if (node != nullptr) |
| { |
| IVideoRendererNode* renderer = reinterpret_cast<IVideoRendererNode*>(node); |
| renderer->UpdateSurface(surface); |
| |
| if (getState() == StreamState::kStreamStateWaitSurface) |
| { |
| setState(StreamState::kStreamStateCreated); |
| start(); |
| } |
| } |
| } |
| } |
| |
| bool VideoStreamGraphRtpRx::OnEvent(int32_t type, uint64_t param1, uint64_t param2) |
| { |
| IMLOGI3("[OnEvent] type[%d], param1[%d], param2[%d]", type, param1, param2); |
| |
| switch (type) |
| { |
| case kRequestRoundTripTimeDelayUpdate: |
| { |
| BaseNode* node = findNode(kNodeIdVideoRenderer); |
| |
| if (node != nullptr) |
| { |
| IVideoRendererNode* pNode = reinterpret_cast<IVideoRendererNode*>(node); |
| pNode->UpdateRoundTripTimeDelay(param1); |
| return true; |
| } |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return false; |
| } |