From 03cd08e1f0f05d5477e797d5184cec61544b0e55 Mon Sep 17 00:00:00 2001
From: Stefan Sayer <stefan.sayer@frafos.com>
Date: Fri, 6 Mar 2015 00:49:55 +0100
Subject: [PATCH] core:codec init: support for fmt params negotiation,
 fmt_description changed

- a codec may export with CODEC_WITH_FMT also a payload format negotiation function
negotiate_fmt

- transcoder adds fmt strings to transcoder codecs

- changed codec fmt_description such that the codec returns a pointer to a
  description array

Conflicts:

	core/plug-in/amr/amr.c
	core/plug-in/speex/speex.c
---
 apps/sbc/SBCCallProfile.cpp |  5 +++--
 core/AmAudio.cpp            | 16 +++++++++-----
 core/AmAudio.h              |  1 +
 core/AmPlugIn.cpp           | 15 +++++++++++++
 core/AmPlugIn.h             | 11 ++++++++++
 core/AmRtpAudio.cpp         | 51 ++++++++++++++++++++++++++-------------------
 core/amci/amci.h            | 28 ++++++++++++++++++++-----
 core/plug-in/adpcm/adpcm.c  |  7 ++++---
 core/plug-in/g722/g722.c    |  6 ++++--
 core/plug-in/g729/g729.c    | 12 +++++++++--
 core/plug-in/gsm/gsm.c      | 19 ++++++++---------
 core/plug-in/ilbc/ilbc.c    | 25 +++++++++++++---------
 core/plug-in/isac/isac.c    | 16 +++++++-------
 core/plug-in/opus/opus.c    | 17 ++++++++-------
 core/plug-in/silk/silk.c    | 36 +++++++++++++++++++-------------
 core/plug-in/speex/speex.c  | 44 +++++++++++++++++++++-----------------
 16 files changed, 197 insertions(+), 112 deletions(-)

diff --git a/apps/sbc/SBCCallProfile.cpp b/apps/sbc/SBCCallProfile.cpp
index 2654fd8..5733fee 100644
--- a/apps/sbc/SBCCallProfile.cpp
+++ b/apps/sbc/SBCCallProfile.cpp
@@ -1391,8 +1391,9 @@ static bool read(const std::string &src, vector<SdpPayload> &codecs)
     if(!payload) {
       ERROR("Ignoring unknown payload found in call profile: '%s/%i'\n",
 	    p.encoding_name.c_str(), p.clock_rate);
-    }
-    else {
+    } else {
+      p.sdp_format_parameters = plugin->getSdpFormatParameters(payload->codec_id, true, "");
+
       if(payload_id < DYNAMIC_PAYLOAD_TYPE_START)
 	p.payload_type = payload->payload_id;
       else
diff --git a/core/AmAudio.cpp b/core/AmAudio.cpp
index 43c8043..bb9f213 100644
--- a/core/AmAudio.cpp
+++ b/core/AmAudio.cpp
@@ -55,7 +55,8 @@ AmAudioFormat::AmAudioFormat(int codec_id, unsigned int rate)
   : channels(1),
     codec_id(codec_id),
     rate(rate),
-    codec(NULL)
+    codec(NULL),
+    sdp_format_parameters_out(NULL)
 {
   codec = getCodec();
 }
@@ -103,13 +104,18 @@ bool AmAudioFormat::operator != (const AmAudioFormat& r) const
 
 void AmAudioFormat::initCodec()
 {
-  amci_codec_fmt_info_t fmt_i[4];
-  fmt_i[0].id=0;
+  amci_codec_fmt_info_t* fmt_i = NULL;
+  sdp_format_parameters_out    = NULL; // reset
 
   if( codec && codec->init ) {
-    if ((h_codec = (*codec->init)(sdp_format_parameters.c_str(), fmt_i)) == -1) {
+    if ((h_codec = (*codec->init)(sdp_format_parameters.c_str(), 
+				  &sdp_format_parameters_out, &fmt_i)) == -1) {
       ERROR("could not initialize codec %i\n",codec->id);
-    }  
+    } else {
+      if (NULL != sdp_format_parameters_out) {
+	DBG("negotiated fmt parameters '%s'\n", sdp_format_parameters_out);
+      }
+    }
   } 
 }
 
diff --git a/core/AmAudio.h b/core/AmAudio.h
index 3fa847d..e87fe23 100644
--- a/core/AmAudio.h
+++ b/core/AmAudio.h
@@ -139,6 +139,7 @@ public:
   int channels;
 
   string sdp_format_parameters;
+  const char*  sdp_format_parameters_out;
     
   AmAudioFormat(int codec_id = CODEC_PCM16,
 		unsigned int rate = SYSTEM_SAMPLECLOCK_RATE);
diff --git a/core/AmPlugIn.cpp b/core/AmPlugIn.cpp
index 7664e91..a677c17 100644
--- a/core/AmPlugIn.cpp
+++ b/core/AmPlugIn.cpp
@@ -400,6 +400,21 @@ amci_payload_t*  AmPlugIn::payload(int payload_id) const
   return 0;
 }
 
