1 /**
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <TextStreamGraphRtpRx.h>
18 #include <ImsMediaTrace.h>
19 #include <ImsMediaNetworkUtil.h>
20 #include <TextConfig.h>
21 #include <RtpDecoderNode.h>
22 #include <SocketReaderNode.h>
23 #include <TextRtpPayloadDecoderNode.h>
24 #include <TextRendererNode.h>
25 
TextStreamGraphRtpRx(BaseSessionCallback * callback,int localFd)26 TextStreamGraphRtpRx::TextStreamGraphRtpRx(BaseSessionCallback* callback, int localFd) :
27         TextStreamGraph(callback, localFd)
28 {
29 }
30 
~TextStreamGraphRtpRx()31 TextStreamGraphRtpRx::~TextStreamGraphRtpRx() {}
32 
create(RtpConfig * config)33 ImsMediaResult TextStreamGraphRtpRx::create(RtpConfig* config)
34 {
35     IMLOGI1("[create] state[%d]", mGraphState);
36 
37     if (config == nullptr)
38     {
39         return RESULT_INVALID_PARAM;
40     }
41 
42     mConfig = new TextConfig(reinterpret_cast<TextConfig*>(config));
43 
44     char localIp[MAX_IP_LEN];
45     uint32_t localPort = 0;
46     ImsMediaNetworkUtil::getLocalIpPortFromSocket(mLocalFd, localIp, MAX_IP_LEN, localPort);
47     RtpAddress localAddress(localIp, localPort);
48 
49     BaseNode* nodeSocketReader = new SocketReaderNode(mCallback);
50     nodeSocketReader->SetMediaType(IMS_MEDIA_TEXT);
51     (static_cast<SocketReaderNode*>(nodeSocketReader))->SetLocalFd(mLocalFd);
52     (static_cast<SocketReaderNode*>(nodeSocketReader))->SetLocalAddress(localAddress);
53     (static_cast<SocketReaderNode*>(nodeSocketReader))->SetProtocolType(kProtocolRtp);
54     nodeSocketReader->SetConfig(config);
55     AddNode(nodeSocketReader);
56 
57     BaseNode* nodeRtpDecoder = new RtpDecoderNode(mCallback);
58     nodeRtpDecoder->SetMediaType(IMS_MEDIA_TEXT);
59     nodeRtpDecoder->SetConfig(mConfig);
60     (static_cast<RtpDecoderNode*>(nodeRtpDecoder))->SetLocalAddress(localAddress);
61     AddNode(nodeRtpDecoder);
62     nodeSocketReader->ConnectRearNode(nodeRtpDecoder);
63 
64     BaseNode* rtpPayloadDecoder = new TextRtpPayloadDecoderNode(mCallback);
65     rtpPayloadDecoder->SetMediaType(IMS_MEDIA_TEXT);
66     rtpPayloadDecoder->SetConfig(mConfig);
67     rtpPayloadDecoder->SetSchedulerCallback(
68             std::static_pointer_cast<StreamSchedulerCallback>(mScheduler));
69     AddNode(rtpPayloadDecoder);
70     nodeRtpDecoder->ConnectRearNode(rtpPayloadDecoder);
71 
72     BaseNode* renderer = new TextRendererNode(mCallback);
73     renderer->SetMediaType(IMS_MEDIA_TEXT);
74     renderer->SetConfig(mConfig);
75     renderer->SetSchedulerCallback(std::static_pointer_cast<StreamSchedulerCallback>(mScheduler));
76     AddNode(renderer);
77     rtpPayloadDecoder->ConnectRearNode(renderer);
78     setState(StreamState::kStreamStateCreated);
79     return RESULT_SUCCESS;
80 }
81 
update(RtpConfig * config)82 ImsMediaResult TextStreamGraphRtpRx::update(RtpConfig* config)
83 {
84     IMLOGI1("[update] state[%d]", mGraphState);
85 
86     if (config == nullptr)
87     {
88         return RESULT_INVALID_PARAM;
89     }
90 
91     TextConfig* pConfig = reinterpret_cast<TextConfig*>(config);
92 
93     if (*mConfig == *pConfig)
94     {
95         IMLOGI0("[update] no update");
96         return RESULT_SUCCESS;
97     }
98 
99     if (mConfig != nullptr)
100     {
101         delete mConfig;
102         mConfig = nullptr;
103     }
104 
105     mConfig = new TextConfig(pConfig);
106 
107     if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW ||
108             mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY ||
109             mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_INACTIVE)
110     {
111         IMLOGI0("[update] pause RX");
112         return stop();
113     }
114 
115     ImsMediaResult ret = RESULT_NOT_READY;
116 
117     if (mGraphState == kStreamStateRunning)
118     {
119         mScheduler->Stop();
120 
121         for (auto& node : mListNodeStarted)
122         {
123             if (node != nullptr)
124             {
125                 IMLOGD1("[update] update node[%s]", node->GetNodeName());
126                 ret = node->UpdateConfig(mConfig);
127                 if (ret != RESULT_SUCCESS)
128                 {
129                     IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret);
130                 }
131             }
132         }
133 
134         mScheduler->Start();
135     }
136     else if (mGraphState == kStreamStateCreated)
137     {
138         for (auto& node : mListNodeToStart)
139         {
140             if (node != nullptr)
141             {
142                 IMLOGD1("[update] update node[%s]", node->GetNodeName());
143                 ret = node->UpdateConfig(mConfig);
144 
145                 if (ret != RESULT_SUCCESS)
146                 {
147                     IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret);
148                 }
149             }
150         }
151     }
152 
153     if (mGraphState == kStreamStateCreated &&
154             (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY ||
155                     pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE))
156     {
157         IMLOGI0("[update] resume RX");
158         return start();
159     }
160 
161     return ret;
162 }
163 
start()164 ImsMediaResult TextStreamGraphRtpRx::start()
165 {
166     IMLOGD1("[start] state[%d]", mGraphState);
167 
168     if (mConfig == nullptr)
169     {
170         return RESULT_INVALID_PARAM;
171     }
172 
173     TextConfig* pConfig = reinterpret_cast<TextConfig*>(mConfig);
174 
175     if (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW ||
176             pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY ||
177             mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_INACTIVE)
178     {
179         IMLOGI1("[start] direction[%d] no need to start", pConfig->getMediaDirection());
180         return RESULT_SUCCESS;
181     }
182 
183     ImsMediaResult result = startNodes();
184 
185     if (result != RESULT_SUCCESS)
186     {
187         setState(StreamState::kStreamStateCreated);
188         mCallback->SendEvent(kImsMediaEventNotifyError, result, kStreamModeRtpRx);
189         return result;
190     }
191 
192     setState(StreamState::kStreamStateRunning);
193     return RESULT_SUCCESS;
194 }
195 
setMediaQualityThreshold(MediaQualityThreshold * threshold)196 bool TextStreamGraphRtpRx::setMediaQualityThreshold(MediaQualityThreshold* threshold)
197 {
198     if (threshold != nullptr)
199     {
200         BaseNode* node = findNode(kNodeIdRtpDecoder);
201 
202         if (node != nullptr)
203         {
204             RtpDecoderNode* decoder = reinterpret_cast<RtpDecoderNode*>(node);
205             decoder->SetInactivityTimerSec(threshold->getRtpInactivityTimerMillis().empty()
206                             ? 0
207                             : threshold->getRtpInactivityTimerMillis().front() / 1000);
208             return true;
209         }
210     }
211 
212     return false;
213 }