static ALenum AddEffectSlotArray(ALCcontext *context, ALeffectslot **start, ALsizei count) { ALenum err = AL_NO_ERROR; LockContext(context); if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_END(context->ActiveAuxSlots), start, start+count)) err = AL_OUT_OF_MEMORY; UnlockContext(context); return err; }
static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName) { qsa_data *data; int card, dev; int status; data = (qsa_data*)calloc(1, sizeof(qsa_data)); if(data == NULL) return ALC_OUT_OF_MEMORY; if(!deviceName) deviceName = qsaDevice; if(strcmp(deviceName, qsaDevice) == 0) status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK); else { const DevMap *iter; if(VECTOR_SIZE(DeviceNameMap) == 0) deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); #define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME); #undef MATCH_DEVNAME if(iter == VECTOR_END(DeviceNameMap)) { free(data); return ALC_INVALID_DEVICE; } status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK); } if(status < 0) { free(data); return ALC_INVALID_DEVICE; } data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK); if(data->audio_fd < 0) { snd_pcm_close(data->pcmHandle); free(data); return ALC_INVALID_DEVICE; } al_string_copy_cstr(&device->DeviceName, deviceName); device->ExtraData = data; return ALC_NO_ERROR; }
static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot) { ALeffectslot **iter; LockContext(context); #define MATCH_SLOT(_i) (slot == *(_i)) VECTOR_FIND_IF(iter, ALeffectslot*, context->ActiveAuxSlots, MATCH_SLOT); if(iter != VECTOR_END(context->ActiveAuxSlots)) { *iter = VECTOR_BACK(context->ActiveAuxSlots); VECTOR_POP_BACK(context->ActiveAuxSlots); } #undef MATCH_SLOT UnlockContext(context); }
static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data) { vector_DevMap *devices = data; OLECHAR *guidstr = NULL; DevMap entry; HRESULT hr; int count; if(!guid) return TRUE; AL_STRING_INIT(entry.name); count = 0; while(1) { const DevMap *iter; al_string_copy_cstr(&entry.name, DEVNAME_HEAD); al_string_append_wcstr(&entry.name, desc); if(count != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", count+1); al_string_append_cstr(&entry.name, str); } #define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY); if(iter == VECTOR_END(*devices)) break; #undef MATCH_ENTRY count++; } entry.guid = *guid; hr = StringFromCLSID(guid, &guidstr); if(SUCCEEDED(hr)) { TRACE("Got device \"%s\", GUID \"%ls\"\n", al_string_get_cstr(entry.name), guidstr); CoTaskMemFree(guidstr); } VECTOR_PUSH_BACK(*devices, entry); return TRUE; }
static void ProbeCaptureDevices(void) { ALuint numdevs; ALuint i; clear_devlist(&CaptureDevices); numdevs = waveInGetNumDevs(); VECTOR_RESIZE(CaptureDevices, 0, numdevs); for(i = 0;i < numdevs;i++) { WAVEINCAPSW WaveCaps; const al_string *iter; al_string dname; AL_STRING_INIT(dname); if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) { ALuint count = 0; while(1) { alstr_copy_cstr(&dname, DEVNAME_HEAD); alstr_append_wcstr(&dname, WaveCaps.szPname); if(count != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", count+1); alstr_append_cstr(&dname, str); } count++; #define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0) VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY); if(iter == VECTOR_END(CaptureDevices)) break; #undef MATCH_ENTRY } TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i); } VECTOR_PUSH_BACK(CaptureDevices, dname); } }
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) { ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); size_t leftover = 0; for(;iter != end;iter++) { ALeffectslot *slot = *iter; if(!slot) continue; *iter = NULL; DeinitEffectSlot(slot); memset(slot, 0, sizeof(*slot)); al_free(slot); ++leftover; } if(leftover > 0) WARN("(%p) Deleted "SZFMT" AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s"); }
void ReleaseALEffects(ALCdevice *device) { EffectSubList *sublist = VECTOR_BEGIN(device->EffectList); EffectSubList *subend = VECTOR_END(device->EffectList); size_t leftover = 0; for(;sublist != subend;++sublist) { ALuint64 usemask = ~sublist->FreeMask; while(usemask) { ALsizei idx = CTZ64(usemask); ALeffect *effect = sublist->Effects + idx; memset(effect, 0, sizeof(*effect)); ++leftover; usemask &= ~(U64(1) << idx); } sublist->FreeMask = ~usemask; } if(leftover > 0) WARN("(%p) Deleted "SZFMT" Effect%s\n", device, leftover, (leftover==1)?"":"s"); }
void ReleaseALFilters(ALCdevice *device) { FilterSubList *sublist = VECTOR_BEGIN(device->FilterList); FilterSubList *subend = VECTOR_END(device->FilterList); size_t leftover = 0; for(;sublist != subend;++sublist) { ALuint64 usemask = ~sublist->FreeMask; while(usemask) { ALsizei idx = CTZ64(usemask); ALfilter *filter = sublist->Filters + idx; memset(filter, 0, sizeof(*filter)); ++leftover; usemask &= ~(U64(1) << idx); } sublist->FreeMask = ~usemask; } if(leftover > 0) WARN("(%p) Deleted "SZFMT" Filter%s\n", device, leftover, (leftover==1)?"":"s"); }
static ALeffect *AllocEffect(ALCcontext *context) { ALCdevice *device = context->Device; EffectSubList *sublist, *subend; ALeffect *effect = NULL; ALsizei lidx = 0; ALsizei slidx; almtx_lock(&device->EffectLock); sublist = VECTOR_BEGIN(device->EffectList); subend = VECTOR_END(device->EffectList); for(;sublist != subend;++sublist) { if(sublist->FreeMask) { slidx = CTZ64(sublist->FreeMask); effect = sublist->Effects + slidx; break; } ++lidx; } if(UNLIKELY(!effect)) { const EffectSubList empty_sublist = { 0, NULL }; /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ if(UNLIKELY(VECTOR_SIZE(device->EffectList) >= 1<<25)) { almtx_unlock(&device->EffectLock); alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); return NULL; } lidx = (ALsizei)VECTOR_SIZE(device->EffectList); VECTOR_PUSH_BACK(device->EffectList, empty_sublist); sublist = &VECTOR_BACK(device->EffectList); sublist->FreeMask = ~U64(0); sublist->Effects = al_calloc(16, sizeof(ALeffect)*64); if(UNLIKELY(!sublist->Effects)) { VECTOR_POP_BACK(device->EffectList); almtx_unlock(&device->EffectLock); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); return NULL; } slidx = 0; effect = sublist->Effects + slidx; } memset(effect, 0, sizeof(*effect)); InitEffectParams(effect, AL_EFFECT_NULL); /* Add 1 to avoid effect ID 0. */ effect->id = ((lidx<<6) | slidx) + 1; sublist->FreeMask &= ~(U64(1)<<slidx); almtx_unlock(&device->EffectLock); return effect; }
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) { ALCdevice *device; ALCcontext *context; ALsizei cur; context = GetContextRef(); if(!context) return; if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n); if(n == 0) goto done; LockEffectSlotList(context); device = context->Device; for(cur = 0;cur < n;cur++) { ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); ALeffectslot *slot = NULL; ALenum err = AL_OUT_OF_MEMORY; for(;iter != end;iter++) { if(!*iter) break; } if(iter == end) { if(device->AuxiliaryEffectSlotMax == VECTOR_SIZE(context->EffectSlotList)) { UnlockEffectSlotList(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Exceeding %u auxiliary effect slot limit", device->AuxiliaryEffectSlotMax); } VECTOR_PUSH_BACK(context->EffectSlotList, NULL); iter = &VECTOR_BACK(context->EffectSlotList); } slot = al_calloc(16, sizeof(ALeffectslot)); if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR) { al_free(slot); UnlockEffectSlotList(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); SETERR_GOTO(context, err, done, "Effect slot object allocation failed"); } aluInitEffectPanning(slot); slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1; *iter = slot; effectslots[cur] = slot->id; } AddActiveEffectSlots(effectslots, n, context); UnlockEffectSlotList(context); done: ALCcontext_DecRef(context); }
static ALfilter *AllocFilter(ALCcontext *context) { ALCdevice *device = context->Device; FilterSubList *sublist, *subend; ALfilter *filter = NULL; ALsizei lidx = 0; ALsizei slidx; almtx_lock(&device->FilterLock); sublist = VECTOR_BEGIN(device->FilterList); subend = VECTOR_END(device->FilterList); for(;sublist != subend;++sublist) { if(sublist->FreeMask) { slidx = CTZ64(sublist->FreeMask); filter = sublist->Filters + slidx; break; } ++lidx; } if(UNLIKELY(!filter)) { const FilterSubList empty_sublist = { 0, NULL }; /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ if(UNLIKELY(VECTOR_SIZE(device->FilterList) >= 1<<25)) { almtx_unlock(&device->FilterLock); alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); return NULL; } lidx = (ALsizei)VECTOR_SIZE(device->FilterList); VECTOR_PUSH_BACK(device->FilterList, empty_sublist); sublist = &VECTOR_BACK(device->FilterList); sublist->FreeMask = ~U64(0); sublist->Filters = al_calloc(16, sizeof(ALfilter)*64); if(UNLIKELY(!sublist->Filters)) { VECTOR_POP_BACK(device->FilterList); almtx_unlock(&device->FilterLock); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); return NULL; } slidx = 0; filter = sublist->Filters + slidx; } memset(filter, 0, sizeof(*filter)); InitFilterParams(filter, AL_FILTER_NULL); /* Add 1 to avoid filter ID 0. */ filter->id = ((lidx<<6) | slidx) + 1; sublist->FreeMask &= ~(U64(1)<<slidx); almtx_unlock(&device->FilterLock); return filter; }
static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName) { qsa_data *data; int card, dev; int format=-1; int status; data=(qsa_data*)calloc(1, sizeof(qsa_data)); if (data==NULL) { return ALC_OUT_OF_MEMORY; } if(!deviceName) deviceName = qsaDevice; if(strcmp(deviceName, qsaDevice) == 0) status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE); else { const DevMap *iter; if(VECTOR_SIZE(CaptureNameMap) == 0) deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); #define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME); #undef MATCH_DEVNAME if(iter == VECTOR_END(CaptureNameMap)) { free(data); return ALC_INVALID_DEVICE; } status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE); } if(status < 0) { free(data); return ALC_INVALID_DEVICE; } data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE); if(data->audio_fd < 0) { snd_pcm_close(data->pcmHandle); free(data); return ALC_INVALID_DEVICE; } al_string_copy_cstr(&device->DeviceName, deviceName); device->ExtraData = data; switch (device->FmtType) { case DevFmtByte: format=SND_PCM_SFMT_S8; break; case DevFmtUByte: format=SND_PCM_SFMT_U8; break; case DevFmtShort: format=SND_PCM_SFMT_S16_LE; break; case DevFmtUShort: format=SND_PCM_SFMT_U16_LE; break; case DevFmtInt: format=SND_PCM_SFMT_S32_LE; break; case DevFmtUInt: format=SND_PCM_SFMT_U32_LE; break; case DevFmtFloat: format=SND_PCM_SFMT_FLOAT_LE; break; } /* we actually don't want to block on reads */ snd_pcm_nonblock_mode(data->pcmHandle, 1); /* Disable mmap to control data transfer to the audio device */ snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP); /* configure a sound channel */ memset(&data->cparams, 0, sizeof(data->cparams)); data->cparams.mode=SND_PCM_MODE_BLOCK; data->cparams.channel=SND_PCM_CHANNEL_CAPTURE; data->cparams.start_mode=SND_PCM_START_GO; data->cparams.stop_mode=SND_PCM_STOP_STOP; data->cparams.buf.block.frag_size=device->UpdateSize* ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType); data->cparams.buf.block.frags_max=device->NumUpdates; data->cparams.buf.block.frags_min=device->NumUpdates; data->cparams.format.interleave=1; data->cparams.format.rate=device->Frequency; data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans); data->cparams.format.format=format; if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) { snd_pcm_close(data->pcmHandle); free(data); device->ExtraData=NULL; return ALC_INVALID_VALUE; } return ALC_NO_ERROR; }
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; }
static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const al_string *iter; UINT DeviceID; MMRESULT res; if(VECTOR_SIZE(PlaybackDevices) == 0) ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid #define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && \ (!deviceName || alstr_cmp_cstr(*(iter), deviceName) == 0)) VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME); if(iter == VECTOR_END(PlaybackDevices)) return ALC_INVALID_VALUE; #undef MATCH_DEVNAME DeviceID = (UINT)(iter - VECTOR_BEGIN(PlaybackDevices)); retry_open: memset(&self->Format, 0, sizeof(WAVEFORMATEX)); if(device->FmtType == DevFmtFloat) { self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; self->Format.wBitsPerSample = 32; } else { self->Format.wFormatTag = WAVE_FORMAT_PCM; if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte) self->Format.wBitsPerSample = 8; else self->Format.wBitsPerSample = 16; } self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); 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=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { if(device->FmtType == DevFmtFloat) { device->FmtType = DevFmtShort; goto retry_open; } ERR("waveOutOpen failed: %u\n", res); goto failure; } alstr_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); return ALC_NO_ERROR; failure: if(self->OutHdl) waveOutClose(self->OutHdl); self->OutHdl = NULL; return ALC_INVALID_VALUE; }