1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker */
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*d57664e9SAndroid Build Coastguard Worker #define LOG_TAG "SoundPool::SoundDecoder"
19*d57664e9SAndroid Build Coastguard Worker #include "utils/Log.h"
20*d57664e9SAndroid Build Coastguard Worker
21*d57664e9SAndroid Build Coastguard Worker #include "SoundDecoder.h"
22*d57664e9SAndroid Build Coastguard Worker
23*d57664e9SAndroid Build Coastguard Worker namespace android::soundpool {
24*d57664e9SAndroid Build Coastguard Worker
25*d57664e9SAndroid Build Coastguard Worker // Maximum Samples that can be background decoded before we block the caller.
26*d57664e9SAndroid Build Coastguard Worker static constexpr size_t kMaxQueueSize = 128;
27*d57664e9SAndroid Build Coastguard Worker
28*d57664e9SAndroid Build Coastguard Worker // The amount of time we wait for a new Sound decode request
29*d57664e9SAndroid Build Coastguard Worker // before the SoundDecoder thread closes.
30*d57664e9SAndroid Build Coastguard Worker static constexpr int32_t kWaitTimeBeforeCloseMs = 1000;
31*d57664e9SAndroid Build Coastguard Worker
SoundDecoder(SoundManager * soundManager,size_t threads,int32_t threadPriority)32*d57664e9SAndroid Build Coastguard Worker SoundDecoder::SoundDecoder(SoundManager* soundManager, size_t threads, int32_t threadPriority)
33*d57664e9SAndroid Build Coastguard Worker : mSoundManager(soundManager)
34*d57664e9SAndroid Build Coastguard Worker {
35*d57664e9SAndroid Build Coastguard Worker ALOGV("%s(%p, %zu)", __func__, soundManager, threads);
36*d57664e9SAndroid Build Coastguard Worker // ThreadPool is created, but we don't launch any threads.
37*d57664e9SAndroid Build Coastguard Worker mThreadPool = std::make_unique<ThreadPool>(
38*d57664e9SAndroid Build Coastguard Worker std::min(threads, (size_t)std::thread::hardware_concurrency()),
39*d57664e9SAndroid Build Coastguard Worker "SoundDecoder_",
40*d57664e9SAndroid Build Coastguard Worker threadPriority);
41*d57664e9SAndroid Build Coastguard Worker }
42*d57664e9SAndroid Build Coastguard Worker
~SoundDecoder()43*d57664e9SAndroid Build Coastguard Worker SoundDecoder::~SoundDecoder()
44*d57664e9SAndroid Build Coastguard Worker {
45*d57664e9SAndroid Build Coastguard Worker ALOGV("%s()", __func__);
46*d57664e9SAndroid Build Coastguard Worker quit();
47*d57664e9SAndroid Build Coastguard Worker }
48*d57664e9SAndroid Build Coastguard Worker
quit()49*d57664e9SAndroid Build Coastguard Worker void SoundDecoder::quit()
50*d57664e9SAndroid Build Coastguard Worker {
51*d57664e9SAndroid Build Coastguard Worker ALOGV("%s()", __func__);
52*d57664e9SAndroid Build Coastguard Worker {
53*d57664e9SAndroid Build Coastguard Worker std::lock_guard lock(mLock);
54*d57664e9SAndroid Build Coastguard Worker mQuit = true;
55*d57664e9SAndroid Build Coastguard Worker mQueueSpaceAvailable.notify_all(); // notify all load waiters
56*d57664e9SAndroid Build Coastguard Worker mQueueDataAvailable.notify_all(); // notify all worker threads
57*d57664e9SAndroid Build Coastguard Worker }
58*d57664e9SAndroid Build Coastguard Worker mThreadPool->quit();
59*d57664e9SAndroid Build Coastguard Worker }
60*d57664e9SAndroid Build Coastguard Worker
run(int32_t id)61*d57664e9SAndroid Build Coastguard Worker void SoundDecoder::run(int32_t id)
62*d57664e9SAndroid Build Coastguard Worker {
63*d57664e9SAndroid Build Coastguard Worker ALOGV("%s(%d): entering", __func__, id);
64*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mLock);
65*d57664e9SAndroid Build Coastguard Worker while (!mQuit) {
66*d57664e9SAndroid Build Coastguard Worker if (mSoundIDs.size() == 0) {
67*d57664e9SAndroid Build Coastguard Worker ALOGV("%s(%d): waiting", __func__, id);
68*d57664e9SAndroid Build Coastguard Worker mQueueDataAvailable.wait_for(
69*d57664e9SAndroid Build Coastguard Worker lock, std::chrono::duration<int32_t, std::milli>(kWaitTimeBeforeCloseMs));
70*d57664e9SAndroid Build Coastguard Worker if (mSoundIDs.size() == 0) {
71*d57664e9SAndroid Build Coastguard Worker break; // no new sound, exit this thread.
72*d57664e9SAndroid Build Coastguard Worker }
73*d57664e9SAndroid Build Coastguard Worker continue;
74*d57664e9SAndroid Build Coastguard Worker }
75*d57664e9SAndroid Build Coastguard Worker const int32_t soundID = mSoundIDs.front();
76*d57664e9SAndroid Build Coastguard Worker mSoundIDs.pop_front();
77*d57664e9SAndroid Build Coastguard Worker mQueueSpaceAvailable.notify_one();
78*d57664e9SAndroid Build Coastguard Worker ALOGV("%s(%d): processing soundID: %d size: %zu", __func__, id, soundID, mSoundIDs.size());
79*d57664e9SAndroid Build Coastguard Worker lock.unlock();
80*d57664e9SAndroid Build Coastguard Worker std::shared_ptr<Sound> sound = mSoundManager->findSound(soundID);
81*d57664e9SAndroid Build Coastguard Worker status_t status = NO_INIT;
82*d57664e9SAndroid Build Coastguard Worker if (sound.get() != nullptr) {
83*d57664e9SAndroid Build Coastguard Worker status = sound->doLoad();
84*d57664e9SAndroid Build Coastguard Worker }
85*d57664e9SAndroid Build Coastguard Worker ALOGV("%s(%d): notifying loaded soundID:%d status:%d", __func__, id, soundID, status);
86*d57664e9SAndroid Build Coastguard Worker mSoundManager->notify(SoundPoolEvent(SoundPoolEvent::SOUND_LOADED, soundID, status));
87*d57664e9SAndroid Build Coastguard Worker lock.lock();
88*d57664e9SAndroid Build Coastguard Worker }
89*d57664e9SAndroid Build Coastguard Worker ALOGV("%s(%d): exiting", __func__, id);
90*d57664e9SAndroid Build Coastguard Worker }
91*d57664e9SAndroid Build Coastguard Worker
loadSound(int32_t soundID)92*d57664e9SAndroid Build Coastguard Worker void SoundDecoder::loadSound(int32_t soundID)
93*d57664e9SAndroid Build Coastguard Worker {
94*d57664e9SAndroid Build Coastguard Worker ALOGV("%s(%d)", __func__, soundID);
95*d57664e9SAndroid Build Coastguard Worker size_t pendingSounds;
96*d57664e9SAndroid Build Coastguard Worker {
97*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mLock);
98*d57664e9SAndroid Build Coastguard Worker while (mSoundIDs.size() == kMaxQueueSize) {
99*d57664e9SAndroid Build Coastguard Worker if (mQuit) return;
100*d57664e9SAndroid Build Coastguard Worker ALOGV("%s: waiting soundID: %d size: %zu", __func__, soundID, mSoundIDs.size());
101*d57664e9SAndroid Build Coastguard Worker mQueueSpaceAvailable.wait(lock);
102*d57664e9SAndroid Build Coastguard Worker }
103*d57664e9SAndroid Build Coastguard Worker if (mQuit) return;
104*d57664e9SAndroid Build Coastguard Worker mSoundIDs.push_back(soundID);
105*d57664e9SAndroid Build Coastguard Worker mQueueDataAvailable.notify_one();
106*d57664e9SAndroid Build Coastguard Worker ALOGV("%s: adding soundID: %d size: %zu", __func__, soundID, mSoundIDs.size());
107*d57664e9SAndroid Build Coastguard Worker pendingSounds = mSoundIDs.size();
108*d57664e9SAndroid Build Coastguard Worker }
109*d57664e9SAndroid Build Coastguard Worker // Launch threads as needed. The "as needed" is weakly consistent as we release mLock.
110*d57664e9SAndroid Build Coastguard Worker if (pendingSounds > mThreadPool->getActiveThreadCount()) {
111*d57664e9SAndroid Build Coastguard Worker const int32_t id = mThreadPool->launch([this](int32_t id) { run(id); });
112*d57664e9SAndroid Build Coastguard Worker (void)id; // avoid clang warning -Wunused-variable -Wused-but-marked-unused
113*d57664e9SAndroid Build Coastguard Worker ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
114*d57664e9SAndroid Build Coastguard Worker }
115*d57664e9SAndroid Build Coastguard Worker }
116*d57664e9SAndroid Build Coastguard Worker
117*d57664e9SAndroid Build Coastguard Worker } // end namespace android::soundpool
118