nkeynes@697 | 1 | /**
|
nkeynes@697 | 2 | * $Id$
|
nkeynes@697 | 3 | *
|
nkeynes@697 | 4 | * The darwin core-audio audio driver
|
nkeynes@697 | 5 | *
|
nkeynes@697 | 6 | * Copyright (c) 2008 Nathan Keynes.
|
nkeynes@697 | 7 | *
|
nkeynes@697 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@697 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@697 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@697 | 11 | * (at your option) any later version.
|
nkeynes@697 | 12 | *
|
nkeynes@697 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@697 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@697 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@697 | 16 | * GNU General Public License for more details.
|
nkeynes@697 | 17 | */
|
nkeynes@697 | 18 | #include <stdio.h>
|
nkeynes@697 | 19 | #include <unistd.h>
|
nkeynes@697 | 20 | #include <AudioToolbox/AudioToolbox.h>
|
nkeynes@697 | 21 | #include <AudioUnit/AudioUnitProperties.h>
|
nkeynes@697 | 22 | #include "aica/audio.h"
|
nkeynes@697 | 23 | #include "lxdream.h"
|
nkeynes@697 | 24 |
|
nkeynes@697 | 25 | static AudioUnit output_au;
|
nkeynes@697 | 26 | static volatile audio_buffer_t output_buffer = NULL;
|
nkeynes@697 | 27 | static int sample_size;
|
nkeynes@697 | 28 |
|
nkeynes@697 | 29 | OSStatus audio_osx_callback( void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
|
nkeynes@697 | 30 | const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
|
nkeynes@697 | 31 | UInt32 inNumberFrames, AudioBufferList *ioData )
|
nkeynes@697 | 32 | {
|
nkeynes@697 | 33 | char *output = ioData->mBuffers[0].mData;
|
nkeynes@697 | 34 | int data_requested = inNumberFrames * sample_size;
|
nkeynes@697 | 35 |
|
nkeynes@697 | 36 | while( output_buffer != NULL && data_requested > 0 ) {
|
nkeynes@697 | 37 | int copysize = output_buffer->length - output_buffer->posn;
|
nkeynes@697 | 38 | if( copysize > data_requested ) {
|
nkeynes@697 | 39 | copysize = data_requested;
|
nkeynes@697 | 40 | }
|
nkeynes@697 | 41 | memcpy( output, &output_buffer->data[output_buffer->posn], copysize );
|
nkeynes@697 | 42 | output += copysize;
|
nkeynes@697 | 43 | data_requested -= copysize;
|
nkeynes@697 | 44 | output_buffer->posn += copysize;
|
nkeynes@697 | 45 | if( output_buffer->posn >= output_buffer->length ) {
|
nkeynes@697 | 46 | output_buffer = audio_next_read_buffer();
|
nkeynes@697 | 47 | }
|
nkeynes@697 | 48 | }
|
nkeynes@697 | 49 | if( data_requested > 0 ) {
|
nkeynes@697 | 50 | memset( output, 0, data_requested );
|
nkeynes@697 | 51 | }
|
nkeynes@697 | 52 | return noErr;
|
nkeynes@697 | 53 | }
|
nkeynes@697 | 54 |
|
nkeynes@697 | 55 | static gboolean audio_osx_shutdown()
|
nkeynes@697 | 56 | {
|
nkeynes@697 | 57 | AudioUnitUninitialize( output_au );
|
nkeynes@697 | 58 | CloseComponent( output_au );
|
nkeynes@697 | 59 | return TRUE;
|
nkeynes@697 | 60 | }
|
nkeynes@697 | 61 |
|
nkeynes@697 | 62 | static gboolean audio_osx_init()
|
nkeynes@697 | 63 | {
|
nkeynes@697 | 64 | AURenderCallbackStruct callbackData;
|
nkeynes@697 | 65 | AudioStreamBasicDescription outputDesc;
|
nkeynes@697 | 66 | UInt32 outputDescSize = sizeof(outputDesc);
|
nkeynes@697 | 67 | ComponentDescription cd;
|
nkeynes@697 | 68 | Component c;
|
nkeynes@697 | 69 |
|
nkeynes@697 | 70 | cd.componentType = kAudioUnitType_Output;
|
nkeynes@697 | 71 | cd.componentSubType = kAudioUnitSubType_DefaultOutput;
|
nkeynes@697 | 72 | cd.componentManufacturer = kAudioUnitManufacturer_Apple;
|
nkeynes@697 | 73 | cd.componentFlags = 0;
|
nkeynes@697 | 74 | cd.componentFlagsMask = 0;
|
nkeynes@697 | 75 |
|
nkeynes@697 | 76 | c = FindNextComponent( NULL, &cd );
|
nkeynes@697 | 77 | if( c == NULL ) {
|
nkeynes@697 | 78 | return FALSE;
|
nkeynes@697 | 79 | }
|
nkeynes@697 | 80 |
|
nkeynes@697 | 81 | if( OpenAComponent( c, &output_au ) != noErr ) {
|
nkeynes@697 | 82 | return FALSE;
|
nkeynes@697 | 83 | }
|
nkeynes@697 | 84 |
|
nkeynes@697 | 85 | if( AudioUnitGetProperty( output_au, kAudioUnitProperty_StreamFormat,
|
nkeynes@697 | 86 | kAudioUnitScope_Global, 0, &outputDesc, &outputDescSize ) != noErr ) {
|
nkeynes@697 | 87 | CloseComponent( output_au );
|
nkeynes@697 | 88 | return FALSE;
|
nkeynes@697 | 89 | }
|
nkeynes@697 | 90 |
|
nkeynes@697 | 91 | outputDesc.mSampleRate = DEFAULT_SAMPLE_RATE;
|
nkeynes@697 | 92 | sample_size = outputDesc.mBytesPerFrame;
|
nkeynes@697 | 93 |
|
nkeynes@697 | 94 | if( AudioUnitSetProperty( output_au, kAudioUnitProperty_StreamFormat,
|
nkeynes@697 | 95 | kAudioUnitScope_Global, 0, &outputDesc, sizeof(outputDesc) ) != noErr ) {
|
nkeynes@697 | 96 | CloseComponent( output_au );
|
nkeynes@697 | 97 | return FALSE;
|
nkeynes@697 | 98 | }
|
nkeynes@697 | 99 |
|
nkeynes@697 | 100 | if( AudioUnitInitialize( output_au ) != noErr ) {
|
nkeynes@697 | 101 | CloseComponent( output_au );
|
nkeynes@697 | 102 | return FALSE;
|
nkeynes@697 | 103 | }
|
nkeynes@697 | 104 |
|
nkeynes@697 | 105 | callbackData.inputProc = audio_osx_callback;
|
nkeynes@697 | 106 | callbackData.inputProcRefCon = NULL;
|
nkeynes@697 | 107 | if( AudioUnitSetProperty( output_au, kAudioUnitProperty_SetRenderCallback,
|
nkeynes@697 | 108 | kAudioUnitScope_Global, 0, &callbackData, sizeof(callbackData)) != noErr ) {
|
nkeynes@697 | 109 | audio_osx_shutdown();
|
nkeynes@697 | 110 | return FALSE;
|
nkeynes@697 | 111 | }
|
nkeynes@697 | 112 |
|
nkeynes@697 | 113 | return TRUE;
|
nkeynes@697 | 114 | }
|
nkeynes@697 | 115 | static gboolean audio_osx_process_buffer( audio_buffer_t buffer )
|
nkeynes@697 | 116 | {
|
nkeynes@697 | 117 | if( output_buffer == NULL ) {
|
nkeynes@697 | 118 | output_buffer = buffer;
|
nkeynes@697 | 119 | output_buffer->posn = 0;
|
nkeynes@697 | 120 | AudioOutputUnitStart(output_au);
|
nkeynes@697 | 121 | return FALSE;
|
nkeynes@697 | 122 | }
|
nkeynes@697 | 123 | }
|
nkeynes@697 | 124 |
|
nkeynes@697 | 125 | void audio_osx_start()
|
nkeynes@697 | 126 | {
|
nkeynes@697 | 127 | }
|
nkeynes@697 | 128 |
|
nkeynes@697 | 129 | void audio_osx_stop()
|
nkeynes@697 | 130 | {
|
nkeynes@697 | 131 | }
|
nkeynes@697 | 132 |
|
nkeynes@697 | 133 |
|
nkeynes@700 | 134 | struct audio_driver audio_osx_driver = {
|
nkeynes@700 | 135 | "osx",
|
nkeynes@700 | 136 | N_("OS X CoreAudio system driver"),
|
nkeynes@697 | 137 | DEFAULT_SAMPLE_RATE,
|
nkeynes@697 | 138 | AUDIO_FMT_FLOATST,
|
nkeynes@697 | 139 | audio_osx_init,
|
nkeynes@697 | 140 | audio_osx_start,
|
nkeynes@697 | 141 | audio_osx_process_buffer,
|
nkeynes@697 | 142 | audio_osx_stop,
|
nkeynes@697 | 143 | audio_osx_shutdown};
|
nkeynes@697 | 144 |
|