Pool.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /**
  2. * Copyright (c) 2006-2016 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. #include "Pool.h"
  21. #include "Source.h"
  22. namespace love
  23. {
  24. namespace audio
  25. {
  26. namespace openal
  27. {
  28. Pool::Pool()
  29. : sources()
  30. , totalSources(0)
  31. {
  32. // Clear errors.
  33. alGetError();
  34. // Generate sources.
  35. for (int i = 0; i < MAX_SOURCES; i++)
  36. {
  37. alGenSources(1, &sources[i]);
  38. // We might hit an implementation-dependent limit on the total number
  39. // of sources before reaching MAX_SOURCES.
  40. if (alGetError() != AL_NO_ERROR)
  41. break;
  42. totalSources++;
  43. }
  44. if (totalSources < 4)
  45. throw love::Exception("Could not generate sources.");
  46. #ifdef AL_SOFT_direct_channels
  47. ALboolean hasext = alIsExtensionPresent("AL_SOFT_direct_channels");
  48. #endif
  49. // Make all sources available initially.
  50. for (int i = 0; i < totalSources; i++)
  51. {
  52. #ifdef AL_SOFT_direct_channels
  53. if (hasext)
  54. {
  55. // Bypass virtualization of speakers for multi-channel sources in OpenAL Soft.
  56. alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE);
  57. }
  58. #endif
  59. available.push(sources[i]);
  60. }
  61. }
  62. Pool::~Pool()
  63. {
  64. stop();
  65. // Free all sources.
  66. alDeleteSources(totalSources, sources);
  67. }
  68. bool Pool::isAvailable() const
  69. {
  70. bool has = false;
  71. {
  72. thread::Lock lock(mutex);
  73. has = !available.empty();
  74. }
  75. return has;
  76. }
  77. bool Pool::isPlaying(Source *s)
  78. {
  79. bool p = false;
  80. {
  81. thread::Lock lock(mutex);
  82. p = (playing.find(s) != playing.end());
  83. }
  84. return p;
  85. }
  86. void Pool::update()
  87. {
  88. thread::Lock lock(mutex);
  89. std::map<Source *, ALuint>::iterator i = playing.begin();
  90. while (i != playing.end())
  91. {
  92. if (!i->first->update())
  93. {
  94. i->first->stopAtomic();
  95. i->first->release();
  96. available.push(i->second);
  97. playing.erase(i++);
  98. }
  99. else
  100. i++;
  101. }
  102. }
  103. int Pool::getSourceCount() const
  104. {
  105. return (int) playing.size();
  106. }
  107. int Pool::getMaxSources() const
  108. {
  109. return totalSources;
  110. }
  111. bool Pool::assignSource(Source *source, ALuint &out, char *wasPlaying)
  112. {
  113. out = 0;
  114. if (findSource(source, out))
  115. {
  116. if (wasPlaying)
  117. *wasPlaying = true;
  118. return true;
  119. }
  120. if (wasPlaying)
  121. *wasPlaying = false;
  122. if (available.empty())
  123. return false;
  124. out = available.front();
  125. available.pop();
  126. playing.insert(std::make_pair(source, out));
  127. source->retain();
  128. return true;
  129. }
  130. bool Pool::play(Source *source)
  131. {
  132. thread::Lock lock(mutex);
  133. ALuint out;
  134. char wasPlaying;
  135. if (!assignSource(source, out, &wasPlaying))
  136. return false;
  137. if (!wasPlaying)
  138. return source->playAtomic(out);
  139. else
  140. {
  141. source->resumeAtomic();
  142. return true;
  143. }
  144. }
  145. bool Pool::play(const std::vector<love::audio::Source*> &sources)
  146. {
  147. thread::Lock lock(mutex);
  148. std::vector<ALuint> ids(sources.size());
  149. // NOTE: not bool, because std::vector<bool> is implemented as a bitvector
  150. // which means no pointers can be created.
  151. std::vector<char> wasPlaying(sources.size());
  152. for (size_t i = 0; i < sources.size(); i++)
  153. {
  154. Source *source = (Source*) sources[i];
  155. if (!assignSource(source, ids[i], &wasPlaying[i]))
  156. {
  157. // Now we need to release the resources we had already allocated
  158. for (size_t j = 0; j < sources.size(); j++)
  159. if (!wasPlaying[j])
  160. release((Source*) sources[j]);
  161. return false;
  162. }
  163. }
  164. return Source::playAtomic(sources, ids, wasPlaying);
  165. }
  166. void Pool::stop()
  167. {
  168. thread::Lock lock(mutex);
  169. for (const auto &i : playing)
  170. {
  171. i.first->stopAtomic();
  172. i.first->release();
  173. available.push(i.second);
  174. }
  175. playing.clear();
  176. }
  177. void Pool::stop(Source *source)
  178. {
  179. thread::Lock lock(mutex);
  180. removeSource(source);
  181. }
  182. void Pool::stop(const std::vector<love::audio::Source*> &sources)
  183. {
  184. thread::Lock lock(mutex);
  185. Source::stopAtomic(sources);
  186. }
  187. std::vector<love::audio::Source*> Pool::pause()
  188. {
  189. thread::Lock lock(mutex);
  190. std::vector<love::audio::Source*> werePlaying;
  191. werePlaying.reserve(playing.size());
  192. for (const auto &i : playing)
  193. {
  194. if (!i.first->isPlaying())
  195. continue;
  196. werePlaying.push_back(i.first);
  197. i.first->pauseAtomic();
  198. }
  199. return werePlaying;
  200. }
  201. void Pool::pause(Source *source)
  202. {
  203. thread::Lock lock(mutex);
  204. ALuint out;
  205. if (findSource(source, out))
  206. source->pauseAtomic();
  207. }
  208. void Pool::pause(const std::vector<love::audio::Source*> &sources)
  209. {
  210. thread::Lock lock(mutex);
  211. Source::pauseAtomic(sources);
  212. }
  213. void Pool::release(Source *source)
  214. {
  215. ALuint s = findi(source);
  216. if (s != 0)
  217. {
  218. available.push(s);
  219. playing.erase(source);
  220. }
  221. }
  222. void Pool::seek(Source *source, float offset, void *unit)
  223. {
  224. thread::Lock lock(mutex);
  225. return source->seekAtomic(offset, unit);
  226. }
  227. float Pool::tell(Source *source, void *unit)
  228. {
  229. thread::Lock lock(mutex);
  230. return source->tellAtomic(unit);
  231. }
  232. double Pool::getDuration(Source *source, void *unit)
  233. {
  234. thread::Lock lock(mutex);
  235. return source->getDurationAtomic(unit);
  236. }
  237. bool Pool::queue(Source *source, void *data, ALsizei length)
  238. {
  239. thread::Lock lock(mutex);
  240. return source->queueAtomic(data, length);
  241. }
  242. ALuint Pool::findi(const Source *source) const
  243. {
  244. std::map<Source *, ALuint>::const_iterator i = playing.find((Source *)source);
  245. if (i != playing.end())
  246. return i->second;
  247. return 0;
  248. }
  249. bool Pool::findSource(Source *source, ALuint &out)
  250. {
  251. std::map<Source *, ALuint>::const_iterator i = playing.find((Source *)source);
  252. bool found = i != playing.end();
  253. if (found)
  254. out = i->second;
  255. return found;
  256. }
  257. bool Pool::removeSource(Source *source)
  258. {
  259. std::map<Source *, ALuint>::iterator i = playing.find((Source *)source);
  260. if (i != playing.end())
  261. {
  262. source->stopAtomic();
  263. available.push(i->second);
  264. playing.erase(i++);
  265. source->release();
  266. return true;
  267. }
  268. return false;
  269. }
  270. } // openal
  271. } // audio
  272. } // love