示例#1
0
static int pulseaudio_allocate_voice(ALLEGRO_VOICE *voice)
{
   PULSEAUDIO_VOICE *pv = al_malloc(sizeof(PULSEAUDIO_VOICE));
   pa_sample_spec ss;
   pa_buffer_attr ba;

   ss.channels = al_get_channel_count(voice->chan_conf);
   ss.rate = voice->frequency;

   if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT8)
      ss.format = PA_SAMPLE_U8;
   else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT16)
      ss.format = PA_SAMPLE_S16NE;
#if PA_API_VERSION > 11
   else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT24)
      ss.format = PA_SAMPLE_S24NE;
#endif
   else if (voice->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32)
      ss.format = PA_SAMPLE_FLOAT32NE;
   else {
      ALLEGRO_ERROR("Unsupported PulseAudio sound format.\n");
      al_free(pv);
      return 1;
   }

   ba.maxlength = 0x10000; // maximum length of buffer
   ba.tlength   = 0x2000;  // target length of buffer
   ba.prebuf    = 0;       // minimum data size required before playback starts
   ba.minreq    = 0;       // minimum size of request 
   ba.fragsize  = -1;      // fragment size (recording)

   pv->s = pa_simple_new(NULL,         // Use the default server.
                   al_get_app_name(),     
                   PA_STREAM_PLAYBACK,
                   NULL,               // Use the default device.
                   "Allegro Voice",    
                   &ss,                
                   NULL,               // Use default channel map
                   &ba,                
                   NULL                // Ignore error code.
   );

   if (!pv->s) {
      al_free(pv);
      return 1;
   }

   voice->extra = pv;

   pv->frame_size = ss.channels * al_get_audio_depth_size(voice->depth);
   pv->status = PV_STOPPED;
   pv->buffer_mutex = al_create_mutex();

   pv->poll_thread = al_create_thread(pulseaudio_update, (void*)voice);
   al_start_thread(pv->poll_thread);

   return 0;
}
示例#2
0
static int pulseaudio_allocate_recorder(ALLEGRO_AUDIO_RECORDER *r)
{
   PULSEAUDIO_RECORDER *pa;
   
   pa = al_calloc(1, sizeof(*pa));
   if (!pa) {
     ALLEGRO_ERROR("Unable to allocate memory for PULSEAUDIO_RECORDER.\n");
     return 1;
   }
   
   pa->ss.channels = al_get_channel_count(r->chan_conf);
   pa->ss.rate = r->frequency;

   if (r->depth == ALLEGRO_AUDIO_DEPTH_UINT8) 
      pa->ss.format = PA_SAMPLE_U8;
   else if (r->depth == ALLEGRO_AUDIO_DEPTH_INT16)
      pa->ss.format = PA_SAMPLE_S16NE;
#if PA_API_VERSION > 11
   else if (r->depth == ALLEGRO_AUDIO_DEPTH_INT24)
      pa->ss.format = PA_SAMPLE_S24NE;
#endif
   else if (r->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32)
      pa->ss.format = PA_SAMPLE_FLOAT32NE;
   else {
      ALLEGRO_ERROR("Unsupported PulseAudio sound format (depth).\n");
      al_free(pa);
      return 1;
   }
   
   /* maximum length of the PulseAudio buffer. -1 => let the server decide. */
   pa->ba.maxlength = -1;
   
   /* fragment size (bytes) controls how much data is returned back per read. 
      The documentation recommends -1 for default behavior, but that sets a
      latency of around 2 seconds. Lower value decreases latency but increases
      overhead. 
      
      The following attempts to set it (the base latency) to 1/8 of a second. 
    */
   pa->ba.fragsize = (r->sample_size * r->frequency) / 8;
   
   pa->s = pa_simple_new(NULL, al_get_app_name(), PA_STREAM_RECORD, NULL, "Allegro Audio Recorder", &pa->ss, NULL, &pa->ba, NULL);
   if (!pa->s) {
      ALLEGRO_ERROR("pa_simple_new() failed.\n");
      al_free(pa);
      return 1;
   }
   
   r->thread = al_create_thread(pulse_audio_update_recorder, r);
   r->extra = pa;
   
   return 0;   
};
示例#3
0
/* _al_kcm_refill_stream:
 *  Called by the mixer when the current buffer has been used up.  It should
 *  point to the next pending buffer and reset the sample position.
 *  Returns true if the next buffer is available and set up.
 *  Otherwise returns false.
 */
bool _al_kcm_refill_stream(ALLEGRO_AUDIO_STREAM *stream)
{
   ALLEGRO_SAMPLE_INSTANCE *spl = &stream->spl;
   void *old_buf = spl->spl_data.buffer.ptr;
   void *new_buf;
   size_t i;

   if (old_buf) {
      /* Slide the buffers down one position and put the
       * completed buffer into the used array to be refilled.
       */
      for (i = 0;
            i < stream->buf_count-1 && stream->pending_bufs[i];
            i++) {
         stream->pending_bufs[i] = stream->pending_bufs[i+1];
      }
      stream->pending_bufs[i] = NULL;

      for (i = 0; stream->used_bufs[i]; i++)
         ;
      stream->used_bufs[i] = old_buf;
   }

   new_buf = stream->pending_bufs[0];
   stream->spl.spl_data.buffer.ptr = new_buf;
   if (!new_buf) {
      ALLEGRO_WARN("Out of buffers\n");
      return false;
   }

   /* Copy the last MAX_LAG sample values to the front of the new buffer
    * for interpolation.
    */
   if (old_buf) {
      const int bytes_per_sample =
         al_get_channel_count(spl->spl_data.chan_conf) *
         al_get_audio_depth_size(spl->spl_data.depth);
      memcpy(
         (char *) new_buf - bytes_per_sample * MAX_LAG,
         (char *) old_buf + bytes_per_sample * (spl->pos-MAX_LAG),
         bytes_per_sample * MAX_LAG);

      stream->consumed_fragments++;
   }

   stream->spl.pos = 0;

   return true;
}
示例#4
0
/* stream_read:
 *  This passes the next waiting stream buffer to the voice via vbuf.
 */
static void stream_read(void *source, void **vbuf, unsigned int *samples,
   ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc)
{
   ALLEGRO_AUDIO_STREAM *stream = (ALLEGRO_AUDIO_STREAM*)source;
   unsigned int len = stream->spl.spl_data.len;
   unsigned int pos = stream->spl.pos;

   if (!stream->spl.is_playing) {
      *vbuf = NULL;
      *samples = 0;
      return;
   }

   if (*samples > len)
      *samples = len;

   if (pos >= len) {
      _al_kcm_refill_stream(stream);
      if (!stream->pending_bufs[0]) {
         if (stream->is_draining) {
            stream->spl.is_playing = false;
         }
         *vbuf = NULL;
         *samples = 0;
         return;
      }
      *vbuf = stream->pending_bufs[0];
      pos = *samples;

      _al_kcm_emit_stream_events(stream);
   }
   else {
      int bytes = pos * al_get_channel_count(stream->spl.spl_data.chan_conf)
                      * al_get_audio_depth_size(stream->spl.spl_data.depth);
      *vbuf = ((char *)stream->pending_bufs[0]) + bytes;

      if (pos + *samples > len)
         *samples = len - pos;
      pos += *samples;
   }

   stream->spl.pos = pos;

   (void)dest_maxc;
   (void)buffer_depth;
}
示例#5
0
static void reset_stopped_stream(ALLEGRO_AUDIO_STREAM *stream)
{
   const int bytes_per_sample =
      al_get_channel_count(stream->spl.spl_data.chan_conf) *
      al_get_audio_depth_size(stream->spl.spl_data.depth);
   const int fragment_buffer_size =
      bytes_per_sample * (stream->spl.spl_data.len + MAX_LAG);
   size_t i, n;

   /* Write silence to the "invisible" part in between fragment buffers to
    * avoid interpolation artifacts.  It's tempting to zero the complete
    * memory block in one go but some of the buffers might be getting
    * refilled.  So they are currently "owned" by the library user and
    * should not be overwritten.  But zeroing the parts not visible to the
    * user should be OK.
    */
   for (i = 0; i < stream->buf_count; ++i) {
      al_fill_silence((char *)stream->main_buffer + i * fragment_buffer_size,
         MAX_LAG, stream->spl.spl_data.depth, stream->spl.spl_data.chan_conf);
   }

   /* Get the current number of entries in the used_buf list. */
   for (n = 0; n < stream->buf_count && stream->used_bufs[n]; n++)
      ;

   /* Move everything from pending_bufs to used_bufs. */
   i = 0;
   while (i < stream->buf_count &&
         n < stream->buf_count &&
         stream->pending_bufs[i])
   {
      stream->used_bufs[n] = stream->pending_bufs[i];
      stream->pending_bufs[i] = NULL;
      n++;
      i++;
   }

   /* No fragment buffer is currently playing. */
   stream->spl.spl_data.buffer.ptr = NULL;
   stream->spl.pos = stream->spl.spl_data.len;
   stream->spl.pos_bresenham_error = 0;
   stream->consumed_fragments = 0;
}
示例#6
0
/* Function: al_attach_audio_stream_to_voice
 */
