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