size_t write(void const *src, size_t len) { size_t const avail = write_avail(); if (avail == 0) return 0; size_t const limit_len = len > avail ? avail : len; size_t const total = wpos + len; size_t first, rest; if (total > CAPACITY) { first = CAPACITY - wpos; rest = total % CAPACITY; } else { first = limit_len; rest = 0; } Genode::memcpy(&_data[wpos], src, first); wpos = (wpos + first) % CAPACITY; if (rest) { Genode::memcpy(&_data[wpos], ((char const*)src) + first, rest); wpos = (wpos + rest) % CAPACITY; } return limit_len; }
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); }
size_t FifoBuffer<T, Container>::write(const T* in, size_t num_elems) { size_t write_amount = num_elems > write_avail() ? write_avail() : num_elems; m_container.insert(m_container.end(), in, in + write_amount); return write_amount; }