bool al_attach_audio_stream_to_voice(ALLEGRO_AUDIO_STREAM *stream,
   ALLEGRO_VOICE *voice)
{
   bool ret;

   ASSERT(voice);
   ASSERT(stream);

   if (voice->attached_stream) {
      _al_set_error(ALLEGRO_INVALID_OBJECT,
         "Attempted to attach to a voice that already has an attachment");
      return false;
   }

   if (stream->spl.parent.u.ptr) {
      _al_set_error(ALLEGRO_INVALID_OBJECT,
         "Attempted to attach a stream that is already attached");
      return false;
   }

   if (voice->chan_conf != stream->spl.spl_data.chan_conf ||
      voice->frequency != stream->spl.spl_data.frequency ||
      voice->depth != stream->spl.spl_data.depth)
   {
      _al_set_error(ALLEGRO_INVALID_OBJECT,
         "Stream settings do not match voice settings");
      return false;
   }

   al_lock_mutex(voice->mutex);

   voice->attached_stream = &stream->spl;

   _al_kcm_stream_set_mutex(&stream->spl, voice->mutex);

   stream->spl.parent.u.voice = voice;
   stream->spl.parent.is_voice = true;

   voice->is_streaming = true;
   voice->num_buffers = stream->buf_count;
   voice->buffer_size = (stream->spl.spl_data.len) *
                        al_get_channel_count(stream->spl.spl_data.chan_conf) *
                        al_get_audio_depth_size(stream->spl.spl_data.depth);

   ASSERT(stream->spl.spl_read == NULL);
   stream->spl.spl_read = stream_read;

   if (voice->driver->start_voice(voice) != 0) {
      voice->attached_stream = NULL;
      _al_kcm_stream_set_mutex(&stream->spl, NULL);
      stream->spl.parent.u.voice = NULL;
      stream->spl.spl_read = NULL;

      _al_set_error(ALLEGRO_GENERIC_ERROR, "Unable to start stream");
      ret = false;
   }
   else {
      ret = true;
   }

   al_unlock_mutex(voice->mutex);

   return ret;
}
示例#7
0
/* Function: al_attach_sample_instance_to_voice
 */
