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 <time.h>
24 #include <chrono>
25 #include <thread>
26 #include <utils/Atomic.h>
27 #include <limits.h>
28 #include <mutex>
29 #include <list>
30 #include <algorithm>
31
32 struct TimerInstance
33 {
34 fn_TimerCb mTimerCb;
35 uint32_t mDuration;
36 bool mRepeat;
37 void* mUserData;
38 bool mTerminateThread;
39 uint32_t mStartTimeMillisecond;
40 std::mutex mMutex;
41 };
42
43 static std::mutex gMutexList;
44 static std::list<TimerInstance*> gTimerList;
45 static std::uint64_t gStartTime = 0;
46
AddTimerToList(TimerInstance * timer)47 static void AddTimerToList(TimerInstance* timer)
48 {
49 std::lock_guard<std::mutex> guard(gMutexList);
50 gTimerList.push_back(timer);
51 }
52
DeleteTimerFromList(TimerInstance * timer)53 static void DeleteTimerFromList(TimerInstance* timer)
54 {
55 std::lock_guard<std::mutex> guard(gMutexList);
56 gTimerList.remove(timer);
57 }
58
IsValidTimer(const TimerInstance * timer)59 static bool IsValidTimer(const TimerInstance* timer)
60 {
61 std::lock_guard<std::mutex> guard(gMutexList);
62
63 if (gTimerList.empty())
64 {
65 return false;
66 }
67
68 auto result = std::find(gTimerList.begin(), gTimerList.end(), timer);
69 return (result != gTimerList.end());
70 }
71
ImsMediaTimer_run(void * arg)72 static void* ImsMediaTimer_run(void* arg)
73 {
74 TimerInstance* timer = reinterpret_cast<TimerInstance*>(arg);
75
76 if (timer == nullptr)
77 {
78 return nullptr;
79 }
80
81 uint32_t sleepTime = timer->mDuration;
82
83 if (timer->mDuration > 10 && timer->mDuration < 100)
84 {
85 sleepTime = 10;
86 }
87 else if (timer->mDuration >= 100 && timer->mDuration < 1000)
88 {
89 sleepTime = timer->mDuration / 10;
90 }
91 else if (timer->mDuration >= 1000)
92 {
93 sleepTime = 100;
94 }
95
96 for (;;)
97 {
98 if (timer->mTerminateThread)
99 {
100 break;
101 }
102
103 std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
104
105 if (timer->mTerminateThread)
106 {
107 break;
108 }
109
110 uint32_t currTimeMillisecond = ImsMediaTimer::GetTimeInMilliSeconds();
111 uint32_t nTimeDiff = currTimeMillisecond - timer->mStartTimeMillisecond;
112
113 if (nTimeDiff >= timer->mDuration)
114 {
115 if (timer->mRepeat)
116 {
117 timer->mStartTimeMillisecond = currTimeMillisecond;
118 }
119
120 { // Critical section
121 std::lock_guard<std::mutex> guard(timer->mMutex);
122 if (timer->mTerminateThread)
123 {
124 break;
125 }
126
127 if (timer->mTimerCb)
128 {
129 timer->mTimerCb(timer, timer->mUserData);
130 }
131 }
132
133 if (!timer->mRepeat)
134 {
135 break;
136 }
137 }
138 }
139
140 DeleteTimerFromList(timer);
141
142 if (timer != nullptr)
143 {
144 delete timer;
145 timer = nullptr;
146 }
147
148 return nullptr;
149 }
150
TimerStart(uint32_t duration,bool repeat,fn_TimerCb timerCallback,void * userData)151 hTimerHandler ImsMediaTimer::TimerStart(
152 uint32_t duration, bool repeat, fn_TimerCb timerCallback, void* userData)
153 {
154 TimerInstance* timer = new TimerInstance;
155
156 if (timer == nullptr)
157 {
158 return nullptr;
159 }
160
161 timer->mTimerCb = timerCallback;
162 timer->mDuration = duration;
163 timer->mRepeat = repeat;
164 timer->mUserData = userData;
165 timer->mTerminateThread = false;
166
167 IMLOGD3("[TimerStart] duration[%u], repeat[%d], userData[%x]", timer->mDuration, repeat,
168 timer->mUserData);
169
170 timer->mStartTimeMillisecond = ImsMediaTimer::GetTimeInMilliSeconds();
171 AddTimerToList(timer);
172
173 std::thread t1(&ImsMediaTimer_run, timer);
174 t1.detach();
175 return (hTimerHandler)timer;
176 }
177
TimerStop(hTimerHandler hTimer,void ** puserData)178 bool ImsMediaTimer::TimerStop(hTimerHandler hTimer, void** puserData)
179 {
180 TimerInstance* timer = reinterpret_cast<TimerInstance*>(hTimer);
181 IMLOGD1("[TimerStop] timer[%x]", timer);
182
183 if (timer == nullptr)
184 {
185 return false;
186 }
187
188 if (IsValidTimer(timer) == false)
189 {
190 return false;
191 }
192
193 {
194 std::lock_guard<std::mutex> guard(timer->mMutex);
195 IMLOGD1("[TimerStop] mutex taken timer[%x]", timer);
196
197 timer->mTerminateThread = true;
198
199 if (puserData)
200 {
201 *puserData = timer->mUserData;
202 }
203 }
204
205 return true;
206 }
207
SetStartTimeInMicroSeconds(uint64_t time)208 void ImsMediaTimer::SetStartTimeInMicroSeconds(uint64_t time)
209 {
210 gStartTime = time;
211 }
212
GetTimeInMicroSeconds(void)213 uint64_t ImsMediaTimer::GetTimeInMicroSeconds(void)
214 {
215 struct timespec time;
216 clock_gettime(CLOCK_MONOTONIC, &time);
217 return gStartTime + (time.tv_sec * 1000000) + (time.tv_nsec / 1000);
218 }
219
GetTimeInMilliSeconds(void)220 uint32_t ImsMediaTimer::GetTimeInMilliSeconds(void)
221 {
222 return (ImsMediaTimer::GetTimeInMicroSeconds() / 1000 % UINT_MAX);
223 }
224
GenerateRandom(uint32_t nRange)225 uint32_t ImsMediaTimer::GenerateRandom(uint32_t nRange)
226 {
227 uint32_t rand;
228 struct timespec time;
229 clock_gettime(CLOCK_MONOTONIC, &time);
230 rand = (time.tv_sec * 13) + (time.tv_nsec / 1000000);
231
232 if (0 == nRange)
233 {
234 return rand * 7;
235 }
236
237 return (rand * 7) % nRange;
238 }
239
Atomic_Inc(int32_t * v)240 int32_t ImsMediaTimer::Atomic_Inc(int32_t* v)
241 {
242 return android_atomic_inc(v);
243 }
Atomic_Dec(int32_t * v)244 int32_t ImsMediaTimer::Atomic_Dec(int32_t* v)
245 {
246 return android_atomic_dec(v);
247 }
248
Sleep(unsigned int t)249 void ImsMediaTimer::Sleep(unsigned int t)
250 {
251 std::this_thread::sleep_for(std::chrono::milliseconds(t));
252 }
253
USleep(unsigned int t)254 void ImsMediaTimer::USleep(unsigned int t)
255 {
256 std::this_thread::sleep_for(std::chrono::microseconds(t));
257 }