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@701 | 20 | #include <CoreAudio/CoreAudio.h>
|
nkeynes@697 | 21 | #include "aica/audio.h"
|
nkeynes@697 | 22 | #include "lxdream.h"
|
nkeynes@697 | 23 |
|
nkeynes@701 | 24 | #define BUFFER_SIZE (sizeof(float)*2*2205)
|
nkeynes@701 | 25 |
|
nkeynes@701 | 26 | static AudioDeviceID output_device;
|
nkeynes@697 | 27 | static volatile audio_buffer_t output_buffer = NULL;
|
nkeynes@701 | 28 | static uint32_t buffer_size;
|
nkeynes@697 | 29 |
|
nkeynes@701 | 30 | OSStatus audio_osx_callback( AudioDeviceID inDevice,
|
nkeynes@701 | 31 | const AudioTimeStamp *inNow,
|
nkeynes@701 | 32 | const AudioBufferList *inInputData,
|
nkeynes@701 | 33 | const AudioTimeStamp *inInputTime,
|
nkeynes@701 | 34 | AudioBufferList *outOutputData,
|
nkeynes@701 | 35 | const AudioTimeStamp *inOutputTime,
|
nkeynes@701 | 36 | void *inClientData)
|
nkeynes@697 | 37 | {
|
nkeynes@701 | 38 | char *output = outOutputData->mBuffers[0].mData;
|
nkeynes@701 | 39 | int data_requested = buffer_size;
|
nkeynes@697 | 40 |
|
nkeynes@697 | 41 | while( output_buffer != NULL && data_requested > 0 ) {
|
nkeynes@697 | 42 | int copysize = output_buffer->length - output_buffer->posn;
|
nkeynes@697 | 43 | if( copysize > data_requested ) {
|
nkeynes@697 | 44 | copysize = data_requested;
|
nkeynes@697 | 45 | }
|
nkeynes@697 | 46 | memcpy( output, &output_buffer->data[output_buffer->posn], copysize );
|
nkeynes@697 | 47 | output += copysize;
|
nkeynes@697 | 48 | data_requested -= copysize;
|
nkeynes@697 | 49 | output_buffer->posn += copysize;
|
nkeynes@697 | 50 | if( output_buffer->posn >= output_buffer->length ) {
|
nkeynes@697 | 51 | output_buffer = audio_next_read_buffer();
|
nkeynes@697 | 52 | }
|
nkeynes@697 | 53 | }
|
nkeynes@697 | 54 | if( data_requested > 0 ) {
|
nkeynes@697 | 55 | memset( output, 0, data_requested );
|
nkeynes@697 | 56 | }
|
nkeynes@697 | 57 | return noErr;
|
nkeynes@697 | 58 | }
|
nkeynes@697 | 59 |
|
nkeynes@697 | 60 | static gboolean audio_osx_shutdown()
|
nkeynes@697 | 61 | {
|
nkeynes@701 | 62 | AudioDeviceStop( output_device, audio_osx_callback );
|
nkeynes@701 | 63 | AudioDeviceRemoveIOProc( output_device, audio_osx_callback );
|
nkeynes@697 | 64 | return TRUE;
|
nkeynes@697 | 65 | }
|
nkeynes@697 | 66 |
|
nkeynes@697 | 67 | static gboolean audio_osx_init()
|
nkeynes@697 | 68 | {
|
nkeynes@701 | 69 | UInt32 size = sizeof(output_device);
|
nkeynes@697 | 70 | AudioStreamBasicDescription outputDesc;
|
nkeynes@697 | 71 | UInt32 outputDescSize = sizeof(outputDesc);
|
nkeynes@701 | 72 |
|
nkeynes@701 | 73 | if( AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
|
nkeynes@701 | 74 | &size, &output_device) != noErr ||
|
nkeynes@701 | 75 | output_device == kAudioDeviceUnknown ) {
|
nkeynes@701 | 76 | return FALSE;
|
nkeynes@701 | 77 | }
|
nkeynes@701 | 78 |
|
nkeynes@701 | 79 | if( AudioDeviceGetProperty( output_device, 1, 0, kAudioDevicePropertyStreamFormat,
|
nkeynes@701 | 80 | &outputDescSize, &outputDesc ) != noErr ) {
|
nkeynes@697 | 81 | return FALSE;
|
nkeynes@697 | 82 | }
|
nkeynes@697 | 83 |
|
nkeynes@701 | 84 | buffer_size = BUFFER_SIZE;
|
nkeynes@701 | 85 |
|
nkeynes@701 | 86 | if( AudioDeviceSetProperty( output_device, 0, 0, 0, kAudioDevicePropertyBufferSize,
|
nkeynes@701 | 87 | sizeof(buffer_size), &buffer_size ) != noErr ) {
|
nkeynes@697 | 88 | return FALSE;
|
nkeynes@697 | 89 | }
|
nkeynes@697 | 90 |
|
nkeynes@701 | 91 | AudioDeviceAddIOProc( output_device, audio_osx_callback, NULL );
|
nkeynes@697 | 92 | return TRUE;
|
nkeynes@697 | 93 | }
|
nkeynes@697 | 94 | static gboolean audio_osx_process_buffer( audio_buffer_t buffer )
|
nkeynes@697 | 95 | {
|
nkeynes@697 | 96 | if( output_buffer == NULL ) {
|
nkeynes@697 | 97 | output_buffer = buffer;
|
nkeynes@697 | 98 | output_buffer->posn = 0;
|
nkeynes@701 | 99 | AudioDeviceStart(output_device, audio_osx_callback);
|
nkeynes@697 | 100 | return FALSE;
|
nkeynes@697 | 101 | }
|
nkeynes@697 | 102 | }
|
nkeynes@697 | 103 |
|
nkeynes@697 | 104 | void audio_osx_start()
|
nkeynes@697 | 105 | {
|
nkeynes@701 | 106 | if( output_buffer != NULL ) {
|
nkeynes@701 | 107 | AudioDeviceStart(output_device, audio_osx_callback);
|
nkeynes@701 | 108 | }
|
nkeynes@697 | 109 | }
|
nkeynes@697 | 110 |
|
nkeynes@697 | 111 | void audio_osx_stop()
|
nkeynes@697 | 112 | {
|
nkeynes@701 | 113 | AudioDeviceStop( output_device, audio_osx_callback );
|
nkeynes@697 | 114 | }
|
nkeynes@697 | 115 |
|
nkeynes@697 | 116 |
|
nkeynes@700 | 117 | struct audio_driver audio_osx_driver = {
|
nkeynes@701 | 118 | "osx",
|
nkeynes@700 | 119 | N_("OS X CoreAudio system driver"),
|
nkeynes@697 | 120 | DEFAULT_SAMPLE_RATE,
|
nkeynes@697 | 121 | AUDIO_FMT_FLOATST,
|
nkeynes@697 | 122 | audio_osx_init,
|
nkeynes@697 | 123 | audio_osx_start,
|
nkeynes@697 | 124 | audio_osx_process_buffer,
|
nkeynes@697 | 125 | audio_osx_stop,
|
nkeynes@697 | 126 | audio_osx_shutdown};
|
nkeynes@697 | 127 |
|