bool al_attach_sample_instance_to_voice(ALLEGRO_SAMPLE_INSTANCE *spl,
   ALLEGRO_VOICE *voice)
{
   bool ret;

   ASSERT(voice);
   ASSERT(spl);

   if (voice->attached_stream) {
      ALLEGRO_WARN(
         "Attempted to attach to a voice that already has an attachment\n");
      _al_set_error(ALLEGRO_INVALID_OBJECT,
         "Attempted to attach to a voice that already has an attachment");
      return false;
   }

   if (spl->parent.u.ptr) {
      ALLEGRO_WARN("Attempted to attach a sample that is already attached\n");
      _al_set_error(ALLEGRO_INVALID_OBJECT,
         "Attempted to attach a sample that is already attached");
      return false;
   }

   if (voice->chan_conf != spl->spl_data.chan_conf ||
      voice->frequency != spl->spl_data.frequency ||
      voice->depth != spl->spl_data.depth)
   {
      ALLEGRO_WARN("Sample settings do not match voice settings\n");
      _al_set_error(ALLEGRO_INVALID_OBJECT,
         "Sample settings do not match voice settings");
      return false;
   }

   al_lock_mutex(voice->mutex);

   voice->attached_stream = spl;

   voice->is_streaming = false;
   voice->num_buffers = 1;
   voice->buffer_size = (spl->spl_data.len) *
                        al_get_channel_count(voice->chan_conf) *
                        al_get_audio_depth_size(voice->depth);

   spl->spl_read = NULL;
   _al_kcm_stream_set_mutex(spl, voice->mutex);

   spl->parent.u.voice = voice;
   spl->parent.is_voice = true;

   if (voice->driver->load_voice(voice, spl->spl_data.buffer.ptr) != 0 ||
      (spl->is_playing && voice->driver->start_voice(voice) != 0))
   {      
      voice->attached_stream = NULL;
      spl->spl_read = NULL;
      _al_kcm_stream_set_mutex(spl, NULL);
      spl->parent.u.voice = NULL;

      ALLEGRO_ERROR("Unable to load sample into voice\n");
      ret = false;
   }
   else {
      ret = true;
   }

   al_unlock_mutex(voice->mutex);

   return ret;
}
示例#8
0
文件: oss.c 项目: sesc4mt/mvcdecoder
static int oss_allocate_voice(ALLEGRO_VOICE *voice)
{
   int format;
   int chan_count;

   OSS_VOICE *ex_data = calloc(1, sizeof(OSS_VOICE));
   if (!ex_data)
      return 1;

   ex_data->fd = open(oss_audio_device, O_WRONLY/*, O_NONBLOCK*/);
   if (ex_data->fd == -1) {
      ALLEGRO_ERROR("Failed to open audio device '%s'.\n",
            oss_audio_device);
      ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno));
      free(ex_data);
      return 1;
   }

   chan_count = al_get_channel_count(voice->chan_conf);

   ex_data->frame_size = chan_count * al_get_depth_size(voice->depth);
   if (!ex_data->frame_size)
      goto Error;

   ex_data->stop = true;
   ex_data->stopped = true;

   if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT8)
      format = AFMT_S8;
   else if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT8)
      format = AFMT_U8;
   else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT16)
      format = AFMT_S16_NE;
   else if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT16)
      format = AFMT_U16_NE;
#ifdef OSS_VER_4
   else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT24)
      format = AFMT_S24_NE;
   else if (voice->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32)
      format = AFMT_FLOAT;
#endif
   else {
      ALLEGRO_ERROR("Unsupported OSS sound format.\n");
      goto Error;
   }

   int tmp_format = format;
   int tmp_chan_count = chan_count;
   unsigned int tmp_freq = voice->frequency;
   int tmp_oss_fragsize = oss_fragsize;

   if (using_ver_4) {
#ifdef OSS_VER_4
      int tmp_oss_timing_policy = oss_timing_policy;
      if (ioctl(ex_data->fd, SNDCTL_DSP_POLICY, &tmp_oss_timing_policy) == -1) {
         ALLEGRO_ERROR("Failed to set_timig policity to '%i'.\n",
               tmp_oss_timing_policy);
         ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno));
         goto Error;
      }
      ALLEGRO_INFO("Accepted timing policy value: %i\n", tmp_oss_timing_policy);
