NTSTATUS KlogInit( ) { NTSTATUS status; HANDLE threadHandle; CreateRingBuffer(); DbgPrint("Call KlogInit\n"); status=PsCreateSystemThread(&threadHandle, GENERIC_ALL, NULL, NULL, NULL, MyThreadStart, NULL); if(NT_SUCCESS(status)){ DbgPrint("Thread Succes\n"); } else{ DbgPrint("No thread\n");} return STATUS_SUCCESS; }
static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName) { const char *devName; snd_pcm_hw_params_t *p; snd_pcm_uframes_t bufferSizeInFrames; ALuint frameSize; alsa_data *data; char driver[64]; char *err; int i; if(!alsa_handle) return ALC_FALSE; strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1); driver[sizeof(driver)-1] = 0; if(!deviceName) deviceName = allCaptureDevNameMap[0].name; else { size_t idx; for(idx = 0;idx < numCaptureDevNames;idx++) { if(allCaptureDevNameMap[idx].name && strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0) { devName = allCaptureDevNameMap[idx].name; if(idx > 0) sprintf(driver, "plughw:%d,%d", allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev); goto open_alsa; } } return ALC_FALSE; } open_alsa: data = (alsa_data*)calloc(1, sizeof(alsa_data)); i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); if(i < 0) { Sleep(200); i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); } if(i >= 0) { i = psnd_pcm_nonblock(data->pcmHandle, 0); if(i < 0) psnd_pcm_close(data->pcmHandle); } if(i < 0) { free(data); AL_PRINT("Could not open capture device '%s': %s\n", driver, psnd_strerror(i)); return ALC_FALSE; } switch(aluBytesFromFormat(pDevice->Format)) { case 1: data->format = SND_PCM_FORMAT_U8; break; case 2: data->format = SND_PCM_FORMAT_S16; break; case 4: data->format = SND_PCM_FORMAT_FLOAT; break; default: AL_PRINT("Unknown format: 0x%x\n", pDevice->Format); psnd_pcm_close(data->pcmHandle); free(data); return ALC_FALSE; } err = NULL; bufferSizeInFrames = pDevice->UpdateSize * pDevice->NumUpdates; psnd_pcm_hw_params_malloc(&p); if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0) err = "any"; /* set interleaved access */ if(err == NULL && (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) err = "set access"; /* set format (implicitly sets sample bits) */ if(err == NULL && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, data->format)) < 0) err = "set format"; /* set channels (implicitly sets frame bits) */ if(err == NULL && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(pDevice->Format))) < 0) err = "set channels"; /* set rate (implicitly constrains period/buffer parameters) */ if(err == NULL && (i=psnd_pcm_hw_params_set_rate(data->pcmHandle, p, pDevice->Frequency, 0)) < 0) err = "set rate near"; /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ if(err == NULL && (i=psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0) err = "set buffer size near"; /* install and prepare hardware configuration */ if(err == NULL && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0) err = "set params"; if(err != NULL) { AL_PRINT("%s failed: %s\n", err, psnd_strerror(i)); psnd_pcm_hw_params_free(p); psnd_pcm_close(data->pcmHandle); free(data); return ALC_FALSE; } if((i=psnd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0) { AL_PRINT("get size failed: %s\n", psnd_strerror(i)); psnd_pcm_hw_params_free(p); psnd_pcm_close(data->pcmHandle); free(data); return ALC_FALSE; } psnd_pcm_hw_params_free(p); frameSize = aluChannelsFromFormat(pDevice->Format); frameSize *= aluBytesFromFormat(pDevice->Format); data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates); if(!data->ring) { AL_PRINT("ring buffer create failed\n"); psnd_pcm_close(data->pcmHandle); free(data); return ALC_FALSE; } data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames); data->buffer = malloc(data->size); if(!data->buffer) { AL_PRINT("buffer malloc failed\n"); psnd_pcm_close(data->pcmHandle); DestroyRingBuffer(data->ring); free(data); return ALC_FALSE; } pDevice->ExtraData = data; data->thread = StartThread(ALSANoMMapCaptureProc, pDevice); if(data->thread == NULL) { AL_PRINT("Could not create capture thread\n"); psnd_pcm_close(data->pcmHandle); DestroyRingBuffer(data->ring); pDevice->ExtraData = NULL; free(data->buffer); free(data); return ALC_FALSE; } pDevice->szDeviceName = strdup(deviceName); return ALC_TRUE; }
static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName) { int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; audio_buf_info info; ALuint frameSize; int numChannels; oss_data *data; int ossFormat; int ossSpeed; char *err; if(!deviceName) deviceName = oss_device; else if(strcmp(deviceName, oss_device) != 0) return ALC_INVALID_VALUE; data = (oss_data*)calloc(1, sizeof(oss_data)); data->killNow = 0; data->fd = open(oss_capture, O_RDONLY); if(data->fd == -1) { free(data); ERR("Could not open %s: %s\n", oss_capture, strerror(errno)); return ALC_INVALID_VALUE; } switch(device->FmtType) { case DevFmtByte: ossFormat = AFMT_S8; break; case DevFmtUByte: ossFormat = AFMT_U8; break; case DevFmtShort: ossFormat = AFMT_S16_NE; break; case DevFmtUShort: case DevFmtInt: case DevFmtUInt: case DevFmtFloat: free(data); ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); return ALC_INVALID_VALUE; } periods = 4; numChannels = ChannelsFromDevFmt(device->FmtChans); frameSize = numChannels * BytesFromDevFmt(device->FmtType); ossSpeed = device->Frequency; log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates * frameSize / periods); /* according to the OSS spec, 16 bytes are the minimum */ if (log2FragmentSize < 4) log2FragmentSize = 4; numFragmentsLogSize = (periods << 16) | log2FragmentSize; #define CHECKERR(func) if((func) < 0) { \ err = #func; \ goto err; \ } CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info)); if(0) { err: ERR("%s failed: %s\n", err, strerror(errno)); close(data->fd); free(data); return ALC_INVALID_VALUE; } #undef CHECKERR if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); close(data->fd); free(data); return ALC_INVALID_VALUE; } if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) { ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); close(data->fd); free(data); return ALC_INVALID_VALUE; } data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates); if(!data->ring) { ERR("Ring buffer create failed\n"); close(data->fd); free(data); return ALC_OUT_OF_MEMORY; } data->data_size = info.fragsize; data->mix_data = calloc(1, data->data_size); device->ExtraData = data; data->thread = StartThread(OSSCaptureProc, device); if(data->thread == NULL) { device->ExtraData = NULL; free(data->mix_data); free(data); return ALC_OUT_OF_MEMORY; } device->szDeviceName = strdup(deviceName); return ALC_NO_ERROR; }
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 ca_open_capture(ALCdevice *device, const ALCchar *deviceName) { AudioStreamBasicDescription requestedFormat; // The application requested format AudioStreamBasicDescription hardwareFormat; // The hardware format AudioStreamBasicDescription outputFormat; // The AudioUnit output format AURenderCallbackStruct input; ComponentDescription desc; AudioDeviceID inputDevice; UInt32 outputFrameCount; UInt32 propertySize; UInt32 enableIO; Component comp; ca_data *data; OSStatus err; desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; // Search for component with given description comp = FindNextComponent(NULL, &desc); if(comp == NULL) { ERR("FindNextComponent failed\n"); return ALC_INVALID_VALUE; } data = calloc(1, sizeof(*data)); device->ExtraData = data; // Open the component err = OpenAComponent(comp, &data->audioUnit); if(err != noErr) { ERR("OpenAComponent failed\n"); goto error; } // Turn off AudioUnit output enableIO = 0; err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // Turn on AudioUnit input enableIO = 1; err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // Get the default input device propertySize = sizeof(AudioDeviceID); err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &inputDevice); if(err != noErr) { ERR("AudioHardwareGetProperty failed\n"); goto error; } if(inputDevice == kAudioDeviceUnknown) { ERR("No input device found\n"); goto error; } // Track the input device err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // set capture callback input.inputProc = ca_capture_callback; input.inputProcRefCon = device; err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // Initialize the device err = AudioUnitInitialize(data->audioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); goto error; } // Get the hardware format propertySize = sizeof(AudioStreamBasicDescription); err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); goto error; } // Set up the requested format description switch(device->FmtType) { case DevFmtUByte: requestedFormat.mBitsPerChannel = 8; requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; break; case DevFmtShort: requestedFormat.mBitsPerChannel = 16; requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; break; case DevFmtInt: requestedFormat.mBitsPerChannel = 32; requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; break; case DevFmtFloat: requestedFormat.mBitsPerChannel = 32; requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); goto error; } switch(device->FmtChans) { case DevFmtMono: requestedFormat.mChannelsPerFrame = 1; break; case DevFmtStereo: requestedFormat.mChannelsPerFrame = 2; break; case DevFmtQuad: case DevFmtX51: case DevFmtX51Side: case DevFmtX61: case DevFmtX71: ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); goto error; } requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame; requestedFormat.mSampleRate = device->Frequency; requestedFormat.mFormatID = kAudioFormatLinearPCM; requestedFormat.mReserved = 0; requestedFormat.mFramesPerPacket = 1; // save requested format description for later use data->format = requestedFormat; data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later outputFormat = requestedFormat; outputFormat.mSampleRate = hardwareFormat.mSampleRate; // Determine sample rate ratio for resampling data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // Set the AudioUnit output format frame count outputFrameCount = device->UpdateSize * data->sampleRateRatio; err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); if(err != noErr) { ERR("AudioUnitSetProperty failed: %d\n", err); goto error; } // Set up sample converter err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter); if(err != noErr) { ERR("AudioConverterNew failed: %d\n", err); goto error; } // Create a buffer for use in the resample callback data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio); // Allocate buffer for the AudioUnit output data->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * data->frameSize * data->sampleRateRatio); if(data->bufferList == NULL) goto error; data->ring = CreateRingBuffer(data->frameSize, (device->UpdateSize * data->sampleRateRatio) * device->NumUpdates); if(data->ring == NULL) goto error; al_string_copy_cstr(&device->DeviceName, deviceName); return ALC_NO_ERROR; error: DestroyRingBuffer(data->ring); free(data->resampleBuffer); destroy_buffer_list(data->bufferList); if(data->audioConverter) AudioConverterDispose(data->audioConverter); if(data->audioUnit) CloseComponent(data->audioUnit); free(data); device->ExtraData = NULL; return ALC_INVALID_VALUE; }
static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName) { ALuint frame_size; pa_data *data; PaError err; if(!deviceName) deviceName = pa_device; else if(strcmp(deviceName, pa_device) != 0) return ALC_INVALID_VALUE; data = (pa_data*)calloc(1, sizeof(pa_data)); if(data == NULL) return ALC_OUT_OF_MEMORY; frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates); if(data->ring == NULL) goto error; data->params.device = -1; if(!ConfigValueInt("port", "capture", &data->params.device) || data->params.device < 0) data->params.device = Pa_GetDefaultOutputDevice(); data->params.suggestedLatency = 0.0f; data->params.hostApiSpecificStreamInfo = NULL; switch(device->FmtType) { case DevFmtByte: data->params.sampleFormat = paInt8; break; case DevFmtUByte: data->params.sampleFormat = paUInt8; break; case DevFmtShort: data->params.sampleFormat = paInt16; break; case DevFmtInt: data->params.sampleFormat = paInt32; break; case DevFmtFloat: data->params.sampleFormat = paFloat32; break; case DevFmtUInt: case DevFmtUShort: ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); goto error; } data->params.channelCount = ChannelsFromDevFmt(device->FmtChans); err = Pa_OpenStream(&data->stream, &data->params, NULL, device->Frequency, paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device); if(err != paNoError) { ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); goto error; } device->DeviceName = strdup(deviceName); device->ExtraData = data; return ALC_NO_ERROR; error: DestroyRingBuffer(data->ring); free(data); return ALC_INVALID_VALUE; }
static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName) { DSoundCaptureData *data = NULL; WAVEFORMATEXTENSIBLE InputType; DSCBUFFERDESC DSCBDescription; LPGUID guid = NULL; HRESULT hr, hrcom; ALuint samples; if(!CaptureDeviceList) { /* Initialize COM to prevent name truncation */ hrcom = CoInitialize(NULL); hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL); if(FAILED(hr)) ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); if(SUCCEEDED(hrcom)) CoUninitialize(); } if(!deviceName && NumCaptureDevices > 0) { deviceName = CaptureDeviceList[0].name; guid = &CaptureDeviceList[0].guid; } else { ALuint i; for(i = 0;i < NumCaptureDevices;i++) { if(strcmp(deviceName, CaptureDeviceList[i].name) == 0) { guid = &CaptureDeviceList[i].guid; break; } } if(i == NumCaptureDevices) return ALC_INVALID_VALUE; } switch(device->FmtType) { case DevFmtByte: case DevFmtUShort: case DevFmtUInt: WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); return ALC_INVALID_ENUM; case DevFmtUByte: case DevFmtShort: case DevFmtInt: case DevFmtFloat: break; } //Initialise requested device data = calloc(1, sizeof(DSoundCaptureData)); if(!data) return ALC_OUT_OF_MEMORY; hr = DS_OK; //DirectSoundCapture Init code if(SUCCEEDED(hr)) hr = DirectSoundCaptureCreate(guid, &data->DSC, NULL); if(SUCCEEDED(hr)) { memset(&InputType, 0, sizeof(InputType)); switch(device->FmtChans) { case DevFmtMono: InputType.dwChannelMask = SPEAKER_FRONT_CENTER; break; case DevFmtStereo: InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break; case DevFmtQuad: InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break; case DevFmtX51: InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break; case DevFmtX51Side: InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break; case DevFmtX61: InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_CENTER | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break; case DevFmtX71: InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break; } InputType.Format.wFormatTag = WAVE_FORMAT_PCM; InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans); InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; InputType.Format.nSamplesPerSec = device->Frequency; InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; InputType.Format.cbSize = 0; if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) { InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; if(device->FmtType == DevFmtFloat) InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; else InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } samples = device->UpdateSize * device->NumUpdates; samples = maxu(samples, 100 * device->Frequency / 1000); memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC)); DSCBDescription.dwSize = sizeof(DSCBUFFERDESC); DSCBDescription.dwFlags = 0; DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign; DSCBDescription.lpwfxFormat = &InputType.Format; hr = IDirectSoundCapture_CreateCaptureBuffer(data->DSC, &DSCBDescription, &data->DSCbuffer, NULL); } if(SUCCEEDED(hr)) { data->Ring = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates); if(data->Ring == NULL) hr = DSERR_OUTOFMEMORY; } if(FAILED(hr)) { ERR("Device init failed: 0x%08lx\n", hr); DestroyRingBuffer(data->Ring); data->Ring = NULL; if(data->DSCbuffer != NULL) IDirectSoundCaptureBuffer_Release(data->DSCbuffer); data->DSCbuffer = NULL; if(data->DSC) IDirectSoundCapture_Release(data->DSC); data->DSC = NULL; free(data); return ALC_INVALID_VALUE; } data->BufferBytes = DSCBDescription.dwBufferBytes; SetDefaultWFXChannelOrder(device); device->DeviceName = strdup(deviceName); device->ExtraData = data; return ALC_NO_ERROR; }
static ALCenum WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName) { ALbyte *BufferData = NULL; DWORD ulCapturedDataSize; WinMMData *pData = NULL; UINT lDeviceID = 0; ALint lBufferSize; MMRESULT res; ALuint i; if(!CaptureDeviceList) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid for(i = 0;i < NumCaptureDevices;i++) { if(CaptureDeviceList[i] && (!deviceName || strcmp(deviceName, CaptureDeviceList[i]) == 0)) { lDeviceID = i; break; } } if(i == NumCaptureDevices) return ALC_INVALID_VALUE; switch(pDevice->FmtChans) { case DevFmtMono: case DevFmtStereo: break; case DevFmtQuad: case DevFmtX51: case DevFmtX51Side: case DevFmtX61: case DevFmtX71: return ALC_INVALID_ENUM; } switch(pDevice->FmtType) { case DevFmtUByte: case DevFmtShort: case DevFmtInt: case DevFmtFloat: break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: return ALC_INVALID_ENUM; } pData = calloc(1, sizeof(*pData)); if(!pData) return ALC_OUT_OF_MEMORY; pDevice->ExtraData = pData; memset(&pData->wfexFormat, 0, sizeof(WAVEFORMATEX)); pData->wfexFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); pData->wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans); pData->wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8; pData->wfexFormat.nBlockAlign = pData->wfexFormat.wBitsPerSample * pData->wfexFormat.nChannels / 8; pData->wfexFormat.nSamplesPerSec = pDevice->Frequency; pData->wfexFormat.nAvgBytesPerSec = pData->wfexFormat.nSamplesPerSec * pData->wfexFormat.nBlockAlign; pData->wfexFormat.cbSize = 0; if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &pData->wfexFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); goto failure; } pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if(pData->hWaveThreadEvent == NULL) { ERR("CreateEvent failed: %lu\n", GetLastError()); goto failure; } // 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 < (pData->wfexFormat.nSamplesPerSec / 10)) ulCapturedDataSize = pData->wfexFormat.nSamplesPerSec / 10; pData->pRing = CreateRingBuffer(pData->wfexFormat.nBlockAlign, ulCapturedDataSize); if(!pData->pRing) goto failure; pData->lWaveBuffersCommitted = 0; // Create 4 Buffers of 50ms each lBufferSize = pData->wfexFormat.nAvgBytesPerSec / 20; lBufferSize -= (lBufferSize % pData->wfexFormat.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_NO_ERROR; failure: if(pData->hWaveThread) CloseHandle(pData->hWaveThread); if(BufferData) { for(i = 0;i < 4;i++) waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR)); free(BufferData); } if(pData->pRing) DestroyRingBuffer(pData->pRing); if(pData->hWaveThreadEvent) CloseHandle(pData->hWaveThreadEvent); if(pData->hWaveHandle.In) waveInClose(pData->hWaveHandle.In); free(pData); pDevice->ExtraData = NULL; return ALC_INVALID_VALUE; }
static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{ { char *pulse_name = NULL; pulse_data *data; pa_stream_flags_t flags = 0; pa_stream_state_t state; pa_channel_map chanmap; if(!allCaptureDevNameMap) probe_devices(AL_TRUE); if(!device_name) device_name = pulse_device; else if(strcmp(device_name, pulse_device) != 0) { ALuint i; for(i = 0;i < numCaptureDevNames;i++) { if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0) { pulse_name = allCaptureDevNameMap[i].device_name; break; } } if(i == numCaptureDevNames) return ALC_INVALID_VALUE; } if(pulse_open(device, device_name) == ALC_FALSE) return ALC_INVALID_VALUE; data = device->ExtraData; pa_threaded_mainloop_lock(data->loop); data->samples = device->UpdateSize * device->NumUpdates; data->frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); data->samples = maxu(data->samples, 100 * device->Frequency / 1000); if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples))) { pa_threaded_mainloop_unlock(data->loop); goto fail; } data->attr.minreq = -1; data->attr.prebuf = -1; data->attr.maxlength = data->samples * data->frame_size; data->attr.tlength = -1; data->attr.fragsize = minu(data->samples, 50*device->Frequency/1000) * data->frame_size; data->spec.rate = device->Frequency; data->spec.channels = ChannelsFromDevFmt(device->FmtChans); switch(device->FmtType) { case DevFmtUByte: data->spec.format = PA_SAMPLE_U8; break; case DevFmtShort: data->spec.format = PA_SAMPLE_S16NE; break; case DevFmtFloat: data->spec.format = PA_SAMPLE_FLOAT32NE; break; case DevFmtByte: case DevFmtUShort: ERR("Capture format type %#x capture not supported on PulseAudio\n", device->FmtType); pa_threaded_mainloop_unlock(data->loop); goto fail; } if(pa_sample_spec_valid(&data->spec) == 0) { ERR("Invalid sample format\n"); pa_threaded_mainloop_unlock(data->loop); goto fail; } if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX)) { ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels); pa_threaded_mainloop_unlock(data->loop); goto fail; } data->stream = pa_stream_new(data->context, "Capture Stream", &data->spec, &chanmap); if(!data->stream) { ERR("pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(data->context))); pa_threaded_mainloop_unlock(data->loop); goto fail; } pa_stream_set_state_callback(data->stream, stream_state_callback, data->loop); flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY; if(pa_stream_connect_record(data->stream, pulse_name, &data->attr, flags) < 0) { ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(data->context))); pa_stream_unref(data->stream); data->stream = NULL; pa_threaded_mainloop_unlock(data->loop); goto fail; } while((state=pa_stream_get_state(data->stream)) != PA_STREAM_READY) { if(!PA_STREAM_IS_GOOD(state)) { ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(data->context))); pa_stream_unref(data->stream); data->stream = NULL; pa_threaded_mainloop_unlock(data->loop); goto fail; } pa_threaded_mainloop_wait(data->loop); } pa_stream_set_state_callback(data->stream, stream_state_callback2, device); pa_threaded_mainloop_unlock(data->loop); return ALC_NO_ERROR; fail: pulse_close(device); return ALC_INVALID_VALUE; } //}}}
static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{ { pulse_data *data; pa_stream_state_t state; if(!pa_handle) return ALC_FALSE; if(!device_name) device_name = pulse_capture_device; else if(strcmp(device_name, pulse_capture_device) != 0) return ALC_FALSE; if(pulse_open(device, device_name) == ALC_FALSE) return ALC_FALSE; data = device->ExtraData; ppa_threaded_mainloop_lock(data->loop); data->samples = device->UpdateSize * device->NumUpdates; data->frame_size = aluBytesFromFormat(device->Format) * aluChannelsFromFormat(device->Format); if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples))) { ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); return ALC_FALSE; } data->attr.minreq = -1; data->attr.prebuf = -1; data->attr.maxlength = -1; data->attr.tlength = -1; data->attr.fragsize = data->frame_size * data->samples / 2; data->stream_name = "Capture Stream"; data->spec.rate = device->Frequency; data->spec.channels = aluChannelsFromFormat(device->Format); switch(aluBytesFromFormat(device->Format)) { case 1: data->spec.format = PA_SAMPLE_U8; break; case 2: data->spec.format = PA_SAMPLE_S16NE; break; case 4: data->spec.format = PA_SAMPLE_FLOAT32NE; break; default: AL_PRINT("Unknown format: 0x%x\n", device->Format); ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); return ALC_FALSE; } if(ppa_sample_spec_valid(&data->spec) == 0) { AL_PRINT("Invalid sample format\n"); ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); return ALC_FALSE; } data->stream = ppa_stream_new(data->context, data->stream_name, &data->spec, NULL); if(!data->stream) { AL_PRINT("pa_stream_new() failed: %s\n", ppa_strerror(ppa_context_errno(data->context))); ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); return ALC_FALSE; } if(ppa_stream_connect_record(data->stream, NULL, &data->attr, PA_STREAM_ADJUST_LATENCY) < 0) { AL_PRINT("Stream did not connect: %s\n", ppa_strerror(ppa_context_errno(data->context))); ppa_stream_unref(data->stream); ppa_threaded_mainloop_unlock(data->loop); data->stream = NULL; pulse_close(device); return ALC_FALSE; } while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY) { if(!PA_STREAM_IS_GOOD(state)) { AL_PRINT("Stream did not get ready: %s\n", ppa_strerror(ppa_context_errno(data->context))); ppa_stream_unref(data->stream); ppa_threaded_mainloop_unlock(data->loop); data->stream = NULL; pulse_close(device); return ALC_FALSE; } ppa_threaded_mainloop_unlock(data->loop); Sleep(1); ppa_threaded_mainloop_lock(data->loop); } ppa_threaded_mainloop_unlock(data->loop); return ALC_TRUE; } //}}}
static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName) { const char *driver = NULL; snd_pcm_hw_params_t *hp; snd_pcm_uframes_t bufferSizeInFrames; snd_pcm_uframes_t periodSizeInFrames; ALboolean needring = AL_FALSE; snd_pcm_format_t format; const char *funcerr; alsa_data *data; int err; if(deviceName) { size_t idx; if(!allCaptureDevNameMap) allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames); for(idx = 0;idx < numCaptureDevNames;idx++) { if(strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0) { driver = allCaptureDevNameMap[idx].device; break; } } if(idx == numCaptureDevNames) return ALC_INVALID_VALUE; } else { deviceName = alsaDevice; driver = GetConfigValue("alsa", "capture", "default"); } data = (alsa_data*)calloc(1, sizeof(alsa_data)); err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); if(err < 0) { ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); free(data); return ALC_INVALID_VALUE; } format = -1; switch(Device->FmtType) { case DevFmtByte: format = SND_PCM_FORMAT_S8; break; case DevFmtUByte: format = SND_PCM_FORMAT_U8; break; case DevFmtShort: format = SND_PCM_FORMAT_S16; break; case DevFmtUShort: format = SND_PCM_FORMAT_U16; break; case DevFmtInt: format = SND_PCM_FORMAT_S32; break; case DevFmtUInt: format = SND_PCM_FORMAT_U32; break; case DevFmtFloat: format = SND_PCM_FORMAT_FLOAT; break; } funcerr = NULL; bufferSizeInFrames = maxu(Device->UpdateSize*Device->NumUpdates, 100*Device->Frequency/1000); periodSizeInFrames = minu(bufferSizeInFrames, 25*Device->Frequency/1000); snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp)); /* set interleaved access */ CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); /* set format (implicitly sets sample bits) */ CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format)); /* set channels (implicitly sets frame bits) */ CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(Device->FmtChans))); /* set rate (implicitly constrains period/buffer parameters) */ CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, Device->Frequency, 0)); /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0) { TRACE("Buffer too large, using intermediate ring buffer\n"); needring = AL_TRUE; CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames)); } /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames, NULL)); /* install and prepare hardware configuration */ CHECK(snd_pcm_hw_params(data->pcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); #undef CHECK snd_pcm_hw_params_free(hp); hp = NULL; if(needring) { data->ring = CreateRingBuffer(FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType), Device->UpdateSize*Device->NumUpdates); if(!data->ring) { ERR("ring buffer create failed\n"); goto error2; } data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames); data->buffer = malloc(data->size); if(!data->buffer) { ERR("buffer malloc failed\n"); goto error2; } } Device->DeviceName = strdup(deviceName); Device->ExtraData = data; return ALC_NO_ERROR; error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); error2: free(data->buffer); DestroyRingBuffer(data->ring); snd_pcm_close(data->pcmHandle); free(data); Device->ExtraData = NULL; return ALC_INVALID_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 oss_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) { int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; audio_buf_info info; ALuint frameSize; int numChannels; char driver[64]; oss_data *data; int ossFormat; int ossSpeed; char *err; int i; strncpy(driver, GetConfigValue("oss", "capture", "/dev/dsp"), sizeof(driver)-1); driver[sizeof(driver)-1] = 0; if(deviceName) { if(strcmp(deviceName, oss_device_capture)) return ALC_FALSE; device->szDeviceName = oss_device_capture; } else device->szDeviceName = oss_device_capture; data = (oss_data*)calloc(1, sizeof(oss_data)); data->killNow = 0; data->fd = open(driver, O_RDONLY); if(data->fd == -1) { free(data); AL_PRINT("Could not open %s: %s\n", driver, strerror(errno)); return ALC_FALSE; } switch(aluBytesFromFormat(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 = 4; numChannels = aluChannelsFromFormat(device->Format); frameSize = numChannels * aluBytesFromFormat(device->Format); ossSpeed = frequency; log2FragmentSize = log2i(SampleSize * 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_GETISPACE, &info), "get space"))) { AL_PRINT("%s failed: %s\n", err, strerror(errno)); close(data->fd); free(data); return ALC_FALSE; } #undef ok 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 input, got format %#x\n", aluBytesFromFormat(device->Format)*8, ossFormat); close(data->fd); free(data); return ALC_FALSE; } data->ring = CreateRingBuffer(frameSize, SampleSize); if(!data->ring) { AL_PRINT("ring buffer create failed\n"); close(data->fd); free(data); return ALC_FALSE; } data->data_size = info.fragsize; data->mix_data = calloc(1, data->data_size); device->ExtraData = data; data->thread = StartThread(OSSCaptureProc, device); if(data->thread == NULL) { device->ExtraData = NULL; free(data->mix_data); free(data); return ALC_FALSE; } return ALC_TRUE; }
static ALCboolean pulse_open_capture( ALCdevice* device, const ALCchar* device_name ) //{{{ { char* pulse_name = NULL; pulse_data* data; pa_stream_flags_t flags = 0; pa_stream_state_t state; pa_channel_map chanmap; if ( !pulse_load() ) { return ALC_FALSE; } if ( !allCaptureDevNameMap ) { probe_devices( AL_TRUE ); } if ( !device_name ) { device_name = allCaptureDevNameMap[0].name; } else { ALuint i; for ( i = 0; i < numCaptureDevNames; i++ ) { if ( strcmp( device_name, allCaptureDevNameMap[i].name ) == 0 ) { pulse_name = allCaptureDevNameMap[i].device_name; break; } } if ( i == numCaptureDevNames ) { return ALC_FALSE; } } if ( pulse_open( device, device_name ) == ALC_FALSE ) { return ALC_FALSE; } data = device->ExtraData; ppa_threaded_mainloop_lock( data->loop ); data->samples = device->UpdateSize * device->NumUpdates; data->frame_size = aluFrameSizeFromFormat( device->Format ); if ( !( data->ring = CreateRingBuffer( data->frame_size, data->samples ) ) ) { ppa_threaded_mainloop_unlock( data->loop ); goto fail; } data->attr.minreq = -1; data->attr.prebuf = -1; data->attr.maxlength = data->frame_size * data->samples; data->attr.tlength = -1; data->attr.fragsize = min( data->frame_size * data->samples, 10 * device->Frequency / 1000 ); data->spec.rate = device->Frequency; data->spec.channels = aluChannelsFromFormat( device->Format ); switch ( aluBytesFromFormat( device->Format ) ) { case 1: data->spec.format = PA_SAMPLE_U8; break; case 2: data->spec.format = PA_SAMPLE_S16NE; break; case 4: data->spec.format = PA_SAMPLE_FLOAT32NE; break; default: AL_PRINT( "Unknown format: 0x%x\n", device->Format ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } if ( ppa_sample_spec_valid( &data->spec ) == 0 ) { AL_PRINT( "Invalid sample format\n" ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } if ( !ppa_channel_map_init_auto( &chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX ) ) { AL_PRINT( "Couldn't build map for channel count (%d)!\n", data->spec.channels ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } data->stream = ppa_stream_new( data->context, "Capture Stream", &data->spec, &chanmap ); if ( !data->stream ) { AL_PRINT( "pa_stream_new() failed: %s\n", ppa_strerror( ppa_context_errno( data->context ) ) ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } ppa_stream_set_state_callback( data->stream, stream_state_callback, data->loop ); flags |= PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY; if ( ppa_stream_connect_record( data->stream, pulse_name, &data->attr, flags ) < 0 ) { AL_PRINT( "Stream did not connect: %s\n", ppa_strerror( ppa_context_errno( data->context ) ) ); ppa_stream_unref( data->stream ); data->stream = NULL; ppa_threaded_mainloop_unlock( data->loop ); goto fail; } while ( ( state = ppa_stream_get_state( data->stream ) ) != PA_STREAM_READY ) { if ( !PA_STREAM_IS_GOOD( state ) ) { AL_PRINT( "Stream did not get ready: %s\n", ppa_strerror( ppa_context_errno( data->context ) ) ); ppa_stream_unref( data->stream ); data->stream = NULL; ppa_threaded_mainloop_unlock( data->loop ); goto fail; } ppa_threaded_mainloop_wait( data->loop ); } ppa_stream_set_state_callback( data->stream, stream_state_callback2, device ); ppa_threaded_mainloop_unlock( data->loop ); 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 ALCenum alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName) { const char *driver = "default"; snd_pcm_hw_params_t *p; snd_pcm_uframes_t bufferSizeInFrames; snd_pcm_uframes_t periodSizeInFrames; snd_pcm_format_t format; ALuint frameSize; alsa_data *data; char str[128]; char *err; int i; ConfigValueStr("alsa", "capture", &driver); if(!allCaptureDevNameMap) allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames); if(!deviceName) deviceName = allCaptureDevNameMap[0].name; else { size_t idx; for(idx = 0;idx < numCaptureDevNames;idx++) { if(allCaptureDevNameMap[idx].name && strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0) { if(idx > 0) { snprintf(str, sizeof(str), "%sCARD=%s,DEV=%d", capture_prefix, allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev); driver = str; } break; } } if(idx == numCaptureDevNames) return ALC_INVALID_VALUE; } data = (alsa_data*)calloc(1, sizeof(alsa_data)); i = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); if(i < 0) { ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(i)); free(data); return ALC_INVALID_VALUE; } format = -1; switch(pDevice->FmtType) { case DevFmtByte: format = SND_PCM_FORMAT_S8; break; case DevFmtUByte: format = SND_PCM_FORMAT_U8; break; case DevFmtShort: format = SND_PCM_FORMAT_S16; break; case DevFmtUShort: format = SND_PCM_FORMAT_U16; break; case DevFmtFloat: format = SND_PCM_FORMAT_FLOAT; break; } err = NULL; bufferSizeInFrames = maxu(pDevice->UpdateSize*pDevice->NumUpdates, 100*pDevice->Frequency/1000); periodSizeInFrames = minu(bufferSizeInFrames, 50*pDevice->Frequency/1000); snd_pcm_hw_params_malloc(&p); if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0) err = "any"; /* set interleaved access */ if(i >= 0 && (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) err = "set access"; /* set format (implicitly sets sample bits) */ if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0) err = "set format"; /* set channels (implicitly sets frame bits) */ if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(pDevice->FmtChans))) < 0) err = "set channels"; /* set rate (implicitly constrains period/buffer parameters) */ if(i >= 0 && (i=snd_pcm_hw_params_set_rate(data->pcmHandle, p, pDevice->Frequency, 0)) < 0) err = "set rate near"; /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0) err = "set buffer size near"; /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ if(i >= 0 && (i=snd_pcm_hw_params_set_period_size_near(data->pcmHandle, p, &periodSizeInFrames, NULL)) < 0) err = "set period size near"; /* install and prepare hardware configuration */ if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0) err = "set params"; if(i < 0) { ERR("%s failed: %s\n", err, snd_strerror(i)); snd_pcm_hw_params_free(p); goto error; } if((i=snd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0) { ERR("get size failed: %s\n", snd_strerror(i)); snd_pcm_hw_params_free(p); goto error; } snd_pcm_hw_params_free(p); frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates); if(!data->ring) { ERR("ring buffer create failed\n"); goto error; } data->size = snd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames); data->buffer = malloc(data->size); if(!data->buffer) { ERR("buffer malloc failed\n"); goto error; } pDevice->szDeviceName = strdup(deviceName); pDevice->ExtraData = data; return ALC_NO_ERROR; error: free(data->buffer); DestroyRingBuffer(data->ring); snd_pcm_close(data->pcmHandle); free(data); pDevice->ExtraData = NULL; return ALC_INVALID_VALUE; }