static size_t ogg_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, size_t buf_size) { AL_OV_DATA *extra = (AL_OV_DATA *) stream->extra; #ifdef ALLEGRO_LITTLE_ENDIAN const int endian = 0; /* 0 for Little-Endian, 1 for Big-Endian */ #else const int endian = 1; /* 0 for Little-Endian, 1 for Big-Endian */ #endif const int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ const int signedness = 1; /* 0 for unsigned, 1 for signed */ unsigned long pos = 0; int read_length = buf_size; #if !defined(ALLEGRO_GP2XWIZ) && !defined(ALLEGRO_IPHONE) double ctime = ov_time_tell(extra->vf); #else double ctime = ov_time_tell(extra->vf)/1000.0; #endif double rate = extra->vi->rate; double btime = ((double)buf_size / (double)word_size) / rate; if (stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) { if (ctime + btime > extra->loop_end) { read_length = (extra->loop_end - ctime) * rate * (double)word_size; if (read_length < 0) return 0; read_length += read_length % word_size; } } while (pos < (unsigned long)read_length) { #if !defined(ALLEGRO_GP2XWIZ) && !defined(ALLEGRO_IPHONE) unsigned long read = ov_read(extra->vf, (char *)data + pos, read_length - pos, endian, word_size, signedness, &extra->bitstream); #else (void)endian; (void)signedness; unsigned long read = ov_read(extra->vf, (char *)data + pos, read_length - pos, &extra->bitstream); #endif pos += read; /* If nothing read then now to silence from here to the end. */ if (read == 0) { int silence = _al_kcm_get_silence(stream->spl.spl_data.depth); memset((char *)data + pos, silence, buf_size - pos); /* return the number of usefull byes written */ return pos; } } return pos; }
/* Custom routine which runs in another thread to periodically check if DirectSound wants more data for a stream */ static void* _dsound_update(ALLEGRO_THREAD *self, void *arg) { ALLEGRO_VOICE *voice = (ALLEGRO_VOICE *)arg; ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA*)voice->extra; const int bytes_per_sample = ex_data->bits_per_sample / 8; DWORD play_cursor = 0; DWORD write_cursor; DWORD saved_play_cursor = 0; unsigned int samples; LPVOID ptr1, ptr2; DWORD block1_bytes, block2_bytes; unsigned char *data; HRESULT hr; (void)self; unsigned char *silence = (unsigned char *)al_malloc(buffer_size); int silence_value = _al_kcm_get_silence(voice->depth); memset(silence, silence_value, buffer_size); /* Fill buffer */ hr = ex_data->ds8_buffer->Lock(0, buffer_size, &ptr1, &block1_bytes, &ptr2, &block2_bytes, DSBLOCK_ENTIREBUFFER); if (!FAILED(hr)) { samples = buffer_size / bytes_per_sample / ex_data->channels; data = (unsigned char *) _al_voice_update(voice, &samples); memcpy(ptr1, data, block1_bytes); memcpy(ptr2, data + block1_bytes, block2_bytes); ex_data->ds8_buffer->Unlock(ptr1, block1_bytes, ptr2, block2_bytes); } ex_data->ds8_buffer->Play(0, 0, DSBPLAY_LOOPING); do { if (!_dsound_voice_is_playing(voice)) { ex_data->ds8_buffer->Play(0, 0, DSBPLAY_LOOPING); } ex_data->ds8_buffer->GetCurrentPosition(&play_cursor, &write_cursor); /* We try to fill the gap between the saved_play_cursor and the * play_cursor. */ int d = play_cursor - saved_play_cursor; if (d < 0) d += buffer_size; /* Don't fill small gaps. Let it accumulate to amortise the cost of * mixing the samples and locking/unlocking the buffer. */ if (d < MIN_FILL) { al_rest(0.005); continue; } /* Don't generate too many samples at once. The buffer may underrun * while we wait for _al_voice_update to complete. */ samples = d / bytes_per_sample / ex_data->channels; if (samples > MAX_FILL) { samples = MAX_FILL; } /* Generate the samples. */ data = (unsigned char *) _al_voice_update(voice, &samples); if (data == NULL) { data = silence; } hr = ex_data->ds8_buffer->Lock(saved_play_cursor, samples * bytes_per_sample * ex_data->channels, &ptr1, &block1_bytes, &ptr2, &block2_bytes, 0); if (!FAILED(hr)) { memcpy(ptr1, data, block1_bytes); memcpy(ptr2, data + block1_bytes, block2_bytes); hr = ex_data->ds8_buffer->Unlock(ptr1, block1_bytes, ptr2, block2_bytes); if (FAILED(hr)) { ALLEGRO_ERROR("Unlock failed: %s\n", ds_get_error(hr)); } } saved_play_cursor += block1_bytes + block2_bytes; saved_play_cursor %= buffer_size; } while (!ex_data->stop_voice); ex_data->ds8_buffer->Stop(); al_free(silence); ex_data->stop_voice = 0; al_broadcast_cond(voice->cond); return NULL; }
static void* oss_update(ALLEGRO_THREAD *self, void *arg) { ALLEGRO_VOICE *voice = arg; OSS_VOICE *oss_voice = voice->extra; (void)self; while (!oss_voice->quit_poll_thread) { /* For possible eventual non-blocking mode: audio_buf_info bi; if (ioctl(oss_voice->fd, SNDCTL_DSP_GETOSPACE, &bi) == -1) { TRACE(PREFIX_E "Error SNDCTL_DSP_GETOSPACE.\n"); TRACE(PREFIX_E "errno: %i -- %s\n", errno, strerror(errno)); return NULL; } len = bi.bytes; */ /* How many bytes are we supposed to try to write at once? */ unsigned int frames = 1024; if (oss_voice->stop && !oss_voice->stopped) { oss_voice->stopped = true; } if (!oss_voice->stop && oss_voice->stopped) { oss_voice->stopped = false; } if (!voice->is_streaming && !oss_voice->stopped) { void *buf; int bytes = frames * oss_voice->frame_size; oss_update_nonstream_voice(voice, &buf, &bytes); frames = bytes / oss_voice->frame_size; if (write(oss_voice->fd, buf, bytes) == -1) { ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); if (errno != EINTR) return NULL; } } else if (voice->is_streaming && !oss_voice->stopped) { const void *data = _al_voice_update(voice, &frames); if (data == NULL) goto silence; if (write(oss_voice->fd, data, frames * oss_voice->frame_size) == -1) { ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); if (errno != EINTR) return NULL; } } else { silence: /* If stopped just fill with silence. */ memset(sil_buf, _al_kcm_get_silence(voice->depth), SIL_BUF_SIZE); if(write(oss_voice->fd, sil_buf, SIL_BUF_SIZE) == -1) { ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); } } } return NULL; }