Index: gstbasertpaudiopayload.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/rtp/gstbasertpaudiopayload.c,v
retrieving revision 1.12
diff -b -u -1 -u -r1.12 gstbasertpaudiopayload.c
--- gstbasertpaudiopayload.c	10 Feb 2007 19:27:48 -0000	1.12
+++ gstbasertpaudiopayload.c	5 Mar 2007 17:54:54 -0000
@@ -64,2 +64,3 @@
 #include <gst/rtp/gstrtpbuffer.h>
+#include <gst/base/gstadapter.h>
 
@@ -80,4 +81,16 @@
   AudioCodecType type;
+  GstAdapter *adapter;
+  guint64 min_ptime;
+  gboolean disposed;
 };
 
+#define DEFAULT_MIN_PTIME               0
+
+enum
+{
+  PROP_0,
+  PROP_MIN_PTIME
+};
+
+
 #define GST_BASE_RTP_AUDIO_PAYLOAD_GET_PRIVATE(o) \
@@ -86,2 +99,3 @@
 
+static void gst_base_rtp_audio_payload_dispose (GObject * object);
 static void gst_base_rtp_audio_payload_finalize (GObject * object);
@@ -89,4 +103,4 @@
 static GstFlowReturn
-gst_base_rtp_audio_payload_push (GstBaseRTPPayload * basepayload, guint8 * data,
-    guint payload_len, GstClockTime timestamp);
+gst_base_rtp_audio_payload_push (GstBaseRTPPayload * basepayload, 
+    const guint8 * data, guint payload_len, GstClockTime timestamp);
 
@@ -103,2 +117,16 @@
 
+static GstStateChangeReturn
+gst_base_rtp_payload_audio_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean
+gst_base_rtp_payload_audio_handle_event (GstPad * pad, GstEvent * event,
+    gpointer data);
+
+static void 
+gst_base_rtp_payload_audio_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void 
+gst_base_rtp_payload_audio_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
 GST_BOILERPLATE (GstBaseRTPAudioPayload, gst_base_rtp_audio_payload,
@@ -125,2 +153,7 @@
       GST_DEBUG_FUNCPTR (gst_base_rtp_audio_payload_finalize);
+  gobject_class->dispose =
+      GST_DEBUG_FUNCPTR (gst_base_rtp_audio_payload_dispose);
+
+  gobject_class->set_property = gst_base_rtp_payload_audio_set_property;
+  gobject_class->get_property = gst_base_rtp_payload_audio_get_property;
 
@@ -131,2 +164,10 @@
 
+  gstelement_class->change_state = 
+      GST_DEBUG_FUNCPTR (gst_base_rtp_payload_audio_change_state);
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME,
+      g_param_spec_int64 ("min-ptime", "Min packet time",
+          "Minimum duration of the packet data in ns (can't go above MTU)",
+          0, G_MAXINT64, DEFAULT_MIN_PTIME, G_PARAM_READWRITE));
+
   GST_DEBUG_CATEGORY_INIT (basertpaudiopayload_debug, "basertpaudiopayload", 0,
@@ -139,2 +180,4 @@
 {
+  GstBaseRTPPayload * basertppayload = GST_BASE_RTP_PAYLOAD (basertpaudiopayload);
+
   basertpaudiopayload->priv =
@@ -152,4 +195,29 @@
   basertpaudiopayload->sample_size = 0;
+
+  basertpaudiopayload->priv->adapter = gst_adapter_new ();
+  basertpaudiopayload->priv->disposed = FALSE;
+
+  gst_pad_add_event_probe (basertppayload->sinkpad, 
+      G_CALLBACK (gst_base_rtp_payload_audio_handle_event), NULL);
+}
+
+
+static void
+gst_base_rtp_audio_payload_dispose (GObject * object)
+{
+  GstBaseRTPAudioPayload *basertpaudiopayload;
+
+  basertpaudiopayload = GST_BASE_RTP_AUDIO_PAYLOAD (object);
+
+  if (basertpaudiopayload->priv->disposed)
+    return;
+  basertpaudiopayload->priv->disposed = TRUE;
+
+  if (basertpaudiopayload->priv->adapter) {
+    g_object_unref (basertpaudiopayload->priv->adapter);
+    basertpaudiopayload->priv->adapter = NULL;
+  }  
 }
 
+
 static void
@@ -219,2 +287,4 @@
   basertpaudiopayload->frame_duration = frame_duration;
+  
+  gst_adapter_clear (basertpaudiopayload->priv->adapter);
 }
