FORCE_ALIGN static int PlaybackThreadProc(void *arg) { ALCdevice *Device = (ALCdevice*)arg; WinMMData *data = Device->ExtraData; WAVEHDR *WaveHdr; MSG msg; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); while(GetMessage(&msg, NULL, 0, 0)) { if(msg.message != WOM_DONE) continue; if(data->killNow) { if(ReadRef(&data->WaveBuffersCommitted) == 0) break; continue; } WaveHdr = ((WAVEHDR*)msg.lParam); aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength / data->Format.nBlockAlign); // Send buffer back to play more data waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR)); IncrementRef(&data->WaveBuffersCommitted); } return 0; }
static int CaptureThreadProc(void *arg) { ALCdevice *Device = (ALCdevice*)arg; WinMMData *data = Device->ExtraData; WAVEHDR *WaveHdr; MSG msg; althrd_setname(althrd_current(), "alsoft-record"); while(GetMessage(&msg, NULL, 0, 0)) { if(msg.message != WIM_DATA) continue; /* Don't wait for other buffers to finish before quitting. We're * closing so we don't need them. */ if(data->killNow) break; WaveHdr = ((WAVEHDR*)msg.lParam); WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData, WaveHdr->dwBytesRecorded/data->Format.nBlockAlign); // Send buffer back to capture more data waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR)); IncrementRef(&data->WaveBuffersCommitted); } return 0; }
static int ALCwinmmCapture_captureProc(void *arg) { ALCwinmmCapture *self = arg; WAVEHDR *WaveHdr; MSG msg; althrd_setname(althrd_current(), RECORD_THREAD_NAME); while(GetMessage(&msg, NULL, 0, 0)) { if(msg.message != WIM_DATA) continue; /* Don't wait for other buffers to finish before quitting. We're * closing so we don't need them. */ if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) break; WaveHdr = ((WAVEHDR*)msg.lParam); ll_ringbuffer_write(self->Ring, WaveHdr->lpData, WaveHdr->dwBytesRecorded / self->Format.nBlockAlign ); // Send buffer back to capture more data waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR)); IncrementRef(&self->WaveBuffersCommitted); } return 0; }
FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) { ALCwinmmPlayback *self = arg; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; WAVEHDR *WaveHdr; MSG msg; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); while(GetMessage(&msg, NULL, 0, 0)) { if(msg.message != WOM_DONE) continue; if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) { if(ReadRef(&self->WaveBuffersCommitted) == 0) break; continue; } WaveHdr = ((WAVEHDR*)msg.lParam); ALCwinmmPlayback_lock(self); aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength / self->Format.nBlockAlign); ALCwinmmPlayback_unlock(self); // Send buffer back to play more data waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR)); IncrementRef(&self->WaveBuffersCommitted); } return 0; }
static int ALCnullBackend_mixerProc(void *ptr) { ALCnullBackend *self = (ALCnullBackend*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; struct timespec now, start; ALuint64 avail, done; const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / device->Frequency / 2); SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); done = 0; if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) { ERR("Failed to get starting time\n"); return 1; } while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) { ERR("Failed to get current time\n"); return 1; } avail = (now.tv_sec - start.tv_sec) * device->Frequency; avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; if(avail < done) { /* Oops, time skipped backwards. Reset the number of samples done * with one update available since we (likely) just came back from * sleeping. */ done = avail - device->UpdateSize; } if(avail-done < device->UpdateSize) al_nssleep(restTime); else while(avail-done >= device->UpdateSize) { ALCnullBackend_lock(self); aluMixData(device, NULL, device->UpdateSize); ALCnullBackend_unlock(self); done += device->UpdateSize; } } return 0; }
void althrd_setname(althrd_t thr, const char *name) { #if defined(HAVE_PTHREAD_SETNAME_NP) #if defined(__GNUC__) pthread_setname_np(thr, name); #elif defined(__APPLE__) if(althrd_equal(thr, althrd_current()) pthread_setname_np(name); #endif #elif defined(HAVE_PTHREAD_SET_NAME_NP) pthread_set_name_np(thr, name); #else (void)thr; (void)name; #endif }
void althrd_setname(althrd_t thr, const char *name) { #if defined(HAVE_PTHREAD_SETNAME_NP) #if defined(PTHREAD_SETNAME_NP_ONE_PARAM) if(althrd_equal(thr, althrd_current())) pthread_setname_np(name); #elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS) pthread_setname_np(thr, "%s", (void*)name); #else pthread_setname_np(thr, name); #endif #elif defined(HAVE_PTHREAD_SET_NAME_NP) pthread_set_name_np(thr, name); #else (void)thr; (void)name; #endif }
static int sndio_proc(void *ptr) { ALCdevice *device = ptr; sndio_data *data = device->ExtraData; ALsizei frameSize; size_t wrote; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); 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"); ALCdevice_Lock(device); aluHandleDisconnect(device); ALCdevice_Unlock(device); break; } len -= wrote; WritePtr += wrote; } } return 0; }
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 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 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; }