/* Gnome-Streamer
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * 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.
 */


#define PLUGIN_NAME "parsewav"


#include <gstparsewav.h>
#include <gmodule.h>
#include <gst/gstplugin.h>
#include <gst/gsttype.h>


/* ParseWav signals and args */
enum {
  /* FILL ME */
  LAST_SIGNAL
};

enum {
  ARG_0,
  /* FILL ME */
};


static void gst_parseau_class_init(GstParseAuClass *klass);
static void gst_parseau_init(GstParseAu *parseau);


static GstFilterClass *parent_class = NULL;
static guint gst_parseau_signals[LAST_SIGNAL] = { 0 };

GtkType
gst_parseau_get_type(void) {
  static GtkType parseau_type = 0;

  if (!parseau_type) {
    static const GtkTypeInfo parseau_info = {
      "GstParseAu",
      sizeof(GstParseAu),
      sizeof(GstParseAuClass),
      (GtkClassInitFunc)gst_parseau_class_init,
      (GtkObjectInitFunc)gst_parseau_init,
      (GtkArgSetFunc)NULL,
      (GtkArgGetFunc)NULL,
      (GtkClassInitFunc)NULL,
    };
    parseau_type = gtk_type_unique(GST_TYPE_FILTER,&parseau_info);
  }
  return parseau_type;
}

static void
gst_parseau_class_init(GstParseAuClass *klass) {
  GstFilterClass *gstfilter_class;

  gstfilter_class = (GstFilterClass*)klass;

  parent_class = gtk_type_class(GST_TYPE_FILTER);
}

static void gst_parseau_init(GstParseAu *parseau) {
  parseau->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
  gst_element_add_pad(GST_ELEMENT(parseau),parseau->sinkpad);
  gst_pad_set_chain_function(parseau->sinkpad,gst_parseau_chain);
  parseau->srcpad = gst_pad_new("src",GST_PAD_SRC);
  gst_element_add_pad(GST_ELEMENT(parseau),parseau->srcpad);

  parseau->offset = 0;
  parseau->size = 0;
  parseau->encoding = 0;
  parseau->frequency = 0;
  parseau->channels = 0;
}

GstElement *gst_parseau_new(gchar *name) {
  GstElement *parseau = GST_ELEMENT(gtk_type_new(GST_TYPE_PARSEAU));
  gst_object_set_name(GST_OBJECT(parseau),name);
  return parseau;
}

void gst_parseau_chain(GstPad *pad,GstBuffer *buf) {
  GstParseAu *parseau;
  gchar *data;
  glong size;

  g_return_if_fail(pad != NULL);
  g_return_if_fail(GST_IS_PAD(pad));
  g_return_if_fail(buf != NULL);
  g_return_if_fail(GST_IS_BUFFER(buf));

  parseau = GST_PARSEAU(pad->parent);
  g_print("gst_parseau_chain: got buffer in '%s'\n",
          gst_object_get_name(GST_OBJECT(parseau)));
  data = (guchar *)buf->data;
  size = buf->datasize;

  /* if we haven't seen any data yet... */
  if (parseau->size == 0) {
    GstBuffer *newbuf;
    glong *head = (glong *)data;
    if (GULONG_FROM_BE(*(head++)) == 0x2e736e64) {
      parseau->offset = GULONG_FROM_BE(*(head++));
      parseau->size = GULONG_FROM_BE(*(head++));
      parseau->encoding = GULONG_FROM_BE(*(head++));
      parseau->frequency = GULONG_FROM_BE(*(head++));
      parseau->channels = GULONG_FROM_BE(*(head++));
      parseau->bps = ((parseau->encoding < 3) ? 1 : 2) * parseau->channels;
      g_print("offset %ld, size %ld, encoding %ld, frequency %ld, channels %d\n",
               parseau->offset,parseau->size,parseau->encoding,
               parseau->frequency,parseau->channels);
    } else {
      g_print("help, dunno what I'm looking at!\n");
      gst_buffer_destroy(buf);
      return;
    }

    switch (parseau->encoding) {
      case 1:
        parseau->meta.format = AFMT_MU_LAW;break;
      case 2:
        parseau->meta.format = AFMT_S8;break;
      case 3:
        parseau->meta.format = AFMT_S16_LE;break;
      default:
        g_print("help!, don't know how to deal with this format yet\n");
        return;
    }
    parseau->meta.frequency = parseau->frequency;
    parseau->meta.channels = parseau->channels;

    newbuf = GST_BUFFER(gst_buffer_new());
    newbuf->data = (gpointer)malloc(size-(parseau->offset));
    memcpy(newbuf->data,data+24,size-(parseau->offset));
    gst_buffer_destroy(buf);
    newbuf->datasize = size-(parseau->offset);
    newbuf->meta = (gpointer)malloc(sizeof(GstAudioMeta));
    memcpy(newbuf->meta,&parseau->meta,sizeof(parseau->meta));
    ((GstAudioMeta *)newbuf->meta)->samples = (size-(parseau->offset)) / parseau->bps;
    gst_pad_push(parseau->srcpad,newbuf);
    return;
  }


  buf->meta = (gpointer)malloc(sizeof(GstAudioMeta));
  memcpy(buf->meta,&parseau->meta,sizeof(parseau->meta));
  ((GstAudioMeta *)buf->meta)->samples = size / parseau->bps;

  gst_pad_push(parseau->srcpad,buf);
}


GstPlugin *plugin_init(GModule *module) {
  GstPlugin *plugin;
  GstElementFactory *factory;
  GstType *autype, *rawtype;

  g_print(__PRETTY_FUNCTION__ ": initializing parseau plugin\n");

  /* create an elementfactory for the parseau element */
  factory = gst_elementfactory_new("parseau",GST_TYPE_PARSEAU,
                                   gst_parseau_new);
  g_return_if_fail(factory != NULL);
  g_print(__PRETTY_FUNCTION__ ": have factory\n");

  /* we're a plugin with one element */
  plugin = gst_plugin_new(PLUGIN_NAME);
  g_return_if_fail(plugin != NULL);
  plugin->elements = g_list_append(plugin->elements,factory);
  g_print(__PRETTY_FUNCTION__ ": have plugin\n");

  /* register the 'au' format */
  autype = gst_type_new("auaudio");
  g_return_if_fail(autype != NULL);
  gst_type_set_mime(autype,"audio/au");
  gst_type_add(autype);

  /* this filter inputs au audio */
  gst_type_add_sink(autype,factory);
  g_print(__PRETTY_FUNCTION__ ": added audio/au as input type\n");

  /* this filter outputs raw audio */
  rawtype = gst_type_get_by_mime("audio/raw");
  g_return_if_fail(rawtype != NULL);
  gst_type_add_src(rawtype,factory);
  g_print(__PRETTY_FUNCTION__ ": added audio/raw as output type\n");

  return plugin;
}
