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("DtmfEncoderNode");
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 size,uint32_t,bool,uint32_t duration,ImsMediaSubType,uint32_t)104 void DtmfEncoderNode::OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* pData, uint32_t size,
105 uint32_t /*volume*/, bool /*mark*/, uint32_t duration, ImsMediaSubType /*dataType*/,
106 uint32_t /*arrivalTime*/)
107 {
108 if (duration != 0 && subtype == MEDIASUBTYPE_DTMF_PAYLOAD)
109 {
110 mStopDtmf = true;
111 IMLOGD1("[OnDataFromFrontNode] Send DTMF string %c", *pData);
112 uint8_t nSignal;
113 if (size == 0 || convertSignal(*pData, nSignal) == false)
114 {
115 return;
116 }
117 SendDataToRearNode(MEDIASUBTYPE_DTMFSTART, nullptr, 0, 0, 0, 0); // set dtmf mode true
118 SendDTMFEvent(nSignal, duration);
119 SendDataToRearNode(MEDIASUBTYPE_DTMFEND, nullptr, 0, 0, 0, 0); // set dtmf mode false
120 }
121 else
122 {
123 if (subtype == MEDIASUBTYPE_DTMFEND)
124 {
125 mMutex.lock();
126 mStopDtmf = true;
127 mMutex.unlock();
128 }
129 else if (subtype == MEDIASUBTYPE_DTMFSTART)
130 {
131 uint8_t nSignal;
132 if (convertSignal(*pData, nSignal) == false)
133 {
134 return;
135 }
136 mMutex.lock();
137 mStopDtmf = false;
138 mMutex.unlock();
139 mListDtmfDigit.push_back(nSignal);
140 mConditionDtmf.signal();
141 }
142 }
143 }
144
run()145 void* DtmfEncoderNode::run()
146 {
147 IMLOGD0("[run] enter");
148 for (;;)
149 {
150 IMLOGD0("[run] wait");
151 mConditionDtmf.wait();
152
153 if (IsThreadStopped())
154 {
155 IMLOGD0("[run] terminated");
156 mConditionExit.signal();
157 break;
158 }
159
160 uint32_t nPeriod = 0;
161 uint8_t pbPayload[BUNDLE_DTMF_DATA_MAX];
162 uint32_t nPayloadSize;
163 uint32_t nTimestamp = ImsMediaTimer::GetTimeInMilliSeconds();
164
165 if (mListDtmfDigit.size() == 0)
166 {
167 continue;
168 }
169
170 bool marker = true;
171 nPayloadSize = MakeDTMFPayload(pbPayload, mListDtmfDigit.front(), false, mVolume, nPeriod);
172 SendDataToRearNode(MEDIASUBTYPE_DTMFSTART, nullptr, 0, 0, 0, 0); // set dtmf mode true
173
174 for (;;)
175 {
176 mMutex.lock();
177
178 if (mStopDtmf)
179 {
180 // make and send DTMF last packet and retransmit it
181 nPayloadSize =
182 MakeDTMFPayload(pbPayload, mListDtmfDigit.front(), true, mVolume, nPeriod);
183 uint32_t nDTMFRetransmitDuration =
184 mRetransmitDuration * (mAudioFrameDuration / mPtime);
185 for (nPeriod = 0; nPeriod <= nDTMFRetransmitDuration;
186 nPeriod += mAudioFrameDuration)
187 {
188 IMLOGD1("[run] send dtmf timestamp[%d]", nTimestamp);
189 SendDataToRearNode(MEDIASUBTYPE_DTMF_PAYLOAD, pbPayload, nPayloadSize,
190 nTimestamp, false, 0);
191
192 nTimestamp += mPtime;
193 uint32_t nCurrTime = ImsMediaTimer::GetTimeInMilliSeconds();
194
195 if (nTimestamp > nCurrTime)
196 {
197 ImsMediaTimer::Sleep(nTimestamp - nCurrTime);
198 }
199 }
200
201 SendDataToRearNode(MEDIASUBTYPE_DTMFEND, nullptr, 0, 0, 0, 0);
202 mListDtmfDigit.pop_front();
203 mMutex.unlock();
204 break;
205 }
206
207 mMutex.unlock();
208 SendDataToRearNode(
209 MEDIASUBTYPE_DTMF_PAYLOAD, pbPayload, nPayloadSize, nTimestamp, marker, 0);
210 nTimestamp += mPtime;
211 uint32_t nCurrTime = ImsMediaTimer::GetTimeInMilliSeconds();
212
213 if (nTimestamp > nCurrTime)
214 {
215 ImsMediaTimer::Sleep(nTimestamp - nCurrTime);
216 }
217
218 marker = false;
219
220 if (IsThreadStopped())
221 {
222 IMLOGD0("[run] terminated");
223 break;
224 }
225 }
226 }
227 return nullptr;
228 }
229
calculateDtmfDuration(uint32_t duration)230 uint32_t DtmfEncoderNode::calculateDtmfDuration(uint32_t duration)
231 {
232 if (duration < DTMF_MINIMUM_DURATION)
233 {
234 // Force minimum duration
235 duration = DTMF_MINIMUM_DURATION;
236 }
237
238 return (((duration + 10) / mPtime * mPtime) * (mAudioFrameDuration / mPtime));
239 }
240
SendDTMFEvent(uint8_t digit,uint32_t duration)241 bool DtmfEncoderNode::SendDTMFEvent(uint8_t digit, uint32_t duration)
242 {
243 uint32_t nPeriod = 0;
244 uint8_t pbPayload[BUNDLE_DTMF_DATA_MAX];
245 uint32_t nPayloadSize;
246 uint32_t nTimestamp = 0;
247 bool marker = true;
248 uint32_t nDTMFDuration = calculateDtmfDuration(duration);
249 uint32_t nDTMFRetransmitDuration = mRetransmitDuration * (mAudioFrameDuration / mPtime);
250
251 // make and send DTMF packet
252 for (nPeriod = mAudioFrameDuration; nPeriod < nDTMFDuration; nPeriod += mAudioFrameDuration)
253 {
254 nPayloadSize = MakeDTMFPayload(pbPayload, digit, false, mVolume, nPeriod);
255 SendDataToRearNode(
256 MEDIASUBTYPE_DTMF_PAYLOAD, pbPayload, nPayloadSize, nTimestamp, marker, 0);
257 nTimestamp += mPtime;
258 marker = false;
259 }
260
261 // make and send DTMF last packet and retransmit it
262 nPayloadSize = MakeDTMFPayload(pbPayload, digit, true, mVolume, nPeriod);
263
264 for (nPeriod = 0; nPeriod <= nDTMFRetransmitDuration; nPeriod += mAudioFrameDuration)
265 {
266 SendDataToRearNode(
267 MEDIASUBTYPE_DTMF_PAYLOAD, pbPayload, nPayloadSize, nTimestamp, false, 0);
268 nTimestamp += mPtime;
269 }
270
271 return true;
272 }
273
convertSignal(uint8_t digit,uint8_t & signal)274 bool DtmfEncoderNode::convertSignal(uint8_t digit, uint8_t& signal)
275 {
276 /* Set input signal */
277 if ((digit >= '0') && (digit <= '9'))
278 signal = digit - '0';
279 else if (digit == '*')
280 signal = 10;
281 else if (digit == '#')
282 signal = 11;
283 else if (digit == 'A')
284 signal = 12;
285 else if (digit == 'B')
286 signal = 13;
287 else if (digit == 'C')
288 signal = 14;
289 else if (digit == 'D')
290 signal = 15;
291 else if (digit == 'F')
292 signal = 16;
293 else
294 {
295 IMLOGE1("[SendDTMF] Wrong DTMF Signal[%c]!", digit);
296 return false;
297 }
298
299 IMLOGD1("[convertSignal] signal[%d]", signal);
300
301 return true;
302 }
303
MakeDTMFPayload(uint8_t * pbPayload,uint8_t digit,bool bEnd,uint8_t nVolume,uint32_t nPeriod)304 uint32_t DtmfEncoderNode::MakeDTMFPayload(
305 uint8_t* pbPayload, uint8_t digit, bool bEnd, uint8_t nVolume, uint32_t nPeriod)
306 {
307 // Event: 8 bits
308 pbPayload[0] = digit;
309
310 // E: 1 bit
311 if (bEnd)
312 {
313 pbPayload[1] = 0x80;
314 }
315 else
316 {
317 pbPayload[1] = 0x00;
318 }
319
320 // Volume: 6 bits
321 pbPayload[1] += nVolume;
322
323 // duration: 16 bits
324 pbPayload[2] = (nPeriod >> 8) & 0xFF;
325 pbPayload[3] = nPeriod & 0xFF;
326 return 4;
327 }
328