PageRenderTime 76ms CodeModel.GetById 18ms app.highlight 55ms RepoModel.GetById 1ms app.codeStats 0ms

/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
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