Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial check-in.

git-svn-id: svn://witness.is-a-geek.org/svn@1 378c4bed-2673-4746-83ae-d22ddc8c5b7c
  • Loading branch information...
commit 5d77434263ebf8cff90d2df19a1d926643f9fc23 0 parents
authored July 04, 2009
52  UKSound.h
... ...
@@ -0,0 +1,52 @@
  1
+//
  2
+//  UKSound.h
  3
+//  MobileMoose
  4
+//
  5
+//  Created by Uli Kusterer on 14.07.08.
  6
+//  Copyright 2008 The Void Software. All rights reserved.
  7
+//
  8
+
  9
+#import <UIKit/UIKit.h>
  10
+#import <AudioToolbox/AudioToolbox.h>
  11
+
  12
+
  13
+#define kNumberBuffers			2
  14
+
  15
+
  16
+@class UKSound;
  17
+
  18
+
  19
+@protocol UKSoundDelegate
  20
+
  21
+@optional
  22
+-(void)	sound: (UKSound*)sender didFinishPlaying: (BOOL)state;
  23
+
  24
+@end
  25
+
  26
+
  27
+
  28
+@interface UKSound : NSObject
  29
+{
  30
+	AudioFileID						mAudioFile;
  31
+	AudioStreamBasicDescription		mDataFormat;
  32
+	AudioQueueRef					mQueue;
  33
+	AudioQueueBufferRef				mBuffers[kNumberBuffers];
  34
+	UInt64							mPacketIndex;
  35
+	UInt32							mNumPacketsToRead;
  36
+	AudioStreamPacketDescription *	mPacketDescs;
  37
+	BOOL							mDone;
  38
+	id<UKSoundDelegate>				delegate;
  39
+	int								maxBufferSizeBytes;
  40
+}
  41
+
  42
+@property (assign) id<UKSoundDelegate> delegate;
  43
+
  44
+-(id)	initWithContentsOfURL: (NSURL*)theURL;
  45
+
  46
+-(void)	play;
  47
+
  48
+
  49
+// private:
  50
+-(void)	audioQueue: (AudioQueueRef)inAQ processBuffer: (AudioQueueBufferRef)inCompleteAQBuffer;
  51
+
  52
+@end
204  UKSound.m
... ...
@@ -0,0 +1,204 @@
  1
+//
  2
+//  UKSound.m
  3
+//  MobileMoose
  4
+//
  5
+//  Created by Uli Kusterer on 14.07.08.
  6
+//  Copyright 2008 The Void Software. All rights reserved.
  7
+//
  8
+
  9
+#import "UKSound.h"
  10
+
  11
+
  12
+static void UKSoundAQBufferCallback(void *					inUserData,
  13
+									AudioQueueRef			inAQ,
  14
+									AudioQueueBufferRef		inCompleteAQBuffer)
  15
+{
  16
+	UKSound*	myself = (UKSound*)inUserData;
  17
+	
  18
+	[myself audioQueue: inAQ processBuffer: inCompleteAQBuffer];
  19
+}
  20
+
  21
+
  22
+static void	UKSoundAQPropertyListenerCallback( void *                  inUserData,
  23
+												AudioQueueRef           inAQ,
  24
+												AudioQueuePropertyID    inID)
  25
+{
  26
+	[(UKSound*)inUserData performSelectorOnMainThread: @selector(notifyDelegatePlaybackStateChanged:) withObject: nil waitUntilDone: NO];
  27
+}
  28
+
  29
+
  30
+@implementation UKSound
  31
+
  32
+@synthesize delegate;
  33
+
  34
+-(id)	initWithContentsOfURL: (NSURL*)theURL
  35
