From 30a1b293516d03457a98b8758c3bee5e38052de1 Mon Sep 17 00:00:00 2001 From: Ken Thomases Date: Thu, 28 Dec 2006 11:05:24 -0600 Subject: [PATCH] winecoreaudio: Add AudioUnit_CreateInputUnit to create an input audio unit. --- dlls/winmm/winecoreaudio/audiounit.c | 133 +++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/dlls/winmm/winecoreaudio/audiounit.c b/dlls/winmm/winecoreaudio/audiounit.c index fe1c7ec4e75..03b4d00de17 100644 --- a/dlls/winmm/winecoreaudio/audiounit.c +++ b/dlls/winmm/winecoreaudio/audiounit.c @@ -33,6 +33,13 @@ extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, UInt32 inNumberFrames, AudioBufferList *ioData); +extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData); + int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au) { OSStatus err; @@ -121,4 +128,130 @@ int AudioUnit_GetVolume(AudioUnit au, float *left, float *right) *right = *left; return 1; } + + +int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au, + WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample) +{ + OSStatus err = noErr; + ComponentDescription description; + Component component; + AudioUnit au; + UInt32 param; + AURenderCallbackStruct callback; + AudioDeviceID defaultInputDevice; + AudioStreamBasicDescription desiredFormat; + + + /* Open the AudioOutputUnit */ + description.componentType = kAudioUnitType_Output; + description.componentSubType = kAudioUnitSubType_HALOutput; + description.componentManufacturer = kAudioUnitManufacturer_Apple; + description.componentFlags = 0; + description.componentFlagsMask = 0; + + component = FindNextComponent(NULL, &description); + if (!component) + { + ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n"); + return 0; + } + + err = OpenAComponent(component, &au); + if (err != noErr || au == NULL) + { + ERR("OpenAComponent failed: %08lx\n", err); + return 0; + } + + /* Configure the AudioOutputUnit */ + /* The AUHAL has two buses (AKA elements). Bus 0 is output from the app + * to the device. Bus 1 is input from the device to the app. Each bus + * has two ends (AKA scopes). Data goes from the input scope to the + * output scope. The terminology is somewhat confusing because the terms + * "input" and "output" have two meanings. Here's a summary: + * + * Bus 0, input scope: refers to the source of data to be output as sound + * Bus 0, output scope: refers to the actual sound output device + * Bus 1, input scope: refers to the actual sound input device + * Bus 1, output scope: refers to the destination of data received by the input device + */ + + /* Enable input on the AUHAL */ + param = 1; + err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, ¶m, sizeof(param)); + if (err != noErr) + { + ERR("Couldn't enable input on AUHAL: %08lx\n", err); + goto error; + } + + /* Disable Output on the AUHAL */ + param = 0; + err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, ¶m, sizeof(param)); + if (err != noErr) + { + ERR("Couldn't disable output on AUHAL: %08lx\n", err); + goto error; + } + + /* Find the default input device */ + param = sizeof(defaultInputDevice); + err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, ¶m, &defaultInputDevice); + if (err != noErr || defaultInputDevice == kAudioDeviceUnknown) + { + ERR("Couldn't get the default audio device ID: %08lx\n", err); + goto error; + } + + /* Set the current device to the default input device. */ + err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &defaultInputDevice, sizeof(defaultInputDevice)); + if (err != noErr) + { + ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err); + goto error; + } + + /* Setup render callback */ + /* This will be called when the AUHAL has input data. However, it won't + * be passed the data itself. The callback will have to all AudioUnitRender. */ + callback.inputProc = CoreAudio_wiAudioUnitIOProc; + callback.inputProcRefCon = wwi; + err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback)); + if (err != noErr) + { + ERR("Couldn't set input callback of AUHAL: %08lx\n", err); + goto error; + } + + /* Setup the desired data format. */ + desiredFormat.mFormatID = kAudioFormatLinearPCM; + desiredFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked; + if (wBitsPerSample != 8) + desiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; + desiredFormat.mSampleRate = nSamplesPerSec; + desiredFormat.mChannelsPerFrame = nChannels; + desiredFormat.mFramesPerPacket = 1; + desiredFormat.mBitsPerChannel = wBitsPerSample; + desiredFormat.mBytesPerFrame = desiredFormat.mBitsPerChannel * desiredFormat.mChannelsPerFrame / 8; + desiredFormat.mBytesPerPacket = desiredFormat.mBytesPerFrame * desiredFormat.mFramesPerPacket; + + /* Set the AudioOutputUnit output data format */ + err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desiredFormat, sizeof(desiredFormat)); + if (err != noErr) + { + ERR("Couldn't set desired input format of AUHAL: %08lx\n", err); + goto error; + } + + *out_au = au; + + return 1; + +error: + if (au) + CloseComponent(au); + return 0; +} + #endif