• 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 <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(&currentNtpTs);
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 }