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