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 <TextStreamGraphRtpTx.h>
18 #include <ImsMediaTrace.h>
19 #include <ImsMediaNetworkUtil.h>
20 #include <TextConfig.h>
21 #include <RtpEncoderNode.h>
22 #include <SocketWriterNode.h>
23 #include <TextRtpPayloadEncoderNode.h>
24 #include <TextSourceNode.h>
25 
TextStreamGraphRtpTx(BaseSessionCallback * callback,int localFd)26 TextStreamGraphRtpTx::TextStreamGraphRtpTx(BaseSessionCallback* callback, int localFd) :
27         TextStreamGraph(callback, localFd)
28 {
29 }
30 
~TextStreamGraphRtpTx()31 TextStreamGraphRtpTx::~TextStreamGraphRtpTx() {}
32 
create(RtpConfig * config)33 ImsMediaResult TextStreamGraphRtpTx::create(RtpConfig* config)
34 {
35     IMLOGI1("[create] state[%d]", mGraphState);
36 
37     if (config == nullptr)
38     {
39         return RESULT_INVALID_PARAM;
40     }
41 
42     TextConfig* pConfig = reinterpret_cast<TextConfig*>(config);
43 
44     if (mConfig != nullptr)
45     {
46         delete mConfig;
47         mConfig = nullptr;
48     }
49 
50     mConfig = new TextConfig(pConfig);
51 
52     char localIp[MAX_IP_LEN];
53     uint32_t localPort = 0;
54     ImsMediaNetworkUtil::getLocalIpPortFromSocket(mLocalFd, localIp, MAX_IP_LEN, localPort);
55     RtpAddress localAddress(localIp, localPort);
56 
57     BaseNode* pNodeSource = new TextSourceNode(mCallback);
58     pNodeSource->SetMediaType(IMS_MEDIA_TEXT);
59     pNodeSource->SetConfig(mConfig);
60     AddNode(pNodeSource);
61 
62     BaseNode* pNodeRtpPayloadEncoder = new TextRtpPayloadEncoderNode(mCallback);
63     pNodeRtpPayloadEncoder->SetMediaType(IMS_MEDIA_TEXT);
64     pNodeRtpPayloadEncoder->SetConfig(mConfig);
65     AddNode(pNodeRtpPayloadEncoder);
66     pNodeSource->ConnectRearNode(pNodeRtpPayloadEncoder);
67 
68     BaseNode* pNodeRtpEncoder = new RtpEncoderNode(mCallback);
69     pNodeRtpEncoder->SetMediaType(IMS_MEDIA_TEXT);
70     pNodeRtpEncoder->SetConfig(mConfig);
71     (static_cast<RtpEncoderNode*>(pNodeRtpEncoder))->SetLocalAddress(localAddress);
72     AddNode(pNodeRtpEncoder);
73     pNodeRtpPayloadEncoder->ConnectRearNode(pNodeRtpEncoder);
74 
75     BaseNode* pNodeSocketWriter = new SocketWriterNode(mCallback);
76     pNodeSocketWriter->SetMediaType(IMS_MEDIA_TEXT);
77     (static_cast<SocketWriterNode*>(pNodeSocketWriter))->SetLocalFd(mLocalFd);
78     (static_cast<SocketWriterNode*>(pNodeSocketWriter))->SetLocalAddress(localAddress);
79     (static_cast<SocketWriterNode*>(pNodeSocketWriter))->SetProtocolType(kProtocolRtp);
80     pNodeSocketWriter->SetConfig(config);
81     AddNode(pNodeSocketWriter);
82     pNodeRtpEncoder->ConnectRearNode(pNodeSocketWriter);
83 
84     setState(StreamState::kStreamStateCreated);
85     return RESULT_SUCCESS;
86 }
87 
update(RtpConfig * config)88 ImsMediaResult TextStreamGraphRtpTx::update(RtpConfig* config)
89 {
90     IMLOGI1("[update] state[%d]", mGraphState);
91 
92     if (config == nullptr)
93     {
94         return RESULT_INVALID_PARAM;
95     }
96 
97     TextConfig* pConfig = reinterpret_cast<TextConfig*>(config);
98 
99     if (*mConfig == *pConfig)
100     {
101         IMLOGI0("[update] no update");
102         return RESULT_SUCCESS;
103     }
104 
105     if (mConfig != nullptr)
106     {
107         delete mConfig;
108         mConfig = nullptr;
109     }
110 
111     ImsMediaResult ret = RESULT_NOT_READY;
112 
113     mConfig = new TextConfig(pConfig);
114 
115     if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW ||
116             mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY ||
117             mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_INACTIVE)
118     {
119         IMLOGI0("[update] pause TX");
120 
121         RtpContextParams rtpContextParams = config->getRtpContextParams();
122         int32_t accessNetwork = pConfig->getAccessNetwork();
123         // TODO: #include <aidl/android/hardware/radio/AccessNetwork.h>
124         if (accessNetwork != 5 &&
125                 mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW)
126         {
127             for (auto& node : mListNodeStarted)
128             {
129                 if (node != nullptr && node->GetNodeId() == kNodeIdRtpEncoder)
130                 {
131                     reinterpret_cast<RtpEncoderNode*>(node)->GetRtpContext(rtpContextParams);
132                     pConfig->setRtpContextParams(rtpContextParams);
133                 }
134             }
135         }
136         return stop();
137     }
138 
139     ret = RESULT_NOT_READY;
140 
141     if (mGraphState == kStreamStateRunning)
142     {
143         mScheduler->Stop();
144 
145         for (auto& node : mListNodeStarted)
146         {
147             if (node != nullptr)
148             {
149                 IMLOGD1("[update] update node[%s]", node->GetNodeName());
150                 ret = node->UpdateConfig(mConfig);
151 
152                 if (ret != RESULT_SUCCESS)
153                 {
154                     IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret);
155                 }
156             }
157         }
158 
159         mScheduler->Start();
160     }
161     else if (mGraphState == kStreamStateCreated)
162     {
163         for (auto& node : mListNodeToStart)
164         {
165             if (node != nullptr)
166             {
167                 IMLOGD1("[update] update node[%s]", node->GetNodeName());
168                 ret = node->UpdateConfig(mConfig);
169 
170                 if (ret != RESULT_SUCCESS)
171                 {
172                     IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret);
173                 }
174             }
175         }
176     }
177 
178     if (mGraphState == kStreamStateCreated &&
179             (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY ||
180                     pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE))
181     {
182         IMLOGI0("[update] resume TX");
183         return start();
184     }
185 
186     return ret;
187 }
188 
start()189 ImsMediaResult TextStreamGraphRtpTx::start()
190 {
191     IMLOGI1("[start] state[%d]", mGraphState);
192 
193     if (mConfig == nullptr)
194     {
195         return RESULT_INVALID_PARAM;
196     }
197 
198     TextConfig* pConfig = reinterpret_cast<TextConfig*>(mConfig);
199 
200     if (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW ||
201             pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY ||
202             pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_INACTIVE)
203     {
204         IMLOGI1("[start] direction[%d] no need to start", pConfig->getMediaDirection());
205         return RESULT_SUCCESS;
206     }
207 
208     ImsMediaResult result = startNodes();
209 
210     if (result != RESULT_SUCCESS)
211     {
212         setState(StreamState::kStreamStateCreated);
213         mCallback->SendEvent(kImsMediaEventNotifyError, result, kStreamModeRtpTx);
214         return result;
215     }
216 
217     setState(StreamState::kStreamStateRunning);
218     return RESULT_SUCCESS;
219 }
220 
sendRtt(const android::String8 * text)221 bool TextStreamGraphRtpTx::sendRtt(const android::String8* text)
222 {
223     IMLOGD1("[sendRtt], state[%d]", mGraphState);
224     TextSourceNode* node = nullptr;
225 
226     if (!mListNodeStarted.empty())
227     {
228         node = reinterpret_cast<TextSourceNode*>(mListNodeStarted.front());
229     }
230 
231     if (node != nullptr)
232     {
233         node->SendRtt(text);
234         return true;
235     }
236 
237     return false;
238 }