#endif
   }
   else {
      if (ioctl(ex_data->fd, SNDCTL_DSP_SETFRAGMENT, &tmp_oss_fragsize) == -1) {
          ALLEGRO_ERROR("Failed to set fragment size.\n");
          ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno));
          goto Error;
      }
   }

   if (ioctl(ex_data->fd, SNDCTL_DSP_SETFMT, &tmp_format) == -1) {
      ALLEGRO_ERROR("Failed to set sample format.\n");
      ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno));
      goto Error;
   }
   if (tmp_format != format) {
      ALLEGRO_ERROR("Sample format not supported by the driver.\n");
      goto Error;
   }

   if (ioctl(ex_data->fd, SNDCTL_DSP_CHANNELS, &tmp_chan_count)) {
      ALLEGRO_ERROR("Failed to set channel count.\n");
      ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno));
      goto Error;
   }
   if (tmp_chan_count != chan_count) {
      ALLEGRO_ERROR("Requested sample channe count %i, got %i.\n",
            tmp_chan_count, chan_count);
   }

   if (ioctl(ex_data->fd, SNDCTL_DSP_SPEED, &tmp_freq) == -1) {
      ALLEGRO_ERROR("Failed to set sample rate.\n");
      ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno));
      goto Error;
   }
   if (voice->frequency != tmp_freq) {
      ALLEGRO_ERROR("Requested sample rate %u, got %iu.\n", voice->frequency,
            tmp_freq);
   }

   voice->extra = ex_data;
   ex_data->quit_poll_thread = false;
   ex_data->poll_thread = al_create_thread(oss_update, (void*)voice);
   al_start_thread(ex_data->poll_thread);

   return 0;

Error:
   close(ex_data->fd);
   free(ex_data);
   return 1;
}
示例#9
0
int main(int argc, char **argv)
{
   ALLEGRO_VOICE *voice;
   ALLEGRO_MIXER *mixer;
   ALLEGRO_SAMPLE_INSTANCE *sample;
   int i;
   char const **filenames;
   int n;

   if (argc < 2) {
      n = 1;
      filenames = malloc(sizeof *filenames);
      filenames[0] = "data/welcome.wav";
   }
   else {
      n = argc - 1;
      filenames = malloc(sizeof *filenames * n);
      for (i = 1; i < argc; ++i) {
         filenames[i - 1] = argv[i];
      }
   }

   if (!al_init()) {
      abort_example("Could not init Allegro.\n");
   }

   open_log();

   al_init_acodec_addon();

   if (!al_install_audio()) {
      abort_example("Could not init sound!\n");
   }

   voice = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16,
      ALLEGRO_CHANNEL_CONF_2);
   if (!voice) {
      abort_example("Could not create ALLEGRO_VOICE.\n");
   }

   mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32,
      ALLEGRO_CHANNEL_CONF_2);
   if (!mixer) {
      abort_example("al_create_mixer failed.\n");
   }

   if (!al_attach_mixer_to_voice(mixer, voice)) {
      abort_example("al_attach_mixer_to_voice failed.\n");
   }

   sample = al_create_sample_instance(NULL);
   if (!sample) {
      abort_example("al_create_sample failed.\n");
   }

   for (i = 0; i < n; ++i) {
      ALLEGRO_SAMPLE *sample_data = NULL;
      const char *filename = filenames[i];
      float sample_time = 0;
      /* A matrix that puts everything in the left channel. */
      float mono_to_stereo[] = {1.0, 0.0};

      /* Load the entire sound file from disk. */
      sample_data = al_load_sample(filename);
      if (!sample_data) {
         abort_example("Could not load sample from '%s'!\n",
            filename);
         continue;
      }

      if (!al_set_sample(sample, sample_data)) {
         abort_example("al_set_sample_instance_ptr failed.\n");
         continue;
      }

      if (!al_attach_sample_instance_to_mixer(sample, mixer)) {
         abort_example("al_attach_sample_instance_to_mixer failed.\n");
         goto done;
      }

      /* Play sample in looping mode. */
      al_set_sample_instance_playmode(sample, ALLEGRO_PLAYMODE_LOOP);
      al_play_sample_instance(sample);

      sample_time = al_get_sample_instance_time(sample);
      log_printf("Playing '%s' (%.3f seconds) normally.\n", filename,
         sample_time);

      al_rest(sample_time);

      if (al_get_channel_count(al_get_sample_instance_channels(sample)) == 1) {
         if (!al_set_sample_instance_channel_matrix(sample, mono_to_stereo)) {
            abort_example("Failed to set channel matrix.\n");
         }
         log_printf("Playing left channel only.\n");
         al_rest(sample_time);
      }

      if (!al_set_sample_instance_gain(sample, 0.5)) {
         abort_example("Failed to set gain.\n");
      }
      log_printf("Playing with gain 0.5.\n");
      al_rest(sample_time);

      if (!al_set_sample_instance_gain(sample, 0.25)) {
         abort_example("Failed to set gain.\n");
      }
      log_printf("Playing with gain 0.25.\n");
      al_rest(sample_time);

      al_stop_sample_instance(sample);
      log_printf("Done playing '%s'\n", filename);

      /* Free the memory allocated. */
      al_set_sample(sample, NULL);
      al_destroy_sample(sample_data);
   }

   al_destroy_sample_instance(sample);
   al_destroy_mixer(mixer);
   al_destroy_voice(voice);

   al_uninstall_audio();

done:
   close_log(true);

   return 0;
}
示例#10
0
static int _dsound_open_recorder(ALLEGRO_AUDIO_RECORDER *r)
{
   HRESULT hr;

   if (capture_device != NULL) {
      /* FIXME: It's wrong to assume only a single recording device, but since
                there is no enumeration of devices, it doesn't matter for now. */
      ALLEGRO_ERROR("Already recording.\n");
      return 1;
   }

   ALLEGRO_INFO("Creating default capture device.\n");

   /* FIXME: Use default device until we have device enumeration */
   hr = DirectSoundCaptureCreate8(NULL, &capture_device, NULL);
   if (FAILED(hr)) {
      ALLEGRO_ERROR("DirectSoundCaptureCreate8 failed: %s\n", ds_get_error(hr));
      return 1;
   }
   
   hr = device->SetCooperativeLevel(get_window(), DSSCL_PRIORITY);
   if (FAILED(hr)) {
      ALLEGRO_ERROR("SetCooperativeLevel failed: %s\n", ds_get_error(hr));
      return 1;
   }

   DSOUND_RECORD_DATA *extra = (DSOUND_RECORD_DATA *) al_calloc(1, sizeof(*extra));

   DSCCAPS dsccaps;   
   dsccaps.dwSize = sizeof(DSCCAPS);
   hr = capture_device->GetCaps(&dsccaps);
   if (FAILED(hr)) {
      ALLEGRO_ERROR("DirectSoundCaptureCreate8::GetCaps failed: %s\n", ds_get_error(hr));
   }
   else {
      ALLEGRO_INFO("caps: %lu %lu\n", dsccaps.dwFormats, dsccaps.dwFormats & WAVE_FORMAT_2M16);
   }

   memset(&extra->wave_fmt, 0, sizeof(extra->wave_fmt));
   extra->wave_fmt.wFormatTag = WAVE_FORMAT_PCM;
   extra->wave_fmt.nChannels = (WORD)al_get_channel_count(r->chan_conf);
   extra->wave_fmt.nSamplesPerSec = r->frequency;
   extra->wave_fmt.wBitsPerSample = (WORD)al_get_audio_depth_size(r->depth) * 8;
   extra->wave_fmt.nBlockAlign = extra->wave_fmt.nChannels * extra->wave_fmt.wBitsPerSample / 8;
   extra->wave_fmt.nAvgBytesPerSec = extra->wave_fmt.nSamplesPerSec * extra->wave_fmt.nBlockAlign;
   
   memset(&extra->desc, 0, sizeof(extra->desc));
   extra->desc.dwSize = sizeof(extra->desc);
   extra->desc.lpwfxFormat = &extra->wave_fmt;
   extra->desc.dwBufferBytes = extra->wave_fmt.nAvgBytesPerSec * 5;

   hr = capture_device->CreateCaptureBuffer(&extra->desc, &extra->buffer, NULL);
   if (FAILED(hr)) {
      al_free(extra);
      ALLEGRO_ERROR("Unable to create Capture Buffer\n");
      return 1;
   }

   extra->buffer->QueryInterface(_al_IID_IDirectSoundCaptureBuffer8, (void **) &extra->buffer8);
   
   r->extra = extra;
   r->thread = al_create_thread(_dsound_update_recorder, r);

   return 0;
}
示例#11
0
/* _al_kcm_feed_stream:
 * A routine running in another thread that feeds the stream buffers as
 * neccesary, usually getting data from some file reader backend.
 */
