1 /*
2  * Copyright (c) 2024 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 #include "audio_thread_task.h"
16 #include <pthread.h>
17 #include "ipc_skeleton.h"
18 #include "audio_schedule_guard.h"
19 
20 namespace OHOS {
21 namespace AudioStandard {
22 constexpr int32_t TIME_OUT_MS = 500;
23 constexpr int32_t MAX_THREAD_NAME_LENGTH = 15;
AudioThreadTask(const std::string & name)24 AudioThreadTask::AudioThreadTask(const std::string &name) : name_(name), state_(RunningState::STOPPED), loop_(nullptr)
25 {
26 }
27 
~AudioThreadTask()28 AudioThreadTask::~AudioThreadTask()
29 {
30     state_ = RunningState::STOPPED;
31     cond_.notify_all();
32     if (loop_) {
33         if (loop_->joinable()) {
34             loop_->join();
35         }
36         loop_ = nullptr;
37     }
38 }
39 
Start()40 void AudioThreadTask::Start()
41 {
42     std::unique_lock lock(stateMutex_);
43     if (state_.load() == RunningState::STOPPING) {
44         cond_.wait(lock, [this] { return state_.load() == RunningState::STOPPED; });
45     }
46     if (state_.load() == RunningState::STOPPED) {
47         if (loop_) {
48             if (loop_->joinable()) {
49                 loop_->join();
50             }
51             loop_ = nullptr;
52         }
53     }
54 
55     state_ = RunningState::STARTED;
56 
57     if (!loop_) {
58         loop_ = std::make_unique<std::thread>([this] { this->RunJob(); });
59         pthread_setname_np(loop_->native_handle(), name_.substr(0, MAX_THREAD_NAME_LENGTH).c_str());
60     }
61     cond_.notify_all();
62 }
63 
Stop()64 void AudioThreadTask::Stop()
65 {
66     std::unique_lock lock(stateMutex_);
67     if (state_.load() != RunningState::STOPPED) {
68         state_ = RunningState::STOPPING;
69         cond_.notify_all();
70         cond_.wait(lock, [this] { return state_.load() == RunningState::STOPPED; });
71         if (loop_) {
72             if (loop_->joinable()) {
73                 loop_->join();
74             }
75             loop_ = nullptr;
76         }
77     }
78 }
79 
CheckThreadIsRunning() const80 bool AudioThreadTask::CheckThreadIsRunning() const noexcept
81 {
82     return state_.load() == RunningState::STARTED;
83 }
84 
StopAsync()85 void AudioThreadTask::StopAsync()
86 {
87     std::lock_guard lock(stateMutex_);
88     if (state_.load() != RunningState::STOPPING && state_.load() != RunningState::STOPPED) {
89         state_ = RunningState::STOPPING;
90         cond_.notify_all();
91     }
92 }
93 
Pause()94 void AudioThreadTask::Pause()
95 {
96     std::unique_lock lock(stateMutex_);
97     switch (state_.load()) {
98         case RunningState::STARTED: {
99             state_ = RunningState::PAUSING;
100             cond_.wait(lock, [this] {
101                 return state_.load() == RunningState::PAUSED || state_.load() == RunningState::STOPPED;
102             });
103             break;
104         }
105         case RunningState::STOPPING: {
106             cond_.wait(lock, [this] { return state_.load() == RunningState::STOPPED; });
107             break;
108         }
109         case RunningState::PAUSING: {
110             cond_.wait(lock, [this] { return state_.load() == RunningState::PAUSED; });
111             break;
112         }
113         default:
114             break;
115     }
116 }
117 
PauseAsync()118 void AudioThreadTask::PauseAsync()
119 {
120     std::lock_guard lock(stateMutex_);
121     if (state_.load() == RunningState::STARTED) {
122         state_ = RunningState::PAUSING;
123     }
124 }
125 
RegisterJob(std::function<void ()> && job)126 void AudioThreadTask::RegisterJob(std::function<void()> &&job)
127 {
128     job_ = std::move(job);
129 }
130 
doEmptyJob()131 void AudioThreadTask::doEmptyJob() {}
132 
RunJob()133 void AudioThreadTask::RunJob()
134 {
135     AudioScheduleGuard scheduleGuard(getpid(), gettid());
136     for (;;) {
137         if (state_.load() == RunningState::STARTED) {
138             job_();
139         }
140         std::unique_lock lock(stateMutex_);
141         if (state_.load() == RunningState::PAUSING || state_.load() == RunningState::PAUSED) {
142             state_ = RunningState::PAUSED;
143             cond_.notify_all();
144             cond_.wait_for(lock, std::chrono::milliseconds(TIME_OUT_MS),
145                 [this] { return state_.load() != RunningState::PAUSED; });
146         }
147         if (state_.load() == RunningState::STOPPING || state_.load() == RunningState::STOPPED) {
148             state_ = RunningState::STOPPED;
149             cond_.notify_all();
150             break;
151         }
152     }
153 }
154 } // namespace AudioStandard
155 } // namespace OHOS
156