/libs/ObjectAL/OpenAL/ALContext.m

http://github.com/kstenerud/ObjectAL-for-iPhone · Objective C · 493 lines · 368 code · 86 blank · 39 comment · 38 complexity · 996a34ad67c11325f6f8b4c8f32a1f84 MD5 · raw file

  1. //
  2. // ALContext.m
  3. // ObjectAL
  4. //
  5. // Created by Karl Stenerud on 10-01-09.
  6. //
  7. // Copyright 2009 Karl Stenerud
  8. //
  9. // Licensed under the Apache License, Version 2.0 (the "License");
  10. // you may not use this file except in compliance with the License.
  11. // You may obtain a copy of the License at
  12. //
  13. // http://www.apache.org/licenses/LICENSE-2.0
  14. //
  15. // Unless required by applicable law or agreed to in writing, software
  16. // distributed under the License is distributed on an "AS IS" BASIS,
  17. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. // See the License for the specific language governing permissions and
  19. // limitations under the License.
  20. //
  21. // Note: You are NOT required to make the license available from within your
  22. // iOS application. Including it in your project is sufficient.
  23. //
  24. // Attribution is not required, but appreciated :)
  25. //
  26. #import "ALContext.h"
  27. #import "NSMutableArray+WeakReferences.h"
  28. #import "ObjectALMacros.h"
  29. #import "ALWrapper.h"
  30. #import "OpenALManager.h"
  31. #import "ALDevice.h"
  32. #pragma mark -
  33. #pragma mark Private Methods
  34. /**
  35. * (INTERNAL USE) Private methods for ALContext.
  36. */
  37. @interface ALContext (Private)
  38. /** (INTERNAL USE) Close any resources belonging to the OS.
  39. */
  40. - (void) closeOSResources;
  41. /** (INTERNAL USE) Called by SuspendHandler.
  42. */
  43. - (void) setSuspended:(bool) value;
  44. @end
  45. @implementation ALContext
  46. #pragma mark Object Management
  47. + (id) contextOnDevice:(ALDevice *) device attributes:(NSArray*) attributes
  48. {
  49. return [[[self alloc] initOnDevice:device attributes:attributes] autorelease];
  50. }
  51. + (id) contextOnDevice:(ALDevice*) device
  52. outputFrequency:(int) outputFrequency
  53. refreshIntervals:(int) refreshIntervals
  54. synchronousContext:(bool) synchronousContext
  55. monoSources:(int) monoSources
  56. stereoSources:(int) stereoSources
  57. {
  58. NSMutableArray* attributes = [NSMutableArray arrayWithCapacity:5];
  59. if(outputFrequency > 0)
  60. {
  61. [attributes addObject:[NSNumber numberWithInt:ALC_FREQUENCY]];
  62. [attributes addObject:[NSNumber numberWithInt:outputFrequency]];
  63. }
  64. if(refreshIntervals > 0)
  65. {
  66. [attributes addObject:[NSNumber numberWithInt:ALC_REFRESH]];
  67. [attributes addObject:[NSNumber numberWithInt:refreshIntervals]];
  68. }
  69. [attributes addObject:[NSNumber numberWithInt:ALC_SYNC]];
  70. [attributes addObject:[NSNumber numberWithInt:synchronousContext ? AL_TRUE : AL_FALSE]];
  71. if(monoSources >= 0)
  72. {
  73. [attributes addObject:[NSNumber numberWithInt:ALC_MONO_SOURCES]];
  74. [attributes addObject:[NSNumber numberWithInt:monoSources]];
  75. }
  76. if(stereoSources >= 0)
  77. {
  78. [attributes addObject:[NSNumber numberWithInt:ALC_STEREO_SOURCES]];
  79. [attributes addObject:[NSNumber numberWithInt:stereoSources]];
  80. }
  81. return [self contextOnDevice:device attributes:attributes];
  82. }
  83. - (id) initOnDevice:(ALDevice*) deviceIn
  84. outputFrequency:(int) outputFrequency
  85. refreshIntervals:(int) refreshIntervals
  86. synchronousContext:(bool) synchronousContext
  87. monoSources:(int) monoSources
  88. stereoSources:(int) stereoSources
  89. {
  90. NSMutableArray* attributesList = [NSMutableArray arrayWithCapacity:5];
  91. if(outputFrequency > 0)
  92. {
  93. [attributesList addObject:[NSNumber numberWithInt:ALC_FREQUENCY]];
  94. [attributesList addObject:[NSNumber numberWithInt:outputFrequency]];
  95. }
  96. if(refreshIntervals > 0)
  97. {
  98. [attributesList addObject:[NSNumber numberWithInt:ALC_REFRESH]];
  99. [attributesList addObject:[NSNumber numberWithInt:refreshIntervals]];
  100. }
  101. [attributesList addObject:[NSNumber numberWithInt:ALC_SYNC]];
  102. [attributesList addObject:[NSNumber numberWithInt:synchronousContext ? AL_TRUE : AL_FALSE]];
  103. if(monoSources >= 0)
  104. {
  105. [attributesList addObject:[NSNumber numberWithInt:ALC_MONO_SOURCES]];
  106. [attributesList addObject:[NSNumber numberWithInt:monoSources]];
  107. }
  108. if(stereoSources >= 0)
  109. {
  110. [attributesList addObject:[NSNumber numberWithInt:ALC_STEREO_SOURCES]];
  111. [attributesList addObject:[NSNumber numberWithInt:stereoSources]];
  112. }
  113. return [self initOnDevice:deviceIn attributes:attributes];
  114. }
  115. - (id) initOnDevice:(ALDevice *) deviceIn attributes:(NSArray*) attributesIn
  116. {
  117. if(nil != (self = [super init]))
  118. {
  119. OAL_LOG_DEBUG(@"%@: Init on %@ with attributes 0x%08x", self, deviceIn, attributesIn);
  120. if(nil == deviceIn)
  121. {
  122. OAL_LOG_ERROR(@"%@: Failed to init because device was nil. Returning nil", self);
  123. [self release];
  124. return nil;
  125. }
  126. suspendHandler = [[OALSuspendHandler alloc] initWithTarget:self selector:@selector(setSuspended:)];
  127. // Build up an ALCint array for OpenAL's createContext function.
  128. ALCint* attributesList = nil;
  129. if([attributesIn count] > 0)
  130. {
  131. attributesList = (ALCint*)malloc(sizeof(ALCint) * [attributesIn count]);
  132. ALCint* attributePtr = attributesList;
  133. for(NSNumber* number in attributesIn)
  134. {
  135. *attributePtr++ = [number intValue];
  136. }
  137. }
  138. // Notify the device that we are being created.
  139. device = [deviceIn retain];
  140. [device notifyContextInitializing:self];
  141. // Open the context with our list of attributes.
  142. context = [ALWrapper createContext:device.device attributes:attributesList];
  143. listener = [[ALListener alloc] initWithContext:self];
  144. sources = [NSMutableArray newMutableArrayUsingWeakReferencesWithCapacity:32];
  145. // Cache all attributes for this context.
  146. attributes = [[NSMutableArray alloc] initWithCapacity:5];
  147. int buffSize = [ALWrapper getInteger:device.device attribute:ALC_ATTRIBUTES_SIZE];
  148. if(buffSize > 0)
  149. {
  150. if(nil != attributesList)
  151. {
  152. free(attributesList);
  153. }
  154. attributesList = malloc(sizeof(ALCint) * buffSize);
  155. if([ALWrapper getIntegerv:device.device attribute:ALC_ALL_ATTRIBUTES size:buffSize data:attributesList])
  156. {
  157. for(int i = 0; i < buffSize; i++)
  158. {
  159. [attributes addObject:[NSNumber numberWithInt:attributesList[i]]];
  160. }
  161. }
  162. }
  163. if(nil != attributesList)
  164. {
  165. free(attributesList);
  166. }
  167. // Manually add a suspend listener for ALListener because if someone
  168. // retains the listener it could outlive the context, even though
  169. // such a thing would be bad form.
  170. [self addSuspendListener:listener];
  171. [device addSuspendListener:self];
  172. }
  173. return self;
  174. }
  175. - (void) dealloc
  176. {
  177. OAL_LOG_DEBUG(@"%@: Dealloc", self);
  178. [self removeSuspendListener:listener];
  179. [device removeSuspendListener:self];
  180. [device notifyContextDeallocating:self];
  181. [self closeOSResources];
  182. [sources release];
  183. [listener release];
  184. [device release];
  185. [attributes release];
  186. [suspendHandler release];
  187. [super dealloc];
  188. }
  189. - (void) closeOSResources
  190. {
  191. OPTIONALLY_SYNCHRONIZED(self)
  192. {
  193. if(nil != context)
  194. {
  195. if([OpenALManager sharedInstance].currentContext == self)
  196. {
  197. [OpenALManager sharedInstance].currentContext = nil;
  198. }
  199. [ALWrapper destroyContext:context];
  200. context = nil;
  201. }
  202. }
  203. }
  204. - (void) close
  205. {
  206. OPTIONALLY_SYNCHRONIZED(self)
  207. {
  208. if(nil != context)
  209. {
  210. [sources makeObjectsPerformSelector:@selector(close)];
  211. [sources release];
  212. sources = nil;
  213. [self closeOSResources];
  214. }
  215. }
  216. }
  217. #pragma mark Properties
  218. - (NSString*) alVersion
  219. {
  220. return [ALWrapper getString:AL_VERSION];
  221. }
  222. @synthesize attributes;
  223. @synthesize context;
  224. @synthesize device;
  225. - (ALenum) distanceModel
  226. {
  227. OPTIONALLY_SYNCHRONIZED(self)
  228. {
  229. return [ALWrapper getInteger:AL_DISTANCE_MODEL];
  230. }
  231. }
  232. - (void) setDistanceModel:(ALenum) value
  233. {
  234. OPTIONALLY_SYNCHRONIZED(self)
  235. {
  236. if(self.suspended)
  237. {
  238. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  239. return;
  240. }
  241. [ALWrapper distanceModel:value];
  242. }
  243. }
  244. - (float) dopplerFactor
  245. {
  246. OPTIONALLY_SYNCHRONIZED(self)
  247. {
  248. return [ALWrapper getFloat:AL_DOPPLER_FACTOR];
  249. }
  250. }
  251. - (void) setDopplerFactor:(float) value
  252. {
  253. OPTIONALLY_SYNCHRONIZED(self)
  254. {
  255. if(self.suspended)
  256. {
  257. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  258. return;
  259. }
  260. [ALWrapper dopplerFactor:value];
  261. }
  262. }
  263. - (NSArray*) extensions
  264. {
  265. return [ALWrapper getSpaceSeparatedStringList:AL_EXTENSIONS];
  266. }
  267. @synthesize listener;
  268. - (NSString*) renderer
  269. {
  270. return [ALWrapper getString:AL_RENDERER];
  271. }
  272. @synthesize sources;
  273. - (float) speedOfSound
  274. {
  275. OPTIONALLY_SYNCHRONIZED(self)
  276. {
  277. return [ALWrapper getFloat:AL_SPEED_OF_SOUND];
  278. }
  279. }
  280. - (void) setSpeedOfSound:(float) value
  281. {
  282. OPTIONALLY_SYNCHRONIZED(self)
  283. {
  284. if(self.suspended)
  285. {
  286. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  287. return;
  288. }
  289. [ALWrapper speedOfSound:value];
  290. }
  291. }
  292. - (NSString*) vendor
  293. {
  294. return [ALWrapper getString:AL_VENDOR];
  295. }
  296. #pragma mark Suspend Handler
  297. - (void) addSuspendListener:(id<OALSuspendListener>) listenerIn
  298. {
  299. [suspendHandler addSuspendListener:listenerIn];
  300. }
  301. - (void) removeSuspendListener:(id<OALSuspendListener>) listenerIn
  302. {
  303. [suspendHandler removeSuspendListener:listenerIn];
  304. }
  305. - (bool) manuallySuspended
  306. {
  307. return suspendHandler.manuallySuspended;
  308. }
  309. - (void) setManuallySuspended:(bool) value
  310. {
  311. suspendHandler.manuallySuspended = value;
  312. }
  313. - (bool) interrupted
  314. {
  315. return suspendHandler.interrupted;
  316. }
  317. - (void) setInterrupted:(bool) value
  318. {
  319. suspendHandler.interrupted = value;
  320. }
  321. - (bool) suspended
  322. {
  323. return suspendHandler.suspended;
  324. }
  325. - (void) setSuspended:(bool) value
  326. {
  327. if(value)
  328. {
  329. [ALWrapper suspendContext:context];
  330. }
  331. else
  332. {
  333. [self process];
  334. }
  335. }
  336. #pragma mark Utility
  337. - (void) clearBuffers
  338. {
  339. OPTIONALLY_SYNCHRONIZED(self)
  340. {
  341. for(ALSource* source in sources)
  342. {
  343. [source clear];
  344. }
  345. }
  346. }
  347. - (void) process
  348. {
  349. if(self.suspended)
  350. {
  351. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  352. return;
  353. }
  354. [ALWrapper processContext:context];
  355. }
  356. - (void) stopAllSounds
  357. {
  358. OPTIONALLY_SYNCHRONIZED(self)
  359. {
  360. if(self.suspended)
  361. {
  362. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  363. return;
  364. }
  365. for(ALSource* source in sources)
  366. {
  367. [source stop];
  368. }
  369. }
  370. }
  371. - (void) ensureContextIsCurrent
  372. {
  373. if(self.suspended)
  374. {
  375. OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self);
  376. return;
  377. }
  378. if([ALWrapper getCurrentContext] != context)
  379. {
  380. [OpenALManager sharedInstance].currentContext = self;
  381. }
  382. }
  383. #pragma mark Extensions
  384. - (bool) isExtensionPresent:(NSString*) name
  385. {
  386. return [ALWrapper isExtensionPresent:name];
  387. }
  388. - (void*) getProcAddress:(NSString*) functionName
  389. {
  390. return [ALWrapper getProcAddress:functionName];
  391. }
  392. #pragma mark Internal Use
  393. - (void) notifySourceInitializing:(ALSource*) source
  394. {
  395. OPTIONALLY_SYNCHRONIZED(self)
  396. {
  397. [sources addObject:source];
  398. }
  399. }
  400. - (void) notifySourceDeallocating:(ALSource*) source
  401. {
  402. OPTIONALLY_SYNCHRONIZED(self)
  403. {
  404. [sources removeObject:source];
  405. }
  406. }
  407. @end