problems with g_cond_wait



Hi

I want to write a composition program and I have some problems, that my
application stays in "real time". I use g_cond_wait for
synchronization.  I'm asking me if g_cond_signal is too slow for my
needs or am I doing something wrong? In the attachment is the C file
which is part of my project. You may to start at the function
ags_devout_run() that's where the threads will be started. I get some
sound when testing with the drum sequencer but it sounds as it has been
played too slow.


#include "ags_devout.h"

#include "ags_audio.h"
#include "ags_channel.h"
#include "ags_audio_signal.h"

#include "recall/ags_play_channel.h"

#include "file/ags_audio_file.h"

#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <errno.h>

#include <string.h>
#include <math.h>
#include <time.h>

GType ags_devout_get_type();
void ags_devout_class_init(AgsDevoutClass *devout);
void ags_devout_init(AgsDevout *devout);
void ags_devout_destroy(GObject *gobject);

void ags_devout_device_init(AgsDevout *devout);
void ags_devout_device_free(AgsDevout *devout);
void ags_devout_ao_device_init(AgsDevout *devout);
void ags_devout_ao_device_free(AgsDevout *devout);

void ags_devout_run(AgsDevout *devout);
// void ags_devout_request(AgsDevout *devout); obsoleted by ags_devout_play_audio
void ags_devout_play_recall(AgsDevout *devout);
void ags_devout_play_audio(AgsDevout *devout);

gpointer ags_devout_play_functions(gpointer devout);
gpointer ags_devout_play(gpointer devout);
gpointer ags_devout_garbage_collector(AgsDevout *devout);
void ags_devout_stop(AgsDevout *devout);

gpointer ags_devout_ao_play(AgsDevout *devout);
void ags_devout_ao_stop(AgsDevout *devout);

GType
ags_devout_get_type (void)
{
  static GType ags_type_devout = 0;

  if(!ags_type_devout){
    static const GTypeInfo ags_devout_info = {
      sizeof (AgsDevoutClass),
      NULL, /* base_init */
      NULL, /* base_finalize */
      (GClassInitFunc) ags_devout_class_init,
      NULL, /* class_finalize */
      NULL, /* class_data */
      sizeof (AgsDevout),
      0,    /* n_preallocs */
      (GInstanceInitFunc) ags_devout_init,
    };
    ags_type_devout = g_type_register_static(G_TYPE_OBJECT, "AgsDevout\0", &ags_devout_info, 0);
  }
  return (ags_type_devout);
}

void
ags_devout_class_init(AgsDevoutClass *devout)
{
  devout->run = ags_devout_run;
  devout->stop = ags_devout_stop;
}

void
ags_devout_init(AgsDevout *devout)
{
  devout->flags = AGS_DEVOUT_WAIT_RECALL | AGS_DEVOUT_WAIT_DEVICE;

  devout->dsp_channels = 2;
  devout->pcm_channels = 2;
  devout->bits = 16;
  devout->buffer_size = 512;
  devout->frequence = 44100;
  //  devout->sleep.tv_sec = 0;
  //  devout->sleep.tv_nsec = (guint) floor(1000000000.0 / (double)devout->frequence  * (double)devout->buffer_size);
  devout->play_cond = g_cond_new();
  devout->play_functions_cond = g_cond_new();
  devout->garbage_collector_cond = g_cond_new();

  devout->offset = 0;

  devout->note_delay = (guint) round((double)devout->frequence / (double)devout->buffer_size * 60.0 / 120.0 / 16.0);
  devout->note_counter = 0;
  devout->note_offset = 0;

  devout->buffer[0] = (short *) malloc(devout->dsp_channels * devout->buffer_size * sizeof(short));
  devout->buffer[1] = (short *) malloc(devout->dsp_channels * devout->buffer_size * sizeof(short));
  devout->buffer[2] = (short *) malloc(devout->dsp_channels * devout->buffer_size * sizeof(short));
  devout->buffer[3] = (short *) malloc(devout->dsp_channels * devout->buffer_size * sizeof(short));

  devout->system = AGS_DEVOUT_OSS;
  devout->device = "/dev/dsp\0";

  devout->garbage_collector = ags_garbage_collector_new();
  devout->garbage_collector->devout = (GObject *) devout;

  devout->recall = NULL;
  devout->audio = NULL;
}

void
ags_devout_destroy(GObject *gobject)
{
  g_object_unref (gobject);
}

