• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #define LOG_TAG "AAudioCommandQueue"
18 //#define LOG_NDEBUG 0
19 
20 #include <chrono>
21 
22 #include <utils/Log.h>
23 
24 #include "AAudioCommandQueue.h"
25 
26 namespace aaudio {
27 
sendCommand(const std::shared_ptr<AAudioCommand> & command)28 aaudio_result_t AAudioCommandQueue::sendCommand(const std::shared_ptr<AAudioCommand>& command) {
29     {
30         std::scoped_lock<std::mutex> _l(mLock);
31         if (!mRunning) {
32             ALOGE("Tried to send command while it was not running");
33             return AAUDIO_ERROR_INVALID_STATE;
34         }
35         mCommands.push(command);
36         mWaitWorkCond.notify_one();
37     }
38 
39     std::unique_lock _cl(command->lock);
40     android::base::ScopedLockAssertion lockAssertion(command->lock);
41     ALOGV("Sending command %d, wait for reply(%d) with timeout %jd",
42            command->operationCode, command->isWaitingForReply, command->timeoutNanoseconds);
43     // `mWaitForReply` is first initialized when the command is constructed. It will be flipped
44     // when the command is completed.
45     auto timeoutExpire = std::chrono::steady_clock::now()
46             + std::chrono::nanoseconds(command->timeoutNanoseconds);
47     while (command->isWaitingForReply) {
48         if (command->conditionVariable.wait_until(_cl, timeoutExpire)
49                 == std::cv_status::timeout) {
50             ALOGD("Command %d time out", command->operationCode);
51             command->result = AAUDIO_ERROR_TIMEOUT;
52             command->isWaitingForReply = false;
53         }
54     }
55     ALOGV("Command %d sent with result as %d", command->operationCode, command->result);
56     return command->result;
57 }
58 
waitForCommand(int64_t timeoutNanos)59 std::shared_ptr<AAudioCommand> AAudioCommandQueue::waitForCommand(int64_t timeoutNanos) {
60     std::shared_ptr<AAudioCommand> command;
61     {
62         std::unique_lock _l(mLock);
63         android::base::ScopedLockAssertion lockAssertion(mLock);
64         if (timeoutNanos >= 0) {
65             mWaitWorkCond.wait_for(_l, std::chrono::nanoseconds(timeoutNanos), [this]() {
66                 android::base::ScopedLockAssertion lockAssertion(mLock);
67                 return !mRunning || !mCommands.empty();
68             });
69         } else {
70             mWaitWorkCond.wait(_l, [this]() {
71                 android::base::ScopedLockAssertion lockAssertion(mLock);
72                 return !mRunning || !mCommands.empty();
73             });
74         }
75         if (!mCommands.empty() && mRunning) {
76             command = mCommands.front();
77             mCommands.pop();
78         }
79     }
80     return command;
81 }
82 
startWaiting()83 void AAudioCommandQueue::startWaiting() {
84     std::scoped_lock<std::mutex> _l(mLock);
85     mRunning = true;
86 }
87 
stopWaiting()88 void AAudioCommandQueue::stopWaiting() {
89     std::scoped_lock<std::mutex> _l(mLock);
90     mRunning = false;
91     // Clear all commands in the queue as the command thread is stopped.
92     while (!mCommands.empty()) {
93         auto command = mCommands.front();
94         mCommands.pop();
95         std::scoped_lock<std::mutex> _cl(command->lock);
96         // If the command is waiting for result, returns AAUDIO_ERROR_INVALID_STATE
97         // as there is no thread waiting for the command.
98         if (command->isWaitingForReply) {
99             command->result = AAUDIO_ERROR_INVALID_STATE;
100             command->isWaitingForReply = false;
101             command->conditionVariable.notify_one();
102         }
103     }
104     mWaitWorkCond.notify_one();
105 }
106 
107 } // namespace aaudio