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