1 /*
2 * Copyright (c) 2025-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef LOG_TAG
16 #define LOG_TAG "AudioPolicyStateMonitor"
17 #endif
18
19 #include <chrono>
20 #include "audio_policy_state_monitor.h"
21 #include "audio_policy_log.h"
22
23 namespace OHOS {
24 namespace AudioStandard {
25
AudioPolicyStateMonitor()26 AudioPolicyStateMonitor::AudioPolicyStateMonitor()
27 {
28 if (stateMonitorThread_ == nullptr) {
29 stateMonitorThread_ = std::make_shared<std::thread>([this] { CheckStateThreadMain(); });
30 if (stateMonitorThread_ == nullptr) {
31 AUDIO_ERR_LOG("Create state monitor thread failed");
32 }
33 }
34 }
35
~AudioPolicyStateMonitor()36 AudioPolicyStateMonitor::~AudioPolicyStateMonitor()
37 {
38 {
39 std::unique_lock<std::mutex> condLock(condMutex_);
40 threadStoped_ = true;
41 }
42
43 if (stateMonitorThread_ != nullptr && stateMonitorThread_->joinable()) {
44 stateMonitorThread_->join();
45 stateMonitorThread_ = nullptr;
46 }
47 }
48
RegisterCallback(const std::shared_ptr<AudioPolicyStateMonitorCallback> & cb,std::time_t delayTime_,CallbackType callbackType)49 int32_t AudioPolicyStateMonitor::RegisterCallback(
50 const std::shared_ptr<AudioPolicyStateMonitorCallback> &cb, std::time_t delayTime_, CallbackType callbackType)
51 {
52 if (stateMonitorThread_ == nullptr) {
53 AUDIO_ERR_LOG("RegisterCallback failed because no thread");
54 return INVALID_CB_ID;
55 }
56
57 if (cb == nullptr) {
58 AUDIO_ERR_LOG("RegisterCallback failed because cb is nullptr");
59 return INVALID_CB_ID;
60 }
61
62 int32_t cbId = AllocateCbId();
63 std::unique_lock<std::mutex> lock(monitorMutex_);
64 if (cbId != INVALID_CB_ID) {
65 cb->startTimeStamp_ = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
66 cb->delayTime_ = delayTime_;
67 cb->callbackType_ = callbackType;
68 monitoredObj_[cbId] = cb;
69 }
70
71 return cbId;
72 }
73
UnRegisterCallback(int32_t cbId)74 void AudioPolicyStateMonitor::UnRegisterCallback(int32_t cbId)
75 {
76 if (stateMonitorThread_ == nullptr) {
77 AUDIO_ERR_LOG("UnRegisterCallback failed because no thread");
78 return;
79 }
80
81 std::unique_lock<std::mutex> lock(monitorMutex_);
82 auto it = monitoredObj_.find(cbId);
83 if (it != monitoredObj_.end()) {
84 monitoredObj_.erase(it);
85 }
86 FreeCbId(cbId);
87 }
88
TraverseAndInvokeTimeoutCallbacks()89 void AudioPolicyStateMonitor::TraverseAndInvokeTimeoutCallbacks()
90 {
91 std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
92 std::unique_lock<std::mutex> monitorLock(monitorMutex_);
93 auto it = monitoredObj_.begin();
94 while (it != monitoredObj_.end()) {
95 auto cb = it->second;
96 if (cb == nullptr) {
97 AUDIO_INFO_LOG("cb is nullptr");
98 ++it;
99 continue;
100 }
101
102 if (now - cb->startTimeStamp_ < cb->delayTime_) {
103 ++it;
104 continue;
105 }
106
107 // Running callback in a standalone thread
108 std::thread callbackThread([](const std::shared_ptr<AudioPolicyStateMonitorCallback> cb) {
109 if (cb == nullptr) {
110 AUDIO_ERR_LOG("ExecCallbackInThread cb is nullptr");
111 return;
112 }
113 cb->OnTimeOut();
114 }, cb);
115 callbackThread.detach();
116
117 if (cb->callbackType_ == CallbackType::ONE_TIME) {
118 FreeCbId(it->first);
119 it = monitoredObj_.erase(it);
120 } else {
121 cb->startTimeStamp_ = now;
122 ++it;
123 }
124 }
125 }
126
CheckStateThreadMain()127 void AudioPolicyStateMonitor::CheckStateThreadMain()
128 {
129 bool shouldExit = false;
130 while (!shouldExit) {
131 TraverseAndInvokeTimeoutCallbacks();
132
133 std::unique_lock<std::mutex> condLock(condMutex_);
134 shouldExit = stopCond_.wait_for(condLock, std::chrono::seconds(1), [this]() { return threadStoped_; });
135 }
136
137 AUDIO_INFO_LOG("AudioPolicyStateMonitor thread has been stopped.");
138 }
139
AllocateCbId()140 int32_t AudioPolicyStateMonitor::AllocateCbId()
141 {
142 std::unique_lock<std::mutex> lock(monitorMutex_);
143 for (int32_t i = 0; i < MAX_CB_ID_NUM; ++i) {
144 if (!idAllocator_[i]) {
145 idAllocator_[i] = true;
146 return i;
147 }
148 }
149
150 AUDIO_INFO_LOG("AllocateCbId failed because no free cbid");
151 return INVALID_CB_ID;
152 }
153
FreeCbId(int32_t cbId)154 void AudioPolicyStateMonitor::FreeCbId(int32_t cbId)
155 {
156 if (cbId <= INVALID_CB_ID || cbId >= MAX_CB_ID_NUM) {
157 AUDIO_INFO_LOG("Invalid cbId = %{public}d", cbId);
158 return;
159 }
160 idAllocator_[cbId] = false;
161 }
162
163 } // namespace AudioStandard
164 } // namespace OHOS
165