• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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