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 <AudioStreamGraphRtpTx.h>
18 #include <ImsMediaTrace.h>
19 #include <ImsMediaNetworkUtil.h>
20 #include <AudioConfig.h>
21 #include <IAudioSourceNode.h>
22 #include <DtmfEncoderNode.h>
23 #include <DtmfSenderNode.h>
24 #include <AudioRtpPayloadEncoderNode.h>
25 #include <RtpEncoderNode.h>
26 #include <SocketWriterNode.h>
27
AudioStreamGraphRtpTx(BaseSessionCallback * callback,int localFd)28 AudioStreamGraphRtpTx::AudioStreamGraphRtpTx(BaseSessionCallback* callback, int localFd) :
29 AudioStreamGraph(callback, localFd)
30 {
31 }
32
~AudioStreamGraphRtpTx()33 AudioStreamGraphRtpTx::~AudioStreamGraphRtpTx() {}
34
create(RtpConfig * config)35 ImsMediaResult AudioStreamGraphRtpTx::create(RtpConfig* config)
36 {
37 IMLOGI1("[create] state[%d]", mGraphState);
38
39 if (config == nullptr)
40 {
41 return RESULT_INVALID_PARAM;
42 }
43
44 mConfig = new AudioConfig(reinterpret_cast<AudioConfig*>(config));
45
46 BaseNode* pNodeSource = new IAudioSourceNode(mCallback);
47 pNodeSource->SetMediaType(IMS_MEDIA_AUDIO);
48 pNodeSource->SetConfig(mConfig);
49 AddNode(pNodeSource);
50
51 BaseNode* pNodeRtpPayloadEncoder = new AudioRtpPayloadEncoderNode(mCallback);
52 pNodeRtpPayloadEncoder->SetMediaType(IMS_MEDIA_AUDIO);
53 pNodeRtpPayloadEncoder->SetConfig(mConfig);
54 AddNode(pNodeRtpPayloadEncoder);
55 pNodeSource->ConnectRearNode(pNodeRtpPayloadEncoder);
56
57 BaseNode* pNodeRtpEncoder = new RtpEncoderNode(mCallback);
58 pNodeRtpEncoder->SetMediaType(IMS_MEDIA_AUDIO);
59 char localIp[MAX_IP_LEN];
60 uint32_t localPort = 0;
61 ImsMediaNetworkUtil::getLocalIpPortFromSocket(mLocalFd, localIp, MAX_IP_LEN, localPort);
62 RtpAddress localAddress(localIp, localPort);
63 pNodeRtpEncoder->SetConfig(mConfig);
64 (static_cast<RtpEncoderNode*>(pNodeRtpEncoder))->SetLocalAddress(localAddress);
65 AddNode(pNodeRtpEncoder);
66 pNodeRtpPayloadEncoder->ConnectRearNode(pNodeRtpEncoder);
67
68 BaseNode* pNodeSocketWriter = new SocketWriterNode(mCallback);
69 pNodeSocketWriter->SetMediaType(IMS_MEDIA_AUDIO);
70 (static_cast<SocketWriterNode*>(pNodeSocketWriter))->SetLocalFd(mLocalFd);
71 (static_cast<SocketWriterNode*>(pNodeSocketWriter))->SetLocalAddress(localAddress);
72 (static_cast<SocketWriterNode*>(pNodeSocketWriter))->SetProtocolType(kProtocolRtp);
73 pNodeSocketWriter->SetConfig(config);
74 AddNode(pNodeSocketWriter);
75 pNodeRtpEncoder->ConnectRearNode(pNodeSocketWriter);
76 setState(StreamState::kStreamStateCreated);
77
78 if (!createDtmfGraph(mConfig, pNodeRtpEncoder))
79 {
80 IMLOGE0("[create] fail to create dtmf graph");
81 }
82
83 return RESULT_SUCCESS;
84 }
85
update(RtpConfig * config)86 ImsMediaResult AudioStreamGraphRtpTx::update(RtpConfig* config)
87 {
88 IMLOGI1("[update] state[%d]", mGraphState);
89
90 if (config == nullptr)
91 {
92 return RESULT_INVALID_PARAM;
93 }
94
95 AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
96
97 if (*reinterpret_cast<AudioConfig*>(mConfig) == *pConfig)
98 {
99 IMLOGI0("[update] no update");
100 return RESULT_SUCCESS;
101 }
102
103 if (mConfig != nullptr)
104 {
105 delete mConfig;
106 }
107
108 mConfig = new AudioConfig(pConfig);
109
110 if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW ||
111 mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY ||
112 mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_INACTIVE)
113 {
114 IMLOGI0("[update] pause TX");
115 RtpContextParams rtpContextParams = config->getRtpContextParams();
116 int32_t accessNetwork = pConfig->getAccessNetwork();
117
118 if (accessNetwork != ACCESS_NETWORK_IWLAN &&
119 mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW)
120 {
121 for (auto& node : mListNodeStarted)
122 {
123 if (node != nullptr && node->GetNodeId() == kNodeIdRtpEncoder)
124 {
125 reinterpret_cast<RtpEncoderNode*>(node)->GetRtpContext(rtpContextParams);
126 pConfig->setRtpContextParams(rtpContextParams);
127 }
128 }
129 }
130 return stop();
131 }
132
133 ImsMediaResult ret = RESULT_NOT_READY;
134
135 if (mGraphState == kStreamStateRunning)
136 {
137 mScheduler->Stop();
138 for (auto& node : mListNodeStarted)
139 {
140 IMLOGD1("[update] update node[%s]", node->GetNodeName());
141 ret = node->UpdateConfig(mConfig);
142 if (ret != RESULT_SUCCESS)
143 {
144 IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret);
145 }
146 }
147 mScheduler->Start();
148 }
149 else if (mGraphState == kStreamStateCreated)
150 {
151 for (auto& node : mListNodeToStart)
152 {
153 IMLOGD1("[update] update node[%s]", node->GetNodeName());
154 ret = node->UpdateConfig(mConfig);
155 if (ret != RESULT_SUCCESS)
156 {
157 IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret);
158 }
159 }
160 }
161
162 if (mGraphState == kStreamStateCreated &&
163 (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY ||
164 pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE))
165 {
166 IMLOGI0("[update] resume TX");
167 return start();
168 }
169
170 return ret;
171 }
172
start()173 ImsMediaResult AudioStreamGraphRtpTx::start()
174 {
175 if (mConfig == nullptr)
176 {
177 return RESULT_NOT_READY;
178 }
179
180 if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY ||
181 mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE)
182 {
183 return BaseStreamGraph::start();
184 }
185
186 // not started
187 return RESULT_SUCCESS;
188 }
189
createDtmfGraph(RtpConfig * config,BaseNode * rtpEncoderNode)190 bool AudioStreamGraphRtpTx::createDtmfGraph(RtpConfig* config, BaseNode* rtpEncoderNode)
191 {
192 if (config == nullptr)
193 {
194 return false;
195 }
196
197 AudioConfig* audioConfig = reinterpret_cast<AudioConfig*>(config);
198
199 if (audioConfig->getTxDtmfPayloadTypeNumber() == 0)
200 {
201 return false;
202 }
203
204 if (mConfig == nullptr)
205 {
206 mConfig = new AudioConfig(*audioConfig);
207 }
208
209 BaseNode* dtmfEncoderNode = new DtmfEncoderNode(mCallback);
210 dtmfEncoderNode->SetMediaType(IMS_MEDIA_AUDIO);
211 dtmfEncoderNode->SetConfig(audioConfig);
212 dtmfEncoderNode->SetSchedulerCallback(
213 std::static_pointer_cast<StreamSchedulerCallback>(mScheduler));
214 AddNode(dtmfEncoderNode);
215 mListDtmfNodes.push_back(dtmfEncoderNode);
216
217 BaseNode* dtmfSenderNode = new DtmfSenderNode(mCallback);
218 dtmfSenderNode->SetMediaType(IMS_MEDIA_AUDIO);
219 dtmfSenderNode->SetConfig(audioConfig);
220 dtmfSenderNode->SetSchedulerCallback(
221 std::static_pointer_cast<StreamSchedulerCallback>(mScheduler));
222 dtmfEncoderNode->ConnectRearNode(dtmfSenderNode);
223 AddNode(dtmfSenderNode);
224 mListDtmfNodes.push_back(dtmfSenderNode);
225
226 if (rtpEncoderNode != nullptr)
227 {
228 dtmfSenderNode->ConnectRearNode(rtpEncoderNode);
229 }
230
231 return true;
232 }
233
sendDtmf(char digit,int duration)234 bool AudioStreamGraphRtpTx::sendDtmf(char digit, int duration)
235 {
236 IMLOGD1("[sendDtmf], state[%d]", mGraphState);
237 BaseNode* pDTMFNode = nullptr;
238 if (!mListDtmfNodes.empty())
239 {
240 pDTMFNode = mListDtmfNodes.front();
241 }
242
243 if (pDTMFNode != nullptr && pDTMFNode->GetNodeId() == kNodeIdDtmfEncoder)
244 {
245 IMLOGD2("[sendDtmf] %c, duration[%d]", digit, duration);
246 ImsMediaSubType subtype = MEDIASUBTYPE_DTMF_PAYLOAD;
247
248 // TODO(249734476): add implementation of continuous DTMF operation
249 if (duration == 0)
250 {
251 subtype = MEDIASUBTYPE_DTMFSTART;
252 }
253
254 pDTMFNode->OnDataFromFrontNode(subtype, (uint8_t*)&digit, 1, 0, 0, duration);
255 return true;
256 }
257 else
258 {
259 IMLOGE0("[sendDtmf] DTMF is not enabled");
260 }
261
262 return false;
263 }
264
processCmr(const uint32_t cmrType,const uint32_t cmrDefine)265 void AudioStreamGraphRtpTx::processCmr(const uint32_t cmrType, const uint32_t cmrDefine)
266 {
267 BaseNode* node = findNode(kNodeIdAudioSource);
268
269 if (node != nullptr)
270 {
271 (reinterpret_cast<IAudioSourceNode*>(node))->ProcessCmr(cmrType, cmrDefine);
272 }
273 }
274
sendRtpHeaderExtension(std::list<RtpHeaderExtension> * listExtension)275 void AudioStreamGraphRtpTx::sendRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension)
276 {
277 BaseNode* node = findNode(kNodeIdRtpEncoder);
278
279 if (node != nullptr)
280 {
281 (reinterpret_cast<RtpEncoderNode*>(node))->SetRtpHeaderExtension(listExtension);
282 }
283 }
284