FORCE_ALIGN static int PlaybackThreadProc(void *arg) { ALCdevice *Device = (ALCdevice*)arg; WinMMData *data = Device->ExtraData; WAVEHDR *WaveHdr; MSG msg; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); while(GetMessage(&msg, NULL, 0, 0)) { if(msg.message != WOM_DONE) continue; if(data->killNow) { if(ReadRef(&data->WaveBuffersCommitted) == 0) break; continue; } WaveHdr = ((WAVEHDR*)msg.lParam); aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength / data->Format.nBlockAlign); // Send buffer back to play more data waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR)); IncrementRef(&data->WaveBuffersCommitted); } return 0; }
static int CaptureThreadProc(void *arg) { ALCdevice *Device = (ALCdevice*)arg; WinMMData *data = Device->ExtraData; WAVEHDR *WaveHdr; MSG msg; althrd_setname(althrd_current(), "alsoft-record"); while(GetMessage(&msg, NULL, 0, 0)) { if(msg.message != WIM_DATA) continue; /* Don't wait for other buffers to finish before quitting. We're * closing so we don't need them. */ if(data->killNow) break; WaveHdr = ((WAVEHDR*)msg.lParam); WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData, WaveHdr->dwBytesRecorded/data->Format.nBlockAlign); // Send buffer back to capture more data waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR)); IncrementRef(&data->WaveBuffersCommitted); } return 0; }
static int ALCwinmmCapture_captureProc(void *arg) { ALCwinmmCapture *self = arg; WAVEHDR *WaveHdr; MSG msg; althrd_setname(althrd_current(), RECORD_THREAD_NAME); while(GetMessage(&msg, NULL, 0, 0)) { if(msg.message != WIM_DATA) continue; /* Don't wait for other buffers to finish before quitting. We're * closing so we don't need them. */ if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) break; WaveHdr = ((WAVEHDR*)msg.lParam); ll_ringbuffer_write(self->Ring, WaveHdr->lpData, WaveHdr->dwBytesRecorded / self->Format.nBlockAlign ); // Send buffer back to capture more data waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR)); IncrementRef(&self->WaveBuffersCommitted); } return 0; }
FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) { ALCwinmmPlayback *self = arg; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; WAVEHDR *WaveHdr; MSG msg; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); while(GetMessage(&msg, NULL, 0, 0)) { if(msg.message != WOM_DONE) continue; if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) { if(ReadRef(&self->WaveBuffersCommitted) == 0) break; continue; } WaveHdr = ((WAVEHDR*)msg.lParam); ALCwinmmPlayback_lock(self); aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength / self->Format.nBlockAlign); ALCwinmmPlayback_unlock(self); // Send buffer back to play more data waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR)); IncrementRef(&self->WaveBuffersCommitted); } return 0; }
static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALbyte *BufferData; ALint BufferSize; ALuint i; ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success) return ALC_FALSE; InitRef(&self->WaveBuffersCommitted, 0); // Create 4 Buffers BufferSize = device->UpdateSize*device->NumUpdates / 4; BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); BufferData = calloc(4, BufferSize); for(i = 0;i < 4;i++) { memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); self->WaveBuffer[i].dwBufferLength = BufferSize; self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : (self->WaveBuffer[i-1].lpData + self->WaveBuffer[i-1].dwBufferLength)); waveOutPrepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); waveOutWrite(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); IncrementRef(&self->WaveBuffersCommitted); } return ALC_TRUE; }
ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids) { ALCdevice *device = context->Device; ALsoundfont **sfonts; ALsizei i; if(self->State != AL_INITIAL && self->State != AL_STOPPED) return AL_INVALID_OPERATION; sfonts = calloc(1, count * sizeof(sfonts[0])); if(!sfonts) return AL_OUT_OF_MEMORY; for(i = 0;i < count;i++) { if(ids[i] == 0) sfonts[i] = ALsoundfont_getDefSoundfont(context); else if(!(sfonts[i]=LookupSfont(device, ids[i]))) { free(sfonts); return AL_INVALID_VALUE; } } for(i = 0;i < count;i++) IncrementRef(&sfonts[i]->ref); sfonts = ExchangePtr((XchgPtr*)&self->Soundfonts, sfonts); count = ExchangeInt(&self->NumSoundfonts, count); for(i = 0;i < count;i++) DecrementRef(&sfonts[i]->ref); free(sfonts); return AL_NO_ERROR; }
static ALCboolean WinMMStartPlayback(ALCdevice *device) { WinMMData *data = (WinMMData*)device->ExtraData; ALbyte *BufferData; ALint BufferSize; ALuint i; data->killNow = AL_FALSE; if(althrd_create(&data->thread, PlaybackThreadProc, device) != althrd_success) return ALC_FALSE; InitRef(&data->WaveBuffersCommitted, 0); // Create 4 Buffers BufferSize = device->UpdateSize*device->NumUpdates / 4; BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType); BufferData = calloc(4, BufferSize); for(i = 0; i < 4; i++) { memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR)); data->WaveBuffer[i].dwBufferLength = BufferSize; data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : (data->WaveBuffer[i-1].lpData + data->WaveBuffer[i-1].dwBufferLength)); waveOutPrepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); waveOutWrite(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); IncrementRef(&data->WaveBuffersCommitted); } return ALC_TRUE; }
void ReadLock(RWLock *lock) { LOCK(lock->read_entry_lock); LOCK(lock->read_lock); if(IncrementRef(&lock->read_count) == 1) LOCK(lock->write_lock); UNLOCK(lock->read_lock); UNLOCK(lock->read_entry_lock); }
AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const ALuint *fsids) { ALCdevice *device; ALCcontext *context; ALsfpreset *preset; ALfontsound **sounds; ALsizei i; context = GetContextRef(); if(!context) return; device = context->Device; if(!(preset=LookupPreset(device, id))) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(count < 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); if(ReadRef(&preset->ref) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); if(count == 0) sounds = NULL; else { sounds = calloc(count, sizeof(sounds[0])); if(!sounds) SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); for(i = 0;i < count;i++) { if(!(sounds[i]=LookupFontsound(device, fsids[i]))) { free(sounds); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); } } } for(i = 0;i < count;i++) IncrementRef(&sounds[i]->ref); sounds = ExchangePtr((XchgPtr*)&preset->Sounds, sounds); count = ExchangeInt(&preset->NumSounds, count); for(i = 0;i < count;i++) DecrementRef(&sounds[i]->ref); free(sounds); done: ALCcontext_DecRef(context); }
int alcnd_wait(alcnd_t *cond, almtx_t *mtx) { _int_alcnd_t *icond = cond->Ptr; int res; IncrementRef(&icond->wait_count); LeaveCriticalSection(mtx); res = WaitForMultipleObjects(2, icond->events, FALSE, INFINITE); if(DecrementRef(&icond->wait_count) == 0 && res == WAIT_OBJECT_0+BROADCAST) ResetEvent(icond->events[BROADCAST]); EnterCriticalSection(mtx); return althrd_success; }
int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_point) { _int_alcnd_t *icond = cond->Ptr; struct timespec curtime; DWORD sleeptime; int res; if(altimespec_get(&curtime, AL_TIME_UTC) != AL_TIME_UTC) return althrd_error; sleeptime = (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000; sleeptime += (time_point->tv_sec - curtime.tv_sec)*1000; IncrementRef(&icond->wait_count); LeaveCriticalSection(mtx); res = WaitForMultipleObjects(2, icond->events, FALSE, sleeptime); if(DecrementRef(&icond->wait_count) == 0 && res == WAIT_OBJECT_0+BROADCAST) ResetEvent(icond->events[BROADCAST]); EnterCriticalSection(mtx); return (res == WAIT_TIMEOUT) ? althrd_timedout : althrd_success; }
static void ALeffectState_IncRef(ALeffectState *state) { uint ref; ref = IncrementRef(&state->Ref); TRACEREF("%p increasing refcount to %u\n", state, ref); }
AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids) { ALCdevice *device; ALCcontext *context; ALsoundfont *sfont; ALsfpreset **presets; ALsizei i; context = GetContextRef(); if(!context) return; device = context->Device; if(id == 0) SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); if(!(sfont=LookupSfont(device, id))) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(count < 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); WriteLock(&sfont->Lock); if(ReadRef(&sfont->ref) != 0) { WriteUnlock(&sfont->Lock); SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); } if(count == 0) presets = NULL; else { presets = calloc(count, sizeof(presets[0])); if(!presets) { WriteUnlock(&sfont->Lock); SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); } for(i = 0;i < count;i++) { if(!(presets[i]=LookupPreset(device, pids[i]))) { free(presets); WriteUnlock(&sfont->Lock); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); } } } for(i = 0;i < count;i++) IncrementRef(&presets[i]->ref); presets = ExchangePtr((XchgPtr*)&sfont->Presets, presets); count = ExchangeInt(&sfont->NumPresets, count); WriteUnlock(&sfont->Lock); for(i = 0;i < count;i++) DecrementRef(&presets[i]->ref); free(presets); done: ALCcontext_DecRef(context); }
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALuint SamplesToDo; ALeffectslot **slot, **slot_end; ALvoice *voice, *voice_end; ALCcontext *ctx; FPUCtl oldMode; ALuint i, c; SetMixerFPUMode(&oldMode); while(size > 0) { ALfloat (*OutBuffer)[BUFFERSIZE]; ALuint OutChannels; IncrementRef(&device->MixCount); OutBuffer = device->DryBuffer; OutChannels = device->NumChannels; SamplesToDo = minu(size, BUFFERSIZE); for(c = 0;c < OutChannels;c++) memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); if(device->Hrtf) { /* Set OutBuffer/OutChannels to correspond to the actual output * with HRTF. Make sure to clear them too. */ OutBuffer += OutChannels; OutChannels = 2; for(c = 0;c < OutChannels;c++) memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); } V0(device->Backend,lock)(); V(device->Synth,process)(SamplesToDo, OutBuffer, OutChannels); ctx = ATOMIC_LOAD(&device->ContextList); while(ctx) { ALenum DeferUpdates = ctx->DeferUpdates; ALenum UpdateSources = AL_FALSE; if(!DeferUpdates) UpdateSources = ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE); if(UpdateSources) CalcListenerParams(ctx->Listener); /* source processing */ voice = ctx->Voices; voice_end = voice + ctx->VoiceCount; while(voice != voice_end) { ALsource *source = voice->Source; if(!source) goto next; if(source->state != AL_PLAYING && source->state != AL_PAUSED) { voice->Source = NULL; goto next; } if(!DeferUpdates && (ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) || UpdateSources)) voice->Update(voice, source, ctx); if(source->state != AL_PAUSED) MixSource(voice, source, device, SamplesToDo); next: voice++; } /* effect slot processing */ slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots); slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots); while(slot != slot_end) { if(!DeferUpdates && ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE)) V((*slot)->EffectState,update)(device, *slot); V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0], device->DryBuffer, device->NumChannels); for(i = 0;i < SamplesToDo;i++) (*slot)->WetBuffer[0][i] = 0.0f; slot++; } ctx = ctx->next; } slot = &device->DefaultSlot; if(*slot != NULL) { if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE)) V((*slot)->EffectState,update)(device, *slot); V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0], device->DryBuffer, device->NumChannels); for(i = 0;i < SamplesToDo;i++) (*slot)->WetBuffer[0][i] = 0.0f; } /* Increment the clock time. Every second's worth of samples is * converted and added to clock base so that large sample counts don't * overflow during conversion. This also guarantees an exact, stable * conversion. */ device->SamplesDone += SamplesToDo; device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES; device->SamplesDone %= device->Frequency; V0(device->Backend,unlock)(); if(device->Hrtf) { HrtfMixerFunc HrtfMix = SelectHrtfMixer(); ALuint irsize = GetHrtfIrSize(device->Hrtf); for(c = 0;c < device->NumChannels;c++) HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset, 0, irsize, &device->Hrtf_Params[c], &device->Hrtf_State[c], SamplesToDo ); device->Hrtf_Offset += SamplesToDo; } else if(device->Bs2b) { /* Apply binaural/crossfeed filter */ for(i = 0;i < SamplesToDo;i++) { float samples[2]; samples[0] = device->DryBuffer[0][i]; samples[1] = device->DryBuffer[1][i]; bs2b_cross_feed(device->Bs2b, samples); device->DryBuffer[0][i] = samples[0]; device->DryBuffer[1][i] = samples[1]; } } if(buffer) { #define WRITE(T, a, b, c, d) do { \ Write_##T((a), (b), (c), (d)); \ buffer = (T*)buffer + (c)*(d); \ } while(0) switch(device->FmtType) { case DevFmtByte: WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUByte: WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtShort: WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUShort: WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtInt: WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUInt: WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtFloat: WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels); break; } #undef WRITE } size -= SamplesToDo; IncrementRef(&device->MixCount); } RestoreFPUMode(&oldMode); }
void WriteLock(RWLock *lock) { if(IncrementRef(&lock->write_count) == 1) LOCK(lock->read_lock); LOCK(lock->write_lock); }
static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) { const al_string *iter, *end; ALbyte *BufferData = NULL; DWORD CapturedDataSize; WinMMData *data = NULL; ALint BufferSize; UINT DeviceID; MMRESULT res; ALuint i; if(VECTOR_SIZE(CaptureDevices) == 0) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid iter = VECTOR_ITER_BEGIN(CaptureDevices); end = VECTOR_ITER_END(CaptureDevices); for(; iter != end; iter++) { if(!al_string_empty(*iter) && (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0)) { DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices)); break; } } if(iter == end) return ALC_INVALID_VALUE; switch(Device->FmtChans) { case DevFmtMono: case DevFmtStereo: break; case DevFmtQuad: case DevFmtX51: case DevFmtX51Side: case DevFmtX61: case DevFmtX71: return ALC_INVALID_ENUM; } switch(Device->FmtType) { case DevFmtUByte: case DevFmtShort: case DevFmtInt: case DevFmtFloat: break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: return ALC_INVALID_ENUM; } data = calloc(1, sizeof(*data)); if(!data) return ALC_OUT_OF_MEMORY; Device->ExtraData = data; memset(&data->Format, 0, sizeof(WAVEFORMATEX)); data->Format.wFormatTag = ((Device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); data->Format.nChannels = ChannelsFromDevFmt(Device->FmtChans); data->Format.wBitsPerSample = BytesFromDevFmt(Device->FmtType) * 8; data->Format.nBlockAlign = data->Format.wBitsPerSample * data->Format.nChannels / 8; data->Format.nSamplesPerSec = Device->Frequency; data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec * data->Format.nBlockAlign; data->Format.cbSize = 0; if((res=waveInOpen(&data->WaveHandle.In, DeviceID, &data->Format, (DWORD_PTR)&WaveInProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); goto failure; } // Allocate circular memory buffer for the captured audio CapturedDataSize = Device->UpdateSize*Device->NumUpdates; // Make sure circular buffer is at least 100ms in size if(CapturedDataSize < (data->Format.nSamplesPerSec / 10)) CapturedDataSize = data->Format.nSamplesPerSec / 10; data->Ring = CreateRingBuffer(data->Format.nBlockAlign, CapturedDataSize); if(!data->Ring) goto failure; InitRef(&data->WaveBuffersCommitted, 0); // Create 4 Buffers of 50ms each BufferSize = data->Format.nAvgBytesPerSec / 20; BufferSize -= (BufferSize % data->Format.nBlockAlign); BufferData = calloc(4, BufferSize); if(!BufferData) goto failure; for(i = 0; i < 4; i++) { memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR)); data->WaveBuffer[i].dwBufferLength = BufferSize; data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : (data->WaveBuffer[i-1].lpData + data->WaveBuffer[i-1].dwBufferLength)); data->WaveBuffer[i].dwFlags = 0; data->WaveBuffer[i].dwLoops = 0; waveInPrepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); waveInAddBuffer(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); IncrementRef(&data->WaveBuffersCommitted); } if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success) goto failure; al_string_copy(&Device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); return ALC_NO_ERROR; failure: if(BufferData) { for(i = 0; i < 4; i++) waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); free(BufferData); } if(data->Ring) DestroyRingBuffer(data->Ring); if(data->WaveHandle.In) waveInClose(data->WaveHandle.In); free(data); Device->ExtraData = NULL; return ALC_INVALID_VALUE; }
static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const al_string *iter; ALbyte *BufferData = NULL; DWORD CapturedDataSize; ALint BufferSize; UINT DeviceID; MMRESULT res; ALuint i; if(VECTOR_SIZE(CaptureDevices) == 0) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid #define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && (!name || alstr_cmp_cstr(*iter, name) == 0)) VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME); if(iter == VECTOR_END(CaptureDevices)) return ALC_INVALID_VALUE; #undef MATCH_DEVNAME DeviceID = (UINT)(iter - VECTOR_BEGIN(CaptureDevices)); switch(device->FmtChans) { case DevFmtMono: case DevFmtStereo: break; case DevFmtQuad: case DevFmtX51: case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: case DevFmtAmbi3D: return ALC_INVALID_ENUM; } switch(device->FmtType) { case DevFmtUByte: case DevFmtShort: case DevFmtInt: case DevFmtFloat: break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: return ALC_INVALID_ENUM; } memset(&self->Format, 0, sizeof(WAVEFORMATEX)); self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; self->Format.nBlockAlign = self->Format.wBitsPerSample * self->Format.nChannels / 8; self->Format.nSamplesPerSec = device->Frequency; self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * self->Format.nBlockAlign; self->Format.cbSize = 0; if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); goto failure; } // Allocate circular memory buffer for the captured audio CapturedDataSize = device->UpdateSize*device->NumUpdates; // Make sure circular buffer is at least 100ms in size if(CapturedDataSize < (self->Format.nSamplesPerSec / 10)) CapturedDataSize = self->Format.nSamplesPerSec / 10; self->Ring = ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false); if(!self->Ring) goto failure; InitRef(&self->WaveBuffersCommitted, 0); // Create 4 Buffers of 50ms each BufferSize = self->Format.nAvgBytesPerSec / 20; BufferSize -= (BufferSize % self->Format.nBlockAlign); BufferData = calloc(4, BufferSize); if(!BufferData) goto failure; for(i = 0;i < 4;i++) { memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); self->WaveBuffer[i].dwBufferLength = BufferSize; self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : (self->WaveBuffer[i-1].lpData + self->WaveBuffer[i-1].dwBufferLength)); self->WaveBuffer[i].dwFlags = 0; self->WaveBuffer[i].dwLoops = 0; waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); IncrementRef(&self->WaveBuffersCommitted); } ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success) goto failure; alstr_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); return ALC_NO_ERROR; failure: if(BufferData) { for(i = 0;i < 4;i++) waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); free(BufferData); } ll_ringbuffer_free(self->Ring); self->Ring = NULL; if(self->InHdl) waveInClose(self->InHdl); self->InHdl = NULL; return ALC_INVALID_VALUE; }