/* Ekiga -- A VoIP and Video-Conferencing application
 * Copyright (C) 2000-2007 Damien Sandras
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library 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.
 */

/*
 *                         gmaudiosrc.c  -  description
 *                         ------------------------------------------
 *   begin                : written in 2007 by Julien Puydt
 *   copyright            : (c) 2007 by Julien Puydt
 *   description          : implementation of a gstreamer source to push data
 *                          from pwlib to a gstreamer pipeline
 *
 */


#include <stdlib.h>
#include <string.h>

#include "gmaudiosrc.h"
#include <gst/gstmarshal.h>

static GstStaticPadTemplate srctemplate =
GST_STATIC_PAD_TEMPLATE ("src",
			 GST_PAD_SRC,
			 GST_PAD_ALWAYS,
			 GST_STATIC_CAPS_ANY);

GST_DEBUG_CATEGORY_STATIC (gm_audio_src_debug);
#define GST_CAT_DEFAULT gm_audio_src_debug

static const GstElementDetails gm_audio_src_details =
GST_ELEMENT_DETAILS ("Ekiga Audio Source",
		     "Source/Audio",
		     "Push data in a gstreamer pipeline",
		     "Julien Puydt <jpuydt@free.fr>");

#define _do_init(bla) \
    GST_DEBUG_CATEGORY_INIT (gm_audio_src_debug, "gmaudiosrc", 0, "gmaudiosrc element");

GST_BOILERPLATE_FULL (GmAudioSrc, gm_audio_src,
		      GstBaseSrc, GST_TYPE_BASE_SRC,
		      _do_init);

static void gm_audio_src_finalize (GObject *object);
static gboolean gm_audio_src_start (GstBaseSrc *basesrc);
static gboolean gm_audio_src_stop (GstBaseSrc *basesrc);
static gboolean gm_audio_src_is_seekable (GstBaseSrc *basesrc);
static GstFlowReturn gm_audio_src_create (GstBaseSrc *src,
					  guint64 offset,
					  guint length,
					  GstBuffer **buf);

static void
gm_audio_src_base_init (gpointer g_class)
{
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);

  gst_element_class_add_pad_template (gstelement_class,
				      gst_static_pad_template_get (&srctemplate));

  gst_element_class_set_details (gstelement_class,
				 &gm_audio_src_details);
}

static void
gm_audio_src_class_init (GmAudioSrcClass *klass)
{
  GObjectClass *gobject_class;
  GstBaseSrcClass *gstbase_src_class;

  g_print ("%s\n", __PRETTY_FUNCTION__);

  gobject_class = G_OBJECT_CLASS (klass);
  gstbase_src_class = GST_BASE_SRC_CLASS (klass);

  gobject_class->finalize = GST_DEBUG_FUNCPTR (gm_audio_src_finalize);

  gstbase_src_class->is_seekable = GST_DEBUG_FUNCPTR (gm_audio_src_is_seekable);
  gstbase_src_class->start = GST_DEBUG_FUNCPTR (gm_audio_src_start);
  gstbase_src_class->stop = GST_DEBUG_FUNCPTR (gm_audio_src_stop);
  gstbase_src_class->create = GST_DEBUG_FUNCPTR (gm_audio_src_create);
}

static void
gm_audio_src_init (GmAudioSrc *src,
		   GmAudioSrcClass *g_class)
{
  g_print ("%s\n", __PRETTY_FUNCTION__);
  src->buffer = NULL;
  gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
}

static void
gm_audio_src_finalize (GObject * object)
{
  GmAudioSrc *src;

  g_print ("%s\n", __PRETTY_FUNCTION__);

  src = GM_AUDIO_SRC (object);

  if (src->buffer)
    gst_object_unref (src->buffer);
  src->buffer = NULL;

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static GstFlowReturn
gm_audio_src_create (GstBaseSrc *basesrc,
		     guint64 offset,
		     guint length,
		     GstBuffer **ret)
{
  GmAudioSrc *src;
  GstFlowReturn result;
  GstCaps *caps;

  g_print ("%s\n", __PRETTY_FUNCTION__);

  src = GM_AUDIO_SRC (basesrc);

  GST_OBJECT_LOCK (src);
  if (src->buffer) {

    *ret = src->buffer;
    src->buffer = NULL;
  } else {

    /* return zero-filled buffer */
    *ret = gst_buffer_new ();
    GST_BUFFER_MALLOCDATA (*ret) = g_malloc0 (length);
    GST_BUFFER_DATA (*ret) = GST_BUFFER_MALLOCDATA (*ret);
    GST_BUFFER_SIZE (*ret) = length;
  }
  GST_BUFFER_OFFSET (*ret) = src->offset++;
  GST_OBJECT_UNLOCK (src);

  return GST_FLOW_OK;
}

static gboolean
gm_audio_src_start (GstBaseSrc *basesrc)
{
  g_print ("%s\n", __PRETTY_FUNCTION__);

  return TRUE;
}

static gboolean
gm_audio_src_stop (GstBaseSrc *basesrc)
{
  g_print ("%s\n", __PRETTY_FUNCTION__);

  return TRUE;
}

static gboolean
gm_audio_src_is_seekable (GstBaseSrc *basesrc)
{
  g_print ("%s\n", __PRETTY_FUNCTION__);

  return FALSE;
}

void
gm_audio_src_push_data (GmAudioSrc *src,
			const void *data,
			guint length)
{
  GstBuffer *buf = NULL;

  g_return_if_fail (GM_IS_AUDIO_SRC (src));
  g_print ("%s\n", __PRETTY_FUNCTION__);

  if (length > 0) {

    buf = gst_buffer_new ();
    GST_BUFFER_MALLOCDATA (buf) = g_malloc0 (length);
    GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf);
    GST_BUFFER_SIZE (buf) = length;
    memcpy (GST_BUFFER_MALLOCDATA (buf), data, length);
    GST_OBJECT_LOCK (src);
    if (src->buffer != NULL) /* will it happen ? */
      gst_buffer_unref (src->buffer);
    src->buffer = buf;
    GST_OBJECT_UNLOCK (src);
  }
}