void *_al_kcm_feed_stream(ALLEGRO_THREAD *self, void *vstream)
{
   ALLEGRO_AUDIO_STREAM *stream = vstream;
   ALLEGRO_EVENT_QUEUE *queue;
   ALLEGRO_EVENT event;
   (void)self;

   ALLEGRO_DEBUG("Stream feeder thread started.\n");

   queue = al_create_event_queue();
   al_register_event_source(queue, &stream->spl.es);

   al_lock_mutex(stream->feed_thread_started_mutex);
   stream->feed_thread_started = true;
   al_broadcast_cond(stream->feed_thread_started_cond);
   al_unlock_mutex(stream->feed_thread_started_mutex);

   stream->quit_feed_thread = false;

   while (!stream->quit_feed_thread) {
      char *fragment;
      ALLEGRO_EVENT event;

      al_wait_for_event(queue, &event);

      if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT
          && !stream->is_draining) {
         unsigned long bytes;
         unsigned long bytes_written;
         ALLEGRO_MUTEX *stream_mutex;

         fragment = al_get_audio_stream_fragment(stream);
         if (!fragment) {
            /* This is not an error. */
            continue;
         }

         bytes = (stream->spl.spl_data.len) *
               al_get_channel_count(stream->spl.spl_data.chan_conf) *
               al_get_audio_depth_size(stream->spl.spl_data.depth);

         stream_mutex = maybe_lock_mutex(stream->spl.mutex);
         bytes_written = stream->feeder(stream, fragment, bytes);
         maybe_unlock_mutex(stream_mutex);

         if (stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) {
            /* Keep rewinding until the fragment is filled. */
            while (bytes_written < bytes &&
                     stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) {
               size_t bw;
               al_rewind_audio_stream(stream);
               stream_mutex = maybe_lock_mutex(stream->spl.mutex);
               bw = stream->feeder(stream, fragment + bytes_written,
                  bytes - bytes_written);
               bytes_written += bw;
               maybe_unlock_mutex(stream_mutex);
            }
         }
         else if (bytes_written < bytes) {
            /* Fill the rest of the fragment with silence. */
            int silence_samples = (bytes - bytes_written) /
               (al_get_channel_count(stream->spl.spl_data.chan_conf) *
                al_get_audio_depth_size(stream->spl.spl_data.depth));
            al_fill_silence(fragment + bytes_written, silence_samples,
                            stream->spl.spl_data.depth, stream->spl.spl_data.chan_conf);
         }

         if (!al_set_audio_stream_fragment(stream, fragment)) {
            ALLEGRO_ERROR("Error setting stream buffer.\n");
            continue;
         }

         /* The streaming source doesn't feed any more, drain buffers and quit. */
         if (bytes_written != bytes &&
            stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONCE) {
            al_drain_audio_stream(stream);
            stream->quit_feed_thread = true;
         }
      }
      else if (event.type == _KCM_STREAM_FEEDER_QUIT_EVENT_TYPE) {
         stream->quit_feed_thread = true;
      }
   }
   
   event.user.type = ALLEGRO_EVENT_AUDIO_STREAM_FINISHED;
   event.user.timestamp = al_get_time();
   al_emit_user_event(&stream->spl.es, &event, NULL);

   al_destroy_event_queue(queue);

   ALLEGRO_DEBUG("Stream feeder thread finished.\n");

   return NULL;
}
示例#12
0
/* Function: al_create_audio_stream
 */
