Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //compile with kernel32, and ole32
- /**
- * \file kit_w32_audio.c
- * \brief Header file for KIT Win32's audio module
- */
- #include <kit_w32_audio.h>
- #include <_kit_w32_audioCOM.h>
- #include <_kit_w32_audioPropKeyDef.h> //#include <Functiondiscoverykeys_devpkey.h>
- #define _KIT_AUDIO_MMONO (SPEAKER_FRONT_LEFT)
- #define _KIT_AUDIO_MSTEREO (_KIT_AUDIO_MMONO |SPEAKER_FRONT_RIGHT )
- #define _KIT_AUDIO_M2_1S (_KIT_AUDIO_MSTEREO|SPEAKER_LOW_FREQUENCY)
- #define _KIT_AUDIO_MQUAD (_KIT_AUDIO_MSTEREO|SPEAKER_BACK_LEFT |SPEAKER_BACK_RIGHT)
- #define _KIT_AUDIO_M4_1S (_KIT_AUDIO_MQUAD |SPEAKER_LOW_FREQUENCY)
- #define _KIT_AUDIO_M5_1S (_KIT_AUDIO_M4_1S |SPEAKER_FRONT_CENTER )
- #define _KIT_AUDIO_M6_1S (_KIT_AUDIO_M2_1S |SPEAKER_FRONT_CENTER |SPEAKER_SIDE_LEFT |SPEAKER_SIDE_RIGHT)
- #define _KIT_AUDIO_M7_1S (_KIT_AUDIO_M5_1S |SPEAKER_SIDE_LEFT |SPEAKER_SIDE_RIGHT)
- #define _KIT_AUDIO_LOCKCALLBACKTHREAD(_device) \
- EnterCriticalSection(&_device->_callback_mutex);
- #define _KIT_AUDIO_UNLOCKCALLBACKTHREAD(_device) \
- LeaveCriticalSection(&_device->_callback_mutex);
- #define _IS_ERROR(_value,_before_goto) \
- { returnStatus=_value; _before_goto; goto _error_; }
- #define _IF_ERROR(_condition,_value,_before_goto) \
- if(_condition){ _IS_ERROR(_value,_before_goto); }
- #define _KIT_AUDIO_FREE(_action,_pointer) \
- if(_pointer != NULL){ _action(_pointer); }
- #define _KIT_AUDIO_RELEASE(_action,_pointer) \
- if(_pointer != NULL){ while(numRefs){ \
- numRefs=_action(_pointer); \
- }} \
- numRefs=1;
- #define _LOCK_GLOBALS_AUDIO EnterCriticalSection(&_kit_audioGlobals.lock);
- #define _UNLOCK_GLOBALS_AUDIO LeaveCriticalSection(&_kit_audioGlobals.lock);
- /*
- typedef struct {
- union {
- WAVEFORMATEX device_format;
- WAVEFORMATEXTENSIBLE device_format_ext;
- };
- IMMDeviceCollection* devices;
- IMMDevice* device;
- IPropertyStore* props;
- IAudioClient* client;
- LPWSTR device_id; //aka wide char* (wchar_t*)!
- LPWSTR device_iname;
- LPWSTR device_name;
- LPWSTR device_desc;
- size_t device_iname_len;
- size_t device_name_len;
- size_t device_desc_len;
- UINT device_index;
- EDataFlow data_flow; //read-only; set by init
- int data_type; //1,2,3 = pcm&format, float&format_ext, pcm&format_ext
- int event_driven_support; //might not be used
- } _kit_audioGlobalsDevInfo;
- struct _kit_audioGlobals_s {
- CRITICAL_SECTION lock;
- IMMDeviceEnumerator* enumerator;
- kit_audioDevice** kit_devices;
- UINT kit_devices_len;
- _kit_audioGlobalsDevInfo i;
- _kit_audioGlobalsDevInfo o;
- int init;
- };
- */
- //(todo: eventually make this struct opaque and anonymous)
- struct _kit_audioGlobals_s _kit_audioGlobals={0};
- //KSDATAFORMAT_SUBTYPE_IEEE_FLOAT="00000003-0000-0010-8000-00aa00389b71"
- const GUID _SUBTYPE_IEEE_FLOAT={.Data1=0x00000003,.Data2=0x0000,.Data3=0x0010,.Data4={0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71}};
- //KSDATAFORMAT_SUBTYPE_PCM ="00000001-0000-0010-8000-00aa00389b71"
- const GUID _SUBTYPE_PCM ={.Data1=0x00000001,.Data2=0x0000,.Data3=0x0010,.Data4={0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71}};
- /* (private) INLINES */
- static inline int _kit_audioCountBits(long long unsigned int bitState){
- int bitCount=0;
- while(bitState){ bitCount+=bitState&1; bitState>>=1; }
- return bitCount;
- }
- /* CALLBACK-RELATED FUNCTIONS */
- /* COM-RELATED FUNCTIONS */
- kit_audioSpec _kit_audioWaveFormatToSpec(WAVEFORMATEX* format_ex, int* returnStatus_p){ /*0 -> 5*/
- int returnStatus=0; kit_audioSpec spec; //memset(&spec,0xff,sizeof(kit_audioSpec));
- WAVEFORMATEXTENSIBLE* format_ext=(void*)format_ex;
- _IF_ERROR(format_ex==NULL,1,;);
- WORD format_tag=format_ex->wFormatTag;
- kit_audioFormat format=0;
- if(format_tag==WAVE_FORMAT_EXTENSIBLE){
- _IF_ERROR(format_ext->Samples.wValidBitsPerSample>256,3,;);
- format|=format_ext->Samples.wValidBitsPerSample-1;
- _IF_ERROR(format_ex->cbSize!=(sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)),4,;);
- GUID* subformat_tag=&format_ext->SubFormat;
- if(IsEqualGUID(subformat_tag,&_SUBTYPE_IEEE_FLOAT)) format |= KIT_AUDIO_FMT_MFLOAT|KIT_AUDIO_FMT_MSIGNED;
- else if(IsEqualGUID(subformat_tag,&_SUBTYPE_PCM)) format |= KIT_AUDIO_FMT_MSIGNED*(format>8);
- else _IS_ERROR(5,;);
- } else if(format_tag==WAVE_FORMAT_PCM){
- _IF_ERROR(format_ex->wBitsPerSample>256,3,;);
- format|=format_ex->wBitsPerSample-1;
- } else _IS_ERROR(2,;);
- spec.format=format;
- spec.frequency=format_ex->nSamplesPerSec;
- spec.channels=format_ex->nChannels;
- spec.buffer_len=spec.buffer_size=0;
- spec.callback=spec.userdata=0;
- _error_:
- if(returnStatus_p != NULL) *returnStatus_p=returnStatus;
- return spec;
- }
- WAVEFORMATEXTENSIBLE _kit_audioSpecToWaveFormat(kit_audioSpec* spec, int* returnStatus_p){ /*0 -> 5*/
- int returnStatus=0; WAVEFORMATEXTENSIBLE format={0}, null={0};
- _IF_ERROR(spec==NULL,1,;);
- //get kit_audioFormat data
- int bitsPerSample=(spec->format&KIT_AUDIO_FMT_MBITSIZE)+1;
- int isFloat =(spec->format&KIT_AUDIO_FMT_MFLOAT )!=0;
- int isBigEndian =(spec->format&KIT_AUDIO_FMT_MENDIAN )!=0;
- int isSigned =(spec->format&KIT_AUDIO_FMT_MSIGNED )!=0;
- _IF_ERROR(isBigEndian ,2,;);
- _IF_ERROR(isFloat&&(!isSigned) ,3,;);
- _IF_ERROR(bitsPerSample<=8 && isSigned,4,;);
- //fill in WAVEFORMATEX info
- format.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE;
- format.Format.nChannels=spec->channels;
- format.Format.nSamplesPerSec=spec->frequency;
- format.Format.wBitsPerSample=(bitsPerSample>=8) ? ((bitsPerSample/8)*8) : 8;
- format.Format.nBlockAlign=spec->channels*(format.Format.wBitsPerSample/8);
- format.Format.nAvgBytesPerSec=spec->frequency*format.Format.nBlockAlign;
- format.Format.cbSize=sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
- //fill in WAVEFORMATEXTENSIBLE info
- format.Samples.wValidBitsPerSample=bitsPerSample;
- //set guid
- if(isFloat) memcpy(&format.SubFormat,&_SUBTYPE_IEEE_FLOAT,sizeof(GUID));
- else memcpy(&format.SubFormat,&_SUBTYPE_PCM ,sizeof(GUID));
- //set channel masks based on channel mapping
- switch(spec->channels){
- case 1: format.dwChannelMask=_KIT_AUDIO_MMONO; break;
- case 2: format.dwChannelMask=_KIT_AUDIO_MSTEREO; break;
- case 3: format.dwChannelMask=_KIT_AUDIO_M2_1S; break;
- case 4: format.dwChannelMask=_KIT_AUDIO_MQUAD; break;
- case 5: format.dwChannelMask=_KIT_AUDIO_M4_1S; break;
- case 6: format.dwChannelMask=_KIT_AUDIO_M5_1S; break;
- case 7: format.dwChannelMask=_KIT_AUDIO_M6_1S; break;
- case 8: format.dwChannelMask=_KIT_AUDIO_M7_1S; break;
- default: _IS_ERROR(5,;); }
- _error_:
- if(returnStatus_p != NULL) *returnStatus_p=returnStatus;
- if(!returnStatus) return format;
- else return null;
- }
- int _kit_audioQueryDevice(unsigned int index, int isCapture){ /*0 -> 4*/ //assumes globals are already locked
- int returnStatus=0; ULONG numRefs=1; UINT numDevices;
- //choose between capture and render
- _kit_audioGlobalsDevInfo* info;
- if(isCapture&1) info=&_kit_audioGlobals.i;
- else info=&_kit_audioGlobals.o;
- //is given id greater than maximum valid index?
- _kit_audioCOM_IMMDeviceCollection_GetCount(info->devices, &numDevices);
- _IF_ERROR((index>=numDevices) && (index!=0xffffffff),1,;);
- //retrieve IMMDevice & IAudioClient, only if given index is different to the last one retrieved
- if(index!=info->device_index || info->device==NULL){
- //retrieve IMMDevice
- //clean up previous references
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IMMDevice_Release,info->device);
- if(index != 0xffffffff){ // index!=-1
- _kit_audioCOM_IMMDeviceCollection_Item(info->devices, (UINT)index, &info->device);
- } else {
- _kit_audioCOM_IMMDeviceEnumerator_GetDefaultAudioEndpoint(_kit_audioGlobals.enumerator,
- info->data_flow, eConsole, &info->device);
- }
- info->device_index=index;
- //retrieve IAudioClient
- //clean up previous references
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IAudioClient_Release,info->client);
- printf("!A!last Win32 error=%lu\n",GetLastError());
- switch(_kit_audioCOM_IMMDevice_Activate(info->device,
- &IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&info->client)
- ){
- case AUDCLNT_E_DEVICE_INVALIDATED: _IS_ERROR(2,;);
- case E_NOINTERFACE: _IS_ERROR(3,;);
- case E_OUTOFMEMORY: _IS_ERROR(4,;);
- case S_OK:;
- }
- printf("!B!last Win32 error=%lu\n",GetLastError());
- }
- _error_: return returnStatus;
- }
- int _kit_audioQueryDeviceProps(unsigned int index, int isCapture){ /*0 -> 14*/ //assumes globals are already locked
- int returnStatus=0, property_init=0; ULONG numRefs=1;
- //choose between capture and render
- _kit_audioGlobalsDevInfo* info;
- if(isCapture&=1) info=&_kit_audioGlobals.i;
- else info=&_kit_audioGlobals.o;
- int equal_to_last_index = index==info->device_index;
- returnStatus=_kit_audioQueryDevice(index,isCapture);
- if(returnStatus) goto _error_; //errors 1 -> 4
- //retrieve property store unless current one is identical
- if(!equal_to_last_index || info->props==NULL){
- //clean up previous references
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IPropertyStore_Release,info->props);
- _IF_ERROR(_kit_audioCOM_IMMDevice_OpenPropertyStore(info->device,
- STGM_READ, &info->props) == E_OUTOFMEMORY,
- 5,;);
- }
- //get WAVEFORMATEX(TENSIBLE) from device's property store
- PROPVARIANT property;
- _kit_audioCOM_IPropertyStore_GetValue(info->props, &PKEY_AudioEngine_DeviceFormat, &property);
- if(property.blob.pBlobData==NULL){
- PropVariantClear(&property);
- //try oem format instead
- _kit_audioCOM_IPropertyStore_GetValue(info->props, &PKEY_AudioEngine_OEMFormat, &property);
- _IF_ERROR(property.blob.pBlobData==NULL,6,;);
- }
- WORD format_tag=((WAVEFORMATEX*)property.blob.pBlobData)->wFormatTag; /* --> */ property_init=1;
- if(format_tag == WAVE_FORMAT_EXTENSIBLE){
- GUID* subformat_tag=&((WAVEFORMATEXTENSIBLE*)property.blob.pBlobData)->SubFormat;
- if(IsEqualGUID(subformat_tag,&_SUBTYPE_IEEE_FLOAT)) info->data_type=2;
- else if(IsEqualGUID(subformat_tag,&_SUBTYPE_PCM)) info->data_type=3;
- else { return returnStatus=8; goto _error_; }
- info->device_format_ext=*(WAVEFORMATEXTENSIBLE*)property.blob.pBlobData;
- } else if(format_tag == WAVE_FORMAT_PCM){ /* --> */ info->data_type=1;
- info->device_format=*(WAVEFORMATEX*)property.blob.pBlobData;
- }
- else{ returnStatus=7; goto _error_; }
- if(property_init) PropVariantClear(&property);
- property_init=0;
- //get whether device supports event-driven mode
- _kit_audioCOM_IPropertyStore_GetValue(info->props, &PKEY_AudioEndpoint_Supports_EventDriven_Mode, &property);
- info->event_driven_support=property.uintVal;
- PropVariantClear(&property);
- //get name of device
- _kit_audioCOM_IPropertyStore_GetValue(info->props, &PKEY_Device_FriendlyName, &property);
- _IF_ERROR(property.pwszVal==NULL,9,;); /* --> */ property_init=1;
- info->device_name_len=wcslen(property.pwszVal);
- info->device_name=_kit_audioRealloc(info->device_name,wchar_t,info->device_name_len+1);
- _IF_ERROR(info->device_name==NULL,10,;);
- wcscpy(info->device_name,property.pwszVal);
- PropVariantClear(&property); /* --> */ property_init=0;
- //get description of device
- _kit_audioCOM_IPropertyStore_GetValue(info->props, &PKEY_Device_DeviceDesc, &property);
- _IF_ERROR(property.pwszVal==NULL,11,;); /* --> */ property_init=1;
- info->device_desc_len=wcslen(property.pwszVal);
- info->device_desc=_kit_audioRealloc(info->device_desc,wchar_t,info->device_desc_len+1);
- _IF_ERROR(info->device_desc==NULL,12,;);
- wcscpy(info->device_desc,property.pwszVal);
- PropVariantClear(&property); /* --> */ property_init=0;
- //get interface name of device
- _kit_audioCOM_IPropertyStore_GetValue(info->props, &PKEY_DeviceInterface_FriendlyName, &property);
- _IF_ERROR(property.pwszVal==NULL,13,;); /* --> */ property_init=1;
- info->device_iname_len=wcslen(property.pwszVal);
- info->device_iname=_kit_audioRealloc(info->device_iname,wchar_t,info->device_iname_len+1);
- _IF_ERROR(info->device_iname==NULL,14,;);
- wcscpy(info->device_iname,property.pwszVal);
- PropVariantClear(&property); /* --> */ property_init=0;
- _error_:
- if(property_init) PropVariantClear(&property);
- return returnStatus;
- }
- int kit_audioQueryDevices(int isCapture, kit_audioDeviceStatus status){ /*0 -> 2*/
- int returnStatus=0; ULONG numRefs=1;
- _LOCK_GLOBALS_AUDIO;
- _IF_ERROR(!(status&ADStatusAll),1,;); //error if status is not a valid enum value
- //choose between capture and render
- _kit_audioGlobalsDevInfo* info;
- if(isCapture&1) info=&_kit_audioGlobals.i;
- else info=&_kit_audioGlobals.o;
- //clean up previous references
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IMMDeviceCollection_Release,info->devices);
- if(_kit_audioCOM_IMMDeviceEnumerator_EnumAudioEndpoints(_kit_audioGlobals.enumerator,
- info->data_flow, (DWORD)status, &info->devices) == E_OUTOFMEMORY
- ) returnStatus=2;
- _error_:
- _UNLOCK_GLOBALS_AUDIO;
- return returnStatus;
- }
- unsigned int kit_audioGetNumDevices(int isCapture){
- UINT numDevices;
- _LOCK_GLOBALS_AUDIO;
- IMMDeviceCollection* devices;
- if(isCapture&1) devices=_kit_audioGlobals.i.devices;
- else devices=_kit_audioGlobals.o.devices;
- _kit_audioCOM_IMMDeviceCollection_GetCount(devices,&numDevices);
- _UNLOCK_GLOBALS_AUDIO;
- return (unsigned int)numDevices;
- }
- wchar_t* kit_audioGetDeviceName(unsigned int index, int isCapture,
- int mode, int* returnStatus_p){ /*0 -> 14*/
- int returnStatus=0; wchar_t* deviceName=NULL;
- _LOCK_GLOBALS_AUDIO;
- //choose between capture and render
- _kit_audioGlobalsDevInfo* info;
- if(isCapture&=1) info=&_kit_audioGlobals.i;
- else info=&_kit_audioGlobals.o;
- returnStatus=_kit_audioQueryDeviceProps(index,isCapture);
- if(returnStatus) goto _error_; //errors 1 -> 14
- switch(mode%3){
- case 0: deviceName=info->device_name; break;
- case 1: deviceName=info->device_desc; break;
- case 2: deviceName=info->device_iname; }
- _error_:
- _UNLOCK_GLOBALS_AUDIO;
- if(returnStatus_p != NULL) *returnStatus_p=returnStatus;
- return deviceName;
- }
- wchar_t* kit_audioGetDeviceID(unsigned int index, int isCapture, int* returnStatus_p){ /*0 -> 5*/
- int returnStatus=0; wchar_t* deviceID=NULL;
- _LOCK_GLOBALS_AUDIO;
- //choose between capture and render
- _kit_audioGlobalsDevInfo* info;
- if(isCapture&=1) info=&_kit_audioGlobals.i;
- else info=&_kit_audioGlobals.o;
- int equal_to_last_index = index==info->device_index;
- returnStatus=_kit_audioQueryDevice(index,isCapture);
- if(returnStatus) goto _error_; //errors 1 -> 4
- //return already cached id if id is the same as the last
- _IF_ERROR(equal_to_last_index,0, deviceID=info->device_id);
- if(_kit_audioCOM_IMMDevice_GetId(info->device,(LPWSTR*)&deviceID) != E_OUTOFMEMORY){
- _KIT_AUDIO_FREE(_kit_audioFree,info->device_id);
- info->device_id=deviceID;
- } else returnStatus=5;
- _error_:
- _UNLOCK_GLOBALS_AUDIO;
- if(returnStatus_p != NULL) *returnStatus_p=returnStatus;
- return deviceID;
- }
- kit_audioDeviceStatus kit_audioGetDeviceStatus(unsigned int index, int isCapture, int* returnStatus_p){ /*0 -> 4*/
- int returnStatus=0; kit_audioDeviceStatus deviceStatus;
- _LOCK_GLOBALS_AUDIO;
- //choose between capture and render
- IMMDevice* device;
- if(isCapture) device=_kit_audioGlobals.i.device;
- else device=_kit_audioGlobals.o.device;
- returnStatus=_kit_audioQueryDevice(index,isCapture&=1);
- if(returnStatus) goto _error_; //errors 1 -> 4
- _kit_audioCOM_IMMDevice_GetState(device, (DWORD*)&deviceStatus);
- _error_:
- _UNLOCK_GLOBALS_AUDIO;
- if(returnStatus){
- deviceStatus=ADStatusInvalid;
- if(returnStatus_p != NULL) *returnStatus_p=returnStatus;
- }
- return deviceStatus;
- }
- int kit_audioGetDeviceSpec(unsigned int index, int isCapture, kit_audioSpec* spec){ /*0 -> 20*/
- int returnStatus=0; //ULONG numRefs=1; //HRESULT hr;
- _LOCK_GLOBALS_AUDIO;
- _IF_ERROR(spec==NULL,1,;);
- //choose between capture and render
- WAVEFORMATEX* device_format;
- if(isCapture&=1) device_format=&_kit_audioGlobals.i.device_format;
- else device_format=&_kit_audioGlobals.o.device_format;
- //retrieve relevant property store info
- returnStatus=_kit_audioQueryDeviceProps(index,isCapture); //calls _kit_audioQueryDevice
- if(returnStatus){ ++returnStatus; goto _error_; } //errors 2 -> 15
- //convert format info to kit_audioSpec
- kit_audioSpec _spec=_kit_audioWaveFormatToSpec(device_format, &returnStatus);
- if(returnStatus){ returnStatus+=15; goto _error_; } //errors 16 -> 20
- *spec=_spec;
- _error_:
- _UNLOCK_GLOBALS_AUDIO;
- return returnStatus;
- }
- int kit_audioIsSpecSupported(unsigned int index, int isCapture, /*int exclusive,*/ /*-1 -> 17*/
- kit_audioSpec* spec, kit_audioSpec* closestMatch){
- int returnStatus=0;
- //AUDCLNT_SHAREMODE shareMode=(exclusive&1) ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED;
- AUDCLNT_SHAREMODE shareMode=AUDCLNT_SHAREMODE_SHARED;
- WAVEFORMATEX* _closestMatch_WFE=NULL;
- _LOCK_GLOBALS_AUDIO;
- _IF_ERROR(spec==NULL,1,;);
- //choose between capture and render
- IAudioClient* client;
- if(isCapture&=1) client=_kit_audioGlobals.i.client;
- else client=_kit_audioGlobals.o.client;
- //retrieve device (as well as the associated audio client)
- returnStatus=_kit_audioQueryDevice(index,isCapture);
- if(returnStatus){ ++returnStatus; goto _error_; } //errors 2 -> 5
- //convert specification to wave format struct
- WAVEFORMATEXTENSIBLE format=_kit_audioSpecToWaveFormat(spec,&returnStatus);
- if(returnStatus){ returnStatus+=5; goto _error_; } //errors 6 -> 10
- switch(_kit_audioCOM_IAudioClient_IsFormatSupported(client,
- shareMode, (WAVEFORMATEX*)&format, &_closestMatch_WFE)
- ){
- //case AUDCLNT_E_UNSUPPORTED_FORMAT: (only applicable in exclusive sharemode)
- //i don't get how this would realistically happen in practice
- //(like, the fundamental audio service isn't running at all?)
- case AUDCLNT_E_SERVICE_NOT_RUNNING: _IS_ERROR(11,;);
- case AUDCLNT_E_DEVICE_INVALIDATED: _IS_ERROR(12,;);
- case S_FALSE: returnStatus=-1;
- case S_OK:;
- }
- _error_:
- _UNLOCK_GLOBALS_AUDIO;
- if(_closestMatch_WFE != NULL){
- kit_audioSpec _closestMatch=_kit_audioWaveFormatToSpec(_closestMatch_WFE,&returnStatus);
- if(returnStatus){ returnStatus+=12; goto free_wfe_; } //errors 13 -> 17
- *closestMatch=_closestMatch;
- }
- free_wfe_:
- _KIT_AUDIO_FREE(_kit_audioFree,_closestMatch_WFE);
- return returnStatus;
- }
- //this is more of a utility function, as everything used here is public anyway
- unsigned int kit_audioGetDeviceIndexFromID(wchar_t* deviceID, int isCapture, int* returnStatus_p){ /*-1 -> 9*/
- int returnStatus=0, locked=0; unsigned int index=0xfffffffe; wchar_t *_deviceID=NULL, *deviceID2;
- _IF_ERROR(deviceID==NULL,1,;);
- //copy id to a temporary location, to make sure globals aren't tripped over
- _LOCK_GLOBALS_AUDIO; locked=1;
- int IDLen=wcslen(deviceID);
- _IF_ERROR(!IDLen,2,;);
- _deviceID=_kit_audioMalloc(wchar_t,IDLen);
- _IF_ERROR(_deviceID==NULL,3,;);
- wcscpy(_deviceID,deviceID);
- _UNLOCK_GLOBALS_AUDIO; locked=0;
- //do a linear search of ids
- unsigned int numDevices=kit_audioGetNumDevices(isCapture&=1);
- _IF_ERROR(!numDevices,4,;);
- for(unsigned int i=-1; (i==-1)||(i<numDevices); ++i){
- deviceID2=kit_audioGetDeviceID(i,isCapture,&returnStatus);
- if(returnStatus){ returnStatus+=4; goto _error_; } //errors 5 -> 9
- _LOCK_GLOBALS_AUDIO; locked=1;
- if(wcscmp(_deviceID,deviceID2)){ index=i; break; }
- _UNLOCK_GLOBALS_AUDIO; locked=0;
- }
- if(index == 0xfffffffe) returnStatus=-1; //index == -2
- _error_:
- if(locked) _UNLOCK_GLOBALS_AUDIO;
- _KIT_AUDIO_FREE(_kit_audioFree,_deviceID);
- if(returnStatus_p != NULL) *returnStatus_p=returnStatus;
- return index;
- }
- /* kit_audioDevice-RELATED FUNCTIONS */
- int kit_audioDevicePlay(kit_audioDevice* device, kit_audioDevicePState playState){
- int returnStatus=0;
- //_error_:
- return returnStatus;
- }
- kit_audioDevicePState kit_audioGetDevicePlayState(kit_audioDevice* device){
- kit_audioDevicePState returnStatus=ADPStateInvalid;
- //_error_:
- return returnStatus;
- }
- /* (UN)INIT FUNCTIONS */
- int kit_audioInit(int initCOM){
- int returnStatus=0, critical_section_init=0;
- //might cause race conditions, but i don't know how to structure this better
- _IF_ERROR(_kit_audioGlobals.init,1,;);
- InitializeCriticalSection(&_kit_audioGlobals.lock);
- critical_section_init=1;
- _LOCK_GLOBALS_AUDIO;
- memset(((void*)&_kit_audioGlobals)+sizeof(CRITICAL_SECTION),0,
- sizeof(_kit_audioGlobals)-sizeof(CRITICAL_SECTION));
- //set i and o's data_flow to eCapture and eRender respectively
- _kit_audioGlobals.i.data_flow=eCapture;
- _kit_audioGlobals.o.data_flow=eRender;
- //initialize com
- if(initCOM&1) CoInitializeEx(NULL,COINIT_MULTITHREADED);
- //create enumerator object
- HRESULT hr=CoCreateInstance(
- &CLSID_MMDeviceEnumerator,
- NULL, CLSCTX_ALL,
- &IID_IMMDeviceEnumerator,
- (void**)&_kit_audioGlobals.enumerator
- ); _IF_ERROR(FAILED(hr),2,;);
- //get input device collection
- hr=_kit_audioCOM_IMMDeviceEnumerator_EnumAudioEndpoints(_kit_audioGlobals.enumerator,
- eCapture, DEVICE_STATEMASK_ALL, &_kit_audioGlobals.i.devices
- ); _IF_ERROR(FAILED(hr),3,;);
- //get output device collection
- hr=_kit_audioCOM_IMMDeviceEnumerator_EnumAudioEndpoints(_kit_audioGlobals.enumerator,
- eRender, DEVICE_STATEMASK_ALL, &_kit_audioGlobals.o.devices
- ); _IF_ERROR(FAILED(hr),4,;);
- _kit_audioGlobals.init=1;
- _error_:
- if(critical_section_init) _UNLOCK_GLOBALS_AUDIO;
- return returnStatus;
- }
- int kit_audioQuit(int uninitCOM){
- int returnStatus=0; ULONG numRefs=1;
- _IF_ERROR(!_kit_audioGlobals.init,1,;);
- _LOCK_GLOBALS_AUDIO;
- //free last i/o device names (wchar_t*)
- _KIT_AUDIO_FREE(_kit_audioFree,_kit_audioGlobals.i.device_name);
- _KIT_AUDIO_FREE(_kit_audioFree,_kit_audioGlobals.i.device_desc);
- _KIT_AUDIO_FREE(_kit_audioFree,_kit_audioGlobals.i.device_iname);
- _KIT_AUDIO_FREE(_kit_audioFree,_kit_audioGlobals.o.device_name);
- _KIT_AUDIO_FREE(_kit_audioFree,_kit_audioGlobals.o.device_desc);
- _KIT_AUDIO_FREE(_kit_audioFree,_kit_audioGlobals.o.device_iname);
- //free last i/o device ids (wchar_t*)
- _KIT_AUDIO_FREE(_kit_audioFree,_kit_audioGlobals.i.device_id);
- _KIT_AUDIO_FREE(_kit_audioFree,_kit_audioGlobals.o.device_id);
- //release last i/o device audio clients
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IAudioClient_Release,_kit_audioGlobals.i.client);
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IAudioClient_Release,_kit_audioGlobals.o.client);
- //release last i/o device property stores
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IPropertyStore_Release,_kit_audioGlobals.i.props);
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IPropertyStore_Release,_kit_audioGlobals.o.props);
- //release last i/o devices
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IMMDevice_Release,_kit_audioGlobals.i.device);
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IMMDevice_Release,_kit_audioGlobals.o.device);
- //release i/o device collections
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IMMDeviceCollection_Release,_kit_audioGlobals.i.devices);
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IMMDeviceCollection_Release,_kit_audioGlobals.o.devices);
- //release enumerator
- _KIT_AUDIO_RELEASE(_kit_audioCOM_IMMDeviceEnumerator_Release,_kit_audioGlobals.enumerator);
- //todo: find out why CoUninitialize() makes GetLastError()=126 (ERROR_MOD_NOT_FOUND)
- if(uninitCOM&1) CoUninitialize();
- _kit_audioGlobals.init=0;
- _error_:
- _UNLOCK_GLOBALS_AUDIO;
- if(!returnStatus) DeleteCriticalSection(&_kit_audioGlobals.lock);
- return returnStatus;
- }
- kit_audioDevice* kit_audioDeviceOpen(kit_audioSpec* spec, unsigned int index,
- int isCapture, int* returnStatus_p){
- int returnStatus=0;
- _IF_ERROR(spec==NULL,1,;);
- _error_:
- if(returnStatus_p != NULL) *returnStatus_p=returnStatus;
- return NULL;
- }
- int kit_audioDeviceClose(kit_audioDevice** device_p){
- int returnStatus=0;
- _IF_ERROR(device_p==NULL,1,;);
- _error_:
- return returnStatus;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement