// This should probably move to another c file but for now ... ALCAPI ALCdevice* ALCAPIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) { ALCboolean DeviceFound = ALC_FALSE; ALCdevice *pDevice = NULL; ALCint i; if(SampleSize <= 0) { alcSetError(ALC_INVALID_VALUE); return NULL; } if(deviceName && !deviceName[0]) deviceName = NULL; pDevice = malloc(sizeof(ALCdevice)); if (pDevice) { //Initialise device structure memset(pDevice, 0, sizeof(ALCdevice)); //Validate device pDevice->Connected = ALC_TRUE; pDevice->IsCaptureDevice = AL_TRUE; pDevice->szDeviceName = NULL; pDevice->Frequency = frequency; pDevice->Format = format; pDevice->UpdateSize = SampleSize; pDevice->NumUpdates = 1; SuspendContext(NULL); for(i = 0;BackendList[i].Init;i++) { pDevice->Funcs = &BackendList[i].Funcs; if(ALCdevice_OpenCapture(pDevice, deviceName)) { pDevice->next = g_pDeviceList; g_pDeviceList = pDevice; g_ulDeviceCount++; DeviceFound = ALC_TRUE; break; } } ProcessContext(NULL); if(!DeviceFound) { alcSetError(ALC_INVALID_VALUE); free(pDevice); pDevice = NULL; } } else alcSetError(ALC_OUT_OF_MEMORY); return pDevice; }
ALCAPI ALCboolean ALCAPIENTRY alcCaptureCloseDevice(ALCdevice *pDevice) { ALCboolean bReturn = ALC_FALSE; ALCdevice **list; if(IsDevice(pDevice) && pDevice->IsCaptureDevice) { SuspendContext(NULL); list = &g_pDeviceList; while(*list != pDevice) list = &(*list)->next; *list = (*list)->next; g_ulDeviceCount--; ProcessContext(NULL); ALCdevice_CloseCapture(pDevice); free(pDevice->szDeviceName); pDevice->szDeviceName = NULL; free(pDevice); bReturn = ALC_TRUE; } else alcSetError(ALC_INVALID_DEVICE); return bReturn; }
/* alcIsExtensionPresent Determines if there is support for a particular extension */ ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) { ALCboolean bResult = ALC_FALSE; (void)device; if (extName) { const char *ptr; size_t len; len = strlen(extName); ptr = alcExtensionList; while(ptr && *ptr) { if(strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) { bResult = ALC_TRUE; break; } if((ptr=strchr(ptr, ' ')) != NULL) { do { ++ptr; } while(isspace(*ptr)); } } } else alcSetError(ALC_INVALID_VALUE); return bResult; }
ALCAPI void ALCAPIENTRY alcCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCsizei lSamples) { if(IsDevice(pDevice) && pDevice->IsCaptureDevice) ALCdevice_CaptureSamples(pDevice, pBuffer, lSamples); else alcSetError(ALC_INVALID_DEVICE); }
/* alcMakeContextCurrent Makes the given Context the active Context */ ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context) { ALCcontext *ALContext; ALboolean bReturn = AL_TRUE; SuspendContext(NULL); // context must be a valid Context or NULL if(context == NULL || IsContext(context)) { if((ALContext=GetContextSuspended()) != NULL) { ALContext->InUse=AL_FALSE; ProcessContext(ALContext); } if((ALContext=context) != NULL && ALContext->Device) { SuspendContext(ALContext); ALContext->InUse=AL_TRUE; ProcessContext(ALContext); } tls_set(LocalContext, NULL); } else { alcSetError(ALC_INVALID_CONTEXT); bReturn = AL_FALSE; } ProcessContext(NULL); return bReturn; }
static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) { DSoundData *pData = NULL; LPGUID guid = NULL; HRESULT hr; if(!DSoundLoad()) return ALC_FALSE; if(!deviceName) deviceName = dsDevice; else if(strcmp(deviceName, dsDevice) != 0) { ALuint i; if(!DeviceList) { hr = pDirectSoundEnumerateA(DSoundEnumDevices, NULL); if(FAILED(hr)) AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); } for(i = 0; i < NumDevices; i++) { if(strcmp(deviceName, DeviceList[i].name) == 0) { if(i > 0) guid = &DeviceList[i].guid; break; } } if(i == NumDevices) return ALC_FALSE; } //Initialise requested device pData = calloc(1, sizeof(DSoundData)); if(!pData) { alcSetError(device, ALC_OUT_OF_MEMORY); return ALC_FALSE; } //DirectSound Init code hr = pDirectSoundCreate(guid, &pData->lpDS, NULL); if(SUCCEEDED(hr)) hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY); if(FAILED(hr)) { if(pData->lpDS) IDirectSound_Release(pData->lpDS); free(pData); AL_PRINT("Device init failed: 0x%08lx\n", hr); return ALC_FALSE; } device->szDeviceName = strdup(deviceName); device->ExtraData = pData; return ALC_TRUE; }
ALCAPI void ALCAPIENTRY alcCaptureStop(ALCdevice *pDevice) { if(IsDevice(pDevice) && pDevice->IsCaptureDevice) ALCdevice_StopCapture(pDevice); else alcSetError(ALC_INVALID_DEVICE); }
static void pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) { pa_data *data = device->ExtraData; if(samples <= (ALCuint)RingBufferSize(data->ring)) ReadRingBuffer(data->ring, buffer, samples); else alcSetError(device, ALC_INVALID_VALUE); }
static void oss_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) { oss_data *data = (oss_data*)pDevice->ExtraData; if(lSamples <= (ALCuint)RingBufferSize(data->ring)) ReadRingBuffer(data->ring, pBuffer, lSamples); else alcSetError(pDevice, ALC_INVALID_VALUE); }
static void pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) //{{{ { pulse_data *data = device->ExtraData; ALCuint available = RingBufferSize(data->ring); const void *buf; size_t length; available *= data->frame_size; samples *= data->frame_size; ppa_threaded_mainloop_lock(data->loop); if(available+ppa_stream_readable_size(data->stream) < samples) { ppa_threaded_mainloop_unlock(data->loop); alcSetError(device, ALC_INVALID_VALUE); return; } available = min(available, samples); if(available > 0) { ReadRingBuffer(data->ring, buffer, available/data->frame_size); buffer = (ALubyte*)buffer + available; samples -= available; } /* Capture is done in fragment-sized chunks, so we loop until we get all * that's requested */ while(samples > 0) { if(ppa_stream_peek(data->stream, &buf, &length) < 0) { AL_PRINT("pa_stream_peek() failed: %s\n", ppa_strerror(ppa_context_errno(data->context))); break; } available = min(length, samples); memcpy(buffer, buf, available); buffer = (ALubyte*)buffer + available; buf = (const ALubyte*)buf + available; samples -= available; length -= available; /* Any unread data in the fragment will be lost, so save it */ length /= data->frame_size; if(length > 0) { if(length > data->samples) length = data->samples; WriteRingBuffer(data->ring, buf, length); } ppa_stream_drop(data->stream); } ppa_threaded_mainloop_unlock(data->loop); } //}}}
static void alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples) { alsa_data *data = (alsa_data*)Device->ExtraData; if(Samples <= alsa_available_samples(Device)) ReadRingBuffer(data->ring, Buffer, Samples); else alcSetError(Device, ALC_INVALID_VALUE); }
static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) { WinMMData *pData = (WinMMData*)pDevice->ExtraData; if(WinMMAvailableSamples(pDevice) >= lSamples) ReadRingBuffer(pData->pRing, pBuffer, lSamples); else alcSetError(pDevice, ALC_INVALID_VALUE); }
static void pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) //{{{ { pulse_data *data = device->ExtraData; ALCuint available = RingBufferSize(data->ring); if(available < samples) alcSetError(ALC_INVALID_VALUE); else ReadRingBuffer(data->ring, buffer, samples); } //}}}
static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) { DSoundData *pData = NULL; LPGUID guid = NULL; HRESULT hr; if(!deviceName) deviceName = dsDevice; else if(strcmp(deviceName, dsDevice) != 0) { ALuint i; for(i = 0;i < NumDevices;i++) { if(strcmp(deviceName, DeviceList[i].name) == 0) { guid = &DeviceList[i].guid; break; } } if(i == NumDevices) return ALC_FALSE; } DSoundLoad(); if(ds_handle == NULL) return ALC_FALSE; //Initialise requested device pData = calloc(1, sizeof(DSoundData)); if(!pData) { alcSetError(ALC_OUT_OF_MEMORY); DSoundUnload(); return ALC_FALSE; } //DirectSound Init code hr = pDirectSoundCreate(guid, &pData->lpDS, NULL); if(SUCCEEDED(hr)) hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY); if(FAILED(hr)) { if(pData->lpDS) IDirectSound_Release(pData->lpDS); free(pData); DSoundUnload(); return ALC_FALSE; } device->szDeviceName = strdup(deviceName); device->ExtraData = pData; return ALC_TRUE; }
static void pulse_capture_samples( ALCdevice* device, ALCvoid* buffer, ALCuint samples ) //{{{ { pulse_data* data = device->ExtraData; if ( pulse_available_samples( device ) >= samples ) { ReadRingBuffer( data->ring, buffer, samples ); } else { alcSetError( device, ALC_INVALID_VALUE ); } } //}}}
/* alcGetContextsDevice Returns the Device that a particular Context is attached to */ ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *pContext) { ALCdevice *pDevice = NULL; SuspendContext(NULL); if (IsContext(pContext)) pDevice = pContext->Device; else alcSetError(ALC_INVALID_CONTEXT); ProcessContext(NULL); return pDevice; }
/* alcGetEnumValue Get the value for a particular ALC Enumerated Value */ ALCAPI ALCenum ALCAPIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) { ALsizei i = 0; ALCenum val; (void)device; while ((enumeration[i].enumName)&&(strcmp(enumeration[i].enumName,enumName))) i++; val = enumeration[i].value; if(!enumeration[i].enumName) alcSetError(ALC_INVALID_VALUE); return val; }
/* alcGetProcAddress Retrieves the function address for a particular extension function */ ALCAPI ALCvoid * ALCAPIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) { ALCvoid *pFunction = NULL; ALsizei i = 0; (void)device; if (funcName) { while(alcFunctions[i].funcName && strcmp(alcFunctions[i].funcName,funcName) != 0) i++; pFunction = alcFunctions[i].address; } else alcSetError(ALC_INVALID_VALUE); return pFunction; }
static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) { WinMMData *pData = (WinMMData*)pDevice->ExtraData; ALuint ulSamples = (unsigned long)lSamples; ALuint ulBytes, ulBytesToCopy; ALuint ulCapturedSamples; ALuint ulReadOffset; ALuint frameSize = aluFrameSizeFromFormat(pDevice->Format); // Check that we have the requested numbers of Samples ulCapturedSamples = (pData->ulWriteCapturedDataPos - pData->ulReadCapturedDataPos) / frameSize; if(ulSamples > ulCapturedSamples) { alcSetError(pDevice, ALC_INVALID_VALUE); return; } ulBytes = ulSamples * frameSize; // Get Read Offset ulReadOffset = (pData->ulReadCapturedDataPos % pData->ulCapturedDataSize); // Check for wrap-around condition if ((ulReadOffset + ulBytes) > pData->ulCapturedDataSize) { // Copy data from last Read position to end of data ulBytesToCopy = pData->ulCapturedDataSize - ulReadOffset; memcpy(pBuffer, pData->pCapturedSampleData + ulReadOffset, ulBytesToCopy); // Copy rest of the data from the start of the captured data memcpy(((char *)pBuffer) + ulBytesToCopy, pData->pCapturedSampleData, ulBytes - ulBytesToCopy); } else { // Copy data from the read position in the captured data memcpy(pBuffer, pData->pCapturedSampleData + ulReadOffset, ulBytes); } // Update Read Position pData->ulReadCapturedDataPos += ulBytes; }
/* alcMakeCurrent Makes the given Context the active Context for the current thread */ ALCboolean ALCAPIENTRY alcMakeCurrent(ALCcontext *context) { ALboolean bReturn = AL_TRUE; SuspendContext(NULL); // context must be a valid Context or NULL if(context == NULL || IsContext(context)) tls_set(LocalContext, context); else { alcSetError(ALC_INVALID_CONTEXT); bReturn = AL_FALSE; } ProcessContext(NULL); return bReturn; }
/* alcGetString Returns information about the Device, and error strings */ ALCAPI const ALCchar* ALCAPIENTRY alcGetString(ALCdevice *pDevice,ALCenum param) { const ALCchar *value = NULL; switch (param) { case ALC_NO_ERROR: value = alcNoError; break; case ALC_INVALID_ENUM: value = alcErrInvalidEnum; break; case ALC_INVALID_VALUE: value = alcErrInvalidValue; break; case ALC_INVALID_DEVICE: value = alcErrInvalidDevice; break; case ALC_INVALID_CONTEXT: value = alcErrInvalidContext; break; case ALC_OUT_OF_MEMORY: value = alcErrOutOfMemory; break; case ALC_DEVICE_SPECIFIER: if(IsDevice(pDevice)) value = pDevice->szDeviceName; else { ProbeDeviceList(); value = alcDeviceList; } break; case ALC_ALL_DEVICES_SPECIFIER: ProbeAllDeviceList(); value = alcAllDeviceList; break; case ALC_CAPTURE_DEVICE_SPECIFIER: if(IsDevice(pDevice)) value = pDevice->szDeviceName; else { ProbeCaptureDeviceList(); value = alcCaptureDeviceList; } break; /* Default devices are always first in the list */ case ALC_DEFAULT_DEVICE_SPECIFIER: free(alcDefaultDeviceSpecifier); alcDefaultDeviceSpecifier = strdup(alcDeviceList ? alcDeviceList : ""); if(!alcDefaultDeviceSpecifier) alcSetError(ALC_OUT_OF_MEMORY); value = alcDefaultDeviceSpecifier; break; case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: free(alcDefaultAllDeviceSpecifier); alcDefaultAllDeviceSpecifier = strdup(alcAllDeviceList ? alcAllDeviceList : ""); if(!alcDefaultAllDeviceSpecifier) alcSetError(ALC_OUT_OF_MEMORY); value = alcDefaultAllDeviceSpecifier; break; case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: free(alcCaptureDefaultDeviceSpecifier); alcCaptureDefaultDeviceSpecifier = strdup(alcCaptureDeviceList ? alcCaptureDeviceList : ""); if(!alcCaptureDefaultDeviceSpecifier) alcSetError(ALC_OUT_OF_MEMORY); value = alcCaptureDefaultDeviceSpecifier; break; case ALC_EXTENSIONS: value = alcExtensionList; break; default: alcSetError(ALC_INVALID_ENUM); break; } return value; }
static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName) { WAVEFORMATEX wfexCaptureFormat; DWORD ulCapturedDataSize; WinMMData *pData = NULL; UINT lDeviceID = 0; ALbyte *BufferData; ALint lBufferSize; MMRESULT res; ALuint i; if(!CaptureDeviceList) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid if(deviceName) { for(i = 0;i < NumCaptureDevices;i++) { if(CaptureDeviceList[i] && strcmp(deviceName, CaptureDeviceList[i]) == 0) { lDeviceID = i; break; } } } else { for(i = 0;i < NumCaptureDevices;i++) { if(CaptureDeviceList[i]) { lDeviceID = i; break; } } } if(i == NumCaptureDevices) return ALC_FALSE; pData = calloc(1, sizeof(*pData)); if(!pData) { alcSetError(pDevice, ALC_OUT_OF_MEMORY); return ALC_FALSE; } pDevice->ExtraData = pData; if((pDevice->FmtChans != DevFmtMono && pDevice->FmtChans != DevFmtStereo) || (pDevice->FmtType != DevFmtUByte && pDevice->FmtType != DevFmtShort)) { alcSetError(pDevice, ALC_INVALID_ENUM); goto failure; } memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX)); wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM; wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans); wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8; wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample * wfexCaptureFormat.nChannels / 8; wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency; wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec * wfexCaptureFormat.nBlockAlign; wfexCaptureFormat.cbSize = 0; if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { AL_PRINT("waveInOpen failed: %u\n", res); goto failure; } pData->hWaveHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInAllHeadersReturned"); pData->hWaveThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInThreadDestroyed"); if(pData->hWaveHdrEvent == NULL || pData->hWaveThreadEvent == NULL) { AL_PRINT("CreateEvent failed: %lu\n", GetLastError()); goto failure; } pData->Frequency = pDevice->Frequency; // Allocate circular memory buffer for the captured audio ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates; // Make sure circular buffer is at least 100ms in size if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10)) ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10; pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize); if(!pData->pRing) goto failure; pData->lWaveBuffersCommitted = 0; // Create 4 Buffers of 50ms each lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20; lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign); BufferData = calloc(4, lBufferSize); if(!BufferData) goto failure; for(i = 0;i < 4;i++) { memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR)); pData->WaveBuffer[i].dwBufferLength = lBufferSize; pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData : (pData->WaveBuffer[i-1].lpData + pData->WaveBuffer[i-1].dwBufferLength)); pData->WaveBuffer[i].dwFlags = 0; pData->WaveBuffer[i].dwLoops = 0; waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); InterlockedIncrement(&pData->lWaveBuffersCommitted); } pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID); if (pData->hWaveThread == NULL) goto failure; pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]); return ALC_TRUE; failure: if(pData->hWaveThread) CloseHandle(pData->hWaveThread); for(i = 0;i < 4;i++) { if(pData->WaveBuffer[i].lpData) { waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); if(i == 0) free(pData->WaveBuffer[i].lpData); } } if(pData->pRing) DestroyRingBuffer(pData->pRing); if(pData->hWaveThreadEvent) CloseHandle(pData->hWaveThreadEvent); if(pData->hWaveHdrEvent) CloseHandle(pData->hWaveHdrEvent); if(pData->hWaveHandle.In) waveInClose(pData->hWaveHandle.In); free(pData); pDevice->ExtraData = NULL; return ALC_FALSE; }
static ALCboolean WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName) { WAVEFORMATEX wfexFormat; WinMMData *pData = NULL; UINT lDeviceID = 0; MMRESULT res; ALuint i = 0; // Find the Device ID matching the deviceName if valid if(!deviceName || strcmp(deviceName, woDefault) == 0) lDeviceID = WAVE_MAPPER; else { if(!PlaybackDeviceList) ProbePlaybackDevices(); for(i = 0;i < NumPlaybackDevices;i++) { if(PlaybackDeviceList[i] && strcmp(deviceName, PlaybackDeviceList[i]) == 0) { lDeviceID = i; break; } } if(i == NumPlaybackDevices) return ALC_FALSE; } pData = calloc(1, sizeof(*pData)); if(!pData) { alcSetError(pDevice, ALC_OUT_OF_MEMORY); return ALC_FALSE; } pDevice->ExtraData = pData; if(pDevice->FmtChans != DevFmtMono) pDevice->FmtChans = DevFmtStereo; switch(pDevice->FmtType) { case DevFmtByte: pDevice->FmtType = DevFmtUByte; break; case DevFmtUShort: case DevFmtFloat: pDevice->FmtType = DevFmtShort; break; case DevFmtUByte: case DevFmtShort: break; } memset(&wfexFormat, 0, sizeof(WAVEFORMATEX)); wfexFormat.wFormatTag = WAVE_FORMAT_PCM; wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans); wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8; wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample * wfexFormat.nChannels / 8; wfexFormat.nSamplesPerSec = pDevice->Frequency; wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec * wfexFormat.nBlockAlign; wfexFormat.cbSize = 0; if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { AL_PRINT("waveInOpen failed: %u\n", res); goto failure; } pData->hWaveHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveOutAllHeadersReturned"); pData->hWaveThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveOutThreadDestroyed"); if(pData->hWaveHdrEvent == NULL || pData->hWaveThreadEvent == NULL) { AL_PRINT("CreateEvent failed: %lu\n", GetLastError()); goto failure; } pData->Frequency = pDevice->Frequency; pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault : PlaybackDeviceList[lDeviceID]); return ALC_TRUE; failure: if(pData->hWaveThreadEvent) CloseHandle(pData->hWaveThreadEvent); if(pData->hWaveHdrEvent) CloseHandle(pData->hWaveHdrEvent); if(pData->hWaveHandle.Out) waveOutClose(pData->hWaveHandle.Out); free(pData); pDevice->ExtraData = NULL; return ALC_FALSE; }
/* alcCreateContext Create and attach a Context to a particular Device. */ ALCAPI ALCcontext* ALCAPIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) { ALuint attrIdx, reqStereoSources; ALCcontext *ALContext; void *temp; ALuint i; SuspendContext(NULL); if(!IsDevice(device) || device->IsCaptureDevice || !device->Connected) { alcSetError(ALC_INVALID_DEVICE); ProcessContext(NULL); return NULL; } // Reset Context Last Error code g_eLastContextError = ALC_NO_ERROR; // If a context is already running on the device, stop playback so the // device attributes can be updated if(device->NumContexts > 0) { ProcessContext(NULL); ALCdevice_StopPlayback(device); SuspendContext(NULL); } // Check for attributes if(attrList) { ALCint level = device->Bs2bLevel; ALCuint freq = device->Frequency; ALCint numMono = device->lNumMonoSources; ALCint numStereo = device->lNumStereoSources; ALCuint numSends = device->NumAuxSends; attrIdx = 0; while(attrList[attrIdx]) { if(attrList[attrIdx] == ALC_FREQUENCY) { freq = attrList[attrIdx + 1]; if(freq == 0) freq = device->Frequency; } if(attrList[attrIdx] == ALC_STEREO_SOURCES) { reqStereoSources = attrList[attrIdx + 1]; if(reqStereoSources > device->MaxNoOfSources) reqStereoSources = device->MaxNoOfSources; numStereo = reqStereoSources; numMono = device->MaxNoOfSources - numStereo; } if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS) { numSends = attrList[attrIdx + 1]; if(numSends > MAX_SENDS) numSends = MAX_SENDS; } attrIdx += 2; } device->Bs2bLevel = GetConfigValueInt(NULL, "cf_level", level); device->Frequency = GetConfigValueInt(NULL, "frequency", freq); device->lNumMonoSources = numMono; device->lNumStereoSources = numStereo; device->NumAuxSends = GetConfigValueInt(NULL, "sends", numSends); } if(ALCdevice_ResetPlayback(device) == ALC_FALSE) { alcSetError(ALC_INVALID_DEVICE); aluHandleDisconnect(device); ProcessContext(NULL); return NULL; } for(i = 0;i < device->NumContexts;i++) { ALCcontext *context = device->Contexts[i]; ALeffectslot *slot; ALsource *source; SuspendContext(context); for(slot = context->AuxiliaryEffectSlot;slot != NULL;slot = slot->next) { if(!slot->EffectState) continue; if(ALEffect_DeviceUpdate(slot->EffectState, device) == AL_FALSE) { alcSetError(ALC_INVALID_DEVICE); aluHandleDisconnect(device); ProcessContext(context); ProcessContext(NULL); ALCdevice_StopPlayback(device); return NULL; } ALEffect_Update(slot->EffectState, context, &slot->effect); } for(source = context->Source;source != NULL;source = source->next) { ALuint s = device->NumAuxSends; while(s < MAX_SENDS) { if(source->Send[s].Slot) source->Send[s].Slot->refcount--; source->Send[s].Slot = NULL; source->Send[s].WetFilter.type = 0; source->Send[s].WetFilter.filter = 0; s++; } } ProcessContext(context); } if(device->Bs2bLevel > 0 && device->Bs2bLevel <= 6) { if(!device->Bs2b) { device->Bs2b = calloc(1, sizeof(*device->Bs2b)); bs2b_clear(device->Bs2b); } bs2b_set_srate(device->Bs2b, device->Frequency); bs2b_set_level(device->Bs2b, device->Bs2bLevel); } else { free(device->Bs2b); device->Bs2b = NULL; } temp = realloc(device->Contexts, (device->NumContexts+1) * sizeof(*device->Contexts)); if(!temp) { alcSetError(ALC_OUT_OF_MEMORY); ProcessContext(NULL); return NULL; } device->Contexts = temp; ALContext = calloc(1, sizeof(ALCcontext)); if(!ALContext) { alcSetError(ALC_OUT_OF_MEMORY); ProcessContext(NULL); return NULL; } device->Contexts[device->NumContexts++] = ALContext; ALContext->Device = device; InitContext(ALContext); ALContext->next = g_pContextList; g_pContextList = ALContext; g_ulContextCount++; ProcessContext(NULL); return ALContext; }
static ALCboolean pa_open_capture(ALCdevice *device, const ALCchar *deviceName) { PaStreamParameters inParams; ALuint frame_size; pa_data *data; PaError err; if(!deviceName) deviceName = pa_device; else if(strcmp(deviceName, pa_device) != 0) return ALC_FALSE; if(!pa_load()) return ALC_FALSE; data = (pa_data*)calloc(1, sizeof(pa_data)); if(data == NULL) { alcSetError(device, ALC_OUT_OF_MEMORY); return ALC_FALSE; } frame_size = aluFrameSizeFromFormat(device->Format); data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates); if(data->ring == NULL) { alcSetError(device, ALC_OUT_OF_MEMORY); goto error; } inParams.device = GetConfigValueInt("port", "capture", -1); if(inParams.device < 0) inParams.device = pPa_GetDefaultOutputDevice(); inParams.suggestedLatency = 0.0f; inParams.hostApiSpecificStreamInfo = NULL; switch(aluBytesFromFormat(device->Format)) { case 1: inParams.sampleFormat = paUInt8; break; case 2: inParams.sampleFormat = paInt16; break; case 4: inParams.sampleFormat = paFloat32; break; default: AL_PRINT("Unknown format: 0x%x\n", device->Format); goto error; } inParams.channelCount = aluChannelsFromFormat(device->Format); err = pPa_OpenStream(&data->stream, &inParams, NULL, device->Frequency, paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device); if(err != paNoError) { AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err)); goto error; } device->szDeviceName = strdup(deviceName); device->ExtraData = data; return ALC_TRUE; error: DestroyRingBuffer(data->ring); free(data); return ALC_FALSE; }
static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName) { WAVEFORMATEX wfexCaptureFormat; WinMMData *pData = NULL; ALint lDeviceID = 0; ALint lBufferSize; ALuint i; if(!CaptureDeviceList) ProbeDevices(); // Find the Device ID matching the deviceName if valid if(deviceName) { for(i = 0;i < NumCaptureDevices;i++) { if(CaptureDeviceList[i] && strcmp(deviceName, CaptureDeviceList[i]) == 0) { lDeviceID = i; break; } } } else { for(i = 0;i < NumCaptureDevices;i++) { if(CaptureDeviceList[i]) { lDeviceID = i; break; } } } if(i == NumCaptureDevices) return ALC_FALSE; pData = calloc(1, sizeof(*pData)); if(!pData) { alcSetError(pDevice, ALC_OUT_OF_MEMORY); return ALC_FALSE; } memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX)); wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM; wfexCaptureFormat.nChannels = aluChannelsFromFormat(pDevice->Format); wfexCaptureFormat.wBitsPerSample = aluBytesFromFormat(pDevice->Format) * 8; wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample * wfexCaptureFormat.nChannels / 8; wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency; wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec * wfexCaptureFormat.nBlockAlign; wfexCaptureFormat.cbSize = 0; if (waveInOpen(&pData->hWaveInHandle, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) goto failure; pData->hWaveInHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInAllHeadersReturned"); if (pData->hWaveInHdrEvent == NULL) goto failure; pData->hWaveInThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInThreadDestroyed"); if (pData->hWaveInThreadEvent == NULL) goto failure; // Allocate circular memory buffer for the captured audio pData->ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates * wfexCaptureFormat.nBlockAlign; // Make sure circular buffer is at least 100ms in size (and an exact multiple of // the block alignment if (pData->ulCapturedDataSize < (wfexCaptureFormat.nAvgBytesPerSec / 10)) { pData->ulCapturedDataSize = wfexCaptureFormat.nAvgBytesPerSec / 10; pData->ulCapturedDataSize -= (pData->ulCapturedDataSize % wfexCaptureFormat.nBlockAlign); } pData->pCapturedSampleData = (ALCchar*)malloc(pData->ulCapturedDataSize); pData->lWaveInBuffersCommitted=0; // Create 4 Buffers of 50ms each lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20; lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign); for (i=0;i<4;i++) { memset(&pData->WaveInBuffer[i], 0, sizeof(WAVEHDR)); pData->WaveInBuffer[i].dwBufferLength = lBufferSize; pData->WaveInBuffer[i].lpData = calloc(1,pData->WaveInBuffer[i].dwBufferLength); pData->WaveInBuffer[i].dwFlags = 0; pData->WaveInBuffer[i].dwLoops = 0; waveInPrepareHeader(pData->hWaveInHandle, &pData->WaveInBuffer[i], sizeof(WAVEHDR)); waveInAddBuffer(pData->hWaveInHandle, &pData->WaveInBuffer[i], sizeof(WAVEHDR)); pData->lWaveInBuffersCommitted++; } pData->ulReadCapturedDataPos = 0; pData->ulWriteCapturedDataPos = 0; pDevice->ExtraData = pData; pData->hWaveInThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveInThreadID); if (pData->hWaveInThread == NULL) goto failure; pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]); return ALC_TRUE; failure: for (i=0;i<4;i++) { if(pData->WaveInBuffer[i].lpData) { waveInUnprepareHeader(pData->hWaveInHandle, &pData->WaveInBuffer[i], sizeof(WAVEHDR)); free(pData->WaveInBuffer[i].lpData); } } free(pData->pCapturedSampleData); if(pData->hWaveInHandle) waveInClose(pData->hWaveInHandle); if(pData->hWaveInThread) CloseHandle(pData->hWaveInThread); if (pData->hWaveInHdrEvent) CloseHandle(pData->hWaveInHdrEvent); if (pData->hWaveInThreadEvent) CloseHandle(pData->hWaveInThreadEvent); free(pData); pDevice->ExtraData = NULL; return ALC_FALSE; }
/* alcDestroyContext Remove a Context */ ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context) { ALCcontext **list; ALuint i; if (IsContext(context)) { ALCdevice *Device = context->Device; if(Device->NumContexts == 1) ALCdevice_StopPlayback(Device); SuspendContext(NULL); for(i = 0;i < Device->NumContexts-1;i++) { if(Device->Contexts[i] == context) { memmove(&Device->Contexts[i], &Device->Contexts[i+1], (Device->NumContexts-i-1) * sizeof(*Device->Contexts)); break; } } Device->NumContexts--; // Lock context SuspendContext(context); if(context->SourceCount > 0) { #ifdef _DEBUG AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", context->SourceCount); #endif ReleaseALSources(context); } if(context->AuxiliaryEffectSlotCount > 0) { #ifdef _DEBUG AL_PRINT("alcDestroyContext(): deleting %d AuxiliaryEffectSlot(s)\n", context->AuxiliaryEffectSlotCount); #endif ReleaseALAuxiliaryEffectSlots(context); } list = &g_pContextList; while(*list != context) list = &(*list)->next; *list = (*list)->next; g_ulContextCount--; // Unlock context ProcessContext(context); ProcessContext(NULL); ExitContext(context); // Free memory (MUST do this after ProcessContext) memset(context, 0, sizeof(ALCcontext)); free(context); } else alcSetError(ALC_INVALID_CONTEXT); }
/* alcGetIntegerv Returns information about the Device and the version of Open AL */ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsizei size,ALCint *data) { if(IsDevice(device) && device->IsCaptureDevice) { SuspendContext(NULL); // Capture device switch (param) { case ALC_CAPTURE_SAMPLES: if ((size) && (data)) *data = ALCdevice_AvailableSamples(device); else alcSetError(ALC_INVALID_VALUE); break; case ALC_CONNECTED: if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = device->Connected; break; default: alcSetError(ALC_INVALID_ENUM); break; } ProcessContext(NULL); } else { if(data) { // Playback Device switch (param) { case ALC_MAJOR_VERSION: if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = alcMajorVersion; break; case ALC_MINOR_VERSION: if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = alcMinorVersion; break; case ALC_EFX_MAJOR_VERSION: if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = alcEFXMajorVersion; break; case ALC_EFX_MINOR_VERSION: if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = alcEFXMinorVersion; break; case ALC_MAX_AUXILIARY_SENDS: if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = (device?device->NumAuxSends:MAX_SENDS); break; case ALC_ATTRIBUTES_SIZE: if(!IsDevice(device)) alcSetError(ALC_INVALID_DEVICE); else if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = 13; break; case ALC_ALL_ATTRIBUTES: if(!IsDevice(device)) alcSetError(ALC_INVALID_DEVICE); else if (size < 13) alcSetError(ALC_INVALID_VALUE); else { int i = 0; SuspendContext(NULL); data[i++] = ALC_FREQUENCY; data[i++] = device->Frequency; data[i++] = ALC_REFRESH; data[i++] = device->Frequency / device->UpdateSize; data[i++] = ALC_SYNC; data[i++] = ALC_FALSE; data[i++] = ALC_MONO_SOURCES; data[i++] = device->lNumMonoSources; data[i++] = ALC_STEREO_SOURCES; data[i++] = device->lNumStereoSources; data[i++] = ALC_MAX_AUXILIARY_SENDS; data[i++] = device->NumAuxSends; data[i++] = 0; ProcessContext(NULL); } break; case ALC_FREQUENCY: if(!IsDevice(device)) alcSetError(ALC_INVALID_DEVICE); else if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = device->Frequency; break; case ALC_REFRESH: if(!IsDevice(device)) alcSetError(ALC_INVALID_DEVICE); else if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = device->Frequency / device->UpdateSize; break; case ALC_SYNC: if(!IsDevice(device)) alcSetError(ALC_INVALID_DEVICE); else if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = ALC_FALSE; break; case ALC_MONO_SOURCES: if(!IsDevice(device)) alcSetError(ALC_INVALID_DEVICE); else if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = device->lNumMonoSources; break; case ALC_STEREO_SOURCES: if(!IsDevice(device)) alcSetError(ALC_INVALID_DEVICE); else if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = device->lNumStereoSources; break; case ALC_CONNECTED: if(!IsDevice(device)) alcSetError(ALC_INVALID_DEVICE); else if(size <= 0) alcSetError(ALC_INVALID_VALUE); else *data = device->Connected; break; default: alcSetError(ALC_INVALID_ENUM); break; } } else if(size) alcSetError(ALC_INVALID_VALUE); } return; }
/* alcOpenDevice Open the Device specified. */ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName) { ALboolean bDeviceFound = AL_FALSE; ALCdevice *device; ALint i; if(deviceName && !deviceName[0]) deviceName = NULL; device = malloc(sizeof(ALCdevice)); if (device) { const char *fmt; //Initialise device structure memset(device, 0, sizeof(ALCdevice)); //Validate device device->Connected = ALC_TRUE; device->IsCaptureDevice = AL_FALSE; device->Bs2b = NULL; device->szDeviceName = NULL; device->Contexts = NULL; device->NumContexts = 0; //Set output format device->Frequency = GetConfigValueInt(NULL, "frequency", SWMIXER_OUTPUT_RATE); if(device->Frequency == 0) device->Frequency = SWMIXER_OUTPUT_RATE; fmt = GetConfigValue(NULL, "format", "AL_FORMAT_STEREO16"); device->Format = GetFormatFromString(fmt); device->NumUpdates = GetConfigValueInt(NULL, "periods", 4); if(device->NumUpdates < 2) device->NumUpdates = 4; i = GetConfigValueInt(NULL, "refresh", 4096); if(i <= 0) i = 4096; device->UpdateSize = GetConfigValueInt(NULL, "period_size", i/device->NumUpdates); if(device->UpdateSize <= 0) device->UpdateSize = i/device->NumUpdates; device->MaxNoOfSources = GetConfigValueInt(NULL, "sources", 256); if((ALint)device->MaxNoOfSources <= 0) device->MaxNoOfSources = 256; device->AuxiliaryEffectSlotMax = GetConfigValueInt(NULL, "slots", 4); if((ALint)device->AuxiliaryEffectSlotMax <= 0) device->AuxiliaryEffectSlotMax = 4; device->lNumStereoSources = 1; device->lNumMonoSources = device->MaxNoOfSources - device->lNumStereoSources; device->NumAuxSends = GetConfigValueInt(NULL, "sends", MAX_SENDS); if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS; device->Bs2bLevel = GetConfigValueInt(NULL, "cf_level", 0); // Find a playback device to open SuspendContext(NULL); for(i = 0;BackendList[i].Init;i++) { device->Funcs = &BackendList[i].Funcs; if(ALCdevice_OpenPlayback(device, deviceName)) { device->next = g_pDeviceList; g_pDeviceList = device; g_ulDeviceCount++; bDeviceFound = AL_TRUE; break; } } ProcessContext(NULL); if (!bDeviceFound) { // No suitable output device found alcSetError(ALC_INVALID_VALUE); free(device); device = NULL; } } else alcSetError(ALC_OUT_OF_MEMORY); return device; }
/* alcCloseDevice Close the specified Device */ ALCAPI ALCboolean ALCAPIENTRY alcCloseDevice(ALCdevice *pDevice) { ALCboolean bReturn = ALC_FALSE; ALCdevice **list; if(IsDevice(pDevice) && !pDevice->IsCaptureDevice) { SuspendContext(NULL); list = &g_pDeviceList; while(*list != pDevice) list = &(*list)->next; *list = (*list)->next; g_ulDeviceCount--; ProcessContext(NULL); if(pDevice->NumContexts > 0) { #ifdef _DEBUG AL_PRINT("alcCloseDevice(): destroying %u Context(s)\n", pDevice->NumContexts); #endif while(pDevice->NumContexts > 0) alcDestroyContext(pDevice->Contexts[0]); } ALCdevice_ClosePlayback(pDevice); if(pDevice->BufferCount > 0) { #ifdef _DEBUG AL_PRINT("alcCloseDevice(): deleting %d Buffer(s)\n", pDevice->BufferCount); #endif ReleaseALBuffers(pDevice); } if(pDevice->EffectCount > 0) { #ifdef _DEBUG AL_PRINT("alcCloseDevice(): deleting %d Effect(s)\n", pDevice->EffectCount); #endif ReleaseALEffects(pDevice); } if(pDevice->FilterCount > 0) { #ifdef _DEBUG AL_PRINT("alcCloseDevice(): deleting %d Filter(s)\n", pDevice->FilterCount); #endif ReleaseALFilters(pDevice); } if(pDevice->DatabufferCount > 0) { #ifdef _DEBUG AL_PRINT("alcCloseDevice(): deleting %d Databuffer(s)\n", pDevice->DatabufferCount); #endif ReleaseALDatabuffers(pDevice); } free(pDevice->Bs2b); pDevice->Bs2b = NULL; free(pDevice->szDeviceName); pDevice->szDeviceName = NULL; free(pDevice->Contexts); pDevice->Contexts = NULL; //Release device structure memset(pDevice, 0, sizeof(ALCdevice)); free(pDevice); bReturn = ALC_TRUE; } else alcSetError(ALC_INVALID_DEVICE); return bReturn; }