/*
    GDAM - Geoff & Dave's Audio Mixer
    Copyright (C) 1999    Dave Benson, Geoff Matters.

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

    Contact:
        daveb@ffem.org <Dave Benson>
        geoff@ugcs.caltech.edu <Geoff Matters>
*/
#ifndef __GDAM_CALLBACK_DEVICE_H_
#define __GDAM_CALLBACK_DEVICE_H_

#include <gdam/common/gdamautoconf.h>

typedef struct _GdamCallbackDevice GdamCallbackDevice;
typedef struct _GdamCallbackDeviceClass GdamCallbackDeviceClass;

#include "gdamoutputdevice.h"
#include <semaphore.h>
#include <gdam/common/gdamfdpoll.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

GtkType gdam_callback_device_get_type();
#define GDAM_TYPE_CALLBACK_DEVICE			(gdam_callback_device_get_type ())
#define GDAM_CALLBACK_DEVICE(obj)              (GTK_CHECK_CAST ((obj), GDAM_TYPE_CALLBACK_DEVICE, GdamCallbackDevice))
#define GDAM_CALLBACK_DEVICE_CLASS(klass)      (GTK_CHECK_CLASS_CAST ((klass), GDAM_TYPE_CALLBACK_DEVICE, GdamCallbackDeviceClass))
#define GDAM_IS_CALLBACK_DEVICE(obj)           (GTK_CHECK_TYPE ((obj), GDAM_TYPE_CALLBACK_DEVICE))
#define GDAM_IS_CALLBACK_DEVICE_CLASS(klass)   (GTK_CHECK_CLASS_TYPE ((klass), GDAM_TYPE_CALLBACK_DEVICE))

struct _GdamCallbackDeviceClass {
  GdamOutputDeviceClass		output_device_class;
};

struct _GdamCallbackDevice {
  GdamOutputDevice		output_device;
  int				frag_buffer_size;
  GdamSample                     *temp_buffer;
  GdamSample                     *fragment_buffer_out;
  gboolean			is_open;

  /* prefill buffer is used in two ways - the fill thread appends data to the
   * end, and increases the amount.  The drain  thread reads data from the
   * start, sets the new starting position, and decreases the amount.
   * The only variable changed by both threads is amount, so use += / -=
   * Lock the semaphore to ensure pre_buffer variables are read / set
   * atomically.
   */
  sem_t                *semaphore;
  /* If the pre_buffer must be filled in an asynchronous fashion, then this 
   * larger lock must be obtained */
  sem_t                *buffer_semaphore;
  /* Whether to use the above semaphores */
  gboolean		use_semaphore;

  /* Avoid frequent repeated allocation */
  char 		       *fill_tmp_buffer;
  
  GdamFdPoll           *ipc_fd_poll;
  int			ipc_read_fd;
  int			ipc_write_fd;
};

gboolean 
gdam_callback_device_fill_one_frag (GdamCallbackDevice  *callback_device, 
                                    GdamSample          *fragment_buffer_out,
				    int                  frag_buffer_size_out, 
                                    int                  _samples_out);
void
gdam_callback_device_add_ipc_poll (GdamCallbackDevice   *callback_device);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif
