/* InitContext Initialize Context variables */ static ALvoid InitContext(ALCcontext *pContext) { int level; //Initialise listener pContext->Listener.Gain = 1.0f; pContext->Listener.MetersPerUnit = 1.0f; pContext->Listener.Position[0] = 0.0f; pContext->Listener.Position[1] = 0.0f; pContext->Listener.Position[2] = 0.0f; pContext->Listener.Velocity[0] = 0.0f; pContext->Listener.Velocity[1] = 0.0f; pContext->Listener.Velocity[2] = 0.0f; pContext->Listener.Forward[0] = 0.0f; pContext->Listener.Forward[1] = 0.0f; pContext->Listener.Forward[2] = -1.0f; pContext->Listener.Up[0] = 0.0f; pContext->Listener.Up[1] = 1.0f; pContext->Listener.Up[2] = 0.0f; //Validate pContext pContext->LastError = AL_NO_ERROR; pContext->InUse = AL_FALSE; //Set output format pContext->Frequency = pContext->Device->Frequency; //Set globals pContext->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED; pContext->DopplerFactor = 1.0f; pContext->DopplerVelocity = 1.0f; pContext->flSpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; pContext->lNumStereoSources = 1; pContext->lNumMonoSources = pContext->Device->MaxNoOfSources - pContext->lNumStereoSources; pContext->ExtensionList = "AL_EXTX_buffer_sub_data AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_LOKI_quadriphonic"; level = GetConfigValueInt(NULL, "cf_level", 0); if(level > 0 && level <= 6) { pContext->bs2b = calloc(1, sizeof(*pContext->bs2b)); bs2b_set_srate(pContext->bs2b, pContext->Frequency); bs2b_set_level(pContext->bs2b, level); } }
// OpenAL {{{ static ALCboolean pulse_open_playback(ALCdevice *device, const ALCchar *device_name) //{{{ { if(!device_name) device_name = pulse_device; else if(strcmp(device_name, pulse_device) != 0) return ALC_FALSE; if(!pulse_load()) return ALC_FALSE; if(pulse_open(device, device_name) != ALC_FALSE) { ALuint len = GetConfigValueInt("pulse", "buffer-length", 2048); if(len != 0) { device->UpdateSize = len; device->NumUpdates = 1; } return ALC_TRUE; } pulse_unload(); return ALC_FALSE; } //}}}
static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName) { int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; audio_buf_info info; ALuint frameSize; char driver[64]; int numChannels; oss_data *data; int ossFormat; int ossSpeed; char *err; int i; strncpy(driver, GetConfigValue("oss", "device", "/dev/dsp"), sizeof(driver)-1); driver[sizeof(driver)-1] = 0; if(deviceName) { if(strcmp(deviceName, oss_device)) return ALC_FALSE; device->szDeviceName = oss_device; } else device->szDeviceName = oss_device; data = (oss_data*)calloc(1, sizeof(oss_data)); data->killNow = 0; data->fd = open(driver, O_WRONLY); if(data->fd == -1) { free(data); AL_PRINT("Could not open %s: %s\n", driver, strerror(errno)); return ALC_FALSE; } switch(aluBytesFromFormat(device->Format)) { case 1: ossFormat = AFMT_U8; break; case 2: ossFormat = AFMT_S16_NE; break; default: ossFormat = -1; AL_PRINT("Unknown format?! %x\n", device->Format); } periods = GetConfigValueInt("oss", "periods", 4); if((int)periods <= 0) periods = 4; numChannels = aluChannelsFromFormat(device->Format); frameSize = numChannels * aluBytesFromFormat(device->Format); ossSpeed = device->Frequency; log2FragmentSize = log2i(device->UpdateSize * frameSize / periods); /* according to the OSS spec, 16 bytes are the minimum */ if (log2FragmentSize < 4) log2FragmentSize = 4; numFragmentsLogSize = (periods << 16) | log2FragmentSize; #define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1)) if (!(ok(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize), "set fragment") && ok(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat), "set format") && ok(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels), "set channels") && ok(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed), "set speed") && ok(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info), "get space"))) { AL_PRINT("%s failed: %s\n", err, strerror(errno)); close(data->fd); free(data); return ALC_FALSE; } #undef ok device->Frequency = ossSpeed; if((int)aluChannelsFromFormat(device->Format) != numChannels) { AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device->Format), numChannels); close(data->fd); free(data); return ALC_FALSE; } if(!((ossFormat == AFMT_U8 && aluBytesFromFormat(device->Format) == 1) || (ossFormat == AFMT_S16_NE && aluBytesFromFormat(device->Format) == 2))) { AL_PRINT("Could not set %d-bit output, got format %#x\n", aluBytesFromFormat(device->Format)*8, ossFormat); close(data->fd); free(data); return ALC_FALSE; } device->UpdateSize = info.fragsize / frameSize; data->data_size = device->UpdateSize * frameSize; data->mix_data = calloc(1, data->data_size); device->ExtraData = data; data->thread = StartThread(OSSProc, device); if(data->thread == NULL) { device->ExtraData = NULL; free(data->mix_data); free(data); return ALC_FALSE; } return ALC_TRUE; }
/* alcOpenDevice Open the Device specified. */ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName) { ALboolean bDeviceFound = AL_FALSE; ALCdevice *device; ALint i; InitAL(); 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->IsCaptureDevice = AL_FALSE; //Set output format device->Frequency = GetConfigValueInt(NULL, "frequency", SWMIXER_OUTPUT_RATE); if((ALint)device->Frequency <= 0) device->Frequency = SWMIXER_OUTPUT_RATE; fmt = GetConfigValue(NULL, "format", "AL_FORMAT_STEREO16"); if(fmt[0]) device->Format = alGetEnumValue(fmt); if(!aluChannelsFromFormat(device->Format)) device->Format = AL_FORMAT_STEREO16; device->UpdateSize = GetConfigValueInt(NULL, "refresh", 4096); if((ALint)device->UpdateSize <= 0) device->UpdateSize = 4096; device->MaxNoOfSources = GetConfigValueInt(NULL, "sources", 256); if((ALint)device->MaxNoOfSources <= 0) device->MaxNoOfSources = 256; // Find a playback device to open for(i = 0;BackendList[i].Init;i++) { device->Funcs = &BackendList[i].Funcs; if(ALCdevice_OpenPlayback(device, deviceName)) { SuspendContext(NULL); device->next = g_pDeviceList; g_pDeviceList = device; g_ulDeviceCount++; ProcessContext(NULL); bDeviceFound = AL_TRUE; break; } } if (!bDeviceFound) { // No suitable output device found SetALCError(ALC_INVALID_VALUE); free(device); device = NULL; } } else SetALCError(ALC_OUT_OF_MEMORY); return device; }
// OpenAL {{{ static ALCboolean pulse_open_playback( ALCdevice* device, const ALCchar* device_name ) //{{{ { char* pulse_name = NULL; pa_sample_spec spec; pulse_data* data; ALuint len; if ( !pulse_load() ) { return ALC_FALSE; } if ( !device_name ) { device_name = pulse_device; } else if ( strcmp( device_name, pulse_device ) != 0 ) { ALuint i; if ( !allDevNameMap ) { probe_devices( AL_FALSE ); } for ( i = 0; i < numDevNames; i++ ) { if ( strcmp( device_name, allDevNameMap[i].name ) == 0 ) { pulse_name = allDevNameMap[i].device_name; break; } } if ( i == numDevNames ) { return ALC_FALSE; } } if ( pulse_open( device, device_name ) == ALC_FALSE ) { return ALC_FALSE; } data = device->ExtraData; ppa_threaded_mainloop_lock( data->loop ); spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; spec.channels = 2; data->device_name = pulse_name; pa_stream* stream = connect_playback_stream( device, 0, NULL, &spec, NULL ); if ( !stream ) { ppa_threaded_mainloop_unlock( data->loop ); goto fail; } if ( ppa_stream_is_suspended( stream ) ) { ppa_stream_disconnect( stream ); ppa_stream_unref( stream ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } data->device_name = strdup( ppa_stream_get_device_name( stream ) ); ppa_stream_disconnect( stream ); ppa_stream_unref( stream ); ppa_threaded_mainloop_unlock( data->loop ); len = GetConfigValueInt( "pulse", "buffer-length", 2048 ); if ( len != 0 ) { device->UpdateSize = len; device->NumUpdates = 1; } return ALC_TRUE; fail: pulse_close( device ); return ALC_FALSE; } //}}}
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 pa_open_playback(ALCdevice *device, const ALCchar *deviceName) { const PaStreamInfo *streamInfo; PaStreamParameters outParams; 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)); data->update_size = device->UpdateSize; device->ExtraData = data; outParams.device = GetConfigValueInt("port", "device", -1); if(outParams.device < 0) outParams.device = pPa_GetDefaultOutputDevice(); outParams.suggestedLatency = (device->UpdateSize*device->NumUpdates) / (float)device->Frequency; outParams.hostApiSpecificStreamInfo = NULL; switch(aluBytesFromFormat(device->Format)) { case 1: outParams.sampleFormat = paUInt8; break; case 2: outParams.sampleFormat = paInt16; break; case 4: outParams.sampleFormat = paFloat32; break; default: AL_PRINT("Unknown format: 0x%x\n", device->Format); device->ExtraData = NULL; free(data); return ALC_FALSE; } outParams.channelCount = aluChannelsFromFormat(device->Format); SetDefaultChannelOrder(device); err = pPa_OpenStream(&data->stream, NULL, &outParams, device->Frequency, device->UpdateSize, paNoFlag, pa_callback, device); if(err != paNoError) { AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err)); device->ExtraData = NULL; free(data); return ALC_FALSE; } streamInfo = pPa_GetStreamInfo(data->stream); device->szDeviceName = strdup(deviceName); device->Frequency = streamInfo->sampleRate; return ALC_TRUE; }
/* 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; }
/* 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; }