@@ -236,2 +306,4 @@
   basertpaudiopayload->sample_size = sample_size;
+
+  gst_adapter_clear (basertpaudiopayload->priv->adapter);
 }
@@ -269,3 +341,3 @@
   guint payload_len;
-  guint8 *data;
+  const guint8 *data = NULL;
   GstFlowReturn ret;
@@ -275,4 +347,8 @@
   guint maxptime_octets = G_MAXUINT;
+  guint minptime_octets = 0;
+  guint min_payload_len;
+  guint max_payload_len;
+  gboolean use_adapter = FALSE;
 
-  ret = GST_FLOW_ERROR;
+  ret = GST_FLOW_OK;
 
@@ -289,14 +365,3 @@
 
-  /* If buffer fits on an RTP packet, let's just push it through */
-  /* this will check against max_ptime and max_mtu */
-  if (!gst_basertppayload_is_filled (basepayload,
-          gst_rtp_buffer_calc_packet_len (GST_BUFFER_SIZE (buffer), 0, 0),
-          GST_BUFFER_DURATION (buffer))) {
-    ret = gst_base_rtp_audio_payload_push (basepayload,
-        GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
-        GST_BUFFER_TIMESTAMP (buffer));
-    gst_buffer_unref (buffer);
 
-    return ret;
-  }
 
@@ -315,2 +380,35 @@
 
+  max_payload_len = MIN (
+                         /* MTU max */
+                         (int) (gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU
+                                    (basertpaudiopayload), 0, 0) / frame_size) * frame_size,
+                         /* ptime max */
+                         maxptime_octets);
+
+  /* min number of bytes based on a given ptime, has to be a multiple
+     of frame duration */
+  {
+    guint minptime_ms = basertpaudiopayload->priv->min_ptime / 1000000;
+    minptime_octets = frame_size * (int) (minptime_ms / frame_duration);
+  }  
+
+  min_payload_len = MAX (minptime_octets, frame_size);
+
+  if (min_payload_len > max_payload_len) {
+    min_payload_len = max_payload_len;
+  }
+
+  GST_DEBUG_OBJECT (basertpaudiopayload, 
+      "Calculated min_payload_len %u and max_payload_len %u",
+      min_payload_len, max_payload_len);
+
+  
+  if (gst_adapter_available (basertpaudiopayload->priv->adapter)) {
+    /* If there is always data in the adapter, we have to use it */
+    gst_adapter_push (basertpaudiopayload->priv->adapter, buffer);
+    available = gst_adapter_available (basertpaudiopayload->priv->adapter);
+    use_adapter = TRUE;
+  } else {
+
+ 
   /* let's set the base timestamp */
@@ -318,4 +416,18 @@
 
+
+    /* If buffer fits on an RTP packet, let's just push it through */
+    /* this will check against max_ptime and max_mtu */
+    if (GST_BUFFER_SIZE (buffer) >= min_payload_len &&
+        GST_BUFFER_SIZE (buffer) <= max_payload_len) {
+      ret = gst_base_rtp_audio_payload_push (basepayload,
+          GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
+          GST_BUFFER_TIMESTAMP (buffer));
+      gst_buffer_unref (buffer);
+
+      return ret;
+    }
+
   available = GST_BUFFER_SIZE (buffer);
   data = (guint8 *) GST_BUFFER_DATA (buffer);
+  }
 
@@ -323,15 +435,11 @@
   /* this loop will push all available buffers till the last frame */
-  while (available >= frame_size) {
+  while (available >= min_payload_len) {
     gfloat ts_inc;
 
-    /* we need to see how many frames we can get based on maximum MTU, maximum
-     * ptime and the number of bytes available */
-    payload_len = MIN (MIN (
-            /* MTU max */
-            (int) (gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU
-                    (basertpaudiopayload), 0, 0) / frame_size) * frame_size,
-            /* ptime max */
-            maxptime_octets),
-        /* currently available */
-        (available / frame_size) * frame_size);
+    /* We send as much as we can */
+    payload_len = MIN (max_payload_len, (available / frame_size) * frame_size);
+
+    if (use_adapter) {
+      data = gst_adapter_peek (basertpaudiopayload->priv->adapter, payload_len);
+    }
 
@@ -345,2 +453,6 @@
 
+    if (use_adapter) {
+      gst_adapter_flush (basertpaudiopayload->priv->adapter, payload_len);
+      available = gst_adapter_available (basertpaudiopayload->priv->adapter);
+    } else {
     available -= payload_len;
@@ -348,10 +460,13 @@
   }
+  }
 
+  if (!use_adapter) {
+    if ( available != 0) {
+    GstBuffer *buf;
+    buf = gst_buffer_create_sub (buffer, 
+        GST_BUFFER_SIZE (buffer) - available, available);
+    gst_adapter_push (basertpaudiopayload->priv->adapter, buf);
+    } else {
   gst_buffer_unref (buffer);
-
-  /* none should be available by now */
-  if (available != 0) {
-    GST_ERROR_OBJECT (basertpaudiopayload, "The buffer size is not a multiple"
-        " of the frame_size");
-    return GST_FLOW_ERROR;
+    }
   }
@@ -367,3 +482,3 @@
   guint payload_len;
-  guint8 *data;
+  const guint8 *data = NULL;
   GstFlowReturn ret;
@@ -372,2 +487,6 @@
   guint maxptime_octets = G_MAXUINT;
+  guint minptime_octets = 0;
+  guint min_payload_len;
+  guint max_payload_len;
+  gboolean use_adapter = FALSE;
 
@@ -375,3 +494,3 @@
 
-  ret = GST_FLOW_ERROR;
+  ret = GST_FLOW_OK;
 
@@ -386,14 +505,2 @@
 
-  /* If buffer fits on an RTP packet, let's just push it through */
-  /* this will check against max_ptime and max_mtu */
-  if (!gst_basertppayload_is_filled (basepayload,
-          gst_rtp_buffer_calc_packet_len (GST_BUFFER_SIZE (buffer), 0, 0),
-          GST_BUFFER_DURATION (buffer))) {
-    ret = gst_base_rtp_audio_payload_push (basepayload,
-        GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
-        GST_BUFFER_TIMESTAMP (buffer));
-    gst_buffer_unref (buffer);
-
-    return ret;
-  }
 
@@ -403,10 +510,49 @@
         (sample_size * GST_SECOND);
-    GST_DEBUG_OBJECT (basertpaudiopayload, "Calculated max_octects %u",
+  }
+
+  max_payload_len = MIN (
+                         /* MTU max */
+                         gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU
+                             (basertpaudiopayload), 0, 0),
+                         /* ptime max */
         maxptime_octets);
+  
+   /* min number of bytes based on a given ptime, has to be a multiple
+     of sample rate */
+  minptime_octets = basertpaudiopayload->priv->min_ptime *
+      basepayload->clock_rate / (sample_size * GST_SECOND);
+
+
+
+  min_payload_len = MAX (minptime_octets, sample_size);
+
+  if (min_payload_len > max_payload_len) {
+    min_payload_len = max_payload_len;
   }
 
