1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#include "Pool.h"
22
23#include "Source.h"
24
25namespace love
26{
27namespace audio
28{
29namespace openal
30{
31
32Pool::Pool()
33 : sources()
34 , totalSources(0)
35{
36 // Clear errors.
37 alGetError();
38
39 // Generate sources.
40 for (int i = 0; i < MAX_SOURCES; i++)
41 {
42 alGenSources(1, &sources[i]);
43
44 // We might hit an implementation-dependent limit on the total number
45 // of sources before reaching MAX_SOURCES.
46 if (alGetError() != AL_NO_ERROR)
47 break;
48
49 totalSources++;
50 }
51
52 if (totalSources < 4)
53 throw love::Exception("Could not generate sources.");
54
55#ifdef AL_SOFT_direct_channels
56 ALboolean hasext = alIsExtensionPresent("AL_SOFT_direct_channels");
57#endif
58
59 // Make all sources available initially.
60 for (int i = 0; i < totalSources; i++)
61 {
62#ifdef AL_SOFT_direct_channels
63 if (hasext)
64 {
65 // Bypass virtualization of speakers for multi-channel sources in OpenAL Soft.
66 alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE);
67 }
68#endif
69
70 available.push(sources[i]);
71 }
72}
73
74Pool::~Pool()
75{
76 Source::stop(this);
77
78 // Free all sources.
79 alDeleteSources(totalSources, sources);
80}
81
82bool Pool::isAvailable() const
83{
84 bool has = false;
85 {
86 thread::Lock lock(mutex);
87 has = !available.empty();
88 }
89 return has;
90}
91
92bool Pool::isPlaying(Source *s)
93{
94 bool p = false;
95 {
96 thread::Lock lock(mutex);
97 p = (playing.find(s) != playing.end());
98 }
99 return p;
100}
101
102void Pool::update()
103{
104 thread::Lock lock(mutex);
105
106 std::vector<Source *> torelease;
107
108 for (const auto &i : playing)
109 {
110 if (!i.first->update())
111 torelease.push_back(i.first);
112 }
113
114 for (Source *s : torelease)
115 releaseSource(s);
116}
117
118int Pool::getActiveSourceCount() const
119{
120 return (int) playing.size();
121}
122
123int Pool::getMaxSources() const
124{
125 return totalSources;
126}
127
128bool Pool::assignSource(Source *source, ALuint &out, char &wasPlaying)
129{
130 out = 0;
131
132 if (findSource(source, out))
133 return wasPlaying = true;
134
135 wasPlaying = false;
136
137 if (available.empty())
138 return false;
139
140 out = available.front();
141 available.pop();
142
143 playing.insert(std::make_pair(source, out));
144 source->retain();
145 return true;
146}
147
148bool Pool::releaseSource(Source *source, bool stop)
149{
150 ALuint s;
151
152 if (findSource(source, s))
153 {
154 if (stop)
155 source->stopAtomic();
156 source->release();
157 available.push(s);
158 playing.erase(source);
159 return true;
160 }
161
162 return false;
163}
164
165bool Pool::findSource(Source *source, ALuint &out)
166{
167 std::map<Source *, ALuint>::const_iterator i = playing.find(source);
168
169 if (i == playing.end())
170 return false;
171
172 out = i->second;
173 return true;
174}
175
176thread::Lock Pool::lock()
177{
178 return thread::Lock(mutex);
179}
180
181std::vector<love::audio::Source*> Pool::getPlayingSources()
182{
183 std::vector<love::audio::Source*> sources;
184 sources.reserve(playing.size());
185 for (auto &i : playing)
186 sources.push_back(i.first);
187 return sources;
188}
189
190} // openal
191} // audio
192} // love
193