static ALCuint alsa_available_samples(ALCdevice *Device) { alsa_data *data = (alsa_data*)Device->ExtraData; snd_pcm_sframes_t avail; avail = (Device->Connected ? snd_pcm_avail_update(data->pcmHandle) : 0); if(avail < 0) { ERR("avail update failed: %s\n", snd_strerror(avail)); if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0) { if(data->doCapture) avail = snd_pcm_start(data->pcmHandle); if(avail >= 0) avail = snd_pcm_avail_update(data->pcmHandle); } if(avail < 0) { ERR("restore error: %s\n", snd_strerror(avail)); aluHandleDisconnect(Device); } } while(avail > 0) { snd_pcm_sframes_t amt; amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size); if(avail < amt) amt = avail; amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0) { if(data->doCapture) amt = snd_pcm_start(data->pcmHandle); if(amt >= 0) amt = snd_pcm_avail_update(data->pcmHandle); } if(amt < 0) { ERR("restore error: %s\n", snd_strerror(amt)); aluHandleDisconnect(Device); break; } avail = amt; continue; } WriteRingBuffer(data->ring, data->buffer, amt); avail -= amt; } return RingBufferSize(data->ring); }
static ALCenum pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) { pulse_data *data = device->ExtraData; ALCuint todo = samples * pa_frame_size(&data->spec); pa_threaded_mainloop_lock(data->loop); /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ data->last_readable -= todo; while(todo > 0) { size_t rem = todo; if(data->cap_len == 0) { pa_stream_state_t state; state = pa_stream_get_state(data->stream); if(!PA_STREAM_IS_GOOD(state)) { aluHandleDisconnect(device); break; } if(pa_stream_peek(data->stream, &data->cap_store, &data->cap_len) < 0) { ERR("pa_stream_peek() failed: %s\n", pa_strerror(pa_context_errno(data->context))); aluHandleDisconnect(device); break; } data->cap_remain = data->cap_len; } if(rem > data->cap_remain) rem = data->cap_remain; memcpy(buffer, data->cap_store, rem); buffer = (ALbyte*)buffer + rem; todo -= rem; data->cap_store = (ALbyte*)data->cap_store + rem; data->cap_remain -= rem; if(data->cap_remain == 0) { pa_stream_drop(data->stream); data->cap_len = 0; } } if(todo > 0) memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo); pa_threaded_mainloop_unlock(data->loop); return ALC_NO_ERROR; }
static ALCuint qsa_available_samples(ALCdevice* device) { qsa_data* data=(qsa_data*)device->ExtraData; snd_pcm_channel_status_t status; ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType); ALint free_size; int rstatus; memset(&status, 0, sizeof (status)); status.channel=SND_PCM_CHANNEL_CAPTURE; snd_pcm_plugin_status(data->pcmHandle, &status); if ((status.status==SND_PCM_STATUS_OVERRUN) || (status.status==SND_PCM_STATUS_READY)) { if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) { ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); aluHandleDisconnect(device); return 0; } snd_pcm_capture_go(data->pcmHandle); return 0; } free_size=data->csetup.buf.block.frag_size*data->csetup.buf.block.frags; free_size-=status.free; return free_size/frame_size; }
static ALuint OSSCaptureProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; oss_data *data = (oss_data*)pDevice->ExtraData; int frameSize; int amt; SetRTPriority(); frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); while(!data->killNow) { amt = read(data->fd, data->mix_data, data->data_size); if(amt < 0) { ERR("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 ALuint sndio_proc(ALvoid *ptr) { ALCdevice *device = ptr; sndio_data *data = device->ExtraData; ALsizei frameSize; size_t wrote; SetRTPriority(); frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); while(!data->killNow && device->Connected) { ALsizei len = data->data_size; ALubyte *WritePtr = data->mix_data; aluMixData(device, WritePtr, len/frameSize); while(len > 0 && !data->killNow) { wrote = sio_write(data->sndHandle, WritePtr, len); if(wrote == 0) { ERR("sio_write failed\n"); aluHandleDisconnect(device); break; } len -= wrote; WritePtr += wrote; } } return 0; }
static ALuint ALSANoMMapProc(ALvoid *ptr) { ALCdevice *Device = (ALCdevice*)ptr; alsa_data *data = (alsa_data*)Device->ExtraData; snd_pcm_sframes_t avail; char *WritePtr; SetRTPriority(); while(!data->killNow) { int state = verify_state(data->pcmHandle); if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); aluHandleDisconnect(Device); break; } WritePtr = data->buffer; avail = data->size / snd_pcm_frames_to_bytes(data->pcmHandle, 1); aluMixData(Device, WritePtr, avail); while(avail > 0) { int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail); switch (ret) { case -EAGAIN: continue; case -ESTRPIPE: case -EPIPE: case -EINTR: ret = snd_pcm_recover(data->pcmHandle, ret, 1); if(ret < 0) avail = 0; break; default: if (ret >= 0) { WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret); avail -= ret; } break; } if (ret < 0) { ret = snd_pcm_prepare(data->pcmHandle); if(ret < 0) break; } } } return 0; }
static void stream_state_callback2(pa_stream *stream, void *pdata) //{{{ { ALCdevice *Device = pdata; if(ppa_stream_get_state(stream) == PA_STREAM_FAILED) { AL_PRINT("Received stream failure!\n"); aluHandleDisconnect(Device); } }//}}}
static void context_state_callback2(pa_context *context, void *pdata) //{{{ { ALCdevice *Device = pdata; if(ppa_context_get_state(context) == PA_CONTEXT_FAILED) { AL_PRINT("Received context failure!\n"); aluHandleDisconnect(Device); } }//}}}
static void DSoundStartCapture(ALCdevice *device) { DSoundCaptureData *pData = device->ExtraData; HRESULT hr; hr = IDirectSoundCaptureBuffer_Start(pData->DSCbuffer, DSCBSTART_LOOPING); if(FAILED(hr)) { ERR("start failed: 0x%08lx\n", hr); aluHandleDisconnect(device); } }
static void context_state_callback2(pa_context *context, void *pdata) //{{{ { ALCdevice *Device = pdata; pulse_data *data = Device->ExtraData; if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); aluHandleDisconnect(Device); } pa_threaded_mainloop_signal(data->loop, 0); }//}}}
static void stream_state_callback2(pa_stream *stream, void *pdata) //{{{ { ALCdevice *Device = pdata; pulse_data *data = Device->ExtraData; if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); aluHandleDisconnect(Device); } pa_threaded_mainloop_signal(data->loop, 0); }//}}}
static void DSoundStopCapture(ALCdevice *device) { DSoundCaptureData *data = device->ExtraData; HRESULT hr; hr = IDirectSoundCaptureBuffer_Stop(data->DSCbuffer); if(FAILED(hr)) { ERR("stop failed: 0x%08lx\n", hr); aluHandleDisconnect(device); } }
static ALuint ALSANoMMapProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; alsa_data *data = (alsa_data*)pDevice->ExtraData; snd_pcm_sframes_t avail; char *WritePtr; while(!data->killNow) { int state = verify_state(data->pcmHandle); if(state < 0) { AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state)); aluHandleDisconnect(pDevice); break; } WritePtr = data->buffer; avail = data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1); aluMixData(pDevice, WritePtr, avail); while(avail > 0) { int ret = psnd_pcm_writei(data->pcmHandle, WritePtr, avail); switch (ret) { case -EAGAIN: continue; case -ESTRPIPE: while((ret=psnd_pcm_resume(data->pcmHandle)) == -EAGAIN) Sleep(1); break; case -EPIPE: break; default: if (ret >= 0) { WritePtr += psnd_pcm_frames_to_bytes(data->pcmHandle, ret); avail -= ret; } break; } if (ret < 0) { ret = psnd_pcm_prepare(data->pcmHandle); if(ret < 0) break; } } } return 0; }
static void alsa_start_capture(ALCdevice *Device) { alsa_data *data = (alsa_data*)Device->ExtraData; int err; err = snd_pcm_start(data->pcmHandle); if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); aluHandleDisconnect(Device); } else data->doCapture = AL_TRUE; }
static ALCuint DSoundAvailableSamples(ALCdevice *pDevice) { DSoundCaptureData *pData = pDevice->ExtraData; DWORD dwRead, dwCursor, dwBufferBytes, dwNumBytes; void *pvAudio1, *pvAudio2; DWORD dwAudioBytes1, dwAudioBytes2; DWORD FrameSize; HRESULT hr; if(!pDevice->Connected) goto done; FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); dwBufferBytes = pData->dwBufferBytes; dwCursor = pData->dwCursor; hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pData->DSCbuffer, NULL, &dwRead); if(SUCCEEDED(hr)) { dwNumBytes = (dwBufferBytes + dwRead - dwCursor) % dwBufferBytes; if(dwNumBytes == 0) goto done; hr = IDirectSoundCaptureBuffer_Lock(pData->DSCbuffer, dwCursor, dwNumBytes, &pvAudio1, &dwAudioBytes1, &pvAudio2, &dwAudioBytes2, 0); } if(SUCCEEDED(hr)) { WriteRingBuffer(pData->pRing, pvAudio1, dwAudioBytes1/FrameSize); if(pvAudio2 != NULL) WriteRingBuffer(pData->pRing, pvAudio2, dwAudioBytes2/FrameSize); hr = IDirectSoundCaptureBuffer_Unlock(pData->DSCbuffer, pvAudio1, dwAudioBytes1, pvAudio2, dwAudioBytes2); pData->dwCursor = (dwCursor + dwAudioBytes1 + dwAudioBytes2) % dwBufferBytes; } if(FAILED(hr)) { ERR("update failed: 0x%08lx\n", hr); aluHandleDisconnect(pDevice); } done: return RingBufferSize(pData->pRing); }
static ALCuint DSoundAvailableSamples(ALCdevice *Device) { DSoundCaptureData *data = Device->ExtraData; DWORD ReadCursor, LastCursor, BufferBytes, NumBytes; VOID *ReadPtr1, *ReadPtr2; DWORD ReadCnt1, ReadCnt2; DWORD FrameSize; HRESULT hr; if(!Device->Connected) goto done; FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); BufferBytes = data->BufferBytes; LastCursor = data->Cursor; hr = IDirectSoundCaptureBuffer_GetCurrentPosition(data->DSCbuffer, NULL, &ReadCursor); if(SUCCEEDED(hr)) { NumBytes = (ReadCursor-LastCursor + BufferBytes) % BufferBytes; if(NumBytes == 0) goto done; hr = IDirectSoundCaptureBuffer_Lock(data->DSCbuffer, LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, &ReadPtr2, &ReadCnt2, 0); } if(SUCCEEDED(hr)) { WriteRingBuffer(data->Ring, ReadPtr1, ReadCnt1/FrameSize); if(ReadPtr2 != NULL) WriteRingBuffer(data->Ring, ReadPtr2, ReadCnt2/FrameSize); hr = IDirectSoundCaptureBuffer_Unlock(data->DSCbuffer, ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); data->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; } if(FAILED(hr)) { ERR("update failed: 0x%08lx\n", hr); aluHandleDisconnect(Device); } done: return RingBufferSize(data->Ring); }
static ALuint ALSANoMMapCaptureProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; alsa_data *data = (alsa_data*)pDevice->ExtraData; snd_pcm_sframes_t avail; while(!data->killNow) { int state = verify_state(data->pcmHandle); if(state < 0) { AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state)); aluHandleDisconnect(pDevice); break; } avail = (snd_pcm_uframes_t)data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1); avail = psnd_pcm_readi(data->pcmHandle, data->buffer, avail); switch(avail) { case -EAGAIN: continue; case -ESTRPIPE: while((avail=psnd_pcm_resume(data->pcmHandle)) == -EAGAIN) Sleep(1); break; case -EPIPE: break; default: if (avail >= 0 && data->doCapture) WriteRingBuffer(data->ring, data->buffer, avail); break; } if(avail < 0) { avail = psnd_pcm_prepare(data->pcmHandle); if(avail < 0) AL_PRINT("prepare error: %s\n", psnd_strerror(avail)); } } return 0; }
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 ALCuint pulse_available_samples(ALCdevice *device) { pulse_data *data = device->ExtraData; size_t readable = data->cap_remain; if(device->Connected) { ssize_t got = pa_stream_readable_size(data->stream); if(got < 0) { ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); aluHandleDisconnect(device); } else if((size_t)got > data->cap_len) readable += got - data->cap_len; } if(data->last_readable < readable) data->last_readable = readable; return data->last_readable / pa_frame_size(&data->spec); }
static int ALCsolarisBackend_mixerProc(void *ptr) { ALCsolarisBackend *self = ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; struct timeval timeout; ALubyte *write_ptr; ALint frame_size; ALint to_write; ssize_t wrote; fd_set wfds; int sret; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); ALCsolarisBackend_lock(self); while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire) != DeviceConnect_Disconnected) { FD_ZERO(&wfds); FD_SET(self->fd, &wfds); timeout.tv_sec = 1; timeout.tv_usec = 0; ALCsolarisBackend_unlock(self); sret = select(self->fd+1, NULL, &wfds, NULL, &timeout); ALCsolarisBackend_lock(self); if(sret < 0) { if(errno == EINTR) continue; ERR("select failed: %s\n", strerror(errno)); aluHandleDisconnect(device, "Failed to wait for playback buffer: %s", strerror(errno)); break; } else if(sret == 0) { WARN("select timeout\n"); continue; } write_ptr = self->mix_data; to_write = self->data_size; aluMixData(device, write_ptr, to_write/frame_size); while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) { wrote = write(self->fd, write_ptr, to_write); if(wrote < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue; ERR("write failed: %s\n", strerror(errno)); aluHandleDisconnect(device, "Failed to write playback samples: %s", strerror(errno)); break; } to_write -= wrote; write_ptr += wrote; } } ALCsolarisBackend_unlock(self); return 0; }
static ALuint ALSAProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; alsa_data *data = (alsa_data*)pDevice->ExtraData; const snd_pcm_channel_area_t *areas = NULL; snd_pcm_sframes_t avail, commitres; snd_pcm_uframes_t offset, frames; char *WritePtr; int err; while(!data->killNow) { int state = verify_state(data->pcmHandle); if(state < 0) { AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state)); aluHandleDisconnect(pDevice); break; } avail = psnd_pcm_avail_update(data->pcmHandle); if(avail < 0) { AL_PRINT("available update failed: %s\n", psnd_strerror(avail)); continue; } // make sure there's frames to process if(avail >= 0 && avail < (snd_pcm_sframes_t)pDevice->UpdateSize) { if(state != SND_PCM_STATE_RUNNING) { err = psnd_pcm_start(data->pcmHandle); if(err < 0) { AL_PRINT("start failed: %s\n", psnd_strerror(err)); continue; } } if(psnd_pcm_wait(data->pcmHandle, 1000) == 0) AL_PRINT("Wait timeout... buffer size too low?\n"); continue; } avail -= avail%pDevice->UpdateSize; // it is possible that contiguous areas are smaller, thus we use a loop while(avail > 0) { frames = avail; err = psnd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames); if(err < 0) { AL_PRINT("mmap begin error: %s\n", psnd_strerror(err)); break; } WritePtr = (char*)areas->addr + (offset * areas->step / 8); aluMixData(pDevice, WritePtr, frames); commitres = psnd_pcm_mmap_commit(data->pcmHandle, offset, frames); if(commitres < 0 || (commitres-frames) != 0) { AL_PRINT("mmap commit error: %s\n", psnd_strerror(commitres >= 0 ? -EPIPE : commitres)); break; } avail -= frames; } } return 0; }
static ALuint WaveProc(ALvoid *ptr) { ALCdevice *Device = (ALCdevice*)ptr; wave_data *data = (wave_data*)Device->ExtraData; ALuint frameSize; ALuint now, start; ALuint64 avail, done; size_t fs; const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 / Device->Frequency / 2; frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); done = 0; start = timeGetTime(); while(!data->killNow && Device->Connected) { now = timeGetTime(); avail = (ALuint64)(now-start) * Device->Frequency / 1000; if(avail < done) { /* Timer wrapped (50 days???). Add the remainder of the cycle to * the available count and reset the number of samples done */ avail += ((ALuint64)1<<32)*Device->Frequency/1000 - done; done = 0; } if(avail-done < Device->UpdateSize) { Sleep(restTime); continue; } while(avail-done >= Device->UpdateSize) { aluMixData(Device, data->buffer, Device->UpdateSize); done += Device->UpdateSize; if(!IS_LITTLE_ENDIAN) { ALuint bytesize = BytesFromDevFmt(Device->FmtType); ALubyte *bytes = data->buffer; ALuint i; if(bytesize == 1) { for(i = 0;i < data->size;i++) fputc(bytes[i], data->f); } else if(bytesize == 2) { for(i = 0;i < data->size;i++) fputc(bytes[i^1], data->f); } else if(bytesize == 4) { for(i = 0;i < data->size;i++) fputc(bytes[i^3], data->f); } } else { fs = fwrite(data->buffer, frameSize, Device->UpdateSize, data->f); fs = fs; } if(ferror(data->f)) { ERR("Error writing to file\n"); ALCdevice_Lock(Device); aluHandleDisconnect(Device); ALCdevice_Unlock(Device); break; } } } return 0; }
static int ALCopenslPlayback_mixerProc(void *arg) { ALCopenslPlayback *self = arg; ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; SLAndroidSimpleBufferQueueItf bufferQueue; ll_ringbuffer_data_t data[2]; SLPlayItf player; SLresult result; size_t padding; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE"); if(SL_RESULT_SUCCESS == result) { result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); } if(SL_RESULT_SUCCESS != result) { ALCopenslPlayback_lock(self); aluHandleDisconnect(device); ALCopenslPlayback_unlock(self); return 1; } /* NOTE: The ringbuffer will be larger than the desired buffer metrics. * Calculate the amount of extra space so we know how much to keep unused. */ padding = ll_ringbuffer_write_space(self->mRing) - device->NumUpdates; ALCopenslPlayback_lock(self); while(ATOMIC_LOAD_SEQ(&self->mKillNow) == AL_FALSE && device->Connected) { size_t todo, len0, len1; if(ll_ringbuffer_write_space(self->mRing) <= padding) { SLuint32 state = 0; result = VCALL(player,GetPlayState)(&state); PRINTERR(result, "player->GetPlayState"); if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING) { result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING); PRINTERR(result, "player->SetPlayState"); } if(SL_RESULT_SUCCESS != result) { aluHandleDisconnect(device); break; } /* NOTE: Unfortunately, there is an unavoidable race condition * here. It's possible for the process() method to run, updating * the read pointer and signaling the condition variable, in * between checking the write size and waiting for the condition * variable here. This will cause alcnd_wait to wait until the * *next* process() invocation signals the condition variable * again. * * However, this should only happen if the mixer is running behind * anyway (as ideally we'll be asleep in alcnd_wait by the time the * process() method is invoked), so this behavior is not completely * unwarranted. It's unfortunate since it'll be wasting time * sleeping that could be used to catch up, but there's no way * around it without blocking in the process() method. */ if(ll_ringbuffer_write_space(self->mRing) <= padding) { alcnd_wait(&self->mCond, &STATIC_CAST(ALCbackend,self)->mMutex); continue; } } ll_ringbuffer_get_write_vector(self->mRing, data); todo = data[0].len+data[1].len - padding; len0 = minu(todo, data[0].len); len1 = minu(todo-len0, data[1].len); aluMixData(device, data[0].buf, len0*device->UpdateSize); for(size_t i = 0;i < len0;i++) { result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize); PRINTERR(result, "bufferQueue->Enqueue"); if(SL_RESULT_SUCCESS == result) ll_ringbuffer_write_advance(self->mRing, 1); data[0].buf += device->UpdateSize*self->mFrameSize; } if(len1 > 0) { aluMixData(device, data[1].buf, len1*device->UpdateSize); for(size_t i = 0;i < len1;i++) { result = VCALL(bufferQueue,Enqueue)(data[1].buf, device->UpdateSize*self->mFrameSize); PRINTERR(result, "bufferQueue->Enqueue"); if(SL_RESULT_SUCCESS == result) ll_ringbuffer_write_advance(self->mRing, 1); data[1].buf += device->UpdateSize*self->mFrameSize; } } } ALCopenslPlayback_unlock(self); return 0; }
static ALuint DSoundPlaybackProc(ALvoid *ptr) { ALCdevice *Device = (ALCdevice*)ptr; DSoundPlaybackData *data = (DSoundPlaybackData*)Device->ExtraData; DSBCAPS DSBCaps; DWORD LastCursor = 0; DWORD PlayCursor; VOID *WritePtr1, *WritePtr2; DWORD WriteCnt1, WriteCnt2; BOOL Playing = FALSE; DWORD FrameSize; DWORD FragSize; DWORD avail; HRESULT err; SetRTPriority(); memset(&DSBCaps, 0, sizeof(DSBCaps)); DSBCaps.dwSize = sizeof(DSBCaps); err = IDirectSoundBuffer_GetCaps(data->Buffer, &DSBCaps); if(FAILED(err)) { ERR("Failed to get buffer caps: 0x%lx\n", err); ALCdevice_Lock(Device); aluHandleDisconnect(Device); ALCdevice_Unlock(Device); return 1; } FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); FragSize = Device->UpdateSize * FrameSize; IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &LastCursor, NULL); while(!data->killNow) { // Get current play cursor IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &PlayCursor, NULL); avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; if(avail < FragSize) { if(!Playing) { err = IDirectSoundBuffer_Play(data->Buffer, 0, 0, DSBPLAY_LOOPING); if(FAILED(err)) { ERR("Failed to play buffer: 0x%lx\n", err); ALCdevice_Lock(Device); aluHandleDisconnect(Device); ALCdevice_Unlock(Device); return 1; } Playing = TRUE; } avail = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE); if(avail != WAIT_OBJECT_0) ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); continue; } avail -= avail%FragSize; // Lock output buffer WriteCnt1 = 0; WriteCnt2 = 0; err = IDirectSoundBuffer_Lock(data->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); // If the buffer is lost, restore it and lock if(err == DSERR_BUFFERLOST) { WARN("Buffer lost, restoring...\n"); err = IDirectSoundBuffer_Restore(data->Buffer); if(SUCCEEDED(err)) { Playing = FALSE; LastCursor = 0; err = IDirectSoundBuffer_Lock(data->Buffer, 0, DSBCaps.dwBufferBytes, &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(Device, WritePtr1, WriteCnt1/FrameSize); aluMixData(Device, WritePtr2, WriteCnt2/FrameSize); // Unlock output buffer only when successfully locked IDirectSoundBuffer_Unlock(data->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); } else { ERR("Buffer lock error: %#lx\n", err); ALCdevice_Lock(Device); aluHandleDisconnect(Device); ALCdevice_Unlock(Device); return 1; } // Update old write cursor location LastCursor += WriteCnt1+WriteCnt2; LastCursor %= DSBCaps.dwBufferBytes; } return 0; }
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 ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) { qsa_data* data=(qsa_data*)device->ExtraData; char* read_ptr; snd_pcm_channel_status_t status; fd_set rfds; int selectret; struct timeval timeout; int bytes_read; ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType); ALint len=samples*frame_size; int rstatus; read_ptr=buffer; while (len>0) { FD_ZERO(&rfds); FD_SET(data->audio_fd, &rfds); timeout.tv_sec=2; timeout.tv_usec=0; /* Select also works like time slice to OS */ bytes_read=0; selectret=select(data->audio_fd+1, &rfds, NULL, NULL, &timeout); switch (selectret) { case -1: aluHandleDisconnect(device); return ALC_INVALID_DEVICE; case 0: break; default: if (FD_ISSET(data->audio_fd, &rfds)) { bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len); break; } break; } if (bytes_read<=0) { if ((errno==EAGAIN) || (errno==EWOULDBLOCK)) { continue; } memset(&status, 0, sizeof (status)); status.channel=SND_PCM_CHANNEL_CAPTURE; snd_pcm_plugin_status(data->pcmHandle, &status); /* we need to reinitialize the sound channel if we've overrun the buffer */ if ((status.status==SND_PCM_STATUS_OVERRUN) || (status.status==SND_PCM_STATUS_READY)) { if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) { ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); aluHandleDisconnect(device); return ALC_INVALID_DEVICE; } snd_pcm_capture_go(data->pcmHandle); } } else { read_ptr+=bytes_read; len-=bytes_read; } } return ALC_NO_ERROR; }
FORCE_ALIGN static int qsa_proc_playback(void* ptr) { ALCdevice* device=(ALCdevice*)ptr; qsa_data* data=(qsa_data*)device->ExtraData; char* write_ptr; int avail; snd_pcm_channel_status_t status; struct sched_param param; fd_set wfds; int selectret; struct timeval timeout; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); /* Increase default 10 priority to 11 to avoid jerky sound */ SchedGet(0, 0, ¶m); param.sched_priority=param.sched_curpriority+1; SchedSet(0, 0, SCHED_NOCHANGE, ¶m); ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType); while (!data->killNow) { ALint len=data->size; write_ptr=data->buffer; avail=len/frame_size; aluMixData(device, write_ptr, avail); while (len>0 && !data->killNow) { FD_ZERO(&wfds); FD_SET(data->audio_fd, &wfds); timeout.tv_sec=2; timeout.tv_usec=0; /* Select also works like time slice to OS */ selectret=select(data->audio_fd+1, NULL, &wfds, NULL, &timeout); switch (selectret) { case -1: aluHandleDisconnect(device); return 1; case 0: break; default: if (FD_ISSET(data->audio_fd, &wfds)) { break; } break; } int wrote=snd_pcm_plugin_write(data->pcmHandle, write_ptr, len); if (wrote<=0) { if ((errno==EAGAIN) || (errno==EWOULDBLOCK)) { continue; } memset(&status, 0, sizeof (status)); status.channel=SND_PCM_CHANNEL_PLAYBACK; snd_pcm_plugin_status(data->pcmHandle, &status); /* we need to reinitialize the sound channel if we've underrun the buffer */ if ((status.status==SND_PCM_STATUS_UNDERRUN) || (status.status==SND_PCM_STATUS_READY)) { if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0) { aluHandleDisconnect(device); break; } } } else { write_ptr+=wrote; len-=wrote; } } } return 0; }
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 ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples) { alsa_data *data = (alsa_data*)Device->ExtraData; if(data->ring) { ReadRingBuffer(data->ring, Buffer, Samples); return ALC_NO_ERROR; } data->last_avail -= Samples; while(Device->Connected && Samples > 0) { snd_pcm_sframes_t amt = 0; if(data->size > 0) { /* First get any data stored from the last stop */ amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size); if((snd_pcm_uframes_t)amt > Samples) amt = Samples; amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt); memmove(Buffer, data->buffer, amt); if(data->size > amt) { memmove(data->buffer, data->buffer+amt, data->size - amt); data->size -= amt; } else { free(data->buffer); data->buffer = NULL; data->size = 0; } amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt); } else if(data->doCapture) amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0) { amt = snd_pcm_start(data->pcmHandle); if(amt >= 0) amt = snd_pcm_avail_update(data->pcmHandle); } if(amt < 0) { ERR("restore error: %s\n", snd_strerror(amt)); aluHandleDisconnect(Device); break; } /* If the amount available is less than what's asked, we lost it * during recovery. So just give silence instead. */ if((snd_pcm_uframes_t)amt < Samples) break; continue; } Buffer = (ALbyte*)Buffer + amt; Samples -= amt; } if(Samples > 0) memset(Buffer, ((Device->FmtType == DevFmtUByte) ? 0x80 : 0), snd_pcm_frames_to_bytes(data->pcmHandle, Samples)); return ALC_NO_ERROR; }
static ALuint WaveProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; wave_data *data = (wave_data*)pDevice->ExtraData; ALuint frameSize; ALuint now, start; ALuint64 avail, done; size_t fs; union { short s; char b[sizeof(short)]; } uSB; const ALuint restTime = (ALuint64)pDevice->UpdateSize * 1000 / pDevice->Frequency / 2; uSB.s = 1; frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); done = 0; start = timeGetTime(); while(!data->killNow && pDevice->Connected) { now = timeGetTime(); avail = (ALuint64)(now-start) * pDevice->Frequency / 1000; if(avail < done) { /* Timer wrapped. Add the remainder of the cycle to the available * count and reset the number of samples done */ avail += (ALuint64)0xFFFFFFFFu*pDevice->Frequency/1000 - done; done = 0; } if(avail-done < pDevice->UpdateSize) { Sleep(restTime); continue; } while(avail-done >= pDevice->UpdateSize) { aluMixData(pDevice, data->buffer, pDevice->UpdateSize); done += pDevice->UpdateSize; if(uSB.b[0] != 1) { ALuint bytesize = BytesFromDevFmt(pDevice->FmtType); ALubyte *bytes = data->buffer; ALuint i; if(bytesize == 1) { for(i = 0;i < data->size;i++) fputc(bytes[i], data->f); } else if(bytesize == 2) { for(i = 0;i < data->size;i++) fputc(bytes[i^1], data->f); } else if(bytesize == 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; } } } return 0; }