static void adapter_thread(void *data) { uint8_t send_command_buf[4096]; struct libusb_adapter *adapter = (struct libusb_adapter*)data; libusb_hid_t *hid = adapter ? adapter->hid : NULL; if (!adapter) return; while (!adapter->quitting) { size_t send_command_size; int tmp; int report_number; int size = 0; slock_lock(adapter->send_control_lock); if (fifo_read_avail(adapter->send_control_buffer) >= sizeof(send_command_size)) { fifo_read(adapter->send_control_buffer, &send_command_size, sizeof(send_command_size)); if (fifo_read_avail(adapter->send_control_buffer) >= sizeof(send_command_size)) { fifo_read(adapter->send_control_buffer, send_command_buf, send_command_size); libusb_interrupt_transfer(adapter->handle, adapter->endpoint_out, send_command_buf, send_command_size, &tmp, 1000); } } slock_unlock(adapter->send_control_lock); libusb_interrupt_transfer(adapter->handle, adapter->endpoint_in, &adapter->data[1], adapter->endpoint_in_max_size, &size, 1000); if (adapter && hid && hid->slots && size) pad_connection_packet(&hid->slots[adapter->slot], adapter->slot, adapter->data, size+1); } }
static void ffmpeg_flush_buffers(ffmpeg_t *handle) { bool did_work; void *video_buf = av_malloc(2 * handle->params.fb_width * handle->params.fb_height * handle->video.pix_size); size_t audio_buf_size = handle->config.audio_enable ? (handle->audio.codec->frame_size * handle->params.channels * sizeof(int16_t)) : 0; void *audio_buf = NULL; if (audio_buf_size) audio_buf = av_malloc(audio_buf_size); /* Try pushing data in an interleaving pattern to * ease the work of the muxer a bit. */ do { struct ffemu_video_data attr_buf; did_work = false; if (handle->config.audio_enable) { if (fifo_read_avail(handle->audio_fifo) >= audio_buf_size) { struct ffemu_audio_data aud = {0}; fifo_read(handle->audio_fifo, audio_buf, audio_buf_size); aud.frames = handle->audio.codec->frame_size; aud.data = audio_buf; ffmpeg_push_audio_thread(handle, &aud, true); did_work = true; } } if (fifo_read_avail(handle->attr_fifo) >= sizeof(attr_buf)) { fifo_read(handle->attr_fifo, &attr_buf, sizeof(attr_buf)); fifo_read(handle->video_fifo, video_buf, attr_buf.height * attr_buf.pitch); attr_buf.data = video_buf; ffmpeg_push_video_thread(handle, &attr_buf); did_work = true; } } while (did_work); /* Flush out last audio. */ if (handle->config.audio_enable) ffmpeg_flush_audio(handle, audio_buf, audio_buf_size); /* Flush out last video. */ ffmpeg_flush_video(handle); av_free(video_buf); av_free(audio_buf); }
static void ffmpeg_flush_audio(ffmpeg_t *handle, void *audio_buf, size_t audio_buf_size) { size_t avail = fifo_read_avail(handle->audio_fifo); if (avail) { struct ffemu_audio_data aud = {0}; fifo_read(handle->audio_fifo, audio_buf, avail); aud.frames = avail / (sizeof(int16_t) * handle->params.channels); aud.data = audio_buf; ffmpeg_push_audio_thread(handle, &aud, false); } for (;;) { AVPacket pkt; if (!encode_audio(handle, &pkt, true) || !pkt.size || av_interleaved_write_frame(handle->muxer.ctx, &pkt) < 0) break; } }
static uint32_t resampler_cb(void *userdata, float **data) { audioport_t *port = userdata; uint32_t has_read = 0; if (port->sample_cb) has_read = port->sample_cb(port->re_pull_buffer, CELL_AUDIO_BLOCK_SAMPLES * port->channels * sizeof(int16_t), port->userdata); else { has_read = CELL_AUDIO_BLOCK_SAMPLES * port->channels; sys_lwmutex_lock(&port->lock, SYS_NO_TIMEOUT); uint32_t avail = fifo_read_avail(port->buffer); if (avail < CELL_AUDIO_BLOCK_SAMPLES * port->channels * sizeof(int16_t)) has_read = avail / sizeof(int16_t); fifo_read(port->buffer, port->re_pull_buffer, has_read * sizeof(int16_t)); sys_lwmutex_unlock(&port->lock); sys_lwcond_signal(&port->cond); } if (has_read < CELL_AUDIO_BLOCK_SAMPLES * port->channels * 2) memset(port->re_pull_buffer + has_read, 0, (CELL_AUDIO_BLOCK_SAMPLES * port->channels - has_read) * sizeof(int16_t)); audio_convert_s16_to_float_altivec(port->re_buffer, port->re_pull_buffer, CELL_AUDIO_BLOCK_SAMPLES * port->channels); *data = port->re_buffer; return CELL_AUDIO_BLOCK_SAMPLES; }
static void pull_event_loop(audioport_t *port, sys_event_queue_t id) { sys_event_t event; int16_t *in_buf = memalign(128, CELL_AUDIO_BLOCK_SAMPLES * port->channels * sizeof(int16_t)); float *conv_buf = memalign(128, CELL_AUDIO_BLOCK_SAMPLES * port->channels * sizeof(float)); while (!port->quit_thread) { uint32_t has_read = 0; if (port->sample_cb) has_read = port->sample_cb(in_buf, CELL_AUDIO_BLOCK_SAMPLES * port->channels, port->userdata); else { has_read = CELL_AUDIO_BLOCK_SAMPLES * port->channels; sys_lwmutex_lock(&port->lock, SYS_NO_TIMEOUT); uint32_t avail = fifo_read_avail(port->buffer); if (avail < CELL_AUDIO_BLOCK_SAMPLES * port->channels * sizeof(int16_t)) has_read = avail / sizeof(int16_t); fifo_read(port->buffer, in_buf, has_read * sizeof(int16_t)); sys_lwmutex_unlock(&port->lock); } if (has_read < CELL_AUDIO_BLOCK_SAMPLES * port->channels) memset(in_buf + has_read, 0, (CELL_AUDIO_BLOCK_SAMPLES * port->channels - has_read) * sizeof(int16_t)); resampler_int16_t_to_float(conv_buf, in_buf, CELL_AUDIO_BLOCK_SAMPLES * port->channels); sys_event_queue_receive(id, &event, SYS_NO_TIMEOUT); cellAudioAddData(port->audio_port, conv_buf, CELL_AUDIO_BLOCK_SAMPLES, 1.0); pthread_cond_signal(&port->cond); } free(conv_buf); }
static void event_loop(uint64_t data) #endif { float out_tmp[CELL_AUDIO_BLOCK_SAMPLES * AUDIO_CHANNELS] __attribute__((aligned(16))); sys_event_queue_t id; sys_ipc_key_t key; sys_event_t event; ps3_audio_t *aud = data; cellAudioCreateNotifyEventQueue(&id, &key); cellAudioSetNotifyEventQueue(key); while (!aud->quit_thread) { sys_event_queue_receive(id, &event, SYS_NO_TIMEOUT); sys_lwmutex_lock(&aud->lock, SYS_NO_TIMEOUT); if (fifo_read_avail(aud->buffer) >= sizeof(out_tmp)) fifo_read(aud->buffer, out_tmp, sizeof(out_tmp)); else memset(out_tmp, 0, sizeof(out_tmp)); sys_lwmutex_unlock(&aud->lock); sys_lwcond_signal(&aud->cond); cellAudioAddData(aud->audio_port, out_tmp, CELL_AUDIO_BLOCK_SAMPLES, 1.0); } cellAudioRemoveNotifyEventQueue(key); sys_ppu_thread_exit(0); }
static OSStatus audio_write_cb(void *userdata, AudioUnitRenderActionFlags *action_flags, const AudioTimeStamp *time_stamp, UInt32 bus_number, UInt32 number_frames, AudioBufferList *io_data) { coreaudio_t *dev = (coreaudio_t*)userdata; (void)time_stamp; (void)bus_number; (void)number_frames; if (!io_data) return noErr; if (io_data->mNumberBuffers != 1) return noErr; unsigned write_avail = io_data->mBuffers[0].mDataByteSize; void *outbuf = io_data->mBuffers[0].mData; pthread_mutex_lock(&dev->lock); if (fifo_read_avail(dev->buffer) < write_avail) { *action_flags = kAudioUnitRenderAction_OutputIsSilence; memset(outbuf, 0, write_avail); // Seems to be needed. pthread_mutex_unlock(&dev->lock); pthread_cond_signal(&dev->cond); // Technically possible to deadlock without. return noErr; } fifo_read(dev->buffer, outbuf, write_avail); pthread_mutex_unlock(&dev->lock); pthread_cond_signal(&dev->cond); return noErr; }
static void ffemu_flush_buffers(ffemu_t *handle) { void *video_buf = av_malloc(2 * handle->params.fb_width * handle->params.fb_height * handle->video.pix_size); size_t audio_buf_size = 512 * handle->params.channels * sizeof(int16_t); int16_t *audio_buf = (int16_t*)av_malloc(audio_buf_size); // Try pushing data in an interleaving pattern to ease the work of the muxer a bit. bool did_work; do { did_work = false; if (fifo_read_avail(handle->audio_fifo) >= audio_buf_size) { fifo_read(handle->audio_fifo, audio_buf, audio_buf_size); struct ffemu_audio_data aud = {0}; aud.frames = 512; aud.data = audio_buf; ffemu_push_audio_thread(handle, &aud, true); did_work = true; } struct ffemu_video_data attr_buf; if (fifo_read_avail(handle->attr_fifo) >= sizeof(attr_buf)) { fifo_read(handle->attr_fifo, &attr_buf, sizeof(attr_buf)); fifo_read(handle->video_fifo, video_buf, attr_buf.height * attr_buf.pitch); attr_buf.data = video_buf; ffemu_push_video_thread(handle, &attr_buf); did_work = true; } } while (did_work); // Flush out last audio. ffemu_flush_audio(handle, audio_buf, audio_buf_size); // Flush out last video. ffemu_flush_video(handle); av_free(video_buf); av_free(audio_buf); }
static void adapter_thread(void *data) { uint8_t __attribute__((aligned(32))) send_command_buf[4096]; struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)data; wiiusb_hid_t *hid = adapter ? adapter->hid : NULL; if (!adapter) return; while (!adapter->quitting) { size_t send_command_size; int tmp; int report_number; int size = 0; (void)tmp; (void)report_number; slock_lock(adapter->send_control_lock); if (fifo_read_avail(adapter->send_control_buffer) >= sizeof(send_command_size)) { fifo_read(adapter->send_control_buffer, &send_command_size, sizeof(send_command_size)); if (fifo_read_avail(adapter->send_control_buffer) >= sizeof(send_command_size)) { fifo_read(adapter->send_control_buffer, send_command_buf, send_command_size); USB_WriteIntrMsg(adapter->handle, adapter->endpoint_out, send_command_size, send_command_buf); } } slock_unlock(adapter->send_control_lock); size = USB_ReadIntrMsg(adapter->handle, adapter->endpoint_in, adapter->endpoint_in_max_size, &adapter->data[0]); /* RARCH_LOG("%p USB_ReadIntrMsg(%i, %i, %i, %p): %i\n", &adapter->data[0], adapter->handle, adapter->endpoint_in, adapter->endpoint_in_max_size, &adapter->data[0], size); */ //RARCH_LOG("%03i %03i %03i %03i\n", adapter->data[0], adapter->data[1], adapter->data[2], adapter->data[3], adapter->data[4]); //memmove(&adapter->data[1], &adapter->data[0], 2048); if (adapter && hid && hid->slots && size) pad_connection_packet(&hid->slots[adapter->slot], adapter->slot, adapter->data - 1, size+1); } }
static void alsa_worker_thread(void *data) { alsa_thread_t *alsa = (alsa_thread_t*)data; uint8_t *buf = (uint8_t *)calloc(1, alsa->period_size); if (!buf) { RARCH_ERR("failed to allocate audio buffer"); goto end; } while (!alsa->thread_dead) { size_t avail; size_t fifo_size; snd_pcm_sframes_t frames; slock_lock(alsa->fifo_lock); avail = fifo_read_avail(alsa->buffer); fifo_size = MIN(alsa->period_size, avail); fifo_read(alsa->buffer, buf, fifo_size); scond_signal(alsa->cond); slock_unlock(alsa->fifo_lock); /* If underrun, fill rest with silence. */ memset(buf + fifo_size, 0, alsa->period_size - fifo_size); frames = snd_pcm_writei(alsa->pcm, buf, alsa->period_frames); if (frames == -EPIPE || frames == -EINTR || frames == -ESTRPIPE) { if (snd_pcm_recover(alsa->pcm, frames, 1) < 0) { RARCH_ERR("[ALSA]: (#2) Failed to recover from error (%s)\n", snd_strerror(frames)); break; } continue; } else if (frames < 0) { RARCH_ERR("[ALSA]: Unknown error occurred (%s).\n", snd_strerror(frames)); break; } } end: slock_lock(alsa->cond_lock); alsa->thread_dead = true; scond_signal(alsa->cond); slock_unlock(alsa->cond_lock); free(buf); }
static ssize_t audio_cb(void *data, size_t bytes, void *userdata) { rsd_t *rsd = (rsd_t*)userdata; size_t avail = fifo_read_avail(rsd->buffer); size_t write_size = bytes > avail ? avail : bytes; fifo_read(rsd->buffer, data, write_size); scond_signal(rsd->cond); return write_size; }
static void sdl_audio_cb(void *data, Uint8 *stream, int len) { sdl_audio_t *sdl = (sdl_audio_t*)data; size_t avail = fifo_read_avail(sdl->buffer); size_t write_size = len > (int)avail ? avail : len; fifo_read(sdl->buffer, stream, write_size); scond_signal(sdl->cond); // If underrun, fill rest with silence. memset(stream + write_size, 0, len - write_size); }
static void ffemu_thread(void *data) { ffemu_t *ff = (ffemu_t*)data; // For some reason, FFmpeg has a tendency to crash if we don't overallocate a bit. :s void *video_buf = av_malloc(2 * ff->params.fb_width * ff->params.fb_height * ff->video.pix_size); assert(video_buf); size_t audio_buf_size = 512 * ff->params.channels * sizeof(int16_t); int16_t *audio_buf = (int16_t*)av_malloc(audio_buf_size); assert(audio_buf); while (ff->alive) { struct ffemu_video_data attr_buf; bool avail_video = false; bool avail_audio = false; slock_lock(ff->lock); if (fifo_read_avail(ff->attr_fifo) >= sizeof(attr_buf)) avail_video = true; if (fifo_read_avail(ff->audio_fifo) >= audio_buf_size) avail_audio = true; slock_unlock(ff->lock); if (!avail_video && !avail_audio) { slock_lock(ff->cond_lock); if (ff->can_sleep) { ff->can_sleep = false; scond_wait(ff->cond, ff->cond_lock); ff->can_sleep = true; } else scond_signal(ff->cond); slock_unlock(ff->cond_lock); } if (avail_video) { slock_lock(ff->lock); fifo_read(ff->attr_fifo, &attr_buf, sizeof(attr_buf)); fifo_read(ff->video_fifo, video_buf, attr_buf.height * attr_buf.pitch); slock_unlock(ff->lock); scond_signal(ff->cond); attr_buf.data = video_buf; ffemu_push_video_thread(ff, &attr_buf); } if (avail_audio) { slock_lock(ff->lock); fifo_read(ff->audio_fifo, audio_buf, audio_buf_size); slock_unlock(ff->lock); scond_signal(ff->cond); struct ffemu_audio_data aud = {0}; aud.frames = 512; aud.data = audio_buf; ffemu_push_audio_thread(ff, &aud, true); } } av_free(video_buf); av_free(audio_buf); }
static void dsound_thread(void *data) { DWORD write_ptr; dsound_t *ds = (dsound_t*)data; SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); get_positions(ds, NULL, &write_ptr); write_ptr = (write_ptr + ds->buffer_size / 2) % ds->buffer_size; while (ds->thread_alive) { struct audio_lock region; DWORD read_ptr, avail, fifo_avail; get_positions(ds, &read_ptr, NULL); avail = write_avail(read_ptr, write_ptr, ds->buffer_size); EnterCriticalSection(&ds->crit); fifo_avail = fifo_read_avail(ds->buffer); LeaveCriticalSection(&ds->crit); if (avail < CHUNK_SIZE || ((fifo_avail < CHUNK_SIZE) && (avail < ds->buffer_size / 2))) { /* No space to write, or we don't have data in our fifo, * but we can wait some time before it underruns ... */ /* We could opt for using the notification interface, * but it is not guaranteed to work, so use high * priority sleeping patterns. */ retro_sleep(1); continue; } if (!grab_region(ds, write_ptr, ®ion)) { ds->thread_alive = false; SetEvent(ds->event); break; } if (fifo_avail < CHUNK_SIZE) { /* Got space to write, but nothing in FIFO (underrun), * fill block with silence. */ memset(region.chunk1, 0, region.size1); memset(region.chunk2, 0, region.size2); release_region(ds, ®ion); write_ptr = (write_ptr + region.size1 + region.size2) % ds->buffer_size; } else { /* All is good. Pull from it and notify FIFO. */ EnterCriticalSection(&ds->crit); if (region.chunk1) fifo_read(ds->buffer, region.chunk1, region.size1); if (region.chunk2) fifo_read(ds->buffer, region.chunk2, region.size2); LeaveCriticalSection(&ds->crit); release_region(ds, ®ion); write_ptr = (write_ptr + region.size1 + region.size2) % ds->buffer_size; SetEvent(ds->event); } } ExitThread(0); }
static void ffmpeg_thread(void *data) { size_t audio_buf_size; void *audio_buf = NULL; ffmpeg_t *ff = (ffmpeg_t*)data; /* For some reason, FFmpeg has a tendency to crash * if we don't overallocate a bit. */ void *video_buf = av_malloc(2 * ff->params.fb_width * ff->params.fb_height * ff->video.pix_size); retro_assert(video_buf); audio_buf_size = ff->config.audio_enable ? (ff->audio.codec->frame_size * ff->params.channels * sizeof(int16_t)) : 0; audio_buf = audio_buf_size ? av_malloc(audio_buf_size) : NULL; while (ff->alive) { struct ffemu_video_data attr_buf; bool avail_video = false; bool avail_audio = false; slock_lock(ff->lock); if (fifo_read_avail(ff->attr_fifo) >= sizeof(attr_buf)) avail_video = true; if (ff->config.audio_enable) if (fifo_read_avail(ff->audio_fifo) >= audio_buf_size) avail_audio = true; slock_unlock(ff->lock); if (!avail_video && !avail_audio) { slock_lock(ff->cond_lock); if (ff->can_sleep) { ff->can_sleep = false; scond_wait(ff->cond, ff->cond_lock); ff->can_sleep = true; } else scond_signal(ff->cond); slock_unlock(ff->cond_lock); } if (avail_video && video_buf) { slock_lock(ff->lock); fifo_read(ff->attr_fifo, &attr_buf, sizeof(attr_buf)); fifo_read(ff->video_fifo, video_buf, attr_buf.height * attr_buf.pitch); slock_unlock(ff->lock); scond_signal(ff->cond); attr_buf.data = video_buf; ffmpeg_push_video_thread(ff, &attr_buf); } if (avail_audio && audio_buf) { struct ffemu_audio_data aud = {0}; slock_lock(ff->lock); fifo_read(ff->audio_fifo, audio_buf, audio_buf_size); slock_unlock(ff->lock); scond_signal(ff->cond); aud.frames = ff->audio.codec->frame_size; aud.data = audio_buf; ffmpeg_push_audio_thread(ff, &aud, true); } } av_free(video_buf); av_free(audio_buf); }