Exemple #1
0
static void *pulseaudio_update(ALLEGRO_THREAD *self, void *data)
{
   ALLEGRO_VOICE *voice = data;
   PULSEAUDIO_VOICE *pv = voice->extra;

   while (!al_get_thread_should_stop(self)) {
      if (pv->status == PV_PLAYING) {
         unsigned int frames = 4096;
         if (voice->is_streaming) { 
            // streaming audio           
            const void *data = _al_voice_update(voice, &frames);
            if (data) {
               pa_simple_write(pv->s, data, frames * pv->frame_size, NULL);
            }
         }
         else {
            // direct buffer audio
            al_lock_mutex(pv->buffer_mutex);
            const char *data = pv->buffer;
            unsigned int len = frames * pv->frame_size;
            pv->buffer += frames * pv->frame_size;
            if (pv->buffer > pv->buffer_end) {
               len = pv->buffer_end - data;
               pv->buffer = voice->attached_stream->spl_data.buffer.ptr;
               voice->attached_stream->pos = 0;
               if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_ONCE) {
                  pv->status = PV_STOPPING;
               }
            }
            else {
               voice->attached_stream->pos += frames;
            }
            al_unlock_mutex(pv->buffer_mutex);

            pa_simple_write(pv->s, data, len, NULL);
         }
      }
      else if (pv->status == PV_STOPPING) {
         pa_simple_flush(pv->s, NULL);
         pv->status = PV_STOPPED;
      }
      else if (pv->status == PV_STOPPED) {
         al_rest(0.001);
      }
   }

   return NULL;
}
/* 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;
}
Exemple #3
0
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;
}
Exemple #4
0
/* TODO: review */
static void *_openal_update(ALLEGRO_THREAD *self, void *arg)
{
   ALLEGRO_VOICE *voice = (ALLEGRO_VOICE*) arg;
   ALLEGRO_AL_DATA *ex_data = (ALLEGRO_AL_DATA*)voice->extra;
   unsigned int i, samples_per_update;
   unsigned int bytes_per_sample;
   const void *data;
   void *silence;

   /* Streams should not be set to looping */
   alSourcei(ex_data->source, AL_LOOPING, AL_FALSE);

   silence = al_calloc(1, ex_data->buffer_size);
   if (ex_data->format == AL_FORMAT_STEREO8 ||
         ex_data->format == AL_FORMAT_MONO8) {
      memset(silence, 0x80, ex_data->buffer_size);
   }

   for (i = 0; i < ex_data->num_buffers; i++) {
      alBufferData(ex_data->buffers[i], ex_data->format, silence,
         ex_data->buffer_size, voice->frequency);
   }

   alSourceQueueBuffers(ex_data->source, ex_data->num_buffers,
      ex_data->buffers);

   alSourcePlay(ex_data->source);

   switch (ex_data->format) {
      case AL_FORMAT_STEREO16:
         bytes_per_sample = 4;
         break;
      case AL_FORMAT_STEREO8:
      case AL_FORMAT_MONO16:
         bytes_per_sample = 2;
         break;
      default:
         bytes_per_sample = 1;
         break;
   }

   samples_per_update = ex_data->buffer_size / bytes_per_sample;

   data = silence;

   while (!al_get_thread_should_stop(self)) {
      ALint status = 0;

      alGetSourcei(ex_data->source, AL_BUFFERS_PROCESSED, &status);
      if (status <= 0) {
         /* FIXME what is this for ? */
         al_rest(0.001);
         continue;
      }

      while (--status >= 0) {
         ALuint buffer;

         data = _al_voice_update(voice, voice->mutex, &samples_per_update);
         if (data == NULL)
            data = silence;

         alSourceUnqueueBuffers(ex_data->source, 1, &buffer);
         alBufferData(buffer, ex_data->format, data,
            samples_per_update * bytes_per_sample, voice->frequency);
         alSourceQueueBuffers(ex_data->source, 1, &buffer);
      }
      alGetSourcei(ex_data->source, AL_SOURCE_STATE, &status);
      if (status == AL_STOPPED) {
         alSourcePlay(ex_data->source);
      }
   }

   alSourceStop(ex_data->source);

   al_free(silence);

   ex_data->stopped = true;
   al_broadcast_cond(voice->cond);

   return NULL;
}
Exemple #5
0
static void *pulseaudio_update(ALLEGRO_THREAD *self, void *data)
{
   ALLEGRO_VOICE *voice = data;
   PULSEAUDIO_VOICE *pv = voice->extra;
   (void)self;

   for (;;) {
      enum PULSEAUDIO_VOICE_STATUS status;

      al_lock_mutex(voice->mutex);
      while ((status = pv->status) == PV_IDLE) {
         al_wait_cond(pv->status_cond, voice->mutex);
      }
      al_unlock_mutex(voice->mutex);

      if (status == PV_JOIN) {
         break;
      }

      if (status == PV_PLAYING) {
         unsigned int frames = pv->buffer_size_in_frames;
         if (voice->is_streaming) { 
            // streaming audio           
            const void *data = _al_voice_update(voice, voice->mutex, &frames);
            if (data) {
               pa_simple_write(pv->s, data,
                  frames * pv->frame_size_in_bytes, NULL);
            }
         }
         else {
            // direct buffer audio
            al_lock_mutex(pv->buffer_mutex);
            const char *data = pv->buffer;
            unsigned int len = frames * pv->frame_size_in_bytes;
            pv->buffer += frames * pv->frame_size_in_bytes;
            if (pv->buffer > pv->buffer_end) {
               len = pv->buffer_end - data;
               pv->buffer = voice->attached_stream->spl_data.buffer.ptr;
               voice->attached_stream->pos = 0;
               if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_ONCE) {
                  al_lock_mutex(voice->mutex);
                  pv->status = PV_STOPPING;
                  al_broadcast_cond(pv->status_cond);
                  al_unlock_mutex(voice->mutex);
               }
            }
            else {
               voice->attached_stream->pos += frames;
            }
            al_unlock_mutex(pv->buffer_mutex);

            pa_simple_write(pv->s, data, len, NULL);
         }
      }
      else if (status == PV_STOPPING) {
         pa_simple_drain(pv->s, NULL);
         al_lock_mutex(voice->mutex);
         pv->status = PV_IDLE;
         al_broadcast_cond(pv->status_cond);
         al_unlock_mutex(voice->mutex);
      }
   }

   return NULL;
}