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 <ImsMediaDefine.h>
18 #include <ImsMediaTrace.h>
19 #include <DtmfEncoderNode.h>
20 #include <ImsMediaTimer.h>
21 #include <AudioConfig.h>
22
23 #define BUNDLE_DTMF_DATA_MAX 32 // Max bundling # : 8 X 4bytes
24 #define DTMF_DEFAULT_DURATION 200
25 #define DTMF_MINIMUM_DURATION 40
26 #define DTMF_DEFAULT_RETRANSMIT_DURATION 40
27 #define DTMF_DEFAULT_VOLUME 10
28 #define DEFAULT_AUDIO_INTERVAL 20
29
DtmfEncoderNode(BaseSessionCallback * callback)30 DtmfEncoderNode::DtmfEncoderNode(BaseSessionCallback* callback) :
31 BaseNode(callback)
32 {
33 mStopDtmf = true;
34 mListDtmfDigit.clear();
35 mSamplingRate = 0;
36 mDuration = DTMF_DEFAULT_DURATION;
37 mRetransmitDuration = DTMF_DEFAULT_RETRANSMIT_DURATION;
38 mVolume = DTMF_DEFAULT_VOLUME;
39 mAudioFrameDuration = 0;
40 mPtime = DEFAULT_AUDIO_INTERVAL;
41 }
42
~DtmfEncoderNode()43 DtmfEncoderNode::~DtmfEncoderNode() {}
44
GetNodeId()45 kBaseNodeId DtmfEncoderNode::GetNodeId()
46 {
47 return kNodeIdDtmfEncoder;
48 }
49
Start()50 ImsMediaResult DtmfEncoderNode::Start()
51 {
52 mAudioFrameDuration = mSamplingRate * mPtime;
53 IMLOGD1("[Start] interval[%d]", mAudioFrameDuration);
54 StartThread();
55 mNodeState = kNodeStateRunning;
56 return RESULT_SUCCESS;
57 }
58
Stop()59 void DtmfEncoderNode::Stop()
60 {
61 IMLOGD0("[Stop]");
62 StopThread();
63 mConditionDtmf.signal();
64 mConditionExit.wait_timeout(1000);
65 mNodeState = kNodeStateStopped;
66 }
67
IsRunTime()68 bool DtmfEncoderNode::IsRunTime()
69 {
70 return true;
71 }
72
IsSourceNode()73 bool DtmfEncoderNode::IsSourceNode()
74 {
75 return false;
76 }
77
SetConfig(void * config)78 void DtmfEncoderNode::SetConfig(void* config)
79 {
80 AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
81
82 if (pConfig != nullptr)
83 {
84 mSamplingRate = pConfig->getDtmfsamplingRateKHz();
85 mDuration = DTMF_DEFAULT_DURATION;
86 mRetransmitDuration = DTMF_DEFAULT_RETRANSMIT_DURATION;
87 mVolume = DTMF_DEFAULT_VOLUME;
88 mPtime = pConfig->getPtimeMillis();
89 }
90 }
91
IsSameConfig(void * config)92 bool DtmfEncoderNode::IsSameConfig(void* config)
93 {
94 if (config == nullptr)
95 {
96 return true;
97 }
98
99 AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
100 return (mSamplingRate == pConfig->getDtmfsamplingRateKHz() &&
101 mPtime == pConfig->getPtimeMillis());
102 }
103
OnDataFromFrontNode(ImsMediaSubType subtype,uint8_t * pData,uint32_t nDataSize,uint32_t volume,bool bMark,uint32_t duration,ImsMediaSubType nDataType,uint32_t arrivalTime)104 void DtmfEncoderNode::OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* pData,
105 uint32_t nDataSize, uint32_t volume, bool bMark, uint32_t duration,
106 ImsMediaSubType nDataType, uint32_t arrivalTime)
107 {
108 (void)bMark;
109 (void)nDataType;
110 (void)volume;
111 (void)arrivalTime;
112
113 if (duration != 0 && subtype == MEDIASUBTYPE_DTMF_PAYLOAD)
114 {
115 mStopDtmf = true;
116 IMLOGD1("[OnDataFromFrontNode] Send DTMF string %c", *pData);
117 uint8_t nSignal;
118 if (nDataSize == 0 || convertSignal(*pData, nSignal) == false)
119 {
120 return;
121 }
122 SendDataToRearNode(MEDIASUBTYPE_DTMFSTART, nullptr, 0, 0, 0, 0); // set dtmf mode true
123 SendDTMFEvent(nSignal, duration);
124 SendDataToRearNode(MEDIASUBTYPE_DTMFEND, nullptr, 0, 0, 0, 0); // set dtmf mode false
125 }
126 else
127 {
128 if (subtype == MEDIASUBTYPE_DTMFEND)
129 {
130 mMutex.lock();
131 mStopDtmf = true;
132 mMutex.unlock();
133 }
134 else if (subtype == MEDIASUBTYPE_DTMFSTART)
135 {
136 uint8_t nSignal;
137 if (convertSignal(*pData, nSignal) == false)
138 {
139 return;
140 }
141 mMutex.lock();
142 mStopDtmf = false;
143 mMutex.unlock();
144 mListDtmfDigit.push_back(nSignal);
145 mConditionDtmf.signal();
146 }
147 }
148 }
149
run()150 void* DtmfEncoderNode::run()
151 {
152 IMLOGD0("[run] enter");
153 for (;;)
154 {
155 IMLOGD0("[run] wait");
156 mConditionDtmf.wait();
157
158 if (IsThreadStopped())
159 {
160 IMLOGD0("[run] terminated");
161 mConditionExit.signal();
162 break;
163 }
164
165 uint32_t nPeriod = 0;
166 uint8_t pbPayload[BUNDLE_DTMF_DATA_MAX];
167 uint32_t nPayloadSize;
168 uint32_t nTimestamp = ImsMediaTimer::GetTimeInMilliSeconds();
169
170 if (mListDtmfDigit.size() == 0)
171 {
172 continue;
173 }
174
175 bool bMarker = true;
176 nPayloadSize = MakeDTMFPayload(pbPayload, mListDtmfDigit.front(), false, mVolume, nPeriod);
177 SendDataToRearNode(MEDIASUBTYPE_DTMFSTART, nullptr, 0, 0, 0, 0); // set dtmf mode true
178
179 for (;;)
180 {
181 mMutex.lock();
182
183 if (mStopDtmf)
184 {
185 // make and send DTMF last packet and retransmit it
186 nPayloadSize =
187 MakeDTMFPayload(pbPayload, mListDtmfDigit.front(), true, mVolume, nPeriod);
188 uint32_t nDTMFRetransmitDuration =
189 mRetransmitDuration * (mAudioFrameDuration / mPtime);
190 for (nPeriod = 0; nPeriod <= nDTMFRetransmitDuration;
191 nPeriod += mAudioFrameDuration)
192 {
193 IMLOGD1("[run] send dtmf timestamp[%d]", nTimestamp);
194 SendDataToRearNode(MEDIASUBTYPE_DTMF_PAYLOAD, pbPayload, nPayloadSize,
195 nTimestamp, false, 0);
196
197 nTimestamp += mPtime;
198 uint32_t nCurrTime = ImsMediaTimer::GetTimeInMilliSeconds();
199
200 if (nTimestamp > nCurrTime)
201 {
202 ImsMediaTimer::Sleep(nTimestamp - nCurrTime);
203 }
204 }
205
206 SendDataToRearNode(MEDIASUBTYPE_DTMFEND, nullptr, 0, 0, 0, 0);
207 mListDtmfDigit.pop_front();
208 mMutex.unlock();
209 break;
210 }
211
212 mMutex.unlock();
213 SendDataToRearNode(
214 MEDIASUBTYPE_DTMF_PAYLOAD, pbPayload, nPayloadSize, nTimestamp, bMarker, 0);
215 nTimestamp += mPtime;
216 uint32_t nCurrTime = ImsMediaTimer::GetTimeInMilliSeconds();
217
218 if (nTimestamp > nCurrTime)
219 {
220 ImsMediaTimer::Sleep(nTimestamp - nCurrTime);
221 }
222
223 bMarker = false;
224
225 if (IsThreadStopped())
226 {
227 IMLOGD0("[run] terminated");
228 break;
229 }
230 }
231 }
232 return nullptr;
233 }
234
calculateDtmfDuration(uint32_t duration)235 uint32_t DtmfEncoderNode::calculateDtmfDuration(uint32_t duration)
236 {
237 if (duration < DTMF_MINIMUM_DURATION)
238 {
239 // Force minimum duration
240 duration = DTMF_MINIMUM_DURATION;
241 }
242
243 return (((duration + 10) / mPtime * mPtime) * (mAudioFrameDuration / mPtime));
244 }
245
SendDTMFEvent(uint8_t digit,uint32_t duration)246 bool DtmfEncoderNode::SendDTMFEvent(uint8_t digit, uint32_t duration)
247 {
248 uint32_t nPeriod = 0;
249 uint8_t pbPayload[BUNDLE_DTMF_DATA_MAX];
250 uint32_t nPayloadSize;
251 uint32_t nTimestamp = 0;
252 bool bMarker = true;
253 uint32_t nDTMFDuration = calculateDtmfDuration(duration);
254 uint32_t nDTMFRetransmitDuration = mRetransmitDuration * (mAudioFrameDuration / mPtime);
255
256 // make and send DTMF packet
257 for (nPeriod = mAudioFrameDuration; nPeriod < nDTMFDuration; nPeriod += mAudioFrameDuration)
258 {
259 nPayloadSize = MakeDTMFPayload(pbPayload, digit, false, mVolume, nPeriod);
260 SendDataToRearNode(
261 MEDIASUBTYPE_DTMF_PAYLOAD, pbPayload, nPayloadSize, nTimestamp, bMarker, 0);
262 nTimestamp += mPtime;
263 bMarker = false;
264 }
265
266 // make and send DTMF last packet and retransmit it
267 nPayloadSize = MakeDTMFPayload(pbPayload, digit, true, mVolume, nPeriod);
268
269 for (nPeriod = 0; nPeriod <= nDTMFRetransmitDuration; nPeriod += mAudioFrameDuration)
270 {
271 SendDataToRearNode(
272 MEDIASUBTYPE_DTMF_PAYLOAD, pbPayload, nPayloadSize, nTimestamp, false, 0);
273 nTimestamp += mPtime;
274 }
275
276 return true;
277 }
278
convertSignal(uint8_t digit,uint8_t & signal)279 bool DtmfEncoderNode::convertSignal(uint8_t digit, uint8_t& signal)
280 {
281 /* Set input signal */
282 if ((digit >= '0') && (digit <= '9'))
283 signal = digit - '0';
284 else if (digit == '*')
285 signal = 10;
286 else if (digit == '#')
287 signal = 11;
288 else if (digit == 'A')
289 signal = 12;
290 else if (digit == 'B')
291 signal = 13;
292 else if (digit == 'C')
293 signal = 14;
294 else if (digit == 'D')
295 signal = 15;
296 else if (digit == 'F')
297 signal = 16;
298 else
299 {
300 IMLOGE1("[SendDTMF] Wrong DTMF Signal[%c]!", digit);
301 return false;
302 }
303
304 IMLOGD1("[convertSignal] signal[%d]", signal);
305
306 return true;
307 }
308
MakeDTMFPayload(uint8_t * pbPayload,uint8_t digit,bool bEnd,uint8_t nVolume,uint32_t nPeriod)309 uint32_t DtmfEncoderNode::MakeDTMFPayload(
310 uint8_t* pbPayload, uint8_t digit, bool bEnd, uint8_t nVolume, uint32_t nPeriod)
311 {
312 // Event: 8 bits
313 pbPayload[0] = digit;
314
315 // E: 1 bit
316 if (bEnd)
317 {
318 pbPayload[1] = 0x80;
319 }
320 else
321 {
322 pbPayload[1] = 0x00;
323 }
324
325 // Volume: 6 bits
326 pbPayload[1] += nVolume;
327
328 // duration: 16 bits
329 pbPayload[2] = (nPeriod >> 8) & 0xFF;
330 pbPayload[3] = nPeriod & 0xFF;
331 return 4;
332 }
333