+{
  36
+	self = [super init];
  37
+	if( self )
  38
+	{
  39
+		maxBufferSizeBytes = 0x10000;
  40
+		OSStatus	err = AudioFileOpenURL(	(CFURLRef)theURL, kAudioFileReadPermission, 0, &mAudioFile );
  41
+		if( err != noErr )
  42
+			NSLog(@"Couldn't open AudioFile.");
  43
+		UInt32 size = sizeof(mDataFormat);
  44
+		err = AudioFileGetProperty( mAudioFile, kAudioFilePropertyDataFormat, &size, &mDataFormat );
  45
+		if( err != noErr )
  46
+			NSLog(@"Couldn't determine audio file format.");
  47
+		err = AudioQueueNewOutput( &mDataFormat, UKSoundAQBufferCallback, self, NULL, NULL, 0, &mQueue );
  48
+		if( err != noErr )
  49
+			NSLog(@"Couldn't create new output for queue.");
  50
+
  51
+		// We have a couple of things to take care of now
  52
+		// (1) Setting up the conditions around VBR or a CBR format - affects how we will read from the file
  53
+		// if format is VBR we need to use a packet table.
  54
+		if( mDataFormat.mBytesPerPacket == 0 || mDataFormat.mFramesPerPacket == 0 )
  55
+		{
  56
+			// first check to see what the max size of a packet is - if it is bigger
  57
+			// than our allocation default size, that needs to become larger
  58
+			UInt32 maxPacketSize;
  59
+			size = sizeof(maxPacketSize);
  60
+			err = AudioFileGetProperty( mAudioFile, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize);
  61
+			if( err != noErr )
  62
+				NSLog(@"Couldn't get max packet size of audio file.");
  63
+			if( maxPacketSize > maxBufferSizeBytes ) 
  64
+				maxBufferSizeBytes = maxPacketSize;
  65
+			
  66
+			// we also need packet descpriptions for the file reading
  67
+			mNumPacketsToRead = maxBufferSizeBytes / maxPacketSize;
  68
+			mPacketDescs = malloc( sizeof(AudioStreamPacketDescription) * mNumPacketsToRead );
  69
+		}
  70
+		else
  71
+		{
  72
+			mNumPacketsToRead = maxBufferSizeBytes / mDataFormat.mBytesPerPacket;
  73
+			mPacketDescs = NULL;
  74
+		}
  75
+
  76
+		// (2) If the file has a cookie, we should get it and set it on the AQ
  77
+		size = sizeof(UInt32);
  78
+		err = AudioFileGetPropertyInfo( mAudioFile, kAudioFilePropertyMagicCookieData, &size, NULL );
  79
+		if( !err && size )
  80
+		{
  81
+			char* cookie = malloc( size );
  82
+			err = AudioFileGetProperty( mAudioFile, kAudioFilePropertyMagicCookieData, &size, cookie );
  83
+			if( err != noErr )
  84
+				NSLog(@"Couldn't get magic cookie of audio file.");
  85
+			err = AudioQueueSetProperty( mQueue, kAudioQueueProperty_MagicCookie, cookie, size );
  86
+			if( err != noErr )
  87
+				NSLog(@"Couldn't transfer magic cookie of audio file to qudio queue.");
  88
+			free( cookie );
  89
+		}
  90
+		
  91
+		err = AudioQueueAddPropertyListener( mQueue, kAudioQueueProperty_IsRunning,
  92
+                                    UKSoundAQPropertyListenerCallback,
  93
+                                    self );
  94
+		if( err != noErr )
  95
+			NSLog(@"Couldn't register for playback state changes.");
  96
+		
  97
+			// prime the queue with some data before starting
  98
+		mDone = false;
  99
+		mPacketIndex = 0;
  100
+		for( int i = 0; i < kNumberBuffers; ++i )
  101
+		{
  102
+			err = AudioQueueAllocateBuffer( mQueue, maxBufferSizeBytes, &mBuffers[i] );
  103
+			if( err != noErr )
  104
+				NSLog(@"Couldn't allocate buffer %d.", i);
  105
+
  106
+			UKSoundAQBufferCallback( self, mQueue, mBuffers[i] );
  107
+			
  108
+			if( mDone ) break;
  109
+		}
  110
+	}
  111
+	
  112
+	return self;
  113
+}
  114
