sound/cocoa_s.c
author bjarni
Sat, 10 Dec 2005 11:16:45 +0000
changeset 2736 3d6487cbbb69
child 2743 a6c91eb763e8
permissions -rw-r--r--
(svn r3281) -Feature: [OSX] added native cocoa sound and video drivers (egladil)
you can still use SDL drivers if you like and you have to run "make upgradeconf" to start using the cocoa drivers (or manually write WITH_COCOA:=1)
since SDL breaks the cocoa drivers, you can't compile with both SDL and cocoa support
Using cocoa drivers makes it easier to make universal binaries and it solves:
-FS#18 [OSX] SDL is weird in universal binaries
-FS#2 [OSX] lazy pointer crash on exit
-FS#10 [OSX] linking error when linking statically to SDL 1.2.8 (needless to explain this, but it means it should be able to compile statically with the default settings now)
-[ 1215073 ] Switching to large size out of fullscreen crashes
Using SDL drivers will still have those issues though
/******************************************************************************************
 *                             Cocoa sound driver                                         *
 * Known things left to do:                                                               *
 * - Might need to do endian checking for it to work on both ppc and x86                  *
 ******************************************************************************************/

#ifdef WITH_COCOA

#include <AudioUnit/AudioUnit.h>

/* Name conflict */
#define Rect		OTTDRect
#define Point		OTTDPoint
#define WindowClass	OTTDWindowClass
/* Defined in stdbool.h */
#ifndef __cplusplus
# ifndef __BEOS__
#  undef bool
#  undef false
#  undef true
# endif
#endif

#include "../stdafx.h"
#include "../openttd.h"
#include "../debug.h"
#include "../driver.h"
#include "../mixer.h"
#include "../sdl.h"

#include "cocoa_s.h"

#undef WindowClass
#undef Point
#undef Rect


static AudioUnit _outputAudioUnit;

/* The CoreAudio callback */
static OSStatus audioCallback (void *inRefCon,  AudioUnitRenderActionFlags inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData)
{
	MxMixSamples(_mixer, ioData->mData, ioData->mDataByteSize / 4);

	return noErr;
}


static const char *CocoaSoundStart(const char * const *parm)
{
	Component comp;
	ComponentDescription desc;
	struct AudioUnitInputCallback callback;
	AudioStreamBasicDescription requestedDesc;

	DEBUG(driver, 1)("cocoa_s: CocoaSoundStart");

	/* Setup a AudioStreamBasicDescription with the requested format */
	requestedDesc.mFormatID = kAudioFormatLinearPCM;
	requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
	requestedDesc.mChannelsPerFrame = 2;
	requestedDesc.mSampleRate = GetDriverParamInt(parm, "hz", 11025);

	requestedDesc.mBitsPerChannel = 16;
	requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
#if 1		// Big endian?
	requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
#endif

	requestedDesc.mFramesPerPacket = 1;
	requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
	requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;


	/* Locate the default output audio unit */
	desc.componentType = kAudioUnitComponentType;
	desc.componentSubType = kAudioUnitSubType_Output;
	desc.componentManufacturer = kAudioUnitID_DefaultOutput;
	desc.componentFlags = 0;
	desc.componentFlagsMask = 0;

	comp = FindNextComponent (NULL, &desc);
	if (comp == NULL)
		return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL";

	/* Open & initialize the default output audio unit */
	if(OpenAComponent(comp, &_outputAudioUnit) != noErr)
		return "cocoa_s: Failed to start CoreAudio: OpenAComponent";

	if(AudioUnitInitialize(_outputAudioUnit) != noErr)
		return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize";

	/* Set the input format of the audio unit. */
	if(AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &requestedDesc, sizeof (requestedDesc)) != noErr)
		return "cocoa_s: Failed to start CoreAudio:  AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)";

	/* Set the audio callback */
	callback.inputProc = audioCallback;
	callback.inputProcRefCon = NULL;
	if(AudioUnitSetProperty(_outputAudioUnit,  kAudioUnitProperty_SetInputCallback,  kAudioUnitScope_Input,  0, &callback,  sizeof(callback)) != noErr)
		return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)";

	/* Finally, start processing of the audio unit */
	if(AudioOutputUnitStart (_outputAudioUnit) != noErr)
		return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart";

	/* We're running! */
	return NULL;
}


static void CocoaSoundStop(void)
{
	struct AudioUnitInputCallback callback;

	DEBUG(driver, 1)("cocoa_s: CocoaSoundStop");

	/* stop processing the audio unit */
	if(AudioOutputUnitStop(_outputAudioUnit) != noErr) {
		DEBUG(driver, 1)("cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed");
		return;
	}

	/* Remove the input callback */
	callback.inputProc = 0;
	callback.inputProcRefCon = 0;
	if(AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
		DEBUG(driver, 1)("cocoa_s: Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback) failed");
		return;
	}

	if (CloseComponent(_outputAudioUnit) != noErr) {
		DEBUG(driver, 1)("cocoa_s: Core_CloseAudio: CloseComponent failed");
		return;
	}
}


const HalSoundDriver _cocoa_sound_driver = {
	CocoaSoundStart,
	CocoaSoundStop,
};

#endif /* WITH_COCOA */