Playing audio on the iPhone decoded by a third-party library
The third-party library generates sequential buffers of 16-bit signed stereo samples of any desired size. I can't figure out which framework/functi开发者_如何转开发ons to use to play from these buffers. I've been working off the example in this answer using AudioQueue
but it's obviously incomplete in ways I can't resolve (local variables are used as if they are object members, undeclared variables, etc).
The code in Apple's SpeakHere example project only shows how to use AudioQueue to play audio from a file. Can someone point me in the right direction?
Figured it out. Here's a simple, complete and working white noise generator using AudioQueue created from the Window-based Application project template.
StaticAppDelegate.h:
// StaticAppDelegate.h
#import <UIKit/UIKit.h>
// STATIC ADDITIONS
// Add > Existing Frameworks... > AudioToolbox.framework to your Target
#import <AudioToolbox/AudioToolbox.h>
// END STATIC ADDITIONS
@interface StaticAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
// STATIC ADDITIONS
- (void)startStatic;
- (void)handleBufferCompleteForQueue:(AudioQueueRef)inAQ
buffer:(AudioQueueBufferRef)inBuffer;
// END STATIC ADDITIONS
@end
StaticAppDelegate.m:
// StaticAppDelegate.m
#import "StaticAppDelegate.h"
// STATIC ADDITIONS
#define kNumberBuffers 4
#define kBufferSize 2048
// AudioQueue callback
void AQOutputCallback(
void *inData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer
)
{
StaticAppDelegate *staticApp = (StaticAppDelegate *)inData;
[staticApp handleBufferCompleteForQueue:inAQ buffer:inBuffer];
}
// END STATIC ADDITIONS
@implementation StaticAppDelegate
@synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after application launch
[window makeKeyAndVisible];
// STATIC ADDITIONS
[self startStatic];
// END STATIC ADDITIONS
}
- (void)dealloc {
[window release];
[super dealloc];
}
// STATIC ADDITIONS
- (void)startStatic
{
srandom(time(NULL));
// initiate audio session
AudioSessionInitialize(NULL, NULL, NULL, NULL);
UInt32 category = kAudioSessionCategory_MediaPlayback; // plays through sleep lock and silent switch
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
AudioSessionSetActive(true);
// following is modified from http://stackoverflow.com/questions/1710133/playing-generated-audio-on-an-iphone
// setup queue
AudioQueueRef audioQueue;
AudioQueueBufferRef buffers[kNumberBuffers];
AudioStreamBasicDescription format;
memset(&format, 0, sizeof(format));
format.mSampleRate = 44100;
format.mFormatID = kAudioFormatLinearPCM;
format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
format.mChannelsPerFrame = 1;
format.mBitsPerChannel = 16;
format.mBytesPerFrame = (format.mBitsPerChannel / 8) * format.mChannelsPerFrame;
format.mFramesPerPacket = 1;
format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
AudioQueueNewOutput(&format,
AQOutputCallback,
self,
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&audioQueue);
// allocate and fill the buffers
for (int i = 0; i < kNumberBuffers; ++i)
{
AudioQueueAllocateBuffer(audioQueue, kBufferSize, &buffers[i]);
AQOutputCallback(self, audioQueue, buffers[i]);
}
AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, 1.0);
AudioQueueStart(audioQueue, NULL);
}
- (void)handleBufferCompleteForQueue:(AudioQueueRef)inAQ
buffer:(AudioQueueBufferRef)inBuffer
{
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
int *buffer = (int *)inBuffer->mAudioData;
for (int i = 0; i < inBuffer->mAudioDataByteSize/sizeof(int); ++i)
{
buffer[i] = (int)rand(); // refill the buffer
}
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
}
// END STATIC ADDITIONS
@end
Once I figured out how to actually refill the buffer (inBuffer->mAudioData
with some type casting) everything else fell into place.
精彩评论