+
  115
+
  116
+-(void)	dealloc
  117
+{
  118
+	OSStatus err = AudioQueueDispose( mQueue, true );
  119
+	err = AudioFileClose( mAudioFile );
  120
+	if( mPacketDescs )
  121
+		free( mPacketDescs );
  122
+	
  123
+	[super dealloc];
  124
+}
  125
+
  126
+
  127
+-(void)	play
  128
+{
  129
+	OSStatus err = AudioQueueStart( mQueue, NULL );
  130
+	if( err != noErr )
  131
+		NSLog(@"Couldn't start audio queue.");
  132
+	else
  133
+		[self retain];
  134
+}
  135
+
  136
+
  137
+-(BOOL)	isPlaying
  138
+{
  139
+	UInt32		state = NO,
  140
+				size = sizeof(UInt32);
  141
+	OSStatus	err = AudioQueueGetProperty( mQueue, kAudioQueueProperty_IsRunning, &state, &size );
  142
+	if( err != noErr )
  143
+		NSLog(@"Couldn't get play state of queue.");
  144
+	
  145
+	return state;
  146
+}
  147
+
  148
+
  149
+-(void)	notifyDelegatePlaybackStateChanged: (id)sender;
  150
+{
  151
+	if( ![self isPlaying] )
  152
+	{
  153
+		[delegate sound: self didFinishPlaying: YES];
  154
+		
  155
+		AudioQueueStop( mQueue, false );
  156
+		[self release];
  157
+	}
  158
+}
  159
+
  160
+
  161
+-(void)	audioQueue: (AudioQueueRef)inAQ processBuffer: (AudioQueueBufferRef)inCompleteAQBuffer
  162
+{
  163
+	if( mDone )
  164
+		return;
  165
+		
  166
+	UInt32 numBytes;
  167
+	UInt32 nPackets = mNumPacketsToRead;
  168
+
  169
+	// Read nPackets worth of data into buffer
  170
+	OSStatus err = AudioFileReadPackets( mAudioFile, false, &numBytes, mPacketDescs, mPacketIndex, &nPackets, 
  171
+										inCompleteAQBuffer->mAudioData);
  172
+	if( err != noErr )
  173
+		NSLog(@"Couldn't read into buffer.");
  174
+	
  175
+	if (nPackets > 0)
  176
+	{
  177
+		inCompleteAQBuffer->mAudioDataByteSize = numBytes;		
  178
+
  179
+		// Queues the buffer for audio input/output.
  180
+		err = AudioQueueEnqueueBuffer( inAQ, inCompleteAQBuffer, (mPacketDescs ? nPackets : 0), mPacketDescs );
  181
+		if( err != noErr )
  182
+			NSLog(@"Couldn't enqueue buffer.");
  183
+		
  184
+		mPacketIndex += nPackets;
  185
+	}
  186
+	else
  187
+	{
  188
+		UInt32		state = NO,
  189
+					size = sizeof(UInt32);
  190
+		OSStatus	err = AudioQueueGetProperty( mQueue, kAudioQueueProperty_IsRunning, &state, &size );
  191
+		
  192
+		// I should be calling the following, but it always makes the app hang.
  193
+		if( state )
  194
+		{
  195
+			err = AudioQueueStop( mQueue, false );
  196
+			if( err != noErr )
  197
+				NSLog(@"Couldn't stop queue.");
  198
+				// reading nPackets == 0 is our EOF condition
  199
+		}
  200
+		mDone = true;
  201
+	}
  202
+}
  203
+
  204
+@end
42  UKSystemSound.h
... ...
@@ -0,0 +1,42 @@
  1
+//
  2
+//  UKSystemSound.h
  3
