static ALuint OSSCaptureProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; oss_data *data = (oss_data*)pDevice->ExtraData; int frameSize; int amt; SetRTPriority(); frameSize = aluFrameSizeFromFormat(pDevice->Format); while(!data->killNow) { amt = read(data->fd, data->mix_data, data->data_size); if(amt < 0) { AL_PRINT("read failed: %s\n", strerror(errno)); aluHandleDisconnect(pDevice); break; } if(amt == 0) { Sleep(1); continue; } if(data->doCapture) WriteRingBuffer(data->ring, data->mix_data, amt/frameSize); } return 0; }
static void* thread_function(void* arg) { ALCdevice* device = (ALCdevice*)arg; AndroidData* data = (AndroidData*)device->ExtraData; JNIEnv* env; (*javaVM)->AttachCurrentThread(javaVM, &env, NULL); (*env)->PushLocalFrame(env, 2); int sampleRateInHz = device->Frequency; int channelConfig = aluChannelsFromFormat(device->Format) == 1 ? CHANNEL_CONFIGURATION_MONO : CHANNEL_CONFIGURATION_STEREO; int audioFormat = aluBytesFromFormat(device->Format) == 1 ? ENCODING_PCM_8BIT : ENCODING_PCM_16BIT; int bufferSizeInBytes = (*env)->CallStaticIntMethod(env, cAudioTrack, mGetMinBufferSize, sampleRateInHz, channelConfig, audioFormat) / 4; int bufferSizeInSamples = bufferSizeInBytes / aluFrameSizeFromFormat(device->Format); jobject track = (*env)->NewObject(env, cAudioTrack, mAudioTrack, STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat, device->NumUpdates * bufferSizeInBytes, MODE_STREAM); (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mPlay); jarray buffer = (*env)->NewByteArray(env, bufferSizeInBytes); while (data->running) { void* pBuffer = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); if (pBuffer) { aluMixData(device, pBuffer, bufferSizeInSamples); (*env)->ReleasePrimitiveArrayCritical(env, buffer, pBuffer, 0); (*env)->CallNonvirtualIntMethod(env, track, cAudioTrack, mWrite, buffer, 0, bufferSizeInBytes); } else { AL_PRINT("Failed to get pointer to array bytes"); } } (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mStop); (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mRelease); (*env)->PopLocalFrame(env, NULL); (*javaVM)->DetachCurrentThread(javaVM); return NULL; }
AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum eParam, const ALint* plValues) { ALCcontext *pContext; ALCdevice *device; ALbuffer *ALBuf; pContext = GetContextSuspended(); if(!pContext) return; device = pContext->Device; if(!plValues) alSetError(pContext, AL_INVALID_VALUE); else if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL) alSetError(pContext, AL_INVALID_NAME); else { switch(eParam) { case AL_LOOP_POINTS: if(ALBuf->refcount > 0) alSetError(pContext, AL_INVALID_OPERATION); else if(plValues[0] < 0 || plValues[1] < 0 || plValues[0] >= plValues[1] || ALBuf->size == 0) alSetError(pContext, AL_INVALID_VALUE); else { ALint maxlen = ALBuf->size / aluFrameSizeFromFormat(ALBuf->format); if(plValues[0] > maxlen || plValues[1] > maxlen) alSetError(pContext, AL_INVALID_VALUE); else { ALBuf->LoopStart = plValues[0]; ALBuf->LoopEnd = plValues[1]; } } break; default: alSetError(pContext, AL_INVALID_ENUM); break; } } ProcessContext(pContext); }
static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) { WinMMData *pData = (WinMMData*)pDevice->ExtraData; ALuint ulSamples = (unsigned long)lSamples; ALuint ulBytes, ulBytesToCopy; ALuint ulCapturedSamples; ALuint ulReadOffset; ALuint frameSize = aluFrameSizeFromFormat(pDevice->Format); // Check that we have the requested numbers of Samples ulCapturedSamples = (pData->ulWriteCapturedDataPos - pData->ulReadCapturedDataPos) / frameSize; if(ulSamples > ulCapturedSamples) { alcSetError(pDevice, ALC_INVALID_VALUE); return; } ulBytes = ulSamples * frameSize; // Get Read Offset ulReadOffset = (pData->ulReadCapturedDataPos % pData->ulCapturedDataSize); // Check for wrap-around condition if ((ulReadOffset + ulBytes) > pData->ulCapturedDataSize) { // Copy data from last Read position to end of data ulBytesToCopy = pData->ulCapturedDataSize - ulReadOffset; memcpy(pBuffer, pData->pCapturedSampleData + ulReadOffset, ulBytesToCopy); // Copy rest of the data from the start of the captured data memcpy(((char *)pBuffer) + ulBytesToCopy, pData->pCapturedSampleData, ulBytes - ulBytesToCopy); } else { // Copy data from the read position in the captured data memcpy(pBuffer, pData->pCapturedSampleData + ulReadOffset, ulBytes); } // Update Read Position pData->ulReadCapturedDataPos += ulBytes; }
static ALuint OSSProc( ALvoid* ptr ) { ALCdevice* pDevice = ( ALCdevice* )ptr; oss_data* data = ( oss_data* )pDevice->ExtraData; ALint frameSize; ssize_t wrote; SetRTPriority(); frameSize = aluFrameSizeFromFormat( pDevice->Format ); while ( !data->killNow && pDevice->Connected ) { ALint len = data->data_size; ALubyte* WritePtr = data->mix_data; aluMixData( pDevice, WritePtr, len / frameSize ); while ( len > 0 && !data->killNow ) { wrote = write( data->fd, WritePtr, len ); if ( wrote < 0 ) { if ( errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR ) { AL_PRINT( "write failed: %s\n", strerror( errno ) ); aluHandleDisconnect( pDevice ); break; } Sleep( 1 ); continue; } len -= wrote; WritePtr += wrote; } } return 0; }
static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName) { snd_pcm_hw_params_t *p; snd_pcm_uframes_t bufferSizeInFrames; snd_pcm_format_t format; ALuint frameSize; alsa_data *data; char driver[64]; char *err; int i; if(!alsa_load()) return ALC_FALSE; strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1); driver[sizeof(driver)-1] = 0; 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) sprintf(driver, "plughw:%d,%d", allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev); break; } } if(idx == numCaptureDevNames) return ALC_FALSE; } 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) { AL_PRINT("Could not open capture device '%s': %s\n", driver, psnd_strerror(i)); free(data); return ALC_FALSE; } switch(aluBytesFromFormat(pDevice->Format)) { case 1: format = SND_PCM_FORMAT_U8; break; case 2: format = SND_PCM_FORMAT_S16; break; case 4: format = SND_PCM_FORMAT_FLOAT; break; default: AL_PRINT("Unknown format: 0x%x\n", pDevice->Format); goto error; } 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(i >= 0 && (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(i >= 0 && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0) err = "set format"; /* set channels (implicitly sets frame bits) */ if(i >= 0 && (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(i >= 0 && (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(i >= 0 && (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(i >= 0 && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0) err = "set params"; if(i < 0) { AL_PRINT("%s failed: %s\n", err, psnd_strerror(i)); psnd_pcm_hw_params_free(p); goto error; } 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); goto error; } psnd_pcm_hw_params_free(p); frameSize = aluFrameSizeFromFormat(pDevice->Format); data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates); if(!data->ring) { AL_PRINT("ring buffer create failed\n"); goto error; } data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames); data->buffer = malloc(data->size); if(!data->buffer) { AL_PRINT("buffer malloc failed\n"); goto error; } pDevice->szDeviceName = strdup(deviceName); pDevice->ExtraData = data; return ALC_TRUE; error: free(data->buffer); DestroyRingBuffer(data->ring); psnd_pcm_close(data->pcmHandle); free(data); pDevice->ExtraData = NULL; return ALC_FALSE; }
static ALCboolean pulse_reset_playback( ALCdevice* device ) //{{{ { pulse_data* data = device->ExtraData; pa_stream_flags_t flags = 0; pa_channel_map chanmap; ppa_threaded_mainloop_lock( data->loop ); if ( !ConfigValueExists( NULL, "format" ) ) { pa_operation* o; o = ppa_context_get_sink_info_by_name( data->context, data->device_name, sink_info_callback, device ); while ( ppa_operation_get_state( o ) == PA_OPERATION_RUNNING ) { ppa_threaded_mainloop_wait( data->loop ); } ppa_operation_unref( o ); } if ( !ConfigValueExists( NULL, "frequency" ) ) { flags |= PA_STREAM_FIX_RATE; } data->frame_size = aluFrameSizeFromFormat( device->Format ); data->attr.minreq = -1; data->attr.prebuf = -1; data->attr.fragsize = -1; data->attr.tlength = device->UpdateSize * device->NumUpdates * data->frame_size; data->attr.maxlength = data->attr.tlength; 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 ); return ALC_FALSE; } data->spec.rate = device->Frequency; data->spec.channels = aluChannelsFromFormat( device->Format ); if ( ppa_sample_spec_valid( &data->spec ) == 0 ) { AL_PRINT( "Invalid sample format\n" ); ppa_threaded_mainloop_unlock( data->loop ); return ALC_FALSE; } 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 ); return ALC_FALSE; } SetDefaultWFXChannelOrder( device ); data->stream = connect_playback_stream( device, flags, &data->attr, &data->spec, &chanmap ); if ( !data->stream ) { ppa_threaded_mainloop_unlock( data->loop ); return ALC_FALSE; } ppa_stream_set_state_callback( data->stream, stream_state_callback2, device ); data->spec = *( ppa_stream_get_sample_spec( data->stream ) ); if ( device->Frequency != data->spec.rate ) { pa_operation* o; /* Server updated our playback rate, so modify the buffer attribs * accordingly. */ data->attr.tlength = ( ALuint64 )( data->attr.tlength / data->frame_size ) * data->spec.rate / device->Frequency * data->frame_size; data->attr.maxlength = data->attr.tlength; o = ppa_stream_set_buffer_attr( data->stream, &data->attr, stream_success_callback, device ); while ( ppa_operation_get_state( o ) == PA_OPERATION_RUNNING ) { ppa_threaded_mainloop_wait( data->loop ); } ppa_operation_unref( o ); device->Frequency = data->spec.rate; } stream_buffer_attr_callback( data->stream, device ); #if PA_CHECK_VERSION(0,9,15) if ( ppa_stream_set_buffer_attr_callback ) { ppa_stream_set_buffer_attr_callback( data->stream, stream_buffer_attr_callback, device ); } #endif ppa_stream_set_moved_callback( data->stream, stream_device_callback, device ); stream_write_callback( data->stream, data->attr.tlength, device ); ppa_stream_set_write_callback( data->stream, stream_write_callback, device ); ppa_threaded_mainloop_unlock( data->loop ); 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 ALuint WaveProc( ALvoid* ptr ) { ALCdevice* pDevice = ( ALCdevice* )ptr; wave_data* data = ( wave_data* )pDevice->ExtraData; ALuint frameSize; ALuint now, last; size_t fs; ALuint avail; union { short s; char b[sizeof( short )]; } uSB; uSB.s = 1; frameSize = aluFrameSizeFromFormat( pDevice->Format ); last = timeGetTime() << 8; while ( !data->killNow && pDevice->Connected ) { now = timeGetTime() << 8; avail = ( ALuint64 )( now - last ) * pDevice->Frequency / ( 1000 << 8 ); if ( avail < pDevice->UpdateSize ) { Sleep( 1 ); continue; } while ( avail >= pDevice->UpdateSize ) { aluMixData( pDevice, data->buffer, pDevice->UpdateSize ); if ( uSB.b[0] != 1 ) { ALubyte* bytes = data->buffer; ALuint i; if ( aluBytesFromFormat( pDevice->Format ) == 1 ) { for ( i = 0; i < data->size; i++ ) { fputc( bytes[i], data->f ); } } else if ( aluBytesFromFormat( pDevice->Format ) == 2 ) { for ( i = 0; i < data->size; i++ ) { fputc( bytes[i ^ 1], data->f ); } } else if ( aluBytesFromFormat( pDevice->Format ) == 4 ) { for ( i = 0; i < data->size; i++ ) { fputc( bytes[i ^ 3], data->f ); } } } else fs = fwrite( data->buffer, frameSize, pDevice->UpdateSize, data->f ); if ( ferror( data->f ) ) { AL_PRINT( "Error writing to file\n" ); aluHandleDisconnect( pDevice ); break; } avail -= pDevice->UpdateSize; last += ( ALuint64 )pDevice->UpdateSize * ( 1000 << 8 ) / pDevice->Frequency; } } return 0; }
static ALCboolean DSoundResetPlayback(ALCdevice *device) { DSoundData *pData = (DSoundData*)device->ExtraData; DSBUFFERDESC DSBDescription; WAVEFORMATEXTENSIBLE OutputType; DWORD frameSize = 0; ALenum format = 0; DWORD speakers; HRESULT hr; memset(&OutputType, 0, sizeof(OutputType)); hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers); if(SUCCEEDED(hr) && ConfigValueExists(NULL, "format")) { if(aluChannelsFromFormat(device->Format) == 1) speakers = DSSPEAKER_COMBINED(DSSPEAKER_MONO, 0); else if(aluChannelsFromFormat(device->Format) == 2) speakers = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, 0); else if(aluChannelsFromFormat(device->Format) == 4) speakers = DSSPEAKER_COMBINED(DSSPEAKER_QUAD, 0); else if(aluChannelsFromFormat(device->Format) == 6) speakers = DSSPEAKER_COMBINED(DSSPEAKER_5POINT1, 0); else if(aluChannelsFromFormat(device->Format) == 8) speakers = DSSPEAKER_COMBINED(DSSPEAKER_7POINT1, 0); else { AL_PRINT("Unknown format: 0x%x\n", device->Format); return ALC_FALSE; } } if(SUCCEEDED(hr)) { speakers = DSSPEAKER_CONFIG(speakers); if(speakers == DSSPEAKER_MONO) { if(aluBytesFromFormat(device->Format) == 1) format = AL_FORMAT_MONO8; else if(aluBytesFromFormat(device->Format) == 2) format = AL_FORMAT_MONO16; else if(aluBytesFromFormat(device->Format) == 4) format = AL_FORMAT_MONO_FLOAT32; OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; } else if(speakers == DSSPEAKER_STEREO) { if(aluBytesFromFormat(device->Format) == 1) format = AL_FORMAT_STEREO8; else if(aluBytesFromFormat(device->Format) == 2) format = AL_FORMAT_STEREO16; else if(aluBytesFromFormat(device->Format) == 4) format = AL_FORMAT_STEREO_FLOAT32; OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; } else if(speakers == DSSPEAKER_QUAD) { if(aluBytesFromFormat(device->Format) == 1) format = AL_FORMAT_QUAD8; else if(aluBytesFromFormat(device->Format) == 2) format = AL_FORMAT_QUAD16; else if(aluBytesFromFormat(device->Format) == 4) format = AL_FORMAT_QUAD32; OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; } else if(speakers == DSSPEAKER_5POINT1) { if(aluBytesFromFormat(device->Format) == 1) format = AL_FORMAT_51CHN8; else if(aluBytesFromFormat(device->Format) == 2) format = AL_FORMAT_51CHN16; else if(aluBytesFromFormat(device->Format) == 4) format = AL_FORMAT_51CHN32; OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; } else if(speakers == DSSPEAKER_7POINT1) { if(aluBytesFromFormat(device->Format) == 1) format = AL_FORMAT_71CHN8; else if(aluBytesFromFormat(device->Format) == 2) format = AL_FORMAT_71CHN16; else if(aluBytesFromFormat(device->Format) == 4) format = AL_FORMAT_71CHN32; OutputType.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; } else format = device->Format; frameSize = aluFrameSizeFromFormat(format); OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; OutputType.Format.nChannels = aluChannelsFromFormat(format); OutputType.Format.wBitsPerSample = aluBytesFromFormat(format) * 8; OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; OutputType.Format.nSamplesPerSec = device->Frequency; OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; OutputType.Format.cbSize = 0; } if(OutputType.Format.nChannels > 2 || OutputType.Format.wBitsPerSample > 16) { OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; OutputType.Format.cbSize = 22; if(OutputType.Format.wBitsPerSample == 32) OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; else OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } else { if(SUCCEEDED(hr)) { memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); DSBDescription.dwSize=sizeof(DSBUFFERDESC); DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER; hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL); } if(SUCCEEDED(hr)) hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format); } if(SUCCEEDED(hr)) { memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); DSBDescription.dwSize=sizeof(DSBUFFERDESC); DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2; DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates * frameSize; DSBDescription.lpwfxFormat=&OutputType.Format; hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL); } if(SUCCEEDED(hr)) hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); if(SUCCEEDED(hr)) { device->Format = format; SetDefaultWFXChannelOrder(device); pData->thread = StartThread(DSoundProc, device); if(!pData->thread) hr = E_FAIL; } if(FAILED(hr)) { if (pData->DSsbuffer) IDirectSoundBuffer_Release(pData->DSsbuffer); pData->DSsbuffer = NULL; if (pData->DSpbuffer) IDirectSoundBuffer_Release(pData->DSpbuffer); pData->DSpbuffer = NULL; return ALC_FALSE; } return ALC_TRUE; }
static ALuint DSoundProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; DSoundData *pData = (DSoundData*)pDevice->ExtraData; DSBCAPS DSBCaps; DWORD LastCursor = 0; DWORD PlayCursor; VOID *WritePtr1, *WritePtr2; DWORD WriteCnt1, WriteCnt2; DWORD FrameSize; DWORD FragSize; DWORD avail; HRESULT err; SetRTPriority(); memset(&DSBCaps, 0, sizeof(DSBCaps)); DSBCaps.dwSize = sizeof(DSBCaps); err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps); if(FAILED(err)) { AL_PRINT("Failed to get buffer caps: 0x%lx\n", err); aluHandleDisconnect(pDevice); return 1; } FrameSize = aluFrameSizeFromFormat(pDevice->Format); FragSize = pDevice->UpdateSize * FrameSize; IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL); while(!pData->killNow) { // Get current play and write cursors IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL); avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; if(avail < FragSize) { Sleep(1); continue; } avail -= avail%FragSize; // Lock output buffer WriteCnt1 = 0; WriteCnt2 = 0; err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); // If the buffer is lost, restore it, play and lock if(err == DSERR_BUFFERLOST) { err = IDirectSoundBuffer_Restore(pData->DSsbuffer); if(SUCCEEDED(err)) err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); if(SUCCEEDED(err)) err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); } // Successfully locked the output buffer if(SUCCEEDED(err)) { // If we have an active context, mix data directly into output buffer otherwise fill with silence aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize); aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize); // Unlock output buffer only when successfully locked IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); } else AL_PRINT("Buffer lock error: %#lx\n", err); // Update old write cursor location LastCursor += WriteCnt1+WriteCnt2; LastCursor %= DSBCaps.dwBufferBytes; } return 0; }
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 ALCuint WinMMAvailableSamples(ALCdevice *pDevice) { WinMMData *pData = (WinMMData*)pDevice->ExtraData; ALCuint lCapturedBytes = (pData->ulWriteCapturedDataPos - pData->ulReadCapturedDataPos); return lCapturedBytes / aluFrameSizeFromFormat(pDevice->Format); }