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 <ImsMediaTimer.h>
18 #include <ImsMediaTrace.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include <chrono>
25 #include <thread>
26 #include <utils/Atomic.h>
27 #include <mutex>
28 #include <list>
29 #include <algorithm>
30
31 struct TimerInstance
32 {
33 fn_TimerCb mTimerCb;
34 uint32_t mDuration;
35 bool mRepeat;
36 void* mUserData;
37 bool mTerminateThread;
38 uint32_t mStartTimeSec;
39 uint32_t mStartTimeMSec;
40 };
41
42 static std::mutex gMutex;
43 static std::mutex gMutexList;
44 static std::list<TimerInstance*> gTimerList;
45
AddTimerToList(TimerInstance * pInstance)46 static void AddTimerToList(TimerInstance* pInstance)
47 {
48 std::lock_guard<std::mutex> guard(gMutexList);
49 gTimerList.push_back(pInstance);
50 }
51
DeleteTimerFromList(TimerInstance * pInstance)52 static void DeleteTimerFromList(TimerInstance* pInstance)
53 {
54 std::lock_guard<std::mutex> guard(gMutexList);
55 gTimerList.remove(pInstance);
56 }
57
IsValidTimer(const TimerInstance * pInstance)58 static bool IsValidTimer(const TimerInstance* pInstance)
59 {
60 std::lock_guard<std::mutex> guard(gMutexList);
61
62 if (gTimerList.empty())
63 {
64 return false;
65 }
66
67 auto result = std::find(gTimerList.begin(), gTimerList.end(), pInstance);
68 return (result != gTimerList.end());
69 }
70
ImsMediaTimer_GetMilliSecDiff(uint32_t startTimeSec,uint32_t startTimeMSec,uint32_t currTimeSec,uint32_t currTimeMSec)71 static int32_t ImsMediaTimer_GetMilliSecDiff(
72 uint32_t startTimeSec, uint32_t startTimeMSec, uint32_t currTimeSec, uint32_t currTimeMSec)
73 {
74 uint32_t nDiffSec;
75 uint32_t nDiffMSec;
76 nDiffSec = currTimeSec - startTimeSec;
77 currTimeMSec += (nDiffSec * 1000);
78 nDiffMSec = currTimeMSec - startTimeMSec;
79 return nDiffMSec;
80 }
81
ImsMediaTimer_run(void * arg)82 static void* ImsMediaTimer_run(void* arg)
83 {
84 TimerInstance* pInstance = reinterpret_cast<TimerInstance*>(arg);
85 uint32_t nSleepTime;
86
87 if (pInstance == nullptr)
88 {
89 return nullptr;
90 }
91
92 if (pInstance->mDuration < 100)
93 {
94 nSleepTime = 10;
95 }
96 else if (pInstance->mDuration < 1000)
97 {
98 nSleepTime = pInstance->mDuration / 10;
99 }
100 else
101 {
102 nSleepTime = 100;
103 }
104
105 for (;;)
106 {
107 struct timeval tp;
108
109 if (pInstance->mTerminateThread)
110 {
111 break;
112 }
113
114 std::this_thread::sleep_for(std::chrono::milliseconds(nSleepTime));
115
116 if (pInstance->mTerminateThread)
117 {
118 break;
119 }
120
121 if (gettimeofday(&tp, nullptr) != -1)
122 {
123 uint32_t nCurrTimeSec, nCurrTimeMSec;
124 uint32_t nTimeDiff;
125 nCurrTimeSec = tp.tv_sec;
126 nCurrTimeMSec = tp.tv_usec / 1000;
127 nTimeDiff = ImsMediaTimer_GetMilliSecDiff(pInstance->mStartTimeSec,
128 pInstance->mStartTimeMSec, nCurrTimeSec, nCurrTimeMSec);
129
130 if (nTimeDiff >= pInstance->mDuration)
131 {
132 if (pInstance->mRepeat == true)
133 {
134 pInstance->mStartTimeSec = nCurrTimeSec;
135 pInstance->mStartTimeMSec = nCurrTimeMSec;
136 }
137
138 gMutex.lock();
139
140 if (pInstance->mTerminateThread)
141 {
142 gMutex.unlock();
143 break;
144 }
145
146 if (pInstance->mTimerCb)
147 {
148 pInstance->mTimerCb(pInstance, pInstance->mUserData);
149 }
150
151 gMutex.unlock();
152
153 if (pInstance->mRepeat == false)
154 {
155 break;
156 }
157 }
158 }
159 }
160
161 DeleteTimerFromList(pInstance);
162
163 if (pInstance != nullptr)
164 {
165 free(pInstance);
166 pInstance = nullptr;
167 }
168
169 return nullptr;
170 }
171
TimerStart(uint32_t nDuration,bool bRepeat,fn_TimerCb pTimerCb,void * pUserData)172 hTimerHandler ImsMediaTimer::TimerStart(
173 uint32_t nDuration, bool bRepeat, fn_TimerCb pTimerCb, void* pUserData)
174 {
175 struct timeval tp;
176 TimerInstance* pInstance = reinterpret_cast<TimerInstance*>(malloc(sizeof(TimerInstance)));
177
178 if (pInstance == nullptr)
179 {
180 return nullptr;
181 }
182
183 pInstance->mTimerCb = pTimerCb;
184 pInstance->mDuration = nDuration;
185 pInstance->mRepeat = bRepeat;
186 pInstance->mUserData = pUserData;
187 pInstance->mTerminateThread = false;
188
189 IMLOGD3("[TimerStart] Duratation[%u], bRepeat[%d], pUserData[%x]", pInstance->mDuration,
190 bRepeat, pInstance->mUserData);
191
192 if (gettimeofday(&tp, nullptr) != -1)
193 {
194 pInstance->mStartTimeSec = tp.tv_sec;
195 pInstance->mStartTimeMSec = tp.tv_usec / 1000;
196 }
197 else
198 {
199 free(pInstance);
200 return nullptr;
201 }
202
203 AddTimerToList(pInstance);
204
205 std::thread t1(&ImsMediaTimer_run, pInstance);
206 t1.detach();
207 return (hTimerHandler)pInstance;
208 }
209
TimerStop(hTimerHandler hTimer,void ** ppUserData)210 bool ImsMediaTimer::TimerStop(hTimerHandler hTimer, void** ppUserData)
211 {
212 TimerInstance* pInstance = reinterpret_cast<TimerInstance*>(hTimer);
213
214 if (pInstance == nullptr)
215 {
216 return false;
217 }
218
219 if (IsValidTimer(pInstance) == false)
220 {
221 return false;
222 }
223
224 gMutex.lock(); // just wait until timer callback returns...
225 pInstance->mTerminateThread = true;
226
227 if (ppUserData)
228 {
229 *ppUserData = pInstance->mUserData;
230 }
231
232 gMutex.unlock();
233 return true;
234 }
235
GetNtpTime(IMNtpTime * pNtpTime)236 void ImsMediaTimer::GetNtpTime(IMNtpTime* pNtpTime)
237 {
238 struct timeval stAndrodTp;
239
240 if (gettimeofday(&stAndrodTp, nullptr) != -1)
241 {
242 // To convert a UNIX timestamp (seconds since 1970) to NTP time, add 2,208,988,800 seconds
243 pNtpTime->ntpHigh32Bits = stAndrodTp.tv_sec + 2208988800UL;
244 pNtpTime->ntpLow32Bits = (unsigned int)(stAndrodTp.tv_usec * 4294UL);
245 }
246 else
247 {
248 pNtpTime->ntpHigh32Bits = 0;
249 pNtpTime->ntpLow32Bits = 0;
250 }
251 }
252
253 /*!
254 * @brief GetRtpTsFromNtpTs
255 * @details Transforms the current NTP time to the corresponding RTP TIme Stamp
256 * using the RTP time stamp rate for the session.
257 */
GetRtpTsFromNtpTs(IMNtpTime * initNtpTimestamp,uint32_t samplingRate)258 uint32_t ImsMediaTimer::GetRtpTsFromNtpTs(IMNtpTime* initNtpTimestamp, uint32_t samplingRate)
259 {
260 IMNtpTime currentNtpTs;
261 int32_t timeDiffHigh32Bits;
262 int32_t timeDiffLow32Bits;
263 uint32_t timeDiff; /*! In Micro seconds: should always be positive */
264
265 GetNtpTime(¤tNtpTs);
266
267 /* SPR #1256 BEGIN */
268 timeDiffHigh32Bits = currentNtpTs.ntpHigh32Bits - initNtpTimestamp->ntpHigh32Bits;
269 timeDiffLow32Bits =
270 (currentNtpTs.ntpLow32Bits / 4294) - (initNtpTimestamp->ntpLow32Bits / 4294);
271 /*! timeDiffHigh32Bits should always be positive */
272 timeDiff = (timeDiffHigh32Bits * 1000) + timeDiffLow32Bits / 1000;
273 return timeDiff * (samplingRate / 1000);
274 }
275
GetTimeInMilliSeconds(void)276 uint32_t ImsMediaTimer::GetTimeInMilliSeconds(void)
277 {
278 struct timeval tp;
279 gettimeofday(&tp, nullptr);
280 return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
281 }
282
GetTimeInMicroSeconds(void)283 uint64_t ImsMediaTimer::GetTimeInMicroSeconds(void)
284 {
285 struct timeval tp;
286 gettimeofday(&tp, nullptr);
287 return (tp.tv_sec * 1000000) + (tp.tv_usec);
288 }
289
GenerateRandom(uint32_t nRange)290 uint32_t ImsMediaTimer::GenerateRandom(uint32_t nRange)
291 {
292 uint32_t rand;
293 struct timeval tp;
294
295 gettimeofday(&tp, nullptr);
296 rand = (tp.tv_sec * 13) + (tp.tv_usec / 1000);
297
298 if (0 == nRange)
299 {
300 return rand * 7;
301 }
302
303 return (rand * 7) % nRange;
304 }
305
Atomic_Inc(int32_t * v)306 int32_t ImsMediaTimer::Atomic_Inc(int32_t* v)
307 {
308 return android_atomic_inc(v);
309 }
Atomic_Dec(int32_t * v)310 int32_t ImsMediaTimer::Atomic_Dec(int32_t* v)
311 {
312 return android_atomic_dec(v);
313 }
314
Sleep(unsigned int t)315 void ImsMediaTimer::Sleep(unsigned int t)
316 {
317 std::this_thread::sleep_for(std::chrono::milliseconds(t));
318 }
319
USleep(unsigned int t)320 void ImsMediaTimer::USleep(unsigned int t)
321 {
322 std::this_thread::sleep_for(std::chrono::microseconds(t));
323 }