+//  iPhoneTestApp
  4
+//
  5
+//  Created by Uli Kusterer on 19.06.08.
  6
+//  Copyright 2008 The Void Software. All rights reserved.
  7
+//
  8
+
  9
+/*
  10
+	An NSSound-like class for the iPhone OS.
  11
+*/
  12
+
  13
+#import <UIKit/UIKit.h>
  14
+#import <AudioToolbox/AudioToolbox.h>
  15
+
  16
+
  17
+@class UKSystemSound;
  18
+
  19
+
  20
+@protocol UKSystemSoundDelegate
  21
+
  22
+@optional
  23
+
  24
+-(void)	sound: (UKSystemSound *)sound didFinishPlaying: (BOOL)aBool;
  25
+
  26
+@end
  27
+
  28
+
  29
+@interface UKSystemSound : NSObject
  30
+{
  31
+	BOOL						soundIDValid;
  32
+	SystemSoundID				systemSoundID;
  33
+	id<UKSystemSoundDelegate>	delegate;
  34
+}
  35
+
  36
+-(id)	initWithContentsOfURL: (NSURL*)fileURL byReference: (BOOL)ignored;	// CAF, AIFF or WAV files only.
  37
+
  38
+@property (nonatomic,assign) id<UKSystemSoundDelegate> delegate;
  39
+
  40
+-(void)	play;
  41
+
  42
+@end
65  UKSystemSound.m
... ...
@@ -0,0 +1,65 @@
  1
+//
  2
+//  UKSystemSound.m
  3
+//  iPhoneTestApp
  4
+//
  5
+//  Created by Uli Kusterer on 19.06.08.
  6
+//  Copyright 2008 The Void Software. All rights reserved.
  7
+//
  8
+
  9
+#import "UKSystemSound.h"
  10
+
  11
+
  12
+void UKSystemSoundAudioServicesSystemSoundCompletionProc( SystemSoundID ssID, void *clientData )
  13
+{
  14
+	if( clientData )
  15
+		[[(UKSystemSound*)clientData delegate] sound: (UKSystemSound*)clientData didFinishPlaying: YES];
  16
+	AudioServicesRemoveSystemSoundCompletion( ssID );
  17
+	[(UKSystemSound*)clientData release];
  18
+}
  19
+
  20
+
  21
+@implementation UKSystemSound
  22
+
  23
+-(id)	initWithContentsOfURL: (NSURL*)fileURL byReference: (BOOL)ignored
  24
+{
  25
+	self = [super init];
  26
+	if( self )
  27
+	{
  28
+		OSStatus err = AudioServicesCreateSystemSoundID( (CFURLRef) fileURL, &systemSoundID );
  29
+		if( err != noErr )
  30
+		{
  31
+			[self autorelease];
  32
+			return nil;
  33
+		}
  34
+		else
  35
+			soundIDValid = YES;
  36
+	}
  37
+	return self;
  38
+}
  39
+
  40
+-(void)	dealloc
  41
+{
  42
+	if( soundIDValid )
  43
+	{
  44
+		AudioServicesDisposeSystemSoundID( systemSoundID );
  45
+		soundIDValid = NO;
  46
+	}
  47
+	
  48
+	[super dealloc];
  49
+}
  50
+
  51
+
  52
+@synthesize delegate;
  53
+
  54
+-(void)	play
  55
+{
  56
+	if( soundIDValid )
  57
+	{
  58
+		AudioServicesPlaySystemSound( systemSoundID );
  59
+		[self retain];
  60
+		AudioServicesAddSystemSoundCompletion( systemSoundID, CFRunLoopGetCurrent(), NULL,
  61
+					UKSystemSoundAudioServicesSystemSoundCompletionProc, self );
  62
+	}
  63
+}
  64
+
  65
+@end

0 notes on commit 5d77434

Please sign in to comment.
Something went wrong with that request. Please try again.