• 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 <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