void
ags_devout_device_init(AgsDevout *devout)
{
  int stereo, fmt;

  if((devout->out.device_fd = open ("/dev/dsp\0", O_WRONLY, 0)) == -1 &&
     (devout->out.device_fd = open ("/dev/sound/dsp\0", O_WRONLY, 0)) == -1){
    perror("ags_devout_device_init : open \0");
    exit(1);
  }

   stereo = 0;
   if(ioctl (devout->out.device_fd, SNDCTL_DSP_STEREO, &stereo) == -1){
     /* Fatal error */
     perror("ags_devout_device_init : stereo \0");
     exit(1);
   }

   if(ioctl (devout->out.device_fd, SNDCTL_DSP_RESET, 0)){
     perror("ags_devout_device_init : reset \0");
     exit(1);
   }

   fmt = AFMT_S16_LE; // CPU_IS_BIG_ENDIAN ? AFMT_S16_BE : AFMT_S16_LE ;
   if(ioctl (devout->out.device_fd, SOUND_PCM_SETFMT, &fmt) != 0){   
     perror("ags_devout_device_init : set format \0");
     exit(1);
   }

   if(ioctl (devout->out.device_fd, SOUND_PCM_WRITE_CHANNELS, &(devout->pcm_channels)) != 0){     
     perror("ags_devout_device_init : channels \0");
     exit(1);
   }

   if(ioctl (devout->out.device_fd, SOUND_PCM_WRITE_RATE, &(devout->frequence)) != 0){
    perror ("ags_devout_device_init : sample rate \0") ;
    exit(1);
  }

  if(ioctl (devout->out.device_fd, SNDCTL_DSP_SYNC, 0) != 0){
    perror("ags_devout_device_init : sync \0") ;
    exit(1);
  }
}

void
ags_devout_device_free(AgsDevout *devout)
{
  if(ioctl (AGS_DEVOUT(devout)->out.device_fd, SNDCTL_DSP_POST, 0) == -1)
    perror ("ioctl (SNDCTL_DSP_POST) \0") ;

  if(ioctl (devout->out.device_fd, SNDCTL_DSP_SYNC, 0) == -1)
    perror ("ioctl (SNDCTL_DSP_SYNC) \0") ;

  close(devout->out.device_fd);
}

void
ags_devout_ao_device_init(AgsDevout *devout)
{
  ao_sample_format *format;

  ao_initialize();
  devout->out.ao.driver_ao = ao_default_driver_id();

  format = &(devout->out.ao.format);
  format->bits = 16;
  format->channels = 2;
  format->rate = 44100;
  format->byte_format = AO_FMT_LITTLE;

  devout->out.ao.device = ao_open_live(devout->out.ao.driver_ao, format, NULL /* no options */);

  if(devout->out.ao.device == NULL){
    fprintf(stderr, "Error opening device.\n\0");
    exit(1);
  }
}

void
ags_devout_ao_device_free(AgsDevout *devout)
{
  ao_close(devout->out.ao.device);
  ao_shutdown();
}

void
ags_devout_play_recall(AgsDevout *devout)
{
  AgsRecall *recall;
  GList *list, *list_next;
  guint whence;
  GStaticMutex mutex = G_STATIC_MUTEX_INIT;

  devout->flags |= AGS_DEVOUT_PLAYING_RECALL;
  whence = 0;

 ags_devout_play_recall0:

  list = devout->recall;

  if(list == NULL){
    devout->flags &= (~AGS_DEVOUT_PLAY_RECALL);
    AGS_DEVOUT_GET_CLASS(devout)->stop(devout);
  }

  while(list != NULL){
    recall = AGS_RECALL(list->data);
    list_next = list->next;

    if((AGS_RECALL_CANCEL & (recall->flags)) != 0){
      g_static_mutex_lock(&mutex);
      devout->play_recall_ref--;
      devout->recall = g_list_remove(devout->recall, recall);
      g_static_mutex_unlock(&mutex);

      g_signal_emit_by_name((GObject *) recall, "cancel\0");
    }else if((AGS_RECALL_REMOVE & (recall->flags)) != 0){
      g_static_mutex_lock(&mutex);
      devout->play_recall_ref--;
      devout->recall = g_list_remove(devout->recall, recall);
      g_static_mutex_unlock(&mutex);

      g_signal_emit_by_name((GObject *) recall, "stop\0");
    }else{
      if(whence == 0){
	g_signal_emit_by_name((GObject *) recall, "run_pre\0");
      }else if(whence == 1){
	g_signal_emit_by_name((GObject *) recall, "run_inter\0");
      }else{
	g_signal_emit_by_name((GObject *) recall, "run_post\0");
      }
    }

    list = list_next;
  }

  if(whence == 0){
    whence = 1;
    goto ags_devout_play_recall0;
  }else if(whence == 1){
    whence = 2;
    goto ags_devout_play_recall0;
  }

  devout->flags &= (~AGS_DEVOUT_PLAYING_RECALL);
}

