cog/Audio/Output/OutputCoreAudio.m

266 lines
6.9 KiB
Matlab
Raw Normal View History

2005-09-07 22:33:16 +00:00
//
// OutputCoreAudio.m
// Cog
//
// Created by Vincent Spader on 8/2/05.
// Copyright 2005 Vincent Spader. All rights reserved.
2005-09-07 22:33:16 +00:00
//
#import "OutputCoreAudio.h"
#import "OutputNode.h"
2005-09-07 22:33:16 +00:00
@implementation OutputCoreAudio
- (id)initWithController:(OutputNode *)c
2005-09-07 22:33:16 +00:00
{
2006-01-20 15:34:02 +00:00
self = [super init];
if (self)
2005-09-07 22:33:16 +00:00
{
2006-01-20 15:34:02 +00:00
outputController = c;
outputUnit = NULL;
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.outputDevice" options:0 context:NULL];
2005-09-07 22:33:16 +00:00
}
2006-01-20 15:34:02 +00:00
return self;
}
static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
{
OutputCoreAudio *output = (OutputCoreAudio *)inRefCon;
OSStatus err = noErr;
void *readPointer = ioData->mBuffers[0].mData;
int amountToRead, amountRead;
if ([output->outputController shouldContinue] == NO)
2005-09-07 22:33:16 +00:00
{
2006-04-04 01:08:21 +00:00
DBLog(@"STOPPING");
2006-01-20 15:34:02 +00:00
AudioOutputUnitStop(output->outputUnit);
// [output stop];
2006-01-20 15:34:02 +00:00
return err;
2005-09-07 22:33:16 +00:00
}
2006-01-20 15:34:02 +00:00
amountToRead = inNumberFrames*(output->deviceFormat.mBytesPerPacket);
amountRead = [output->outputController readData:(readPointer) amount:amountToRead];
// NSLog(@"Amount read: %i %i", amountRead, [output->outputController endOfStream]);
if ((amountRead < amountToRead) && [output->outputController endOfStream] == NO) //Try one more time! for track changes!
{
int amountRead2; //Use this since return type of readdata isnt known...may want to fix then can do a simple += to readdata
amountRead2 = [output->outputController readData:(readPointer+amountRead) amount:amountToRead-amountRead];
amountRead += amountRead2;
}
2005-09-07 22:33:16 +00:00
// NSLog(@"Amount read: %i", amountRead);
2006-01-20 15:34:02 +00:00
ioData->mBuffers[0].mDataByteSize = amountRead;
2005-09-07 22:33:16 +00:00
return err;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"values.outputDevice"]) {
NSLog(@"CHANGED!");
NSDictionary *device = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"outputDevice"];
NSNumber *deviceID = [device objectForKey:@"deviceID"];
NSLog(@"Selecting output device %d %@", [deviceID longValue], [device objectForKey:@"name"]);
[self setOutputDevice:[deviceID longValue]];
}
}
- (BOOL)setOutputDevice:(AudioDeviceID)outputDevice
{
// Set the output device
AudioDeviceID deviceID = outputDevice; //XXX use default if null
NSLog(@"Using output device %d", deviceID);
OSStatus err;
if (outputDevice == -1) {
UInt32 size = sizeof(AudioDeviceID);
err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
&size,
&deviceID);
if (err != noErr) {
NSLog(@"THERES NO DEFAULT OUTPUT DEVICE! GARRRGGHHH");
return NO;
}
NSLog(@"Default output device: %i", deviceID);
}
err = AudioUnitSetProperty(outputUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
0,
&deviceID,
sizeof(AudioDeviceID));
if (err != noErr) {
NSLog(@"THERES NO OUTPUT DEVICE! AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!!! %i", err);
return NO;
}
return YES;
}
2005-09-07 22:33:16 +00:00
2006-01-20 15:34:02 +00:00
- (BOOL)setup
2005-09-07 22:33:16 +00:00
{
if (outputUnit)
[self stop];
2005-09-07 22:33:16 +00:00
ComponentDescription desc;
OSStatus err;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
Component comp = FindNextComponent(NULL, &desc); //Finds an component that meets the desc spec's
if (comp == NULL)
return NO;
err = OpenAComponent(comp, &outputUnit); //gains access to the services provided by the component
if (err)
return NO;
// Initialize AudioUnit
err = AudioUnitInitialize(outputUnit);
if (err != noErr)
return NO;
NSLog(@"SETUP");
2005-09-07 22:33:16 +00:00
UInt32 size = sizeof (AudioStreamBasicDescription);
Boolean outWritable;
//Gets the size of the Stream Format Property and if it is writable
AudioUnitGetPropertyInfo(outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0,
&size,
&outWritable);
//Get the current stream format of the output
err = AudioUnitGetProperty (outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0,
&deviceFormat,
&size);
if (err != noErr)
return NO;
// change output format...
///Seems some 3rd party devices return incorrect stuff...or I just don't like noninterleaved data.
deviceFormat.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
2006-01-20 15:34:02 +00:00
// deviceFormat.mFormatFlags &= ~kLinearPCMFormatFlagIsFloat;
// deviceFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
2005-09-07 22:33:16 +00:00
deviceFormat.mBytesPerFrame = deviceFormat.mChannelsPerFrame*(deviceFormat.mBitsPerChannel/8);
deviceFormat.mBytesPerPacket = deviceFormat.mBytesPerFrame * deviceFormat.mFramesPerPacket;
// DBLog(@"stuff: %i %i %i %i", deviceFormat.mBitsPerChannel, deviceFormat.mBytesPerFrame, deviceFormat.mBytesPerPacket, deviceFormat.mFramesPerPacket);
err = AudioUnitSetProperty (outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0,
&deviceFormat,
size);
//Set the stream format of the output to match the input
err = AudioUnitSetProperty (outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&deviceFormat,
size);
//setup render callbacks
renderCallback.inputProc = Sound_Renderer;
renderCallback.inputProcRefCon = self;
AudioUnitSetProperty(outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(AURenderCallbackStruct));
2006-01-20 15:34:02 +00:00
[outputController setFormat:&deviceFormat];
2005-09-07 22:33:16 +00:00
2006-01-20 15:34:02 +00:00
DBLog(@"Audio output successfully initialized");
NSDictionary *device = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"outputDevice"];
if (device) {
NSLog(@"THIS ONE");
BOOL ok = [self setOutputDevice:[[device objectForKey:@"deviceID"] longValue]];
if (!ok) {
//Ruh roh.
[self setOutputDevice: -1];
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] removeObjectForKey:@"outputDevice"];
}
}
else {
NSLog(@"THAT ONE");
[self setOutputDevice: -1];
}
NSLog(@"DONE SETTING UP");
2005-09-07 22:33:16 +00:00
return (err == noErr);
}
2006-01-20 15:34:02 +00:00
- (void)setVolume:(double)v
{
AudioUnitSetParameter (outputUnit,
kHALOutputParam_Volume,
kAudioUnitScope_Global,
0,
v * 0.01f,
0);
}
2005-09-07 22:33:16 +00:00
- (void)start
{
2006-04-04 01:08:21 +00:00
DBLog(@"START OUTPUT\n");
2005-09-07 22:33:16 +00:00
AudioOutputUnitStart(outputUnit);
}
- (void)stop
{
2006-04-04 01:08:21 +00:00
DBLog(@"STOP!");
2005-09-07 22:33:16 +00:00
if (outputUnit)
2006-01-20 15:34:02 +00:00
{
2005-09-07 22:33:16 +00:00
AudioOutputUnitStop(outputUnit);
2006-01-20 15:34:02 +00:00
AudioUnitUninitialize (outputUnit);
CloseComponent(outputUnit);
}
2005-09-07 22:33:16 +00:00
}
- (void)dealloc
{
[self stop];
[super dealloc];
}
2006-01-29 14:57:48 +00:00
- (void)pause
{
NSLog(@"PAUSE");
2006-01-29 14:57:48 +00:00
AudioOutputUnitStop(outputUnit);
}
- (void)resume
{
NSLog(@"RESUME");
2006-01-29 14:57:48 +00:00
AudioOutputUnitStart(outputUnit);
}
2005-09-07 22:33:16 +00:00
@end