/libs/ObjectAL/OpenAL/ALContext.m
Objective C | 493 lines | 368 code | 86 blank | 39 comment | 38 complexity | 996a34ad67c11325f6f8b4c8f32a1f84 MD5 | raw file
Possible License(s): Apache-2.0
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 27#import "ALContext.h" 28#import "NSMutableArray+WeakReferences.h" 29#import "ObjectALMacros.h" 30#import "ALWrapper.h" 31#import "OpenALManager.h" 32#import "ALDevice.h" 33 34 35#pragma mark - 36#pragma mark Private Methods 37 38/** 39 * (INTERNAL USE) Private methods for ALContext. 40 */ 41@interface ALContext (Private) 42 43/** (INTERNAL USE) Close any resources belonging to the OS. 44 */ 45- (void) closeOSResources; 46 47/** (INTERNAL USE) Called by SuspendHandler. 48 */ 49- (void) setSuspended:(bool) value; 50 51@end 52 53 54@implementation ALContext 55 56#pragma mark Object Management 57 58+ (id) contextOnDevice:(ALDevice *) device attributes:(NSArray*) attributes 59{ 60 return [[[self alloc] initOnDevice:device attributes:attributes] autorelease]; 61} 62 63+ (id) contextOnDevice:(ALDevice*) device 64 outputFrequency:(int) outputFrequency 65 refreshIntervals:(int) refreshIntervals 66 synchronousContext:(bool) synchronousContext 67 monoSources:(int) monoSources 68 stereoSources:(int) stereoSources 69{ 70 NSMutableArray* attributes = [NSMutableArray arrayWithCapacity:5]; 71 if(outputFrequency > 0) 72 { 73 [attributes addObject:[NSNumber numberWithInt:ALC_FREQUENCY]]; 74 [attributes addObject:[NSNumber numberWithInt:outputFrequency]]; 75 } 76 if(refreshIntervals > 0) 77 { 78 [attributes addObject:[NSNumber numberWithInt:ALC_REFRESH]]; 79 [attributes addObject:[NSNumber numberWithInt:refreshIntervals]]; 80 } 81 [attributes addObject:[NSNumber numberWithInt:ALC_SYNC]]; 82 [attributes addObject:[NSNumber numberWithInt:synchronousContext ? AL_TRUE : AL_FALSE]]; 83 84 if(monoSources >= 0) 85 { 86 [attributes addObject:[NSNumber numberWithInt:ALC_MONO_SOURCES]]; 87 [attributes addObject:[NSNumber numberWithInt:monoSources]]; 88 } 89 if(stereoSources >= 0) 90 { 91 [attributes addObject:[NSNumber numberWithInt:ALC_STEREO_SOURCES]]; 92 [attributes addObject:[NSNumber numberWithInt:stereoSources]]; 93 } 94 95 return [self contextOnDevice:device attributes:attributes]; 96} 97 98- (id) initOnDevice:(ALDevice*) deviceIn 99 outputFrequency:(int) outputFrequency 100 refreshIntervals:(int) refreshIntervals 101 synchronousContext:(bool) synchronousContext 102 monoSources:(int) monoSources 103 stereoSources:(int) stereoSources 104{ 105 NSMutableArray* attributesList = [NSMutableArray arrayWithCapacity:5]; 106 if(outputFrequency > 0) 107 { 108 [attributesList addObject:[NSNumber numberWithInt:ALC_FREQUENCY]]; 109 [attributesList addObject:[NSNumber numberWithInt:outputFrequency]]; 110 } 111 if(refreshIntervals > 0) 112 { 113 [attributesList addObject:[NSNumber numberWithInt:ALC_REFRESH]]; 114 [attributesList addObject:[NSNumber numberWithInt:refreshIntervals]]; 115 } 116 [attributesList addObject:[NSNumber numberWithInt:ALC_SYNC]]; 117 [attributesList addObject:[NSNumber numberWithInt:synchronousContext ? AL_TRUE : AL_FALSE]]; 118 119 if(monoSources >= 0) 120 { 121 [attributesList addObject:[NSNumber numberWithInt:ALC_MONO_SOURCES]]; 122 [attributesList addObject:[NSNumber numberWithInt:monoSources]]; 123 } 124 if(stereoSources >= 0) 125 { 126 [attributesList addObject:[NSNumber numberWithInt:ALC_STEREO_SOURCES]]; 127 [attributesList addObject:[NSNumber numberWithInt:stereoSources]]; 128 } 129 130 return [self initOnDevice:deviceIn attributes:attributes]; 131} 132 133- (id) initOnDevice:(ALDevice *) deviceIn attributes:(NSArray*) attributesIn 134{ 135 if(nil != (self = [super init])) 136 { 137 OAL_LOG_DEBUG(@"%@: Init on %@ with attributes 0x%08x", self, deviceIn, attributesIn); 138 139 if(nil == deviceIn) 140 { 141 OAL_LOG_ERROR(@"%@: Failed to init because device was nil. Returning nil", self); 142 [self release]; 143 return nil; 144 } 145 146 suspendHandler = [[OALSuspendHandler alloc] initWithTarget:self selector:@selector(setSuspended:)]; 147 148 // Build up an ALCint array for OpenAL's createContext function. 149 ALCint* attributesList = nil; 150 151 if([attributesIn count] > 0) 152 { 153 attributesList = (ALCint*)malloc(sizeof(ALCint) * [attributesIn count]); 154 ALCint* attributePtr = attributesList; 155 for(NSNumber* number in attributesIn) 156 { 157 *attributePtr++ = [number intValue]; 158 } 159 } 160 161 // Notify the device that we are being created. 162 device = [deviceIn retain]; 163 [device notifyContextInitializing:self]; 164 165 // Open the context with our list of attributes. 166 context = [ALWrapper createContext:device.device attributes:attributesList]; 167 168 listener = [[ALListener alloc] initWithContext:self]; 169 170 sources = [NSMutableArray newMutableArrayUsingWeakReferencesWithCapacity:32]; 171 172 // Cache all attributes for this context. 173 attributes = [[NSMutableArray alloc] initWithCapacity:5]; 174 int buffSize = [ALWrapper getInteger:device.device attribute:ALC_ATTRIBUTES_SIZE]; 175 if(buffSize > 0) 176 { 177 if(nil != attributesList) 178 { 179 free(attributesList); 180 } 181 attributesList = malloc(sizeof(ALCint) * buffSize); 182 if([ALWrapper getIntegerv:device.device attribute:ALC_ALL_ATTRIBUTES size:buffSize data:attributesList]) 183 { 184 for(int i = 0; i < buffSize; i++) 185 { 186 [attributes addObject:[NSNumber numberWithInt:attributesList[i]]]; 187 } 188 } 189 } 190 191 if(nil != attributesList) 192 { 193 free(attributesList); 194 } 195 196 // Manually add a suspend listener for ALListener because if someone 197 // retains the listener it could outlive the context, even though 198 // such a thing would be bad form. 199 [self addSuspendListener:listener]; 200 201 [device addSuspendListener:self]; 202 } 203 return self; 204} 205 206- (void) dealloc 207{ 208 OAL_LOG_DEBUG(@"%@: Dealloc", self); 209 210 [self removeSuspendListener:listener]; 211 [device removeSuspendListener:self]; 212 [device notifyContextDeallocating:self]; 213 214 [self closeOSResources]; 215 216 [sources release]; 217 [listener release]; 218 [device release]; 219 [attributes release]; 220 [suspendHandler release]; 221 222 [super dealloc]; 223} 224 225- (void) closeOSResources 226{ 227 OPTIONALLY_SYNCHRONIZED(self) 228 { 229 if(nil != context) 230 { 231 if([OpenALManager sharedInstance].currentContext == self) 232 { 233 [OpenALManager sharedInstance].currentContext = nil; 234 } 235 [ALWrapper destroyContext:context]; 236 context = nil; 237 } 238 } 239} 240 241- (void) close 242{ 243 OPTIONALLY_SYNCHRONIZED(self) 244 { 245 if(nil != context) 246 { 247 [sources makeObjectsPerformSelector:@selector(close)]; 248 [sources release]; 249 sources = nil; 250 251 [self closeOSResources]; 252 } 253 } 254} 255 256 257#pragma mark Properties 258 259- (NSString*) alVersion 260{ 261 return [ALWrapper getString:AL_VERSION]; 262} 263 264@synthesize attributes; 265 266@synthesize context; 267 268@synthesize device; 269 270- (ALenum) distanceModel 271{ 272 OPTIONALLY_SYNCHRONIZED(self) 273 { 274 return [ALWrapper getInteger:AL_DISTANCE_MODEL]; 275 } 276} 277 278- (void) setDistanceModel:(ALenum) value 279{ 280 OPTIONALLY_SYNCHRONIZED(self) 281 { 282 if(self.suspended) 283 { 284 OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self); 285 return; 286 } 287 288 [ALWrapper distanceModel:value]; 289 } 290} 291 292- (float) dopplerFactor 293{ 294 OPTIONALLY_SYNCHRONIZED(self) 295 { 296 return [ALWrapper getFloat:AL_DOPPLER_FACTOR]; 297 } 298} 299 300- (void) setDopplerFactor:(float) value 301{ 302 OPTIONALLY_SYNCHRONIZED(self) 303 { 304 if(self.suspended) 305 { 306 OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self); 307 return; 308 } 309 310 [ALWrapper dopplerFactor:value]; 311 } 312} 313 314- (NSArray*) extensions 315{ 316 return [ALWrapper getSpaceSeparatedStringList:AL_EXTENSIONS]; 317} 318 319@synthesize listener; 320 321- (NSString*) renderer 322{ 323 return [ALWrapper getString:AL_RENDERER]; 324} 325 326@synthesize sources; 327 328- (float) speedOfSound 329{ 330 OPTIONALLY_SYNCHRONIZED(self) 331 { 332 return [ALWrapper getFloat:AL_SPEED_OF_SOUND]; 333 } 334} 335 336- (void) setSpeedOfSound:(float) value 337{ 338 OPTIONALLY_SYNCHRONIZED(self) 339 { 340 if(self.suspended) 341 { 342 OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self); 343 return; 344 } 345 346 [ALWrapper speedOfSound:value]; 347 } 348} 349 350- (NSString*) vendor 351{ 352 return [ALWrapper getString:AL_VENDOR]; 353} 354 355 356#pragma mark Suspend Handler 357 358- (void) addSuspendListener:(id<OALSuspendListener>) listenerIn 359{ 360 [suspendHandler addSuspendListener:listenerIn]; 361} 362 363- (void) removeSuspendListener:(id<OALSuspendListener>) listenerIn 364{ 365 [suspendHandler removeSuspendListener:listenerIn]; 366} 367 368- (bool) manuallySuspended 369{ 370 return suspendHandler.manuallySuspended; 371} 372 373- (void) setManuallySuspended:(bool) value 374{ 375 suspendHandler.manuallySuspended = value; 376} 377 378- (bool) interrupted 379{ 380 return suspendHandler.interrupted; 381} 382 383- (void) setInterrupted:(bool) value 384{ 385 suspendHandler.interrupted = value; 386} 387 388- (bool) suspended 389{ 390 return suspendHandler.suspended; 391} 392 393- (void) setSuspended:(bool) value 394{ 395 if(value) 396 { 397 [ALWrapper suspendContext:context]; 398 } 399 else 400 { 401 [self process]; 402 } 403} 404 405 406#pragma mark Utility 407 408- (void) clearBuffers 409{ 410 OPTIONALLY_SYNCHRONIZED(self) 411 { 412 for(ALSource* source in sources) 413 { 414 [source clear]; 415 } 416 } 417} 418 419- (void) process 420{ 421 if(self.suspended) 422 { 423 OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self); 424 return; 425 } 426 427 [ALWrapper processContext:context]; 428} 429 430- (void) stopAllSounds 431{ 432 OPTIONALLY_SYNCHRONIZED(self) 433 { 434 if(self.suspended) 435 { 436 OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self); 437 return; 438 } 439 440 for(ALSource* source in sources) 441 { 442 [source stop]; 443 } 444 } 445} 446 447- (void) ensureContextIsCurrent 448{ 449 if(self.suspended) 450 { 451 OAL_LOG_DEBUG(@"%@: Called mutator on suspended object", self); 452 return; 453 } 454 455 if([ALWrapper getCurrentContext] != context) 456 { 457 [OpenALManager sharedInstance].currentContext = self; 458 } 459} 460 461#pragma mark Extensions 462 463- (bool) isExtensionPresent:(NSString*) name 464{ 465 return [ALWrapper isExtensionPresent:name]; 466} 467 468- (void*) getProcAddress:(NSString*) functionName 469{ 470 return [ALWrapper getProcAddress:functionName]; 471} 472 473 474#pragma mark Internal Use 475 476- (void) notifySourceInitializing:(ALSource*) source 477{ 478 OPTIONALLY_SYNCHRONIZED(self) 479 { 480 [sources addObject:source]; 481 } 482} 483 484- (void) notifySourceDeallocating:(ALSource*) source 485{ 486 OPTIONALLY_SYNCHRONIZED(self) 487 { 488 [sources removeObject:source]; 489 } 490} 491 492 493@end