+  GST_DEBUG_OBJECT (basertpaudiopayload, 
+      "Calculated min_payload_len %u and max_payload_len %u",
+      min_payload_len, max_payload_len);
+  
+  if (gst_adapter_available (basertpaudiopayload->priv->adapter)) {
+    /* If there is always data in the adapter, we have to use it */
+    gst_adapter_push (basertpaudiopayload->priv->adapter, buffer);
+    available = gst_adapter_available (basertpaudiopayload->priv->adapter);
+    use_adapter = TRUE;
+  } else {
   /* let's set the base timestamp */
   basertpaudiopayload->base_ts = GST_BUFFER_TIMESTAMP (buffer);
-  GST_DEBUG_OBJECT (basertpaudiopayload, "Setting to %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
+
+
+    /* If buffer fits on an RTP packet, let's just push it through */
+    /* this will check against max_ptime and max_mtu */
+    if (GST_BUFFER_SIZE (buffer) >= min_payload_len &&
+        GST_BUFFER_SIZE (buffer) <= max_payload_len) {
+      ret = gst_base_rtp_audio_payload_push (basepayload,
+          GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
+          GST_BUFFER_TIMESTAMP (buffer));
+      gst_buffer_unref (buffer);
+
+      return ret;
+    }
 
@@ -414,2 +560,3 @@
   data = (guint8 *) GST_BUFFER_DATA (buffer);
+  }
 
@@ -417,15 +564,10 @@
   /* this loop will use all available data until the last byte */
-  while (available) {
+  while (available >= min_payload_len) {
     gfloat num, datarate;
 
-    /* we need to see how many frames we can get based on maximum MTU, maximum
-     * ptime and the number of bytes available */
-    payload_len = MIN (MIN (
-            /* MTU max */
-            gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU
-                (basertpaudiopayload), 0, 0),
-            /* ptime max */
-            maxptime_octets),
-        /* currently available */
-        available);
+    payload_len = MIN (max_payload_len, (available/sample_size) * sample_size);
+
+    if (use_adapter) {
+      data = gst_adapter_peek (basertpaudiopayload->priv->adapter, payload_len);
+    }
 
@@ -443,2 +585,7 @@
 
+
+    if (use_adapter) {
+      gst_adapter_flush (basertpaudiopayload->priv->adapter, payload_len);
+      available = gst_adapter_available (basertpaudiopayload->priv->adapter);
+    } else {
     available -= payload_len;
@@ -446,4 +593,14 @@
   }
+  }
 
+  if (!use_adapter) {
+    if ( available != 0) {
+    GstBuffer *buf;
+    buf = gst_buffer_create_sub (buffer, 
+        GST_BUFFER_SIZE (buffer) - available, available);
+    gst_adapter_push (basertpaudiopayload->priv->adapter, buf);
+    } else {
   gst_buffer_unref (buffer);
+    }
+  }
 
@@ -453,4 +610,4 @@
 static GstFlowReturn
-gst_base_rtp_audio_payload_push (GstBaseRTPPayload * basepayload, guint8 * data,
-    guint payload_len, GstClockTime timestamp)
+gst_base_rtp_audio_payload_push (GstBaseRTPPayload * basepayload, 
+    const guint8 * data, guint payload_len, GstClockTime timestamp)
 {
@@ -476 +633,92 @@
 }
+
+static GstStateChangeReturn
+gst_base_rtp_payload_audio_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstBaseRTPAudioPayload *basertppayload;
+  GstStateChangeReturn ret;
+
+  basertppayload = GST_BASE_RTP_AUDIO_PAYLOAD (element);
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (basertppayload->priv->adapter) {
+        gst_adapter_clear (basertppayload->priv->adapter);
+      }
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void 
+gst_base_rtp_payload_audio_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstBaseRTPAudioPayload *basertpaudiopayload;
+
+  basertpaudiopayload = GST_BASE_RTP_AUDIO_PAYLOAD (object);
+
+  switch (prop_id) {
+     case PROP_MIN_PTIME:
+      basertpaudiopayload->priv->min_ptime = g_value_get_int64 (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void 
+gst_base_rtp_payload_audio_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstBaseRTPAudioPayload *basertpaudiopayload;
+
+  basertpaudiopayload = GST_BASE_RTP_AUDIO_PAYLOAD (object);
+
+  switch (prop_id) {
+    case PROP_MIN_PTIME:
+      g_value_set_int64 (value, basertpaudiopayload->priv->min_ptime);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+
+static gboolean
+gst_base_rtp_payload_audio_handle_event (GstPad * pad, GstEvent * event,
+    gpointer data)
+{
+  GstBaseRTPAudioPayload *basertpaudiopayload;
+  gboolean res = FALSE;
+
+  basertpaudiopayload = GST_BASE_RTP_AUDIO_PAYLOAD (gst_pad_get_parent (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      if (!basertpaudiopayload->priv->adapter) {
+        gst_adapter_clear (basertpaudiopayload->priv->adapter);
+      }
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      if (!basertpaudiopayload->priv->adapter) {
+        gst_adapter_clear (basertpaudiopayload->priv->adapter);
+      }
+      break;
+    default:
+      break;
+  }
+
+  gst_object_unref (basertpaudiopayload);
+
+  return res;
+}
