• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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