void
ags_devout_play_audio(AgsDevout *devout)
{
  AgsAudio *audio;
  AgsChannel *channel;
  GList *list_audio, *list_next_audio;
  guint whence;
  gboolean cancel;
  GStaticMutex mutex = G_STATIC_MUTEX_INIT;
  void ags_devout_play_audio_play(AgsChannel *channel){
    AgsRecall *recall;
    GList *list_play, *list_next_play;

    list_play = channel->play;

    while(list_play != NULL){
      list_next_play = list_play->next;

      recall = AGS_RECALL(list_play->data);

      if((AGS_RECALL_HIDE & recall->flags) == 0){
	if((AGS_RECALL_CANCEL & (recall->flags)) != 0 || cancel){
	  g_signal_emit_by_name((GObject *) recall, "cancel\0");
	}else if((AGS_RECALL_REMOVE & (recall->flags)) != 0){
	  channel->play = g_list_remove(channel->play, recall);

	  g_signal_emit_by_name((GObject *) recall, "stop\0");
	}else{
	  if(whence == 0)
	    g_signal_emit_by_name((GObject *) recall, "run_pre\0");
	  else if(whence == 1)
	    g_signal_emit_by_name((GObject *) recall, "run_inter\0");
	  else
	    g_signal_emit_by_name((GObject *) recall, "run_post\0");
	}
      }

      list_play = list_next_play;
    }
  }
  void ags_devout_play_audio_recall(AgsChannel *channel){
    AgsRecall *recall;
    GList *list_recall, *list_next_recall;

    list_recall = channel->recall;

    while(list_recall != NULL){
      list_next_recall = list_recall->next;

      recall = AGS_RECALL(list_recall->data);

      if((AGS_RECALL_HIDE & recall->flags) == 0){
	if((AGS_RECALL_CANCEL & (recall->flags)) != 0 || cancel){
	  g_signal_emit_by_name((GObject *) recall, "cancel\0");
	}else if((AGS_RECALL_REMOVE & (recall->flags)) != 0){
	  channel->play = g_list_remove(channel->play, recall);
	  
	  g_signal_emit_by_name((GObject *) recall, "stop\0");
	}else{
	  if(whence == 0)
	    g_signal_emit_by_name((GObject *) recall, "run_pre\0");
	  else if(whence == 1)
	    g_signal_emit_by_name((GObject *) recall, "run_inter\0");
	  else
	    g_signal_emit_by_name((GObject *) recall, "run_post\0");
	}
      }

      list_recall = list_next_recall;
    }
  }
  void ags_devout_play_audio_audio_recall(AgsAudio *audio){
    AgsRecall *recall;
    GList *list_recall, *list_next_recall;

    list_recall = audio->recall;

    while(list_recall != NULL){
      list_next_recall = list_recall->next;

      recall = AGS_RECALL(list_recall->data);
	
      if((AGS_RECALL_HIDE & recall->flags) == 0){
	if((AGS_RECALL_CANCEL & (recall->flags)) != 0 || cancel){
	  g_signal_emit_by_name((GObject *) recall, "cancel\0");
	}else if((AGS_RECALL_REMOVE & (recall->flags)) != 0){
	  audio->recall = g_list_remove(audio->recall, recall);

	  g_signal_emit_by_name((GObject *) recall, "stop\0");
	}else{
	  if(whence == 0)
	    g_signal_emit_by_name((GObject *) recall, "run_pre\0");
	  else if(whence == 1)
	    g_signal_emit_by_name((GObject *) recall, "run_inter\0");
	  else
	    g_signal_emit_by_name((GObject *) recall, "run_post\0");
	}
      }

      list_recall = list_next_recall;
    }
  }
  void ags_devout_play_audio_recursive_recall(AgsChannel *output){
    AgsAudio *audio;
    AgsChannel *current, *input;

    audio = AGS_AUDIO(output->audio);

    if((AGS_AUDIO_SYNC & (audio->flags)) != 0){
      if((AGS_AUDIO_ASYNC & (audio->flags)) != 0){
	if(((AGS_CHANNEL_PRE_SYNC_ASYNC_DONE & (output->flags)) == 0 && whence == 0) ||
	   ((AGS_CHANNEL_INTER_SYNC_ASYNC_DONE & (output->flags)) == 0 && whence == 1) ||
	   ((AGS_CHANNEL_POST_SYNC_ASYNC_DONE & (output->flags)) == 0 && whence == 2)){
	  input = ags_channel_nth(audio->input, output->audio_channel);

	  while(input != NULL){
	    if(input->link != NULL)
	      ags_devout_play_audio_recursive_recall(input->link);

	    ags_devout_play_audio_recall(input);

	    input = input->next_pad;
	  }

	  current = output->next_pad;

	  while(current != NULL){
	    if(whence == 0)
	      current->flags |= AGS_CHANNEL_PRE_SYNC_ASYNC_DONE;
	    else if(whence == 1)
	      current->flags |= AGS_CHANNEL_INTER_SYNC_ASYNC_DONE;
	    else
	      current->flags |= AGS_CHANNEL_POST_SYNC_ASYNC_DONE;

	    current = current->next_pad;
	  }

	  current = output->prev_pad;

	  while(current != NULL){
	    if(whence == 0)
	      current->flags |= AGS_CHANNEL_PRE_SYNC_ASYNC_DONE;
	    else if(whence == 1)
	      current->flags |= AGS_CHANNEL_INTER_SYNC_ASYNC_DONE;
	    else
	      current->flags |= AGS_CHANNEL_POST_SYNC_ASYNC_DONE;

	    current = current->prev_pad;
	  }
	}else{
	  if(whence == 0)
	    output->flags &= (~AGS_CHANNEL_PRE_SYNC_ASYNC_DONE);
	  else if(whence == 1)
	    output->flags &= (~AGS_CHANNEL_INTER_SYNC_ASYNC_DONE);
	  else
	    output->flags &= (~AGS_CHANNEL_POST_SYNC_ASYNC_DONE);
	}
      }else{
	input = ags_channel_nth(audio->input, output->line);

	if(input->link != NULL)
	  ags_devout_play_audio_recursive_recall(input->link);

	ags_devout_play_audio_recall(input);
      }
    }else{
      input = ags_channel_nth(audio->input, output->audio_channel);

      while(input != NULL){
	if(input->link != NULL)
	  ags_devout_play_audio_recursive_recall(input->link);

	ags_devout_play_audio_recall(input);

	input = input->next_pad;
      }
    }

    /* call AgsAudio */
    if((AGS_CHANNEL_AUDIO_DONE & (output->flags)) == 0){
      ags_devout_play_audio_audio_recall(audio);

      current = output->prev;

      while(current != NULL){
	current->flags |= AGS_CHANNEL_AUDIO_DONE;

	current = current->prev;
      }

      current = output->next;

      while(current != NULL){
	current->flags |= AGS_CHANNEL_AUDIO_DONE;

	current = current->next;
      }
    }else
      output->flags &= (~AGS_CHANNEL_AUDIO_DONE);

    /* call output*/
    ags_devout_play_audio_recall(output);
  }
  void ags_devout_play_audio_recursive_play(AgsChannel *output){
    AgsAudio *audio;
    AgsChannel *current, *input;

    audio = AGS_AUDIO(output->audio);

    if((AGS_AUDIO_SYNC & (audio->flags)) != 0){
      if((AGS_AUDIO_ASYNC & (audio->flags)) != 0){

	if(((AGS_CHANNEL_PRE_SYNC_ASYNC_DONE & (output->flags)) == 0 && whence == 0) ||
	   ((AGS_CHANNEL_INTER_SYNC_ASYNC_DONE & (output->flags)) == 0 && whence == 1) ||
	   ((AGS_CHANNEL_POST_SYNC_ASYNC_DONE & (output->flags)) == 0 && whence == 2)){

	  input = ags_channel_nth(audio->input, output->audio_channel);
	  
	  if((AGS_AUDIO_OUTPUT_HAS_RECYCLING & (audio->flags)) != 0){
	    /* AgsInput recursive AgsRecall */
	    while(input != NULL){
	      if(input->link != NULL)
		ags_devout_play_audio_recursive_recall(input->link);

	      ags_devout_play_audio_recall(input);

	      input = input->next_pad;
	    }
	  }else{
	    /* !AGS_AUDIO_OUTPUT_HAS_RECYCLING */

	    while(input != NULL){
	      if(input->link != NULL)
		ags_devout_play_audio_recursive_play(input->link);
	      
	      ags_devout_play_audio_play(input);

	      input = input->next_pad;
	    }
	  }

	  current = output->next_pad;

	  while(current != NULL){
	    if(whence == 0)
	      current->flags |= AGS_CHANNEL_PRE_SYNC_ASYNC_DONE;
	    else if(whence == 1)
	      current->flags |= AGS_CHANNEL_INTER_SYNC_ASYNC_DONE;
	    else
	      current->flags |= AGS_CHANNEL_POST_SYNC_ASYNC_DONE;

	    current = current->next_pad;
	  }

	  current = output->prev_pad;

	  while(current != NULL){
	    if(whence == 0)
	      current->flags |= AGS_CHANNEL_PRE_SYNC_ASYNC_DONE;
	    else if(whence == 1)
	      current->flags |= AGS_CHANNEL_INTER_SYNC_ASYNC_DONE;
	    else
	      current->flags |= AGS_CHANNEL_POST_SYNC_ASYNC_DONE;

	    current = current->prev_pad;
	  }
	}else{
	  if(whence == 0)
	    output->flags &= (~AGS_CHANNEL_PRE_SYNC_ASYNC_DONE);
	  else if(whence == 1)
	    output->flags &= (~AGS_CHANNEL_INTER_SYNC_ASYNC_DONE);
	  else
	    output->flags &= (~AGS_CHANNEL_POST_SYNC_ASYNC_DONE);
	}
      }else{
	input = ags_channel_nth(audio->input, output->line);

	if((AGS_AUDIO_OUTPUT_HAS_RECYCLING & (audio->flags)) != 0){
	  if(input->link != NULL)
	    ags_devout_play_audio_recursive_recall(input->link);

	  ags_devout_play_audio_recall(input);
	}else{
	  if(input->link != NULL)
	    ags_devout_play_audio_recursive_play(input->link);

	  ags_devout_play_audio_play(input);
	}
      }
    }else{
      input = ags_channel_nth(audio->input, output->audio_channel);

      if((AGS_AUDIO_OUTPUT_HAS_RECYCLING & (audio->flags)) != 0){
	while(input != NULL){
	  if(input->link != NULL)
	    ags_devout_play_audio_recursive_recall(input->link);

	  ags_devout_play_audio_recall(input);

	  input = input->next_pad;
	}
      }else{
	while(input != NULL){
	  if(input->link != NULL)
	    ags_devout_play_audio_recursive_play(input->link);

	  ags_devout_play_audio_play(input);

	  input = input->next_pad;
	}
      }
    }

    /* call AgsAudio */
    if((AGS_CHANNEL_AUDIO_DONE & (output->flags)) == 0){
      if(whence != 2)
	ags_devout_play_audio_audio_recall(audio);

      current = output->prev;

      while(current != NULL){
	current->flags |= AGS_CHANNEL_AUDIO_DONE;

	current = current->prev;
      }

      current = output->next;

      while(current != NULL){
	current->flags |= AGS_CHANNEL_AUDIO_DONE;

	current = current->next;
      }
    }else
      output->flags &= (~AGS_CHANNEL_AUDIO_DONE);

    /* call output */
    ags_devout_play_audio_play(output);
  }

  devout->flags |= AGS_DEVOUT_PLAYING_AUDIO;

  /* run_pre */
  list_audio = devout->audio;

  if(list_audio == NULL){
    AGS_DEVOUT_GET_CLASS(devout)->stop(devout);
    devout->flags &= (~AGS_DEVOUT_PLAY_AUDIO);
  }

  whence = 0;

  while(list_audio != NULL){
    if(list_audio->data == NULL){
      list_audio = list_audio->next;
      continue;
    }

    audio = AGS_AUDIO(list_audio->data);
    list_next_audio = list_audio->next;

    if((AGS_AUDIO_DEVOUT_PLAY_CANCEL & (audio->flags)) != 0){
      devout->audio = g_list_remove(devout->audio, audio);
      cancel = TRUE;
    }else
      cancel = FALSE;

    channel = audio->output;

    while(channel != NULL){
      ags_devout_play_audio_recursive_play(channel);

      channel = channel->next;
    }

    list_audio = list_next_audio;
  }

  /* run_inter */
  list_audio = devout->audio;
  whence = 1;

  while(list_audio != NULL){
    if(list_audio->data == NULL){
      list_audio = list_audio->next;
      continue;
    }

    audio = AGS_AUDIO(list_audio->data);
    list_next_audio = list_audio->next;

    if((AGS_AUDIO_DEVOUT_PLAY_CANCEL & (audio->flags)) != 0){
      devout->audio = g_list_remove(devout->audio, audio);
      cancel = TRUE;
    }else
      cancel = FALSE;

    channel = audio->output;

    while(channel != NULL){
      ags_devout_play_audio_recursive_play(channel);

      channel = channel->next;
    }

    list_audio = list_next_audio;
  }

  /* run_post */
  list_audio = devout->audio;
  whence = 2;

  while(list_audio != NULL){
    if(list_audio->data == NULL){
      list_audio = list_audio->next;
      continue;
    }

    audio = AGS_AUDIO(list_audio->data);
    list_next_audio = list_audio->next;

    if((AGS_AUDIO_DEVOUT_PLAY_CANCEL & (audio->flags)) != 0){
      devout->audio = g_list_remove(devout->audio, audio);
      cancel = TRUE;
    }else
      cancel = FALSE;

    channel = audio->output;

    while(channel != NULL){
      ags_devout_play_audio_recursive_play(channel);

      channel = channel->next;
    }

    if((AGS_AUDIO_DEVOUT_PLAY_REMOVE & (audio->flags)) != 0){
      g_static_mutex_lock(&mutex);
      devout->play_audio_ref--;
      devout->audio = g_list_remove(devout->audio, audio);
      g_static_mutex_unlock(&mutex);
    }

    list_audio = list_next_audio;
  }


  devout->flags &= (~AGS_DEVOUT_PLAYING_AUDIO);
}

void
ags_devout_run(AgsDevout *devout)
{
  GList *stream;
  guint i;

  if((AGS_DEVOUT_PLAY & devout->flags) != 0){
    fprintf(stdout, "ags_devout_run:  allready playing\n\0");
    return;
  }

  if((AGS_DEVOUT_LIBAO & devout->flags) != 0)
    ags_devout_ao_device_init(devout);
  else
    ags_devout_device_init(devout);

  memset(devout->buffer[0], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
  memset(devout->buffer[1], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
  memset(devout->buffer[2], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
  memset(devout->buffer[3], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));

  devout->flags |= (AGS_DEVOUT_BUFFER0 | AGS_DEVOUT_PLAY | AGS_DEVOUT_WAIT_DEVICE | AGS_DEVOUT_WAIT_RECALL);

  if((AGS_DEVOUT_LIBAO & devout->flags) != 0)
    devout->play_thread = g_thread_create(ags_devout_ao_play, devout, FALSE, NULL);
  else
    devout->play_thread = g_thread_create(ags_devout_play, devout, FALSE, NULL);

  devout->play_functions_thread = g_thread_create(ags_devout_play_functions, devout, FALSE, NULL);
}

gpointer
ags_devout_play_functions(gpointer devout0)
{
  AgsDevout *devout = devout0;
  //  static struct timespec ts;
  GStaticMutex mutex = G_STATIC_MUTEX_INIT;
  void ags_devout_play_functions_timing(){
    while((AGS_DEVOUT_WAIT_DEVICE & devout->flags) != 0){
      g_cond_wait(devout->play_functions_cond,
      		  g_static_mutex_get_mutex(&mutex));
      //      nanosleep(&ts, NULL);
    }

    devout->flags |= AGS_DEVOUT_WAIT_RECALL;
    devout->flags |= AGS_DEVOUT_WAIT_DEVICE;
    g_static_mutex_unlock(&mutex);
  }

  fprintf(stdout, "ags_devout_play_functions:  start\n\0");

  //  ts.tv_sec = 0;
  //  ts.tv_nsec = 100;

  while((AGS_DEVOUT_PLAY & devout->flags) != 0){

    if((AGS_DEVOUT_PLAY_RECALL & devout->flags) != 0){
      ags_devout_play_recall(devout);

      if(devout->play_recall_ref == 0){
	devout->flags &= (~AGS_DEVOUT_PLAY_RECALL);
	AGS_DEVOUT_GET_CLASS(devout)->stop(devout);
	fprintf(stdout, "devout->play_recall_ref == 0\n\0");
      }
    }

    if((AGS_DEVOUT_PLAY_AUDIO & devout->flags) != 0){
      ags_devout_play_audio(devout);

      if(devout->play_audio_ref == 0){
	devout->flags &= (~AGS_DEVOUT_PLAY_AUDIO);
	AGS_DEVOUT_GET_CLASS(devout)->stop(devout);
	fprintf(stdout, "devout->play_audio_ref == 0\n\0");
      }
    }

    g_static_mutex_lock(&mutex);
    devout->flags &= (~AGS_DEVOUT_WAIT_RECALL);

    if((AGS_DEVOUT_WAIT_DEVICE & devout->flags) != 0){
      ags_devout_play_functions_timing();
    }else{
      g_cond_signal(devout->play_cond);
      g_static_mutex_unlock(&mutex);
    }
  }

  return(NULL);
}

gpointer
ags_devout_play(gpointer devout0)
{
  AgsDevout *devout = devout0;
  //  struct timespec ts;
  GStaticMutex mutex = G_STATIC_MUTEX_INIT;
  void ags_devout_play_timing(){
    while((AGS_DEVOUT_WAIT_RECALL & devout->flags) != 0){
      g_cond_wait(devout->play_functions_cond,
      		  g_static_mutex_get_mutex(&mutex));
      //      nanosleep(&ts, NULL);
    }

    devout->flags |= AGS_DEVOUT_WAIT_RECALL;
    devout->flags |= AGS_DEVOUT_WAIT_DEVICE;
    g_static_mutex_unlock(&mutex);
  }

  //  ts.tv_sec = 0;
  //  ts.tv_nsec = 100;

  while((AGS_DEVOUT_PLAY & devout->flags) != 0){
    if((AGS_DEVOUT_BUFFER0 & devout->flags) != 0){
      memset(devout->buffer[3], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
      write(devout->out.device_fd, devout->buffer[0], devout->buffer_size * sizeof(short));

      g_static_mutex_lock(&mutex);
      devout->flags &= (~AGS_DEVOUT_BUFFER0);
      devout->flags |= AGS_DEVOUT_BUFFER1;
      g_static_mutex_unlock(&mutex);
    }else if((AGS_DEVOUT_BUFFER1 & devout->flags) != 0){
      memset(devout->buffer[0], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
      write(devout->out.device_fd, devout->buffer[1], devout->buffer_size * sizeof(short));

      g_static_mutex_lock(&mutex);
      devout->flags &= (~AGS_DEVOUT_BUFFER1);
      devout->flags |= AGS_DEVOUT_BUFFER2;
      g_static_mutex_unlock(&mutex);
    }else if((AGS_DEVOUT_BUFFER2 & devout->flags) != 0){
      memset(devout->buffer[1], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
      write(devout->out.device_fd, devout->buffer[2], devout->buffer_size * sizeof(short));

      g_static_mutex_lock(&mutex);
      devout->flags &= (~AGS_DEVOUT_BUFFER2);
      devout->flags |= AGS_DEVOUT_BUFFER3;
      g_static_mutex_unlock(&mutex);
    }else if((AGS_DEVOUT_BUFFER3 & devout->flags) != 0){
      memset(devout->buffer[2], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
      write(devout->out.device_fd, devout->buffer[3], devout->buffer_size * sizeof(short));

      g_static_mutex_lock(&mutex);
      devout->flags &= (~AGS_DEVOUT_BUFFER3);
      devout->flags |= AGS_DEVOUT_BUFFER0;
      g_static_mutex_unlock(&mutex);
    }

    if((AGS_DEVOUT_COUNT & devout->flags) != 0)
      devout->offset++;

    g_static_mutex_lock(&mutex);
    devout->flags &= (~AGS_DEVOUT_WAIT_DEVICE);

    if((AGS_DEVOUT_WAIT_RECALL & devout->flags) != 0){
      ags_devout_play_timing();
    }else{
      g_cond_signal(devout->play_functions_cond);
      g_static_mutex_unlock(&mutex);
    }
  }

  if((AGS_DEVOUT_BUFFER0 & devout->flags) != 0){
    memset(devout->buffer[3], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
    write(devout->out.device_fd, devout->buffer[0], devout->buffer_size * sizeof(short));

    devout->flags &= (~AGS_DEVOUT_BUFFER0);
  }else if((AGS_DEVOUT_BUFFER1 & devout->flags) != 0){
    memset(devout->buffer[0], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
    write(devout->out.device_fd, devout->buffer[1], devout->buffer_size * sizeof(short));

    devout->flags &= (~AGS_DEVOUT_BUFFER1);
  }else if((AGS_DEVOUT_BUFFER2 & devout->flags) != 0){
    memset(devout->buffer[1], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
    write(devout->out.device_fd, devout->buffer[2], devout->buffer_size * sizeof(short));

    devout->flags &= (~AGS_DEVOUT_BUFFER2);
  }else if((AGS_DEVOUT_BUFFER3 & devout->flags) != 0){
    memset(devout->buffer[2], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
    write(devout->out.device_fd, devout->buffer[3], devout->buffer_size * sizeof(short));

    devout->flags &= (~AGS_DEVOUT_BUFFER3);
  }

  //  fprintf(stdout, "ags_devout_play: end\n\0");
  ags_devout_device_free(devout);

  return(NULL);
}

gpointer
ags_devout_garbage_collector(AgsDevout *devout)
{
  return(NULL);
}

void
ags_devout_stop(AgsDevout *devout)
{
  //  fprintf(stdout, "ags_devout_stop:\n\0");

  if((AGS_DEVOUT_PLAY_RECALL & devout->flags) == 0 && (AGS_DEVOUT_PLAY_AUDIO & devout->flags) == 0)
    devout->flags &= (~AGS_DEVOUT_PLAY);
}


gpointer
ags_devout_ao_play(AgsDevout *devout)
{
  //  struct timespec ts;
  GStaticMutex mutex = G_STATIC_MUTEX_INIT;
  void ags_devout_ao_play_timing(){
    while((AGS_DEVOUT_WAIT_RECALL & devout->flags) != 0){
      g_cond_wait(devout->play_cond,
		  g_static_mutex_get_mutex(&mutex));
      //      nanosleep(&ts, NULL);
    }

    devout->flags |= AGS_DEVOUT_WAIT_RECALL;
    g_static_mutex_unlock(&mutex);
  }

  //  ts.tv_sec = 0;
  //  ts.tv_nsec = 100;
  //  fprintf(stdout, "ags_devout_play:  start\n\0");

  while((AGS_DEVOUT_PLAY & devout->flags) != 0){
    //    fprintf(stdout, "ags_devout_play:\n  loop\n\0");

    if((AGS_DEVOUT_BUFFER0 & devout->flags) != 0){
      memset(devout->buffer[3], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
      ao_play(devout->out.ao.device, devout->buffer[0], devout->buffer_size * sizeof(short));

      g_static_mutex_lock(&mutex);
      devout->flags &= (~AGS_DEVOUT_BUFFER0);
      devout->flags |= AGS_DEVOUT_BUFFER1;
      g_static_mutex_unlock(&mutex);
    }else if((AGS_DEVOUT_BUFFER1 & devout->flags) != 0){
      memset(devout->buffer[0], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
      ao_play(devout->out.ao.device, devout->buffer[1], devout->buffer_size * sizeof(short));

      g_static_mutex_lock(&mutex);
      devout->flags &= (~AGS_DEVOUT_BUFFER1);
      devout->flags |= AGS_DEVOUT_BUFFER2;
      g_static_mutex_unlock(&mutex);
    }else if((AGS_DEVOUT_BUFFER2 & devout->flags) != 0){
      memset(devout->buffer[1], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
      ao_play(devout->out.ao.device, devout->buffer[2], devout->buffer_size * sizeof(short));

      g_static_mutex_lock(&mutex);
      devout->flags &= (~AGS_DEVOUT_BUFFER2);
      devout->flags |= AGS_DEVOUT_BUFFER3;
      g_static_mutex_unlock(&mutex);
    }else if((AGS_DEVOUT_BUFFER3 & devout->flags) != 0){
      memset(devout->buffer[2], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
      ao_play(devout->out.ao.device, devout->buffer[3], devout->buffer_size * sizeof(short));

      g_static_mutex_lock(&mutex);
      devout->flags &= (~AGS_DEVOUT_BUFFER3);
      devout->flags |= AGS_DEVOUT_BUFFER0;
      g_static_mutex_unlock(&mutex);
    }

    if((AGS_DEVOUT_COUNT & devout->flags) != 0)
      devout->offset++;

    g_static_mutex_lock(&mutex);
    devout->flags &= (~AGS_DEVOUT_WAIT_DEVICE);

    if((AGS_DEVOUT_WAIT_RECALL & devout->flags) != 0){
      ags_devout_ao_play_timing();
    }else{
      g_cond_signal(devout->play_functions_cond);
      g_static_mutex_unlock(&mutex);
    }
  }

  if((AGS_DEVOUT_BUFFER0 & devout->flags) != 0){
    memset(devout->buffer[3], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
    ao_play(devout->out.ao.device, devout->buffer[0], devout->buffer_size * sizeof(short));

    devout->flags &= (~AGS_DEVOUT_BUFFER0);
  }else if((AGS_DEVOUT_BUFFER1 & devout->flags) != 0){
    memset(devout->buffer[0], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
    ao_play(devout->out.ao.device, devout->buffer[1], devout->buffer_size * sizeof(short));

    devout->flags &= (~AGS_DEVOUT_BUFFER1);
  }else if((AGS_DEVOUT_BUFFER2 & devout->flags) != 0){
    memset(devout->buffer[1], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
    ao_play(devout->out.ao.device, devout->buffer[2], devout->buffer_size * sizeof(short));

    devout->flags &= (~AGS_DEVOUT_BUFFER2);
  }else if((AGS_DEVOUT_BUFFER3 & devout->flags) != 0){
    memset(devout->buffer[2], 0, devout->dsp_channels * devout->buffer_size * sizeof(short));
    ao_play(devout->out.ao.device, devout->buffer[3], devout->buffer_size * sizeof(short));

    devout->flags &= (~AGS_DEVOUT_BUFFER3);
  }

  fprintf(stdout, "ags_devout_play: end\n\0");
  ags_devout_ao_device_free(devout);

  return(NULL);
}

void
ags_devout_ao_stop(AgsDevout *devout)
{
  if((AGS_DEVOUT_PLAY_RECALL & devout->flags) == 0 && (AGS_DEVOUT_PLAY_AUDIO & devout->flags) == 0)
    devout->flags &= (~AGS_DEVOUT_PLAY);
}

AgsDevout*
ags_devout_new()
{
  AgsDevout *devout;

  devout = (AgsDevout *) g_object_new(AGS_TYPE_DEVOUT, NULL);

  return(devout);
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]