+string AmPlugIn::getSdpFormatParameters(int codec_id, bool is_offer, const string& fmt_params_in) {
+  amci_codec_t* c = codec(codec_id);
+  if (NULL == c)
+    return ""; // empty for unsupported codec
+
+  if (NULL == c->negotiate_fmt)
+    return ""; // empty if codec doesn't know either
+
+  char out_fmt[256] = { '\0' };
+  if ((c->negotiate_fmt)(is_offer ? 1:0, fmt_params_in.c_str(), out_fmt, 256) >=0 )
+    return string(out_fmt);
+
+  return "";
+}
+
 int AmPlugIn::getDynPayload(const string& name, int rate, int encoding_param) const {
   // find a dynamic payload by name/rate and encoding_param (channels, if > 0)
   for(std::map<int, amci_payload_t*>::const_iterator pl_it = payloads.begin();
diff --git a/core/AmPlugIn.h b/core/AmPlugIn.h
index b8e6485..95d3152 100644
--- a/core/AmPlugIn.h
+++ b/core/AmPlugIn.h
@@ -199,6 +199,17 @@ class AmPlugIn : public AmPayloadProvider
    */
   amci_codec_t*    codec(int id);
 
+  /** 
+   * get codec format parameters
+   * @param id Codec ID (see amci/codecs.h).
+   * @param is_offer for an offer?
+   * @param fmt_params_in input parameters for an answer
+   * @return fmt parameters for SDP (offer or answer)
+   */
+  string getSdpFormatParameters(int codec_id, bool is_offer, const string& fmt_params_in);
+
+
+
   /**
    * Application lookup function
    * @param app_name application name
diff --git a/core/AmRtpAudio.cpp b/core/AmRtpAudio.cpp
index a8cacde..a6bd259 100644
--- a/core/AmRtpAudio.cpp
+++ b/core/AmRtpAudio.cpp
@@ -62,34 +62,41 @@ int AmAudioRtpFormat::setCurrentPayload(Payload pl)
 
 void AmAudioRtpFormat::initCodec()
 {
-  amci_codec_fmt_info_t fmt_i[4];
-
-  fmt_i[0].id=0;
+  amci_codec_fmt_info_t* fmt_i = NULL;
+  sdp_format_parameters_out = NULL; // reset
 
   if( codec && codec->init ) {
-    if ((h_codec = (*codec->init)(sdp_format_parameters.c_str(), fmt_i)) == -1) {
+    if ((h_codec = (*codec->init)(sdp_format_parameters.c_str(), 
+				  &sdp_format_parameters_out, &fmt_i)) == -1) {
       ERROR("could not initialize codec %i\n",codec->id);
     } else {
-      string s; 
-      int i=0;
-      while (fmt_i[i].id) {
-	switch (fmt_i[i].id) {
-	case AMCI_FMT_FRAME_LENGTH : {
-	  //frame_length=fmt_i[i].value; 
-	} break;
-	case AMCI_FMT_FRAME_SIZE: {
-	  frame_size=fmt_i[i].value; 
-	} break;
-	case AMCI_FMT_ENCODED_FRAME_SIZE: {
-	//   frame_encoded_size=fmt_i[i].value; 
-	} break;
-	default: {
-	  DBG("Unknown codec format descriptor: %d\n", fmt_i[i].id);
-	} break;
+      if (NULL != sdp_format_parameters_out) {
+	DBG("negotiated fmt parameters '%s'\n", sdp_format_parameters_out);
+	log_demangled_stacktrace(L_DBG, 30);
+      }
+
+      if (NULL != fmt_i) {	
+	unsigned int i=0;
+	while (i<4 && fmt_i[i].id) {
+	  switch (fmt_i[i].id) {
+	  case AMCI_FMT_FRAME_LENGTH : {
+	    //frame_length=fmt_i[i].value; // ignored 
+	  } break;
+	  case AMCI_FMT_FRAME_SIZE: {
+	    frame_size=fmt_i[i].value; 
+	  } break;
+	  case AMCI_FMT_ENCODED_FRAME_SIZE: {
+	    //   frame_encoded_size=fmt_i[i].value;  // ignored 
+	  } break;
+	  default: {
+	    DBG("Unknown codec format descriptor: %d\n", fmt_i[i].id);
+	  } break;
+	  }
+
+	  i++;
 	}
-	i++;
       }
-    }  
+    }
   } 
 }
 
diff --git a/core/amci/amci.h b/core/amci/amci.h
index 39b15cb..de6dbdb 100644
--- a/core/amci/amci.h
+++ b/core/amci/amci.h
@@ -238,8 +238,10 @@ typedef void (*amci_codec_module_destroy_t)(void);
 /**
  * \brief Codec's init function pointer.
  *
- * @param format_parameters  [in] parameters as passed by fmtp tag, 0 if none 
- * @param format_description [out] pointer to describing block, with amci_codec_fmt_info_t array; zero-terminated. 0 if none
+ * @param format_parameters      [in]  parameters as passed by fmtp tag, NULL if none 
+ * @param format_parameters_out  [out] parameters passed back to fmtp, NULL if none 
+ * @param format_description     [out] pointer to describing block, with amci_codec_fmt_info_t array; zero-terminated. 
+        NULL if none
  *   <table><tr><td><b>key</b></td><td><b>value</b></td></tr>
  *     <tr><td>AMCI_FMT_FRAME_LENGTH (1)</td><td>  frame length in ms (for framed codecs; must be multiple of 10)</td></tr>
  *     <tr><td>AMCI_FMT_FRAME_SIZE (2)</td><td>  frame size in samples</td></tr>
@@ -254,7 +256,8 @@ typedef void (*amci_codec_module_destroy_t)(void);
     int value;
   } amci_codec_fmt_info_t;
 
-typedef long (*amci_codec_init_t)(const char* format_parameters, amci_codec_fmt_info_t* format_description);
+  typedef long (*amci_codec_init_t)(const char* format_parameters, const char** format_parameters_out,
+				    amci_codec_fmt_info_t** fmt_info);
 
 /**
  * \brief Codec's destroy function pointer.
@@ -273,6 +276,11 @@ typedef unsigned int (*amci_codec_bytes2samples_t)(long h_codec, unsigned int nu
 typedef unsigned int (*amci_codec_samples2bytes_t)(long h_codec, unsigned int num_samples);
 
 /**
+ * \brief Codec's function for negotiating codec format; this needs to be dry-run, i.e. no codec instantiated
+ */
+typedef int (*amci_codec_negotiate_fmt_t)(int is_offer, const char* params_in, char* params_out, unsigned int params_out_len);
+
+/**
  * \brief Codec description
  */
 struct amci_codec_t {
@@ -302,6 +310,9 @@ struct amci_codec_t {
 
     /** Function for calculating the number of samples from bytes. */
     amci_codec_samples2bytes_t samples2bytes;
+
+    /** function for dry-negotiating codec format - no codec instance is created */
+    amci_codec_negotiate_fmt_t negotiate_fmt;
 };
   
   /** \brief supported subtypes for a file */
@@ -464,7 +475,7 @@ struct amci_exports_t {
  * @hideinitializer
  */
 #define END_CODECS \
-                    { -1, 0, 0, 0, 0, 0, 0, 0 } \
+                    { -1, 0, 0, 0, 0, 0, 0, 0, 0 }			\
                 },
 
 /**
@@ -473,7 +484,14 @@ struct amci_exports_t {
  * @hideinitializer
  */
 #define CODEC(id, intern2type,type2intern,plc,init,destroy,bytes2samples,samples2bytes) \
-                    { id, intern2type, type2intern, plc, init, destroy, bytes2samples, samples2bytes },
+       { id, intern2type, type2intern, plc, init, destroy, bytes2samples, samples2bytes, 0 },
+
+  /**
+     A codec with negotiate_fmt function
+     @hideinitializer
+   */
+#define CODEC_WITH_FMT(id, intern2type,type2intern,plc,init,destroy,bytes2samples,samples2bytes,negotiate_fmt) \
+       { id, intern2type, type2intern, plc, init, destroy, bytes2samples, samples2bytes, negotiate_fmt},
 
 /**
  * Portable export definition macro
diff --git a/core/plug-in/adpcm/adpcm.c b/core/plug-in/adpcm/adpcm.c
index ae2db28..4c6fc37 100644
--- a/core/plug-in/adpcm/adpcm.c
+++ b/core/plug-in/adpcm/adpcm.c
@@ -40,7 +40,8 @@
 /* or ATM-AAL packing  -> RFC3551 has the names AAL2-G726-xy for the big-endian packing */
 #define G726_PACK_RFC3551   1 
 
-static long G726_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
+static long G726_create(const char* format_parameters, const char** format_parameters_out,
+			amci_codec_fmt_info_t** format_description);
 static void G726_destroy(long h_inst);
 
 static int Pcm16_2_G726_16( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
@@ -108,7 +109,8 @@ struct G726_twoway {
   struct g72x_state from_g726;  
 };
 
-static long G726_create(const char* format_parameters, amci_codec_fmt_info_t* format_description) {
+static long G726_create(const char* format_parameters, const char** format_parameters_out,
+			amci_codec_fmt_info_t** format_description) {
   struct G726_twoway* cinst = calloc(1, sizeof(struct G726_twoway));
   if (!cinst)
     return -1;
@@ -116,7 +118,6 @@ static long G726_create(const char* format_parameters, amci_codec_fmt_info_t* fo
   g72x_init_state(&cinst->to_g726);
   g72x_init_state(&cinst->from_g726);
 
-  format_description[0].id = 0;
   return (long) cinst;
 }
 
diff --git a/core/plug-in/g722/g722.c b/core/plug-in/g722/g722.c
index de08f87..9ee9b63 100644
--- a/core/plug-in/g722/g722.c
+++ b/core/plug-in/g722/g722.c
@@ -36,7 +36,8 @@ int Pcm16_2_G722NB( unsigned char* out_buf, unsigned char* in_buf, unsigned int
 int G722NB_2_Pcm16( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
 		     unsigned int channels, unsigned int rate, long h_codec );
 
-long G722NB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
+long G722NB_create(const char* format_parameters, const char** format_parameters_out,
+		   amci_codec_fmt_info_t** format_description);
 void G722NB_destroy(long handle);
 
 static unsigned int G722NB_bytes2samples(long, unsigned int);
@@ -67,7 +68,8 @@ typedef struct {
 } G722State;
 
 
-long G722NB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description)
+long G722NB_create(const char* format_parameters, const char** format_parameters_out,
+		   amci_codec_fmt_info_t** format_description)
 {
   G722State* gs;
         
diff --git a/core/plug-in/g729/g729.c b/core/plug-in/g729/g729.c
index 4e0131e..d83f270 100644
--- a/core/plug-in/g729/g729.c
+++ b/core/plug-in/g729/g729.c
@@ -56,12 +56,19 @@ static int pcm16_2_g729(unsigned char* out_buf, unsigned char* in_buf, unsigned
 static int g729_2_pcm16(unsigned char* out_buf, unsigned char* in_buf, unsigned int size, 
 		       unsigned int channels, unsigned int rate, long h_codec );
 
-static long g729_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
+static long g729_create(const char* format_parameters, const char** format_parameters_out,
+			amci_codec_fmt_info_t** format_description);
 static void g729_destroy(long h_codec);
 
 static unsigned int g729_bytes2samples(long, unsigned int);
 static unsigned int g729_samples2bytes(long, unsigned int);
 
+static amci_codec_fmt_info_t[] gsm_fmt_description = { { AMCI_FMT_FRAME_LENGTH, 20 },
+						       { AMCI_FMT_FRAME_SIZE, 160 },
+						       { AMCI_FMT_ENCODED_FRAME_SIZE, 33 },
+						       { 0, 0 }
+};
+
 #define G729_PAYLOAD_ID          18
 #define G729_BYTES_PER_FRAME     10
 #define G729_SAMPLES_PER_FRAME   10
@@ -176,7 +183,8 @@ stream_destroy(struct stream *st)
 }
 
 
-long g729_create(const char* format_parameters, amci_codec_fmt_info_t* format_description)
+long g729_create(const char* format_parameters, const char** format_parameters_out,
+		 amci_codec_fmt_info_t** format_description)
 {
     USC_CodecInfo pInfo;  
     struct G729_codec *codec;
diff --git a/core/plug-in/gsm/gsm.c b/core/plug-in/gsm/gsm.c
index cf779c1..b8a5f67 100644
--- a/core/plug-in/gsm/gsm.c
+++ b/core/plug-in/gsm/gsm.c
@@ -39,13 +39,18 @@ static int pcm16_2_gsm(unsigned char* out_buf, unsigned char* in_buf, unsigned i
 static int gsm_2_pcm16(unsigned char* out_buf, unsigned char* in_buf, unsigned int size, 
 		       unsigned int channels, unsigned int rate, long h_codec );
 
-static long gsm_create_if(const char* format_parameters, amci_codec_fmt_info_t* format_description); 
+static long gsm_create_if(const char* format_parameters, const char** format_parameters_out,
+			  amci_codec_fmt_info_t** format_description); 
 
 static void gsm_destroy_if(long h_codec);
 
 static unsigned int gsm_bytes2samples(long, unsigned int);
 static unsigned int gsm_samples2bytes(long, unsigned int);
 
+static amci_codec_fmt_info_t gsm_fmt_description[] = { {AMCI_FMT_FRAME_LENGTH, 20},
+						       {AMCI_FMT_FRAME_SIZE, 160},
+						       {AMCI_FMT_ENCODED_FRAME_SIZE, 33}, {0,0}};
+
 BEGIN_EXPORTS( "gsm", AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY )
 
   BEGIN_CODECS
@@ -126,7 +131,8 @@ static int gsm_2_pcm16(unsigned char* out_buf, unsigned char* in_buf, unsigned i
 }
 
 
-static long gsm_create_if(const char* format_parameters, amci_codec_fmt_info_t* format_description)
+static long gsm_create_if(const char* format_parameters, const char** format_parameters_out,
+			  amci_codec_fmt_info_t** format_description)
 { 
   gsm* h_codec=0;
     
@@ -139,15 +145,8 @@ static long gsm_create_if(const char* format_parameters, amci_codec_fmt_info_t*
   h_codec[0] = gsm_create();
   h_codec[1] = gsm_create();
 
-  format_description[0].id = AMCI_FMT_FRAME_LENGTH ;
-  format_description[0].value = 20;
-  format_description[1].id = AMCI_FMT_FRAME_SIZE;
-  format_description[1].value = 160;
-  format_description[2].id =  AMCI_FMT_ENCODED_FRAME_SIZE;
-  format_description[2].value = 33;
-  format_description[3].id = 0;
+  *format_description = gsm_fmt_description;
 
-    
   return (long)h_codec;
 }
 
diff --git a/core/plug-in/ilbc/ilbc.c b/core/plug-in/ilbc/ilbc.c
index bc60978..7f5eca9 100644
--- a/core/plug-in/ilbc/ilbc.c
+++ b/core/plug-in/ilbc/ilbc.c
@@ -73,7 +73,8 @@ static int iLBC_PLC( unsigned char* out_buf, unsigned int size,
 
 static int Pcm16_2_iLBC( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
 			 unsigned int channels, unsigned int rate, long h_codec );
-static long iLBC_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
+static long iLBC_create(const char* format_parameters, const char** format_parameters_out,
+			amci_codec_fmt_info_t** format_description);
 static void iLBC_destroy(long h_inst);
 static int iLBC_open(FILE* fp, struct amci_file_desc_t* fmt_desc, int options, long h_codec);
 static int iLBC_close(FILE* fp, struct amci_file_desc_t* fmt_desc, int options, long h_codec, struct amci_codec_t *codec);
@@ -81,6 +82,14 @@ static int iLBC_close(FILE* fp, struct amci_file_desc_t* fmt_desc, int options,
 static unsigned int ilbc_bytes2samples(long, unsigned int);
 static unsigned int ilbc_samples2bytes(long, unsigned int);
 
+static amci_codec_fmt_info_t ilbc_fmt_description_30[] = { {AMCI_FMT_FRAME_LENGTH, 30},
+							   {AMCI_FMT_FRAME_SIZE, 240},
+							   {AMCI_FMT_ENCODED_FRAME_SIZE, 50}, {0,0}};
+
+static amci_codec_fmt_info_t ilbc_fmt_description_20[] = { {AMCI_FMT_FRAME_LENGTH, 20},
+							   {AMCI_FMT_FRAME_SIZE, 160},
+							   {AMCI_FMT_ENCODED_FRAME_SIZE, 38}, {0,0}};
+
 BEGIN_EXPORTS( "ilbc" , AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY )
 
   BEGIN_CODECS
@@ -129,7 +138,8 @@ static unsigned int ilbc_samples2bytes(long h_codec, unsigned int num_samples)
     return (num_samples / 160) * 38;
 }
 
-long iLBC_create(const char* format_parameters, amci_codec_fmt_info_t* format_description) {
+long iLBC_create(const char* format_parameters, const char** format_parameters_out,
+			amci_codec_fmt_info_t** format_description) {
 
   iLBC_Codec_Inst_t* codec_inst;
   int mode;
@@ -156,14 +166,9 @@ long iLBC_create(const char* format_parameters, amci_codec_fmt_info_t* format_de
       }
     }
   }
-  format_description[0].id = AMCI_FMT_FRAME_LENGTH ;
-  format_description[0].value = mode;
-  format_description[1].id = AMCI_FMT_FRAME_SIZE;
-  format_description[1].value = mode==30 ? 240 : 160;
-  format_description[2].id = AMCI_FMT_ENCODED_FRAME_SIZE;
-  format_description[2].value = mode==30 ? 50 : 38;
-  format_description[3].id = 0;
-    
+
+  *format_description = (mode == 30) ? ilbc_fmt_description_30 : ilbc_fmt_description_20;
+
   if (format_parameters) {
     DBG("ilbc with format parameters : '%s', mode=%d.\n", format_parameters, mode);
   }
diff --git a/core/plug-in/isac/isac.c b/core/plug-in/isac/isac.c
index 36c110f..9c771ae 100644
--- a/core/plug-in/isac/isac.c
+++ b/core/plug-in/isac/isac.c
@@ -33,13 +33,15 @@ int Pcm16_2_iSAC( unsigned char* out_buf, unsigned char* in_buf, unsigned int si
 int iSAC_2_Pcm16( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
 		  unsigned int channels, unsigned int rate, long h_codec );
 
-static long iSAC_create(const char* format_parameters, 
-			amci_codec_fmt_info_t* format_description);
+static long iSAC_create(const char* format_parameters, const char** format_parameters_out,
+			amci_codec_fmt_info_t** format_description);
 static void iSAC_destroy(long handle);
 
 static unsigned int iSAC_bytes2samples(long, unsigned int);
 static unsigned int iSAC_samples2bytes(long, unsigned int);
 
+static amci_codec_fmt_info_t isac_fmt_description[] = {{AMCI_FMT_FRAME_SIZE, iSAC_FRAME_MS * iSAC_SAMPLE_RATE / 1000}, {0,0}};
+
 BEGIN_EXPORTS("isac", AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY)
 
 BEGIN_CODECS
@@ -62,8 +64,8 @@ END_FILE_FORMATS
 
 END_EXPORTS
 
-static long iSAC_create(const char* format_parameters, 
-			amci_codec_fmt_info_t* format_description)
+static long iSAC_create(const char* format_parameters, const char** format_parameters_out,
+			amci_codec_fmt_info_t** format_description)
 {
   ISACStruct *iSAC_st=NULL;
   int err = WebRtcIsac_Create(&iSAC_st);
@@ -85,11 +87,7 @@ static long iSAC_create(const char* format_parameters,
     return 0;
   }
 
-  format_description[0].id = AMCI_FMT_FRAME_SIZE;
-  format_description[0].value = iSAC_FRAME_MS * iSAC_SAMPLE_RATE / 1000;
-  DBG("set AMCI_FMT_FRAME_SIZE to %d\n", format_description[0].value);
-    
-  format_description[1].id = 0;
+  *format_description = isac_fmt_description;
 
   return (long)iSAC_st;
 }
diff --git a/core/plug-in/opus/opus.c b/core/plug-in/opus/opus.c
index 8cb6f39..57a92bc 100644
--- a/core/plug-in/opus/opus.c
+++ b/core/plug-in/opus/opus.c
@@ -84,7 +84,8 @@ static int opus_plc( unsigned char* out_buf, unsigned int size,
 
 static int pcm16_2_opus( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
 			 unsigned int channels, unsigned int rate, long h_codec );
-static long opus_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
+static long opus_create(const char* format_parameters, const char** format_parameters_out,
+			  amci_codec_fmt_info_t** format_description);
 static void opus_destroy(long h_inst);
 
 #if SYSTEM_SAMPLECLOCK_RATE >= 48000
@@ -99,6 +100,9 @@ static void opus_destroy(long h_inst);
 #error Minimal sample rate for OPUS codec is 8000.
 #endif
 
+static amci_codec_fmt_info_t opus_fmt_description[] = { {AMCI_FMT_FRAME_LENGTH, 20},
+						       {AMCI_FMT_FRAME_SIZE, 20 * _OPUS_RATE / 1000}, {0,0}};
+
 BEGIN_EXPORTS( "opus" , AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY )
 
   BEGIN_CODECS
@@ -122,19 +126,14 @@ typedef struct {
   OpusDecoder* opus_dec;
 } opus_state_t;
 
-long opus_create(const char* format_parameters, amci_codec_fmt_info_t* format_description) {
+long opus_create(const char* format_parameters, const char** format_parameters_out,
+		 amci_codec_fmt_info_t** format_description) {
   opus_state_t* codec_inst;
   int error;
  
   if (format_parameters) {
     DBG("OPUS params: >>%s<<.\n", format_parameters);
   } 
-
-  format_description[0].id = AMCI_FMT_FRAME_LENGTH ;
-  format_description[0].value = 20;
-  format_description[1].id = AMCI_FMT_FRAME_SIZE;
-  format_description[1].value = 20 * _OPUS_RATE / 1000;
-  format_description[2].id = 0;
     
   codec_inst = (opus_state_t*)malloc(sizeof(opus_state_t));
 
@@ -161,6 +160,8 @@ long opus_create(const char* format_parameters, amci_codec_fmt_info_t* format_de
     return -1;
   }
 
+  *format_description = opus_fmt_description;
+
   return (long)codec_inst;
 }
 
diff --git a/core/plug-in/silk/silk.c b/core/plug-in/silk/silk.c
index 7bfd3ce..30326f8 100644
--- a/core/plug-in/silk/silk.c
+++ b/core/plug-in/silk/silk.c
@@ -35,10 +35,14 @@ int Pcm16_2_SILK( unsigned char* out_buf, unsigned char* in_buf, unsigned int si
 int SILK_2_Pcm16( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
 		  unsigned int channels, unsigned int rate, long h_codec );
 
-long SILK_NB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
-long SILK_MB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
-long SILK_WB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
-long SILK_UB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
+long SILK_NB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description);
+long SILK_MB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description);
+long SILK_WB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description);
+long SILK_UB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description);
 void SILK_destroy(long handle);
 
 static unsigned int SILK_bytes2samples(long, unsigned int);
@@ -169,9 +173,7 @@ static int create_SILK_decoder(SILK_state* st,
 }
 
 static long SILK_create(unsigned int rtp_Hz,
-			unsigned int avg_bit_rate,
-			const char* format_parameters, 
-			amci_codec_fmt_info_t* format_description)
+			unsigned int avg_bit_rate)
 {
   SILK_state* st = malloc(sizeof(SILK_state));
   if(st == NULL) {
@@ -195,24 +197,28 @@ static long SILK_create(unsigned int rtp_Hz,
   return 0;
 }
 
-long SILK_NB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description)
+long SILK_NB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description)
 {
-  return SILK_create(8000,20000,format_parameters,format_description);
+  return SILK_create(8000,20000);
 }
 
-long SILK_MB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description)
+long SILK_MB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description)
 {
-  return SILK_create(12000,25000,format_parameters,format_description);
+  return SILK_create(12000,25000);
 }
 
-long SILK_WB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description)
+long SILK_WB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description)
 {
-  return SILK_create(16000,30000,format_parameters,format_description);
+  return SILK_create(16000,30000);
 }
 
-long SILK_UB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description)
+long SILK_UB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description)
 {
-  return SILK_create(24000,40000,format_parameters,format_description);
+  return SILK_create(24000,40000);
 }
 
 void SILK_destroy(long handle)
diff --git a/core/plug-in/speex/speex.c b/core/plug-in/speex/speex.c
index 2917b17..992c841 100644
--- a/core/plug-in/speex/speex.c
+++ b/core/plug-in/speex/speex.c
@@ -79,9 +79,12 @@ int Pcm16_2_Speex( unsigned char* out_buf, unsigned char* in_buf, unsigned int s
 int Speex_2_Pcm16( unsigned char* out_buf, unsigned char* in_buf, unsigned int size,
 		   unsigned int channels, unsigned int rate, long h_codec );
 
-long speexNB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
-long speexWB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
-long speexUB_create(const char* format_parameters, amci_codec_fmt_info_t* format_description);
+long speexNB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description);
+long speexWB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description);
+long speexUB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description);
 void speex_destroy(long handle);
 
 /* static unsigned int speex_bytes2samples(long, unsigned int); */
@@ -130,9 +133,10 @@ typedef struct {
   unsigned int frames_per_packet; /* in samples */
   unsigned int frame_size;
 
+  amci_codec_fmt_info_t fmt_info[3];
 } SpeexState;
 
-#if 0
+#if 0 /* SDP parameters ignored ? */
 
 /*
   Search for a parameter assignement in input string.
@@ -145,7 +149,7 @@ static char* read_param(char* input, const char *param, char** param_value)
   int param_size;
 
   /* Eat spaces and semi-colons */
-  while (*input && *input==' ' && *input==';' && *input!='"')
+  while (*input && (*input==' ' || *input==';' || *input=='"'))
     input++;
 
   *param_value = NULL;
@@ -222,7 +226,7 @@ void decode_format_parameters(const char* format_parameters, SpeexState* ss) {
 
 long speex_create(unsigned int sample_rate, 
 		  const char* format_parameters, 
-		  amci_codec_fmt_info_t* format_description)
+		  amci_codec_fmt_info_t** format_description)
 {
   int speex_mode = 0, on=1, quality=0;
   SpeexState* ss=NULL;
@@ -272,17 +276,19 @@ long speex_create(unsigned int sample_rate,
   ss->decoder.state = speex_decoder_init(speex_lib_get_mode(speex_mode));
   speex_decoder_ctl(ss->decoder.state, SPEEX_SET_ENH, &on);
     
-  format_description[0].id = AMCI_FMT_FRAME_LENGTH;
-  format_description[0].value = SPEEX_FRAME_MS * ss->frames_per_packet;
+  ss->fmt_info[0].id = AMCI_FMT_FRAME_LENGTH;
+  ss->fmt_info[0].value = SPEEX_FRAME_MS * ss->frames_per_packet;
     
   ss->frame_size = SPEEX_FRAME_MS * (sample_rate / 1000);
-  format_description[1].id = AMCI_FMT_FRAME_SIZE;
-  format_description[1].value = ss->frame_size * ss->frames_per_packet;
+  ss->fmt_info[1].id = AMCI_FMT_FRAME_SIZE;
+  ss->fmt_info[1].value = ss->frame_size * ss->frames_per_packet;
     
-  format_description[2].id = 0;
+  ss->fmt_info[2].id = 0;
 
-  DBG("set AMCI_FMT_FRAME_LENGTH to %d\n", format_description[0].value);
-  DBG("set AMCI_FMT_FRAME_SIZE to %d\n", format_description[1].value);
+  *format_description = ss->fmt_info;
+
+  DBG("set AMCI_FMT_FRAME_LENGTH to %d\n", ss->fmt_info[0].value);
+  DBG("set AMCI_FMT_FRAME_SIZE to %d\n",   ss->fmt_info[1].value);
 
   DBG("SpeexState %p inserted with %d frames per packet,\n", 
       ss, ss->frames_per_packet);
@@ -290,20 +296,20 @@ long speex_create(unsigned int sample_rate,
   return (long)ss;
 }
 
-long speexNB_create(const char* format_parameters, 
-		    amci_codec_fmt_info_t* format_description)
+long speexNB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description)
 {
   return speex_create(8000,format_parameters,format_description);
 }
 
-long speexWB_create(const char* format_parameters, 
-		    amci_codec_fmt_info_t* format_description)
+long speexWB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description)
 {
   return speex_create(16000,format_parameters,format_description);
 }
 
-long speexUB_create(const char* format_parameters, 
-		    amci_codec_fmt_info_t* format_description)
+long speexUB_create(const char* format_parameters, const char** format_parameters_out,
+		    amci_codec_fmt_info_t** format_description)
 {
   return speex_create(32000,format_parameters,format_description);
 }
-- 
2.1.4