ALLEGRO_AUDIO_STREAM *al_create_audio_stream(size_t fragment_count,
   unsigned int frag_samples, unsigned int freq, ALLEGRO_AUDIO_DEPTH depth,
   ALLEGRO_CHANNEL_CONF chan_conf)
{
   ALLEGRO_AUDIO_STREAM *stream;
   unsigned long bytes_per_sample;
   unsigned long bytes_per_frag_buf;
   size_t i;

   if (!fragment_count) {
      _al_set_error(ALLEGRO_INVALID_PARAM,
         "Attempted to create stream with no buffers");
      return NULL;
   }
   if (!frag_samples) {
      _al_set_error(ALLEGRO_INVALID_PARAM,
          "Attempted to create stream with no buffer size");
      return NULL;
   }
   if (!freq) {
      _al_set_error(ALLEGRO_INVALID_PARAM,
         "Attempted to create stream with no frequency");
      return NULL;
   }

   bytes_per_sample = al_get_channel_count(chan_conf) *
         al_get_audio_depth_size(depth);
   bytes_per_frag_buf = frag_samples * bytes_per_sample;

   stream = al_calloc(1, sizeof(*stream));
   if (!stream) {
      _al_set_error(ALLEGRO_GENERIC_ERROR,
         "Out of memory allocating stream object");
      return NULL;
   }

   stream->spl.is_playing = true;
   stream->is_draining = false;

   stream->spl.loop      = _ALLEGRO_PLAYMODE_STREAM_ONCE;
   stream->spl.spl_data.depth     = depth;
   stream->spl.spl_data.chan_conf = chan_conf;
   stream->spl.spl_data.frequency = freq;
   stream->spl.speed     = 1.0f;
   stream->spl.gain      = 1.0f;
   stream->spl.pan       = 0.0f;

   stream->spl.step = 0;
   stream->spl.pos  = frag_samples;
   stream->spl.spl_data.len  = stream->spl.pos;

   stream->buf_count = fragment_count;

   stream->used_bufs = al_calloc(1, fragment_count * sizeof(void *) * 2);
   if (!stream->used_bufs) {
      al_free(stream->used_bufs);
      al_free(stream);
      _al_set_error(ALLEGRO_GENERIC_ERROR,
         "Out of memory allocating stream buffer pointers");
      return NULL;
   }
   stream->pending_bufs = stream->used_bufs + fragment_count;

   /* The main_buffer holds all the buffer fragments in contiguous memory.
    * To support interpolation across buffer fragments, we allocate extra
    * MAX_LAG samples at the start of each buffer fragment, to hold the
    * last few sample values which came before that fragment.
    */
   stream->main_buffer = al_calloc(1,
      (MAX_LAG * bytes_per_sample + bytes_per_frag_buf) * fragment_count);
   if (!stream->main_buffer) {
      al_free(stream->used_bufs);
      al_free(stream);
      _al_set_error(ALLEGRO_GENERIC_ERROR,
         "Out of memory allocating stream buffer");
      return NULL;
   }

   for (i = 0; i < fragment_count; i++) {
      char *buffer = (char *)stream->main_buffer
         + i * (MAX_LAG * bytes_per_sample + bytes_per_frag_buf);
      al_fill_silence(buffer, MAX_LAG, depth, chan_conf);
      stream->used_bufs[i] = buffer + MAX_LAG * bytes_per_sample;
   }

   al_init_user_event_source(&stream->spl.es);

   /* This can lead to deadlocks on shutdown, hence we don't do it. */
   /* _al_kcm_register_destructor(stream, (void (*)(void *)) al_destroy_audio_stream); */

   return stream;
}