helpers.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 2011 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17. * Boston, MA 02111-1307, USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include <stdlib.h>
  22. #ifdef HAVE_DLFCN_H
  23. #include <dlfcn.h>
  24. #endif
  25. #if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
  26. #define INITGUID
  27. #include <windows.h>
  28. #ifdef HAVE_GUIDDEF_H
  29. #include <guiddef.h>
  30. #else
  31. #include <initguid.h>
  32. #endif
  33. DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71);
  34. DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71);
  35. DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16);
  36. DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e);
  37. DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6);
  38. DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
  39. DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
  40. #ifdef HAVE_MMDEVAPI
  41. #include <devpropdef.h>
  42. DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
  43. #endif
  44. #endif
  45. #include "alMain.h"
  46. #ifdef _WIN32
  47. void pthread_once(pthread_once_t *once, void (*callback)(void))
  48. {
  49. LONG ret;
  50. while((ret=InterlockedExchange(once, 1)) == 1)
  51. sched_yield();
  52. if(ret == 0)
  53. callback();
  54. InterlockedExchange(once, 2);
  55. }
  56. int pthread_key_create(pthread_key_t *key, void (*callback)(void*))
  57. {
  58. *key = TlsAlloc();
  59. if(callback)
  60. InsertUIntMapEntry(&TlsDestructor, *key, callback);
  61. return 0;
  62. }
  63. int pthread_key_delete(pthread_key_t key)
  64. {
  65. InsertUIntMapEntry(&TlsDestructor, key, NULL);
  66. TlsFree(key);
  67. return 0;
  68. }
  69. void *pthread_getspecific(pthread_key_t key)
  70. { return TlsGetValue(key); }
  71. int pthread_setspecific(pthread_key_t key, void *val)
  72. {
  73. TlsSetValue(key, val);
  74. return 0;
  75. }
  76. void *LoadLib(const char *name)
  77. { return LoadLibraryA(name); }
  78. void CloseLib(void *handle)
  79. { FreeLibrary((HANDLE)handle); }
  80. void *GetSymbol(void *handle, const char *name)
  81. {
  82. void *ret;
  83. ret = (void*)GetProcAddress((HANDLE)handle, name);
  84. if(ret == NULL)
  85. ERR("Failed to load %s\n", name);
  86. return ret;
  87. }
  88. WCHAR *strdupW(const WCHAR *str)
  89. {
  90. const WCHAR *n;
  91. WCHAR *ret;
  92. size_t len;
  93. n = str;
  94. while(*n) n++;
  95. len = n - str;
  96. ret = calloc(sizeof(WCHAR), len+1);
  97. if(ret != NULL)
  98. memcpy(ret, str, sizeof(WCHAR)*len);
  99. return ret;
  100. }
  101. #else
  102. void InitializeCriticalSection(CRITICAL_SECTION *cs)
  103. {
  104. pthread_mutexattr_t attrib;
  105. int ret;
  106. ret = pthread_mutexattr_init(&attrib);
  107. assert(ret == 0);
  108. ret = pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE);
  109. #ifdef HAVE_PTHREAD_NP_H
  110. if(ret != 0)
  111. ret = pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE);
  112. #endif
  113. assert(ret == 0);
  114. ret = pthread_mutex_init(cs, &attrib);
  115. assert(ret == 0);
  116. pthread_mutexattr_destroy(&attrib);
  117. }
  118. void DeleteCriticalSection(CRITICAL_SECTION *cs)
  119. {
  120. int ret;
  121. ret = pthread_mutex_destroy(cs);
  122. assert(ret == 0);
  123. }
  124. void EnterCriticalSection(CRITICAL_SECTION *cs)
  125. {
  126. int ret;
  127. ret = pthread_mutex_lock(cs);
  128. assert(ret == 0);
  129. }
  130. void LeaveCriticalSection(CRITICAL_SECTION *cs)
  131. {
  132. int ret;
  133. ret = pthread_mutex_unlock(cs);
  134. assert(ret == 0);
  135. }
  136. /* NOTE: This wrapper isn't quite accurate as it returns an ALuint, as opposed
  137. * to the expected DWORD. Both are defined as unsigned 32-bit types, however.
  138. * Additionally, Win32 is supposed to measure the time since Windows started,
  139. * as opposed to the actual time. */
  140. ALuint timeGetTime(void)
  141. {
  142. #if _POSIX_TIMERS > 0
  143. struct timespec ts;
  144. int ret = -1;
  145. #if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)
  146. #if _POSIX_MONOTONIC_CLOCK == 0
  147. static int hasmono = 0;
  148. if(hasmono > 0 || (hasmono == 0 &&
  149. (hasmono=sysconf(_SC_MONOTONIC_CLOCK)) > 0))
  150. #endif
  151. ret = clock_gettime(CLOCK_MONOTONIC, &ts);
  152. #endif
  153. if(ret != 0)
  154. ret = clock_gettime(CLOCK_REALTIME, &ts);
  155. assert(ret == 0);
  156. return ts.tv_nsec/1000000 + ts.tv_sec*1000;
  157. #else
  158. struct timeval tv;
  159. int ret;
  160. ret = gettimeofday(&tv, NULL);
  161. assert(ret == 0);
  162. return tv.tv_usec/1000 + tv.tv_sec*1000;
  163. #endif
  164. }
  165. void Sleep(ALuint t)
  166. {
  167. struct timespec tv, rem;
  168. tv.tv_nsec = (t*1000000)%1000000000;
  169. tv.tv_sec = t/1000;
  170. while(nanosleep(&tv, &rem) == -1 && errno == EINTR)
  171. tv = rem;
  172. }
  173. #ifdef HAVE_DLFCN_H
  174. void *LoadLib(const char *name)
  175. {
  176. const char *err;
  177. void *handle;
  178. dlerror();
  179. handle = dlopen(name, RTLD_NOW);
  180. if((err=dlerror()) != NULL)
  181. handle = NULL;
  182. return handle;
  183. }
  184. void CloseLib(void *handle)
  185. { dlclose(handle); }
  186. void *GetSymbol(void *handle, const char *name)
  187. {
  188. const char *err;
  189. void *sym;
  190. dlerror();
  191. sym = dlsym(handle, name);
  192. if((err=dlerror()) != NULL)
  193. {
  194. WARN("Failed to load %s: %s\n", name, err);
  195. sym = NULL;
  196. }
  197. return sym;
  198. }
  199. #endif
  200. #endif
  201. void al_print(const char *func, const char *fmt, ...)
  202. {
  203. char str[256];
  204. int i;
  205. i = snprintf(str, sizeof(str), "AL lib: %s: ", func);
  206. if(i < (int)sizeof(str) && i > 0)
  207. {
  208. va_list ap;
  209. va_start(ap, fmt);
  210. vsnprintf(str+i, sizeof(str)-i, fmt, ap);
  211. va_end(ap);
  212. }
  213. str[sizeof(str)-1] = 0;
  214. fprintf(LogFile, "%s", str);
  215. fflush(LogFile);
  216. }
  217. void SetRTPriority(void)
  218. {
  219. ALboolean failed = AL_FALSE;
  220. #ifdef _WIN32
  221. if(RTPrioLevel > 0)
  222. failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  223. #elif defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__)
  224. if(RTPrioLevel > 0)
  225. {
  226. struct sched_param param;
  227. /* Use the minimum real-time priority possible for now (on Linux this
  228. * should be 1 for SCHED_RR) */
  229. param.sched_priority = sched_get_priority_min(SCHED_RR);
  230. failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, &param);
  231. }
  232. #else
  233. /* Real-time priority not available */
  234. failed = (RTPrioLevel>0);
  235. #endif
  236. if(failed)
  237. ERR("Failed to set priority level for thread\n");
  238. }
  239. static void Lock(volatile ALenum *l)
  240. {
  241. while(ExchangeInt(l, AL_TRUE) == AL_TRUE)
  242. sched_yield();
  243. }
  244. static void Unlock(volatile ALenum *l)
  245. {
  246. ExchangeInt(l, AL_FALSE);
  247. }
  248. void RWLockInit(RWLock *lock)
  249. {
  250. lock->read_count = 0;
  251. lock->write_count = 0;
  252. lock->read_lock = AL_FALSE;
  253. lock->read_entry_lock = AL_FALSE;
  254. lock->write_lock = AL_FALSE;
  255. }
  256. void ReadLock(RWLock *lock)
  257. {
  258. Lock(&lock->read_entry_lock);
  259. Lock(&lock->read_lock);
  260. if(IncrementRef(&lock->read_count) == 1)
  261. Lock(&lock->write_lock);
  262. Unlock(&lock->read_lock);
  263. Unlock(&lock->read_entry_lock);
  264. }
  265. void ReadUnlock(RWLock *lock)
  266. {
  267. if(DecrementRef(&lock->read_count) == 0)
  268. Unlock(&lock->write_lock);
  269. }
  270. void WriteLock(RWLock *lock)
  271. {
  272. if(IncrementRef(&lock->write_count) == 1)
  273. Lock(&lock->read_lock);
  274. Lock(&lock->write_lock);
  275. }
  276. void WriteUnlock(RWLock *lock)
  277. {
  278. Unlock(&lock->write_lock);
  279. if(DecrementRef(&lock->write_count) == 0)
  280. Unlock(&lock->read_lock);
  281. }
  282. void InitUIntMap(UIntMap *map, ALsizei limit)
  283. {
  284. map->array = NULL;
  285. map->size = 0;
  286. map->maxsize = 0;
  287. map->limit = limit;
  288. RWLockInit(&map->lock);
  289. }
  290. void ResetUIntMap(UIntMap *map)
  291. {
  292. WriteLock(&map->lock);
  293. free(map->array);
  294. map->array = NULL;
  295. map->size = 0;
  296. map->maxsize = 0;
  297. WriteUnlock(&map->lock);
  298. }
  299. ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value)
  300. {
  301. ALsizei pos = 0;
  302. WriteLock(&map->lock);
  303. if(map->size > 0)
  304. {
  305. ALsizei low = 0;
  306. ALsizei high = map->size - 1;
  307. while(low < high)
  308. {
  309. ALsizei mid = low + (high-low)/2;
  310. if(map->array[mid].key < key)
  311. low = mid + 1;
  312. else
  313. high = mid;
  314. }
  315. if(map->array[low].key < key)
  316. low++;
  317. pos = low;
  318. }
  319. if(pos == map->size || map->array[pos].key != key)
  320. {
  321. if(map->size == map->limit)
  322. {
  323. WriteUnlock(&map->lock);
  324. return AL_OUT_OF_MEMORY;
  325. }
  326. if(map->size == map->maxsize)
  327. {
  328. ALvoid *temp = NULL;
  329. ALsizei newsize;
  330. newsize = (map->maxsize ? (map->maxsize<<1) : 4);
  331. if(newsize >= map->maxsize)
  332. temp = realloc(map->array, newsize*sizeof(map->array[0]));
  333. if(!temp)
  334. {
  335. WriteUnlock(&map->lock);
  336. return AL_OUT_OF_MEMORY;
  337. }
  338. map->array = temp;
  339. map->maxsize = newsize;
  340. }
  341. if(pos < map->size)
  342. memmove(&map->array[pos+1], &map->array[pos],
  343. (map->size-pos)*sizeof(map->array[0]));
  344. map->size++;
  345. }
  346. map->array[pos].key = key;
  347. map->array[pos].value = value;
  348. WriteUnlock(&map->lock);
  349. return AL_NO_ERROR;
  350. }
  351. ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key)
  352. {
  353. ALvoid *ptr = NULL;
  354. WriteLock(&map->lock);
  355. if(map->size > 0)
  356. {
  357. ALsizei low = 0;
  358. ALsizei high = map->size - 1;
  359. while(low < high)
  360. {
  361. ALsizei mid = low + (high-low)/2;
  362. if(map->array[mid].key < key)
  363. low = mid + 1;
  364. else
  365. high = mid;
  366. }
  367. if(map->array[low].key == key)
  368. {
  369. ptr = map->array[low].value;
  370. if(low < map->size-1)
  371. memmove(&map->array[low], &map->array[low+1],
  372. (map->size-1-low)*sizeof(map->array[0]));
  373. map->size--;
  374. }
  375. }
  376. WriteUnlock(&map->lock);
  377. return ptr;
  378. }
  379. ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key)
  380. {
  381. ALvoid *ptr = NULL;
  382. ReadLock(&map->lock);
  383. if(map->size > 0)
  384. {
  385. ALsizei low = 0;
  386. ALsizei high = map->size - 1;
  387. while(low < high)
  388. {
  389. ALsizei mid = low + (high-low)/2;
  390. if(map->array[mid].key < key)
  391. low = mid + 1;
  392. else
  393. high = mid;
  394. }
  395. if(map->array[low].key == key)
  396. ptr = map->array[low].value;
  397. }
  398. ReadUnlock(&map->lock);
  399. return ptr;
  400. }