Bug 784515: add hints to webrtc/signaling CreateOffer and CreateAnswer APIs r=jesup
authorEnda Mannion <emannion@gmail.com>
Fri, 28 Sep 2012 11:09:09 +0100
changeset 110577 9ba7d327ce675fca4d353c36fc0be10cdba8237e
parent 110576 73f735acc3e1ee32b5f2e5c3017cbd8defb0d51c
child 110578 073b904aed0cd056c425125a14323e263cc58e4c
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersjesup
bugs784515
milestone19.0a1
Bug 784515: add hints to webrtc/signaling CreateOffer and CreateAnswer APIs r=jesup
media/webrtc/signaling/include/CC_Call.h
media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
media/webrtc/signaling/src/sipcc/core/ccapp/CCProvider.h
media/webrtc/signaling/src/sipcc/core/ccapp/cc_call_feature.c
media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_call.c
media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c
media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
media/webrtc/signaling/src/sipcc/core/gsm/h/gsm_sdp.h
media/webrtc/signaling/src/sipcc/core/includes/ccapi.h
media/webrtc/signaling/src/sipcc/core/includes/sessionTypes.h
media/webrtc/signaling/src/sipcc/include/cc_call_feature.h
media/webrtc/signaling/src/sipcc/include/cc_constants.h
media/webrtc/signaling/src/sipcc/include/ccapi_call.h
media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.cpp
media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.h
media/webrtc/signaling/test/signaling_unittests.cpp
--- a/media/webrtc/signaling/include/CC_Call.h
+++ b/media/webrtc/signaling/include/CC_Call.h
@@ -263,19 +263,19 @@ namespace CSF
            @param [in] video_pref - video direction desired on call
            @param [in] digits - digits to be dialed. can be empty then this API simply goes offhook
            @param [in] ip address - the ip address of the peer to call
 
            @return void
           */
         virtual void originateP2PCall (cc_sdp_direction_t video_pref, const std::string & digits, const std::string & ip) = 0;
 
-        virtual void createOffer (const std::string & hints) = 0;
+        virtual void createOffer (const cc_media_constraints_t* constraints) = 0;
 
-        virtual void createAnswer(const std::string & hints, const std::string & offersdp) = 0;
+        virtual void createAnswer(const cc_media_constraints_t* constraints, const std::string & offersdp) = 0;
 
         virtual void setLocalDescription(cc_jsep_action_t action, const std::string & sdp) = 0;
 
         virtual void setRemoteDescription(cc_jsep_action_t action, const std::string & sdp) = 0;
 
         virtual void setPeerConnection(const std::string& handle) = 0;
 
         virtual void addStream(cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type) = 0;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
@@ -102,21 +102,24 @@ void PeerConnectionCtx::onDeviceEvent(cc
 
   if (CC_STATE_INS == state) {
     // SIPCC is up
     if (PeerConnectionImpl::kStarting == mSipccState ||
         PeerConnectionImpl::kIdle == mSipccState) {
       ChangeSipccState(PeerConnectionImpl::kStarted);
     } else {
       CSFLogError(logTag, "%s PeerConnection in wrong state", __FUNCTION__);
-      Cleanup();
+      /*
+       * Cleanup is causing a deadlock, commenting for now, see Bug 801620
+       */
+      //Cleanup();
       MOZ_ASSERT(PR_FALSE);
     }
   } else {
-    Cleanup();
+    //Cleanup();
     NS_NOTREACHED("Unsupported Signaling State Transition");
   }
 }
 
 // Demux the call event to the right PeerConnection
 void PeerConnectionCtx::onCallEvent(ccapi_call_event_e aCallEvent,
                                     CSF::CC_CallPtr aCall,
                                     CSF::CC_CallInfoPtr aInfo) {
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1,23 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <string>
 #include <iostream>
 
-
 #include "vcm.h"
 #include "CSFLog.h"
 #include "CSFLogStream.h"
 #include "ccapi_call_info.h"
 #include "CC_SIPCCCallInfo.h"
 #include "ccapi_device_info.h"
 #include "CC_SIPCCDeviceInfo.h"
+#include "cpr_string.h"
+#include "cpr_stdlib.h"
 
 #include "nspr.h"
 #include "nss.h"
 #include "pk11pub.h"
 
 #include "nsNetCID.h"
 #include "nsIServiceManager.h"
 #include "nsServiceManagerUtils.h"
@@ -53,16 +54,55 @@ class nsIDOMDataChannel;
 static const char* logTag = "PeerConnectionImpl";
 static const mozilla::TrackID TRACK_AUDIO = 0;
 static const mozilla::TrackID TRACK_VIDEO = 1;
 static const int DTLS_FINGERPRINT_LENGTH = 64;
 static const int MEDIA_STREAM_MUTE = 0x80;
 
 namespace sipcc {
 
+void MediaConstraints::setBooleanConstraint(const std::string& constraint, bool enabled, bool mandatory) {
+
+  ConstraintInfo booleanconstraint;
+  booleanconstraint.mandatory = mandatory;
+
+  if (enabled)
+    booleanconstraint.value = "TRUE";
+  else
+    booleanconstraint.value = "FALSE";
+
+  mConstraints[constraint] = booleanconstraint;
+}
+
+void MediaConstraints::buildArray(cc_media_constraints_t** constraintarray) {
+
+  if (0 == mConstraints.size())
+    return;
+
+  short i = 0;
+  std::string tmpStr;
+  *constraintarray = (cc_media_constraints_t*) cpr_malloc(sizeof(cc_media_constraints_t));
+
+  (*constraintarray)->constraints = (cc_media_constraint_t**) cpr_malloc(mConstraints.size() * sizeof(cc_media_constraint_t));
+
+  for (constraints_map::iterator it = mConstraints.begin();
+          it != mConstraints.end(); ++it) {
+    (*constraintarray)->constraints[i] = (cc_media_constraint_t*) cpr_malloc(sizeof(cc_media_constraint_t));
+    tmpStr = it->first;
+    (*constraintarray)->constraints[i]->name = (char*) cpr_malloc(tmpStr.size());
+    sstrncpy((*constraintarray)->constraints[i]->name, tmpStr.c_str(), tmpStr.size()+1);
+    tmpStr = it->second.value;
+    (*constraintarray)->constraints[i]->value = (char*) cpr_malloc(tmpStr.size());
+    sstrncpy((*constraintarray)->constraints[i]->value, tmpStr.c_str(), tmpStr.size()+1);
+    (*constraintarray)->constraints[i]->mandatory = it->second.mandatory;
+    i++;
+  }
+  (*constraintarray)->constraint_count = i;
+}
+
 typedef enum {
   PC_OBSERVER_CALLBACK,
   PC_OBSERVER_CONNECTION,
   PC_OBSERVER_CLOSEDCONNECTION,
   PC_OBSERVER_DATACHANNEL,
   PC_OBSERVER_ICE,
   PC_OBSERVER_READYSTATE
 } PeerConnectionObserverType;
@@ -680,36 +720,63 @@ PeerConnectionImpl::NotifyDataChannel(mo
       return;
     }
     runnable->Run();
   }
 #endif
 }
 
 /*
- * CC_SDP_DIRECTION_SENDRECV will not be used when Constraints are implemented
+ * the Constraints UI IDL work is being done. The CreateOffer below is the one
+ * currently called by the signaling unit tests.
  */
 NS_IMETHODIMP
-PeerConnectionImpl::CreateOffer(const char* aHints) {
-  MOZ_ASSERT(aHints);
+PeerConnectionImpl::CreateOffer(const char* constraints) {
+  MOZ_ASSERT(constraints);
 
   CheckIceState();
   mRole = kRoleOfferer;  // TODO(ekr@rtfm.com): Interrogate SIPCC here?
-  mCall->createOffer(aHints);
+  MediaConstraints aconstraints;
+  CreateOffer(aconstraints);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PeerConnectionImpl::CreateAnswer(const char* aHints, const char* aOffer) {
-  MOZ_ASSERT(aHints);
+PeerConnectionImpl::CreateOffer(MediaConstraints& constraints) {
+
+  cc_media_constraints_t* cc_constraints = nullptr;
+  constraints.buildArray(&cc_constraints);
+
+  mCall->createOffer(cc_constraints);
+  return NS_OK;
+}
+
+/*
+ * the Constraints UI IDL work is being done. The CreateAnswer below is the one
+ * currently called by the signaling unit tests.
+ */
+NS_IMETHODIMP
+PeerConnectionImpl::CreateAnswer(const char* constraints, const char* aOffer) {
+  MOZ_ASSERT(constraints);
   MOZ_ASSERT(aOffer);
 
   CheckIceState();
   mRole = kRoleAnswerer;  // TODO(ekr@rtfm.com): Interrogate SIPCC here?
-  mCall->createAnswer(aHints, aOffer);
+  MediaConstraints aconstraints;
+  CreateAnswer(aconstraints, aOffer);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PeerConnectionImpl::CreateAnswer(MediaConstraints& constraints, const char* offer) {
+
+  cc_media_constraints_t* cc_constraints = nullptr;
+  constraints.buildArray(&cc_constraints);
+
+  mCall->createAnswer(cc_constraints, offer);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP) {
   if (!aSDP) {
     CSFLogError(logTag, "%s - aSDP is NULL", __FUNCTION__);
     return NS_ERROR_FAILURE;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -46,16 +46,32 @@ namespace mozilla {
   class DataChannel;
 }
 #endif
 
 using namespace mozilla;
 
 namespace sipcc {
 
+struct ConstraintInfo {
+  std::string  value;
+  bool         mandatory;
+};
+typedef std::map<std::string, ConstraintInfo> constraints_map;
+
+class MediaConstraints {
+public:
+  void setBooleanConstraint(const std::string& constraint, bool enabled, bool mandatory);
+
+  void buildArray(cc_media_constraints_t** constraintarray);
+
+private:
+  constraints_map  mConstraints;
+};
+
 /* Temporary for providing audio data */
 class Fake_AudioGenerator {
  public:
 Fake_AudioGenerator(nsDOMMediaStream* aStream) : mStream(aStream), mCount(0) {
     mTimer = do_CreateInstance("@mozilla.org/timer;1");
     PR_ASSERT(mTimer);
 
     // Make a track
@@ -375,16 +391,20 @@ public:
   // Get the DTLS identity
   mozilla::RefPtr<DtlsIdentity> const GetIdentity() { return mIdentity; }
 
   // Create a fake media stream
   nsresult CreateFakeMediaStream(uint32_t hint, nsIDOMMediaStream** retval);
 
   nsPIDOMWindow* GetWindow() const { return mWindow; }
 
+  NS_IMETHODIMP CreateOffer(MediaConstraints& constraints);
+
+  NS_IMETHODIMP CreateAnswer(MediaConstraints& constraints, const char* offer);
+
 private:
   PeerConnectionImpl(const PeerConnectionImpl&rhs);
   PeerConnectionImpl& operator=(PeerConnectionImpl);
 
   void ChangeReadyState(ReadyState aReadyState);
   void CheckIceState() {
     PR_ASSERT(mIceState != kIceGathering);
   }
--- a/media/webrtc/signaling/src/sipcc/core/ccapp/CCProvider.h
+++ b/media/webrtc/signaling/src/sipcc/core/ccapp/CCProvider.h
@@ -93,17 +93,17 @@ typedef struct cc_call_info_t_{
     cc_string_t   info_body;
     cc_call_log_t call_log;
     cc_boolean    audio_mute;
     cc_boolean    video_mute;
     cc_call_conference_Info_t call_conference;
     cc_string_t   sdp;
     unsigned int  media_stream_track_id;
     unsigned int  media_stream_id;
-
+    const cc_media_constraints_t* cc_constraints;
 } session_data_t;
 
 typedef enum {
     NO_ACTION=0,
     RESET_ACTION,
     RESTART_ACTION,
     RE_REGISTER_ACTION,
     STOP_ACTION,
--- a/media/webrtc/signaling/src/sipcc/core/ccapp/cc_call_feature.c
+++ b/media/webrtc/signaling/src/sipcc/core/ccapp/cc_call_feature.c
@@ -6,16 +6,18 @@
 #include "CCProvider.h"
 #include "sessionConstants.h"
 #include "sessionTypes.h"
 #include "lsm.h"
 #include "phone_debug.h"
 #include "text_strings.h"
 #include "ccapi.h"
 #include "ccapp_task.h"
+#include "sessionHash.h"
+#include "cpr_rand.h"
 
 extern cpr_status_e ccappTaskPostMsg(unsigned int msgId, void * data, uint16_t len, int appId);
 
 /**
  * Internal method: create call handle
  * @param line
  * @paran call_id
  */
@@ -90,35 +92,54 @@ cc_return_t cc_invokeFeature(cc_call_han
             return CC_FAILURE;
 	}
 	return CC_SUCCESS;
 }
 
 /**
  * Invoke a call feature.
  */
-cc_return_t cc_invokeFeatureSDPMode(cc_call_handle_t call_handle, group_cc_feature_t featureId, cc_sdp_direction_t video_pref,
-                             cc_jsep_action_t action, cc_media_stream_id_t stream_id, cc_media_track_id_t track_id,
-                             cc_media_type_t media_type, uint16_t level, string_t data, string_t data1) {
-	session_feature_t callFeature;
+cc_return_t cc_invokeFeatureSDPMode(cc_call_handle_t call_handle, group_cc_feature_t featureId, cc_jsep_action_t action,
+                                    cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type,
+                                    uint16_t level, const cc_media_constraints_t *constraints, string_t data, string_t data1) {
+    session_feature_t callFeature;
+    session_data_t * sessionData;
+    unsigned int session_id = 0;
     callFeature.session_id = (SESSIONTYPE_CALLCONTROL << CC_SID_TYPE_SHIFT) + call_handle;
     callFeature.featureID = featureId;
-    callFeature.featData.ccData.state = video_pref;
     callFeature.featData.ccData.action = action;
     callFeature.featData.ccData.media_type = media_type;
     callFeature.featData.ccData.stream_id = stream_id;
     callFeature.featData.ccData.track_id = track_id;
     callFeature.featData.ccData.level = level;
+    callFeature.featData.ccData.has_constraints = FALSE;
+
+    /* If constraints exist add to session hash */
+    if (constraints) {
+        if (constraints->constraint_count > 0 &&
+            (CC_FEATURE_CREATEOFFER == featureId || CC_FEATURE_CREATEANSWER == featureId )) {
+            /* A random number of 5 digits will not conflict with any
+             * other usage of the hash table */
+            session_id = abs(cpr_rand()) % 60000;
+            sessionData = (session_data_t *)findhash(session_id);
+            sessionData = cpr_malloc(sizeof(session_data_t));
+            memset(sessionData, 0, sizeof(session_data_t));
+            sessionData->cc_constraints = constraints;
+            (void) addhash(session_id, sessionData);
+            callFeature.featData.ccData.sessionid = session_id;
+            callFeature.featData.ccData.has_constraints = TRUE;
+        }
+    }
 
     CCAPP_DEBUG(DEB_F_PREFIX"cc_invokeFeatureSDPMode:sid=%d, line=%d, cid=%d, fid=%d, video_pref=%s data=%s\n",
                         DEB_F_PREFIX_ARGS("cc_call_feature", "cc_invokeFeatureSDPMode"),
                         callFeature.session_id,
                         GET_LINE_ID(call_handle),
                         GET_CALL_ID(call_handle),
-                        featureId, SDP_DIRECTION_PRINT(video_pref),
+                        featureId,
                         ((featureId == CC_FEATURE_KEYPRESS) ? "...": data));
 
     switch (featureId) {
     case CC_FEATURE_KEYPRESS:
     case CC_FEATURE_DIALSTR:
     case CC_FEATURE_SPEEDDIAL:
     case CC_FEATURE_BLIND_XFER_WITH_DIALSTRING:
     case CC_FEATURE_END_CALL:
@@ -270,74 +291,87 @@ cc_return_t CC_CallFeature_dial(cc_call_
 
     if (cpr_strcasecmp(numbers, "DIAL") == 0) {
 	    return cc_invokeFeature(call_handle, CC_FEATURE_DIAL, video_pref, numbers);
     }
 
 	return cc_invokeFeature(call_handle, CC_FEATURE_DIALSTR, video_pref, numbers);
 }
 
-cc_return_t CC_CallFeature_CreateOffer(cc_call_handle_t call_handle) {
-	CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
-			GET_LINE_ID(call_handle), __FUNCTION__));
+cc_return_t CC_CallFeature_CreateOffer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints) {
+    CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
+                GET_LINE_ID(call_handle), __FUNCTION__));
 
-	return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_CREATEOFFER, CC_SDP_DIRECTION_SENDRECV, JSEP_NO_ACTION, 0, 0, NO_STREAM, 0, NULL, NULL);
+    return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_CREATEOFFER, JSEP_NO_ACTION,
+                                   0, 0, NO_STREAM, 0, constraints, NULL, NULL);
 }
 
-cc_return_t CC_CallFeature_CreateAnswer(cc_call_handle_t call_handle, string_t sdp) {
-	CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
-			GET_LINE_ID(call_handle), __FUNCTION__));
+cc_return_t CC_CallFeature_CreateAnswer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints, string_t sdp) {
+    CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
+                GET_LINE_ID(call_handle), __FUNCTION__));
 
-	return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_CREATEANSWER, CC_SDP_DIRECTION_SENDRECV, JSEP_NO_ACTION, 0, 0, NO_STREAM, 0, sdp, NULL);
+    return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_CREATEANSWER, JSEP_NO_ACTION,
+                                   0, 0, NO_STREAM, 0, constraints, sdp, NULL);
 }
 
 cc_return_t CC_CallFeature_SetLocalDescription(cc_call_handle_t call_handle, cc_jsep_action_t action, string_t sdp) {
-	CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
-			GET_LINE_ID(call_handle), __FUNCTION__));
+    const cc_media_constraints_t *constraints = NULL;
+    CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
+            GET_LINE_ID(call_handle), __FUNCTION__));
 
-	return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_SETLOCALDESC, CC_SDP_DIRECTION_SENDRECV, action, 0, 0, NO_STREAM, 0, sdp, NULL);
+    return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_SETLOCALDESC, action,
+                                   0, 0, NO_STREAM, 0, constraints, sdp, NULL);
 }
 
 cc_return_t CC_CallFeature_SetRemoteDescription(cc_call_handle_t call_handle, cc_jsep_action_t action, string_t sdp) {
-	CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
-			GET_LINE_ID(call_handle), __FUNCTION__));
+    const cc_media_constraints_t *constraints = NULL;
+    CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
+            GET_LINE_ID(call_handle), __FUNCTION__));
 
-	return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_SETREMOTEDESC, CC_SDP_DIRECTION_SENDRECV, action, 0, 0, NO_STREAM, 0, sdp, NULL);
+    return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_SETREMOTEDESC, action,
+                                   0, 0, NO_STREAM, 0, constraints, sdp, NULL);
 }
 
 cc_return_t CC_CallFeature_SetPeerConnection(cc_call_handle_t call_handle, cc_peerconnection_t pc) {
-	CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
-			GET_LINE_ID(call_handle), __FUNCTION__));
+    const cc_media_constraints_t *constraints = NULL;
+    CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
+                GET_LINE_ID(call_handle), __FUNCTION__));
 
-	return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_SETPEERCONNECTION,
-          CC_SDP_DIRECTION_SENDRECV, JSEP_NO_ACTION, 0, 0, NO_STREAM, 0, pc, NULL);
+    return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_SETPEERCONNECTION, JSEP_NO_ACTION,
+                                   0, 0, NO_STREAM, 0, constraints, pc, NULL);
 }
 
-cc_return_t CC_CallFeature_AddStream(cc_call_handle_t call_handle, cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type) {
-	CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
-			GET_LINE_ID(call_handle), __FUNCTION__));
+cc_return_t CC_CallFeature_AddStream(cc_call_handle_t call_handle, cc_media_stream_id_t stream_id,
+                                            cc_media_track_id_t track_id, cc_media_type_t media_type) {
+    const cc_media_constraints_t *constraints = NULL;
+    CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
+            GET_LINE_ID(call_handle), __FUNCTION__));
 
-	return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_ADDSTREAM,
-			CC_SDP_DIRECTION_SENDRECV, JSEP_NO_ACTION, stream_id, track_id, media_type, 0, NULL, NULL);
+    return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_ADDSTREAM, JSEP_NO_ACTION,
+                                   stream_id, track_id, media_type, 0, constraints, NULL, NULL);
 }
 
-cc_return_t CC_CallFeature_RemoveStream(cc_call_handle_t call_handle, cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type) {
-	CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
-			GET_LINE_ID(call_handle), __FUNCTION__));
+cc_return_t CC_CallFeature_RemoveStream(cc_call_handle_t call_handle, cc_media_stream_id_t stream_id,
+                                               cc_media_track_id_t track_id, cc_media_type_t media_type) {
 
-	return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_REMOVESTREAM,
-			CC_SDP_DIRECTION_SENDRECV, JSEP_NO_ACTION, stream_id, track_id, media_type, 0, NULL, NULL);
+    const cc_media_constraints_t *constraints = NULL;
+    CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
+                GET_LINE_ID(call_handle), __FUNCTION__));
+
+    return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_REMOVESTREAM, JSEP_NO_ACTION,
+                                   stream_id, track_id, media_type, 0, constraints, NULL, NULL);
 }
 
 cc_return_t CC_CallFeature_AddICECandidate(cc_call_handle_t call_handle, const char* candidate, const char *mid, cc_level_t level) {
+    const cc_media_constraints_t *constraints = NULL;
     CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
             GET_LINE_ID(call_handle), __FUNCTION__));
 
-    return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_ADDICECANDIDATE,
-    		CC_SDP_DIRECTION_SENDRECV, JSEP_NO_ACTION, 0, 0, NO_STREAM, (uint16_t)level, candidate, mid);
+    return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_ADDICECANDIDATE, JSEP_NO_ACTION,
+                                   0, 0, NO_STREAM, (uint16_t)level, constraints, candidate, mid);
 }
 
 /**
  * Initiate a speed dial.
  * @param call handle
  * @param callid call id
  * @param speed dial numbers.
  * @return SUCCESS or FAILURE
--- a/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_call.c
+++ b/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_call.c
@@ -85,22 +85,22 @@ cc_lineid_t CCAPI_Call_getLine(cc_call_h
  * @param [in] video_pref - video direction desired on call
  * @param [in] digits - digits to be dialed
  * @return SUCCESS or FAILURE
  */
 cc_return_t CCAPI_Call_originateCall(cc_call_handle_t handle, cc_sdp_direction_t video_pref, cc_string_t digits){
 	return CC_CallFeature_dial(handle, video_pref, digits);
 }
 
-cc_return_t CCAPI_CreateOffer(cc_call_handle_t handle) {
-	return CC_CallFeature_CreateOffer(handle);
+cc_return_t CCAPI_CreateOffer(cc_call_handle_t handle, const cc_media_constraints_t *constraints) {
+	return CC_CallFeature_CreateOffer(handle, constraints);
 }
 
-cc_return_t CCAPI_CreateAnswer(cc_call_handle_t handle, cc_string_t offersdp) {
-	return CC_CallFeature_CreateAnswer(handle, offersdp);
+cc_return_t CCAPI_CreateAnswer(cc_call_handle_t handle, const cc_media_constraints_t *constraints, cc_string_t offersdp) {
+	return CC_CallFeature_CreateAnswer(handle, constraints, offersdp);
 }
 
 cc_return_t CCAPI_SetLocalDescription(cc_call_handle_t handle, cc_jsep_action_t action, cc_string_t sdp) {
 	return CC_CallFeature_SetLocalDescription(handle, action, sdp);
 }
 
 cc_return_t CCAPI_SetRemoteDescription(cc_call_handle_t handle, cc_jsep_action_t action, cc_string_t sdp) {
     return CC_CallFeature_SetRemoteDescription(handle, action, sdp);
--- a/media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c
+++ b/media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c
@@ -584,19 +584,23 @@ processSessionEvent (line_t line_id, cal
 	     break;
          case CC_FEATURE_KEYPRESS:
              dp_int_update_keypress(line_id, call_id, (unsigned char)*data);
              break;
          case CC_FEATURE_BKSPACE:
              dp_int_update_keypress(line_id, call_id, BKSP_KEY);
              break;
          case CC_FEATURE_CREATEOFFER:
+             featdata.session.sessionid = ccData.sessionid;
+             featdata.session.has_constraints = ccData.has_constraints;
              cc_createoffer (CC_SRC_UI, CC_SRC_GSM, call_id, (line_t)instance, CC_FEATURE_CREATEOFFER, &featdata);
              break;
          case CC_FEATURE_CREATEANSWER:
+             featdata.session.sessionid = ccData.sessionid;
+             featdata.session.has_constraints = ccData.has_constraints;
              cc_createanswer (CC_SRC_UI, CC_SRC_GSM, call_id, (line_t)instance, CC_FEATURE_CREATEANSWER, data, &featdata);
              break;
          case CC_FEATURE_SETLOCALDESC:
              cc_setlocaldesc (CC_SRC_UI, CC_SRC_GSM, call_id, (line_t)instance, CC_FEATURE_SETLOCALDESC, ccData.action, data, &featdata);
              break;
          case CC_FEATURE_SETREMOTEDESC:
              cc_setremotedesc (CC_SRC_UI, CC_SRC_GSM, call_id, (line_t)instance, CC_FEATURE_SETREMOTEDESC, ccData.action, data, &featdata);
              break;
--- a/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <limits.h>
-
+#include "CCProvider.h"
 #include "cpr_types.h"
 #include "cpr_stdlib.h"
 #include "cpr_stdio.h"
 #include "cpr_string.h"
 #include "cpr_rand.h"
 #include "cpr_timers.h"
 #include "cpr_errno.h"
 #include "phone.h"
@@ -32,16 +32,17 @@
 #include "prot_configmgr.h"
 #include "sip_interface_regmgr.h"
 #include "dialplanint.h"
 #include "subapi.h"
 #include "text_strings.h"
 #include "platform_api.h"
 #include "peer_connection_types.h"
 #include "prlog.h"
+#include "sessionHash.h"
 
 extern void update_kpmlconfig(int kpmlVal);
 extern boolean g_disable_mass_reg_debug_print;
 void escalateDeescalate();
 
 #define FSMDEF_NO_NUMBER    (NULL)
 #define DIGIT_POUND         ('#')
 #define FSMDEF_MAX_DCBS     (LSM_MAX_CALLS)
@@ -2759,17 +2760,17 @@ fsmdef_dialstring (fsm_fcb_t *fcb, const
     default:
         if (dialstring) {
             dcb->caller_id.called_number =
                 strlib_update(dcb->caller_id.called_number, dialstring);
         }
         break;
     }
 
-    cause = gsmsdp_create_local_sdp(dcb, FALSE);
+    cause = gsmsdp_create_local_sdp(dcb, FALSE, TRUE, TRUE, TRUE);
     if (cause != CC_CAUSE_OK) {
         FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
         /* Force clean up call without sending release */
         return (fsmdef_release(fcb, cause, FALSE));
     }
 
     /* Build SDP for sending out */
     cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
@@ -2864,30 +2865,44 @@ fsmdef_ev_createoffer (sm_event_t *event
     cc_feature_t        *msg = (cc_feature_t *) event->msg;
     line_t              line = msg->line;
     callid_t            call_id = msg->call_id;
     cc_causes_t         lsm_rc;
     int                 sdpmode = 0;
     char                *ufrag = NULL;
     char                *ice_pwd = NULL;
     short               vcm_res;
+    session_data_t      *sess_data_p = NULL;
 
     FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
     if (!sdpmode) {
       /* Force clean up call without sending release */
       return (fsmdef_release(fcb, cause, FALSE));
     }
 
     if (dcb == NULL) {
       FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
       return SM_RC_CLEANUP;
     }
 
+   if (msg->data.session.has_constraints) {
+        sess_data_p = (session_data_t *)findhash(msg->data.session.sessionid);
+        if (sess_data_p) {
+            gsmsdp_process_cap_constraints(dcb, sess_data_p->cc_constraints);
+
+            if (0 > delhash(msg->data.session.sessionid)) {
+                FSM_DEBUG_SM (DEB_F_PREFIX"failed to delete hash sessid=0x%08x\n",
+                DEB_F_PREFIX_ARGS(SIP_CC_PROV, __FUNCTION__), msg->data.session.sessionid);
+            }
+            cpr_free(sess_data_p);
+        }
+    }
+
     vcmGetIceParams(dcb->peerconnection, &ufrag, &ice_pwd);
     if (!ufrag || !ice_pwd) {
       ui_create_offer(evCreateOfferError, line, call_id, dcb->caller_id.call_instance_id, NULL);
       return (fsmdef_release(fcb, cause, FALSE));
     }
 
     dcb->ice_ufrag = (char *)cpr_malloc(strlen(ufrag) + 1);
     if (!dcb->ice_ufrag)
@@ -2908,17 +2923,17 @@ fsmdef_ev_createoffer (sm_event_t *event
                     dcb->digest_alg, FSMDEF_MAX_DIGEST_ALG_LEN,
                     dcb->digest, FSMDEF_MAX_DIGEST_LEN);
 
     if (vcm_res) {
     	FSM_DEBUG_SM(DEB_F_PREFIX"vcmGetDtlsIdentity returned an error\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         return SM_RC_END;
     }
 
-    cause = gsmsdp_create_local_sdp(dcb, FALSE);
+    cause = gsmsdp_create_local_sdp(dcb, FALSE, TRUE, TRUE, TRUE);
     if (cause != CC_CAUSE_OK) {
         ui_create_offer(evCreateOfferError, line, call_id, dcb->caller_id.call_instance_id, NULL);
         FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
         return (fsmdef_release(fcb, cause, FALSE));
     }
 
     cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
     if (cause != CC_CAUSE_OK) {
@@ -2954,29 +2969,43 @@ fsmdef_ev_createanswer (sm_event_t *even
     int                 sdpmode = 0;
     const char          *called_number = "1234";
     cc_causes_t         lsm_rc;
     cc_msgbody_t        *part;
     uint32_t            body_length;
     char                *ufrag = NULL;
     char                *ice_pwd = NULL;
     short               vcm_res;
+    session_data_t      *sess_data_p;
 
     FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
     if (!sdpmode) {
         return (fsmdef_release(fcb, cause, FALSE));
     }
 
     if (dcb == NULL) {
         FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         return SM_RC_CLEANUP;
     }
 
+    if (msg->data.session.has_constraints) {
+        sess_data_p = (session_data_t *)findhash(msg->data.session.sessionid);
+        if (sess_data_p) {
+            gsmsdp_process_cap_constraints(dcb, sess_data_p->cc_constraints);
+
+            if (0 > delhash(msg->data.session.sessionid)) {
+                FSM_DEBUG_SM (DEB_F_PREFIX"failed to delete hash sessid=0x%08x\n",
+                DEB_F_PREFIX_ARGS(SIP_CC_PROV, __FUNCTION__), msg->data.session.sessionid);
+            }
+            cpr_free(sess_data_p);
+        }
+    }
+
     vcmGetIceParams(dcb->peerconnection, &ufrag, &ice_pwd);
     if (!ufrag || !ice_pwd) {
       ui_create_offer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL);
       return (fsmdef_release(fcb, cause, FALSE));
     }
 
     dcb->ice_ufrag = (char *)cpr_malloc(strlen(ufrag) + 1);
     if (!dcb->ice_ufrag)
@@ -3001,17 +3030,17 @@ fsmdef_ev_createanswer (sm_event_t *even
         FSM_DEBUG_SM(DEB_F_PREFIX"vcmGetDtlsIdentity returned an error\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         return SM_RC_END;
     }
 
     /*
      * The sdp member of the dcb has local and remote sdp
      * this next function fills in the local part
      */
-    cause = gsmsdp_create_local_sdp(dcb, FALSE);
+    cause = gsmsdp_create_local_sdp(dcb, FALSE, TRUE, TRUE, TRUE);
     if (cause != CC_CAUSE_OK) {
         ui_create_answer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL);
         FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
         // Force clean up call without sending release
         return (fsmdef_release(fcb, cause, FALSE));
     }
 
     /* TODO(ekr@rtfm.com): The second true is because we are acting as if we are
@@ -3159,22 +3188,26 @@ fsmdef_ev_setremotedesc(sm_event_t *even
     int                 action = msg->action;
     int                 sdpmode = 0;
     callid_t            call_id = msg->call_id;
     line_t              line = msg->line;
     cc_causes_t         lsm_rc;
     cc_msgbody_t        *part;
     uint32_t            body_length;
     cc_msgbody_info_t   msg_body;
+    boolean             has_audio;
+    boolean             has_video;
+    boolean             has_data;
 
     FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
     if (!sdpmode) {
-        ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
+        ui_set_remote_description(evSetRemoteDescError, line, call_id,
+            dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
         return (SM_RC_END);
     }
 
     if (dcb == NULL) {
         FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         return SM_RC_CLEANUP;
     }
 
@@ -3188,59 +3221,70 @@ fsmdef_ev_setremotedesc(sm_event_t *even
     part->body_length = body_length;
     part->content_type = cc_content_type_SDP;
     part->content_disposition.required_handling = FALSE;
     part->content_disposition.disposition = cc_disposition_session;
     part->content_id = NULL;
 
     if (JSEP_OFFER == action) {
 
+        cause = gsmsdp_process_offer_sdp(fcb, &msg_body, TRUE);
+        if (cause != CC_CAUSE_OK) {
+            ui_set_remote_description(evSetRemoteDescError, line, call_id,
+                dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
+            return (SM_RC_END);
+        }
+
+        /*
+         * Determine what media types are offered, used to create matching local SDP
+         * for negotiation.
+         */
+        gsmsdp_get_offered_media_types(fcb, dcb->sdp, &has_audio, &has_video, &has_data);
+
         /*
          * The sdp member of the dcb has local and remote sdp
          * this next function fills in the local part
          */
-        cause = gsmsdp_create_local_sdp(dcb, TRUE);
+        cause = gsmsdp_create_local_sdp(dcb, TRUE, has_audio, has_video, has_data);
         if (cause != CC_CAUSE_OK) {
-            ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
+            ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id,
+                NULL, PC_SETREMOTEDESCERROR);
             FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
             // Force clean up call without sending release
             return (fsmdef_release(fcb, cause, FALSE));
         }
 
-        cause = gsmsdp_process_offer_sdp(fcb, &msg_body, TRUE);
-        if (cause != CC_CAUSE_OK) {
-            ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
-            return (SM_RC_END);
-        }
-
         cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp, TRUE, TRUE, TRUE);
         if (cause != CC_CAUSE_OK) {
-            ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
+            ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id,
+                NULL, PC_SETREMOTEDESCERROR);
             return (fsmdef_release(fcb, cause, FALSE));
         }
 
         gsmsdp_clean_media_list(dcb);
 
         fsm_change_state(fcb, __LINE__, FSMDEF_S_INCOMING_ALERTING);
 
     } else if (JSEP_ANSWER == action) {
 
         cause = gsmsdp_negotiate_answer_sdp(fcb, &msg_body);
         if (cause != CC_CAUSE_OK) {
-            ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
+            ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id,
+                NULL, PC_SETREMOTEDESCERROR);
             return (SM_RC_END);
         }
 
         /*
          * Now that we have negotiated the media, time to set up ICE.
          * There also needs to be an ICE check in negotiate_media_lines.
          */
         cause = gsmsdp_install_peer_ice_attributes(fcb);
         if (cause != CC_CAUSE_OK) {
-            ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
+            ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id,
+                NULL, PC_SETREMOTEDESCERROR);
             return (SM_RC_END);
         }
 
         cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED, FSMDEF_CC_CALLER_ID);
 
         /* we may want to use the functionality in the following method
          * to handle media capability changes, needs discussion
          * fsmdef_transition_to_connected(fcb);
@@ -3432,22 +3476,22 @@ fsmdef_ev_removestream(sm_event_t *event
     }
 
     /*
      * This is temporary code to allow configuration of the two
      * default streams. When multiple streams > 2 are supported this
      * will be re-implemented.
      */
     if (msg->data.track.media_type == VIDEO) {
+        dcb->media_cap_tbl->cap[CC_AUDIO_1].enabled = FALSE;
+        dcb->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_INACTIVE;
+        dcb->video_pref = SDP_DIRECTION_SENDRECV;
+    } else if (msg->data.track.media_type == AUDIO) {
         dcb->media_cap_tbl->cap[CC_VIDEO_1].enabled = FALSE;
         dcb->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_INACTIVE;
-        dcb->video_pref = SDP_DIRECTION_SENDRECV;
-    } else if (msg->data.track.media_type == AUDIO) {
-        dcb->media_cap_tbl->cap[CC_AUDIO_1].enabled = FALSE;
-        dcb->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_INACTIVE;
     } else {
         return (SM_RC_END);
     }
 
 	return (SM_RC_END);
 }
 
 static sm_rcs_t
@@ -7698,17 +7742,17 @@ fsmdef_cfwd_clear_ccm (fsm_fcb_t *fcb)
     FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
     // to clear CFA in CCM mode... only put service uri... no dialstring.
     fsmdef_append_dialstring_to_feature_uri(dcb, NULL);
 
     // From here on all we need to do is send INVITE out.
     // Since, its not a real call there is no need to update UI etc.
     // Response to this call will be 5xx so it will be released by the SIP stack.
-    cause = gsmsdp_create_local_sdp(dcb, FALSE);
+    cause = gsmsdp_create_local_sdp(dcb, FALSE, TRUE, TRUE, TRUE);
     if (cause != CC_CAUSE_OK) {
         FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
         return (fsmdef_release(fcb, cause, dcb->send_release));
     }
 
     /* Build SDP for sending out */
     cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
     if (cause != CC_CAUSE_OK) {
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -161,16 +161,51 @@ static const cc_media_cap_table_t *gsmsd
     	dcb_p->media_cap_tbl->cap[CC_DATACHANNEL_1].enabled = TRUE;
     } else {
         dcb_p->media_cap_tbl->cap[CC_DATACHANNEL_1].enabled = FALSE;
     }
 
     return (dcb_p->media_cap_tbl);
 }
 
+/*
+ * Process constraints only related to media capabilities. i.e OfferToReceiveAudio, OfferToReceiveVideo
+ */
+void gsmsdp_process_cap_constraints(fsmdef_dcb_t *dcb, const cc_media_constraints_t* constraints) {
+  int i = 0;
+
+  for (i=0; i<constraints->constraint_count; i++) {
+
+    if (strcmp(constraints_table[OfferToReceiveAudio].name, constraints->constraints[i]->name) == 0) {
+      if (cpr_strcasecmp("FALSE", constraints->constraints[i]->value) == 0) {
+        dcb->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_SENDONLY;
+      } else if (cpr_strcasecmp("TRUE", constraints->constraints[i]->value) == 0 &&
+                                 TRUE == dcb->media_cap_tbl->cap[CC_AUDIO_1].enabled) {
+        dcb->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_SENDRECV;
+      } else if (cpr_strcasecmp("TRUE", constraints->constraints[i]->value) == 0 ) {
+        dcb->media_cap_tbl->cap[CC_AUDIO_1].enabled = TRUE;
+        dcb->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_RECVONLY;
+      }
+    }
+
+    if (strcmp("OfferToReceiveVideo", constraints->constraints[i]->name) == 0) {
+      if (cpr_strcasecmp("FALSE", constraints->constraints[i]->value) == 0) {
+        dcb->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_SENDONLY;
+      } else if (cpr_strcasecmp("TRUE", constraints->constraints[i]->value) == 0 &&
+                                 TRUE == dcb->media_cap_tbl->cap[CC_VIDEO_1].enabled) {
+        dcb->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_SENDRECV;
+      } else if (cpr_strcasecmp("TRUE", constraints->constraints[i]->value) == 0 ) {
+        dcb->media_cap_tbl->cap[CC_VIDEO_1].enabled = TRUE;
+        dcb->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_RECVONLY;
+      }
+    }
+  }
+
+}
+
 /**
  * Sets up the media track table
  *
  * @param[in]dcb     - pointer to the fsmdef_dcb_t
  *
  * @return           - pointer to the the media track table for session
  */
 static const cc_media_remote_stream_table_t *gsmsdp_get_media_stream_table (fsmdef_dcb_t *dcb_p)
@@ -2191,24 +2226,27 @@ gsmsdp_update_local_sdp_media (fsmdef_dc
                               sdp_transport_e transport)
 {
     static const char fname[] = "gsmsdp_update_local_sdp_media";
     uint16_t        port;
     sdp_result_e    result;
     int             dynamic_payload_type;
     uint16_t        level;
     void           *sdp_p;
+    int             sdpmode = 0;
 
     if (!dcb_p || !media)  {
         GSM_ERR_MSG(get_debug_string(FSMDEF_DBG_INVALID_DCB), fname);
         return;
     }
     level = media->level;
     port  = media->src_port;
 
+    config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
     sdp_p = cc_sdp_p ? (void *) cc_sdp_p->src_sdp : NULL;
 
     if (sdp_p == NULL) {
 
         gsmsdp_init_local_sdp(&(dcb_p->sdp));
 
         cc_sdp_p = dcb_p->sdp;
         if ((cc_sdp_p == NULL) || (cc_sdp_p->src_sdp == NULL)) {
@@ -2290,18 +2328,18 @@ gsmsdp_update_local_sdp_media (fsmdef_dc
             gsmsdp_set_media_attributes(media->payload, sdp_p, level,
                                     (uint16_t)dynamic_payload_type);
             break;
         case SDP_MEDIA_VIDEO:
             gsmsdp_set_video_media_attributes(media->payload, cc_sdp_p, level,
                             (uint16_t)dynamic_payload_type);
             break;
         case SDP_MEDIA_APPLICATION:
-        	gsmsdp_set_sctp_attributes (sdp_p, level);
-        	break;
+            gsmsdp_set_sctp_attributes (sdp_p, level);
+            break;
         default:
             GSM_ERR_MSG(GSM_L_C_F_PREFIX"SDP ERROR media %d for level %d is not"
                         " supported\n",
                         dcb_p->line, dcb_p->call_id, fname, media->level);
             break;
         }
 
         /*
@@ -2314,17 +2352,19 @@ gsmsdp_update_local_sdp_media (fsmdef_dc
             if (result != SDP_SUCCESS) {
                 GSM_ERR_MSG(GSM_L_C_F_PREFIX"Adding AVT payload type failed\n",
                             dcb_p->line, dcb_p->call_id, fname);
             }
             gsmsdp_set_media_attributes(RTP_AVT, sdp_p, level,
                 (uint16_t) media->avt_payload_type);
         }
     }
-    gsmsdp_set_anat_attr(dcb_p, media);
+
+    if (!sdpmode)
+        gsmsdp_set_anat_attr(dcb_p, media);
 }
 
 /*
  * gsmsdp_update_local_sdp
  *
  * Description:
  *
  * Updates the local SDP of the DCB based on the remote SDP.
@@ -4122,17 +4162,17 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t 
              */
             if (media_type == SDP_MEDIA_VIDEO ) {
                 video_avail = media->direction;
             }
 
             if (update_local_ret_value == TRUE) {
                 media->previous_sdp.dest_port = media->dest_port;
                 media->dest_port = port;
-                if (media_type == SDP_MEDIA_AUDIO) {
+                if (media_type == SDP_MEDIA_AUDIO || sdpmode) {
                     /* at least found one workable audio media line */
                     media_found = TRUE;
                 }
             } else {
                 /*
                  * Rejecting multicast because direction is not RECVONLY
                  */
                 unsupported_line = TRUE;
@@ -4167,19 +4207,18 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t 
                   }
 
                   if (notify_stream_added) {
                     /*
                      * Add track to remote streams in dcb
                      */
                      int pc_stream_id = 0;
 
-                     lsm_add_remote_stream (dcb_p->line, dcb_p->call_id, media, &pc_stream_id);
-
                      if (SDP_MEDIA_APPLICATION != media_type) {
+                         lsm_add_remote_stream (dcb_p->line, dcb_p->call_id, media, &pc_stream_id);
                          gsmsdp_add_remote_stream(i-1, pc_stream_id, dcb_p, media);
                      } else {
                          /*
                           * Inform VCM that a Data Channel has been negotiated
                           */
                          lsm_data_channel_negotiated(dcb_p->line, dcb_p->call_id, media, &pc_stream_id);
                      }
                   }
@@ -4261,23 +4300,25 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t 
 
             /* ToDO(emannion)
              * Fail negotiation if ICE is not negotiated.
              */
 
             /*
              * Bubble the stream added event up to the PC UI
              */
-             if (notify_stream_added) {
-
+            if (notify_stream_added) {
                 for (j=0; j < CC_MAX_STREAMS; j++ ) {
-                    // If this stream has been created it should have >0 tracks.
+                    /* If this stream has been created it should have > 0 tracks. */
                     if (dcb_p->remote_media_stream_tbl->streams[j].num_tracks) {
                         ui_on_remote_stream_added(evOnRemoteStreamAdd, dcb_p->line, dcb_p->call_id,
-                               dcb_p->caller_id.call_instance_id, dcb_p->remote_media_stream_tbl->streams[j]);
+                           dcb_p->caller_id.call_instance_id, dcb_p->remote_media_stream_tbl->streams[j]);
+
+                        /* Setting num_tracks == 0 indicates stream not set */
+                        dcb_p->remote_media_stream_tbl->streams[j].num_tracks = 0;
                     }
                 }
             }
         }
     }
     /*
      * We have negotiated the line, clear flag that we have set
      * that we are waiting for an answer SDP in ack.
@@ -4295,16 +4336,59 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t 
     dcb_p->cur_video_avail |= (uint8_t)video_avail;
 
     lsm_update_video_avail(dcb_p->line, dcb_p->call_id, dcb_p->cur_video_avail);
 
     return cause;
 }
 
 /*
+ * This function returns boolean parameters indicating what media types
+ * exist in the offered SDP.
+ */
+cc_causes_t
+gsmsdp_get_offered_media_types (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean *has_audio,
+                                boolean *has_video, boolean *has_data)
+{
+    cc_causes_t     cause = CC_CAUSE_OK;
+    uint16_t        num_m_lines = 0;
+    uint16_t        i = 0;
+    sdp_media_e     media_type;
+    fsmdef_dcb_t   *dcb_p = fcb_p->dcb;
+    boolean         result;
+
+    num_m_lines = sdp_get_num_media_lines(sdp_p->dest_sdp);
+    if (num_m_lines == 0) {
+        GSM_DEBUG(DEB_L_C_F_PREFIX"no media lines found.\n",
+                  DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, __FUNCTION__));
+        return CC_CAUSE_NO_MEDIA;
+    }
+
+    *has_audio = FALSE;
+    *has_video = FALSE;
+    *has_data = FALSE;
+
+    /*
+     * Process each media line in the remote SDP
+     */
+    for (i = 1; i <= num_m_lines; i++) {
+        media_type = sdp_get_media_type(sdp_p->dest_sdp, i);
+
+        if(SDP_MEDIA_AUDIO == media_type)
+            *has_audio = TRUE;
+        else if(SDP_MEDIA_VIDEO == media_type)
+            *has_video = TRUE;
+        else if(SDP_MEDIA_APPLICATION == media_type)
+            *has_data = TRUE;
+    }
+
+    return cause;
+}
+
+/*
  * gsmsdp_init_local_sdp
  *
  * Description:
  *
  * This function initializes the local sdp for generation of an offer sdp or
  * an answer sdp. The following sdp values are initialized.
  *
  * v= line
@@ -4609,27 +4693,29 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb
  * force_streams_enabled - temporarily generate SDP even when no
  *                         streams are added
  *
  * returns    cc_causes_t
  *            CC_CAUSE_OK - indicates success
  *            CC_CAUSE_ERROR - indicates failure
  */
 cc_causes_t
-gsmsdp_create_local_sdp (fsmdef_dcb_t *dcb_p, boolean force_streams_enabled)
+gsmsdp_create_local_sdp (fsmdef_dcb_t *dcb_p, boolean force_streams_enabled,
+                         boolean audio, boolean video, boolean data)
 {
     static const char fname[] = "gsmsdp_create_local_sdp";
     uint16_t        level;
     const cc_media_cap_table_t *media_cap_tbl;
     const cc_media_cap_t       *media_cap;
     cpr_ip_mode_e   ip_mode;
     uint8_t         cap_index;
     fsmdef_media_t  *media;
     boolean         has_audio;
     int             sdpmode = 0;
+    boolean         media_enabled;
 
     if ( CC_CAUSE_OK != gsmsdp_init_local_sdp(&(dcb_p->sdp)) )
       return CC_CAUSE_ERROR;
 
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
 
     dcb_p->src_sdp_version = 0;
 
@@ -4640,20 +4726,31 @@ gsmsdp_create_local_sdp (fsmdef_dcb_t *d
         GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media capbility available\n",
                     dcb_p->line, dcb_p->call_id, fname);
         return (CC_CAUSE_ERROR);
     }
 
     media_cap = &media_cap_tbl->cap[0];
     level = 0;
     for (cap_index = 0; cap_index < CC_MAX_MEDIA_CAP; cap_index++) {
+
+        /* Build local m lines based on m lines that were in the offered SDP */
+        media_enabled = TRUE;
+        if (FALSE == audio && SDP_MEDIA_AUDIO == media_cap->type) {
+            media_enabled = FALSE;
+        } else if (FALSE == video && SDP_MEDIA_VIDEO == media_cap->type) {
+            media_enabled = FALSE;
+        } else if (FALSE == data && SDP_MEDIA_APPLICATION == media_cap->type) {
+            media_enabled = FALSE;
+        }
+
         /*
          * Add each enabled media line to the SDP
          */
-        if (media_cap->enabled || force_streams_enabled) {
+        if (media_enabled && ( media_cap->enabled || force_streams_enabled)) {
             level = level + 1;  /* next level */
             ip_mode = platform_get_ip_address_mode();
             if (ip_mode >= CPR_IP_MODE_IPV6) {
                 if (gsmsdp_add_media_line(dcb_p, media_cap, cap_index,
                                           level, CPR_IP_ADDR_IPV6)
                     == NULL) {
                     /* fail to add a media line, go back one level */
                     level = level - 1;
@@ -5748,17 +5845,17 @@ gsmsdp_process_offer_sdp (fsm_fcb_t *fcb
         DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), init);
     if (num_sdp_bodies == 0) {
         /*
          * No remote SDP. So we will offer in our response and receive far end
          * answer in the ack. Only need to create local sdp if this is first offer
          * of a session. Otherwise, we will send what we have.
          */
         if (init) {
-            if ( CC_CAUSE_OK != gsmsdp_create_local_sdp(dcb_p, FALSE)) {
+            if ( CC_CAUSE_OK != gsmsdp_create_local_sdp(dcb_p, FALSE, TRUE, TRUE, TRUE)) {
                 return CC_CAUSE_ERROR;
             }
         } else {
             /*
              * Reset all media entries that we have to offer all capabilities
              */
            (void)gsmsdp_update_local_sdp_media_capability(dcb_p, TRUE, FALSE);
         }
--- a/media/webrtc/signaling/src/sipcc/core/gsm/h/gsm_sdp.h
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/h/gsm_sdp.h
@@ -27,17 +27,35 @@
     for (media = start_media; (media != NULL);                \
          media = (media != end_media ?                        \
                    GSMSDP_NEXT_MEDIA_ENTRY(media) : NULL))
 
 #define GSMSDP_FOR_ALL_MEDIA(media, dcb) \
     for (media = GSMSDP_FIRST_MEDIA_ENTRY(dcb); (media != NULL); \
          media = GSMSDP_NEXT_MEDIA_ENTRY(media))
 
-cc_causes_t gsmsdp_create_local_sdp(fsmdef_dcb_t *dcb_p, boolean force_streams_enabled);
+typedef struct {
+    const char *name;
+    int         value;
+} gsmsdp_key_table_entry_t;
+
+typedef enum constraints_ {
+    OfferToReceiveAudio     = 0,
+    OfferToReceiveVideo     = 1,
+    VoiceActivityDetection  = 2
+} constraints;
+
+static const gsmsdp_key_table_entry_t constraints_table[] = {
+    {"OfferToReceiveAudio",         OfferToReceiveAudio},
+    {"OfferToReceiveVideo",         OfferToReceiveVideo},
+    {"VoiceActivityDetection",      VoiceActivityDetection}
+};
+
+cc_causes_t gsmsdp_create_local_sdp(fsmdef_dcb_t *dcb_p, boolean force_streams_enabled,
+                                    boolean audio, boolean video, boolean data);
 void gsmsdp_create_options_sdp(cc_sdp_t **sdp_pp);
 void gsmsdp_reset_local_sdp_media(fsmdef_dcb_t *dcb, fsmdef_media_t *media,
                                   boolean hold);
 void gsmsdp_set_local_sdp_direction(fsmdef_dcb_t *dcb_p, fsmdef_media_t *media,
                                     sdp_direction_e direction);
 void gsmsdp_set_local_hold_sdp(fsmdef_dcb_t *dcb, fsmdef_media_t *media);
 void gsmsdp_set_local_resume_sdp(fsmdef_dcb_t *dcb, fsmdef_media_t *media);
 cc_causes_t gsmsdp_negotiate_answer_sdp(fsm_fcb_t *fcb,
@@ -106,11 +124,14 @@ extern boolean gsmsdp_handle_media_cap_c
 extern boolean gsmsdp_update_local_sdp_media_capability(fsmdef_dcb_t *dcb_p,
                                               boolean refresh, boolean hold);
 boolean is_gsmsdp_media_ip_updated_to_latest( fsmdef_dcb_t * dcb );
 
 void gsmsdp_add_remote_stream(uint16_t idx, int pc_stream_id, fsmdef_dcb_t * dcb, fsmdef_media_t *media);
 cc_causes_t gsmsdp_install_peer_ice_attributes(fsm_fcb_t *fcb_p);
 cc_causes_t gsmsdp_configure_dtls_data_attributes(fsm_fcb_t *fcb_p);
 cc_causes_t gsmsdp_find_level_from_mid(fsmdef_dcb_t * dcb, const char * mid, uint16_t *level);
+void gsmsdp_process_cap_constraints(fsmdef_dcb_t *dcb, const cc_media_constraints_t* constraints);
+cc_causes_t
+gsmsdp_get_offered_media_types (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean *has_audio, boolean *has_video, boolean *has_data);
 
 #endif
 
--- a/media/webrtc/signaling/src/sipcc/core/includes/ccapi.h
+++ b/media/webrtc/signaling/src/sipcc/core/includes/ccapi.h
@@ -830,16 +830,20 @@ typedef struct cc_feature_data_track_t_ 
 
 
 typedef struct cc_feature_candidate_t_ {
   uint16_t    level;
   char        candidate[CANDIDATE_SIZE];
   char        mid[MID_SIZE];
 } cc_feature_candidate_t;
 
+typedef struct cc_feature_session_t_ {
+  unsigned int  sessionid;
+  cc_boolean    has_constraints;
+} cc_feature_session_t;
 
 
 typedef union cc_feature_data_t {
     cc_feature_data_newcall_t   newcall;
     cc_feature_data_xfer_t      xfer;
     cc_feature_data_ind_t       indication;
     cc_feature_data_endcall_t   endcall;
     cc_feature_data_hold_t      hold;
@@ -856,16 +860,17 @@ typedef union cc_feature_data_t {
     cc_feature_data_b2b_join_t  b2bjoin;
     cc_feature_data_generic_t   generic;
     cc_feature_data_cnf_t       cnf;
     cc_feature_data_b2bcnf_t    cancel;
     cc_media_cap_t              caps;
     cc_feature_data_pc_t        pc;
     cc_feature_data_track_t     track;
     cc_feature_candidate_t      candidate;
+    cc_feature_session_t        session;
 } cc_feature_data_t;
 
 typedef struct cc_setup_t_ {
     cc_msgs_t       msg_id;
     cc_srcs_t       src_id;
     callid_t        call_id;
     line_t          line;
     cc_alerting_type alert_info;
--- a/media/webrtc/signaling/src/sipcc/core/includes/sessionTypes.h
+++ b/media/webrtc/signaling/src/sipcc/core/includes/sessionTypes.h
@@ -34,24 +34,26 @@ typedef struct {
 } ccProvider_state_t;
 
 typedef struct {
   line_t  line_id;
   string_t dial;
 } ccSession_create_param_t;
 
 typedef struct {
-  string_t info;
-  string_t info1;
-  unsigned int state;
-  cc_jsep_action_t     action;
-  cc_media_stream_id_t stream_id;
-  cc_media_track_id_t  track_id;
-  cc_media_type_t      media_type;
-  cc_level_t           level;
+  string_t                  info;
+  string_t                  info1;
+  unsigned int              state;
+  cc_jsep_action_t          action;
+  cc_media_stream_id_t      stream_id;
+  cc_media_track_id_t       track_id;
+  cc_media_type_t           media_type;
+  cc_level_t                level;
+  unsigned int              sessionid;
+  cc_boolean                has_constraints;
 } ccSession_feature_t;
 
 typedef struct {
   int          state;
   int          attr;
   int          inst;
   line_t       line_id;
   int          cause;
--- a/media/webrtc/signaling/src/sipcc/include/cc_call_feature.h
+++ b/media/webrtc/signaling/src/sipcc/include/cc_call_feature.h
@@ -146,19 +146,19 @@ cc_return_t CC_CallFeature_backSpace(cc_
  * Send a dial digit string on an active call, e.g."9191234567".
  * @param call_handle call handle
  * @param video_pref the sdp direction
  * @param numbers dialed string
  * @return SUCCESS or FAILURE
  */
 cc_return_t CC_CallFeature_dial(cc_call_handle_t call_handle, cc_sdp_direction_t video_pref, const cc_string_t numbers);
 
-cc_return_t CC_CallFeature_CreateOffer(cc_call_handle_t call_handle);
+cc_return_t CC_CallFeature_CreateOffer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints);
 
-cc_return_t CC_CallFeature_CreateAnswer(cc_call_handle_t call_handle, const char* sdp);
+cc_return_t CC_CallFeature_CreateAnswer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints, const char* sdp);
 
 cc_return_t CC_CallFeature_SetLocalDescription(cc_call_handle_t call_handle, cc_jsep_action_t action, const char* sdp);
 
 cc_return_t CC_CallFeature_SetRemoteDescription(cc_call_handle_t call_handle, cc_jsep_action_t action, const char* sdp);
 
 cc_return_t CC_CallFeature_SetPeerConnection(cc_call_handle_t call_handle, cc_peerconnection_t pc);
 
 cc_return_t CC_CallFeature_AddStream(cc_call_handle_t call_handle, cc_media_stream_id_t stream_id, cc_media_track_id_t id, cc_media_type_t media_type);
--- a/media/webrtc/signaling/src/sipcc/include/cc_constants.h
+++ b/media/webrtc/signaling/src/sipcc/include/cc_constants.h
@@ -541,11 +541,21 @@ typedef unsigned int cc_media_track_id_t
 typedef enum {
   NO_STREAM = -1,
   AUDIO,
   VIDEO,
   TYPE_MAX
 } cc_media_type_t;
 
 
+typedef struct {
+  char        *name;
+  char        *value;
+  cc_boolean   mandatory;
+} cc_media_constraint_t;
+
+typedef struct {
+  cc_media_constraint_t**  constraints;
+  cc_uint16_t              constraint_count;
+} cc_media_constraints_t;
 
 #endif /* _CC_CONSTANTS_H_ */
 
--- a/media/webrtc/signaling/src/sipcc/include/ccapi_call.h
+++ b/media/webrtc/signaling/src/sipcc/include/ccapi_call.h
@@ -43,19 +43,19 @@ cc_lineid_t CCAPI_Call_getLine(cc_call_h
  * @param [in] handle - call handle
  * @param [in] video_pref - video direction desired on call
  * @param [in] digits - digits to be dialed. can be empty then this API simply goes offhook
  * @return SUCCESS or FAILURE
  */
 cc_return_t CCAPI_Call_originateCall(cc_call_handle_t handle, cc_sdp_direction_t video_pref, cc_string_t digits);
 
 
-cc_return_t CCAPI_CreateOffer(cc_call_handle_t handle);
+cc_return_t CCAPI_CreateOffer(cc_call_handle_t handle, const cc_media_constraints_t *constraints);
 
-cc_return_t CCAPI_CreateAnswer(cc_call_handle_t handle, cc_string_t offersdp);
+cc_return_t CCAPI_CreateAnswer(cc_call_handle_t handle, const cc_media_constraints_t *constraints, cc_string_t offersdp);
 
 cc_return_t CCAPI_SetLocalDescription(cc_call_handle_t handle, cc_jsep_action_t action, cc_string_t sdp);
 
 cc_return_t CCAPI_SetRemoteDescription(cc_call_handle_t handle, cc_jsep_action_t action, cc_string_t sdp);
 
 cc_return_t CCAPI_SetPeerConnection(cc_call_handle_t handle, cc_peerconnection_t pc);
 
 cc_return_t CCAPI_AddStream(cc_call_handle_t handle, cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type);
--- a/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.cpp
+++ b/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.cpp
@@ -516,41 +516,39 @@ bool CC_SIPCCCall::setVolume(int volume)
 
 CC_SIPCCCallMediaDataPtr CC_SIPCCCall::getMediaData()
 {
     return  pMediaData;
 }
 
 void CC_SIPCCCall::originateP2PCall (cc_sdp_direction_t video_pref, const std::string & digits, const std::string & ip)
 {
-	CCAPI_Config_set_server_address(ip.c_str());
+    CCAPI_Config_set_server_address(ip.c_str());
     CCAPI_Call_originateCall(callHandle, video_pref, digits.c_str());
 }
 
 /*
- * This method works asynchronously, there will be an onCallEvent with the resulting SDP
- * When Constraints are implemented the Audio and Video port will not be a parameter to CCAPI_CreateAnswer
+ * This method works asynchronously, is an onCallEvent with the resulting SDP
  */
-void CC_SIPCCCall::createOffer (const std::string& hints) {
-	CCAPI_CreateOffer(callHandle);
+void CC_SIPCCCall::createOffer (const cc_media_constraints_t *constraints) {
+    CCAPI_CreateOffer(callHandle, constraints);
 }
-
 /*
- * This method works asynchronously, there will be an onCallEvent with the resulting SDP
+ * This method works asynchronously, there is onCallEvent with the resulting SDP
  */
-void CC_SIPCCCall::createAnswer (const std::string & hints, const std::string & offersdp) {
-	CCAPI_CreateAnswer(callHandle, offersdp.c_str());
+void CC_SIPCCCall::createAnswer (const cc_media_constraints_t *constraints, const std::string & offersdp) {
+    CCAPI_CreateAnswer(callHandle, constraints, offersdp.c_str());
 }
 
 void CC_SIPCCCall::setLocalDescription(cc_jsep_action_t action, const std::string & sdp) {
-	CCAPI_SetLocalDescription(callHandle, action, sdp.c_str());
+    CCAPI_SetLocalDescription(callHandle, action, sdp.c_str());
 }
 
 void CC_SIPCCCall::setRemoteDescription(cc_jsep_action_t action, const std::string & sdp) {
-	CCAPI_SetRemoteDescription(callHandle, action, sdp.c_str());
+    CCAPI_SetRemoteDescription(callHandle, action, sdp.c_str());
 }
 
 void CC_SIPCCCall::setPeerConnection(const std::string& handle)
 {
   CSFLogDebug(logTag, "setPeerConnection");
 
   peerconnection = handle;  // Cache this here. we need it to make the CC_SIPCCCallInfo
   CCAPI_SetPeerConnection(callHandle, handle.c_str());
--- a/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.h
+++ b/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.h
@@ -105,18 +105,18 @@ namespace CSF
         virtual bool muteAudio();
         virtual bool unmuteAudio();
         virtual bool muteVideo();
         virtual bool unmuteVideo();
         virtual void addStream(int streamId, bool isVideo);
         virtual void removeStream(int streamId);
         virtual bool setVolume(int volume);
         virtual void originateP2PCall (cc_sdp_direction_t video_pref, const std::string & digits, const std::string & ip);
-        virtual void createOffer(const std::string & hints);
-        virtual void createAnswer(const std::string & hints, const std::string & offersdp);
+        virtual void createOffer(const  cc_media_constraints_t *constraints);
+        virtual void createAnswer(const  cc_media_constraints_t *constraints, const std::string & offersdp);
         virtual void setLocalDescription(cc_jsep_action_t action, const std::string & sdp);
         virtual void setRemoteDescription(cc_jsep_action_t action, const std::string & sdp);
         virtual void setPeerConnection(const std::string& handle);
         virtual const std::string& getPeerConnection() const;
         virtual void addStream(cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type);
         virtual void removeStream(cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type);
         virtual CC_SIPCCCallMediaDataPtr getMediaData();
         virtual void addICECandidate(const std::string & candidate, const std::string & mid, unsigned short level);
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -473,17 +473,17 @@ class SignalingAgent {
     // Shutdown is synchronous evidently.
     // ASSERT_TRUE(pObserver->WaitForObserverCall());
     // ASSERT_EQ(pc->sipcc_state(), sipcc::PeerConnectionInterface::kIdle);
   }
 
   char* offer() const { return offer_; }
   char* answer() const { return answer_; }
 
-  void CreateOffer(const char* hints, bool audio, bool video) {
+  void CreateOffer(sipcc::MediaConstraints& constraints, bool audio, bool video) {
 
     // Create a media stream as if it came from GUM
     Fake_AudioStreamSource *audio_stream =
       new Fake_AudioStreamSource();
 
     nsresult ret;
     test_utils.sts_target()->Dispatch(
       WrapRunnableRet(audio_stream, &Fake_MediaStream::Start, &ret),
@@ -508,44 +508,54 @@ class SignalingAgent {
 
     domMediaStream->SetHintContents(aHintContents);
 
     pc->AddStream(domMediaStream);
     domMediaStream_ = domMediaStream;
 
     // Now call CreateOffer as JS would
     pObserver->state = TestObserver::stateNoResponse;
-    ASSERT_EQ(pc->CreateOffer(hints), NS_OK);
+    ASSERT_EQ(pc->CreateOffer(constraints), NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
     SDPSanityCheck(pObserver->lastString, audio, video, true);
     offer_ = pObserver->lastString;
   }
 
-  void CreateOfferExpectError(const char* hints) {
-    ASSERT_EQ(pc->CreateOffer(hints), NS_OK);
+  void CreateOfferExpectError(sipcc::MediaConstraints& constraints) {
+    ASSERT_EQ(pc->CreateOffer(constraints), NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateError, kDefaultTimeout);
   }
 
-  void CreateAnswer(const char* hints, std::string offer) {
+  void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer, bool audio, bool video) {
     // Create a media stream as if it came from GUM
     nsRefPtr<nsDOMMediaStream> domMediaStream = new nsDOMMediaStream();
 
-    // Pretend GUM got both audio and video.
-    domMediaStream->SetHintContents(nsDOMMediaStream::HINT_CONTENTS_AUDIO | nsDOMMediaStream::HINT_CONTENTS_VIDEO);
+    uint32_t aHintContents = 0;
+
+    if (audio) {
+      aHintContents |= nsDOMMediaStream::HINT_CONTENTS_AUDIO;
+    }
+    if (video) {
+      aHintContents |= nsDOMMediaStream::HINT_CONTENTS_VIDEO;
+    }
+
+    PR_ASSERT(aHintContents);
+
+    domMediaStream->SetHintContents(aHintContents);
 
     pc->AddStream(domMediaStream);
 
     pObserver->state = TestObserver::stateNoResponse;
-    ASSERT_EQ(pc->CreateAnswer(hints, offer.c_str()), NS_OK);
+    ASSERT_EQ(pc->CreateAnswer(constraints, offer.c_str()), NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
-    SDPSanityCheck(pObserver->lastString, true, true, false);
+    SDPSanityCheck(pObserver->lastString, audio, video, false);
     answer_ = pObserver->lastString;
   }
 
-  void CreateOfferRemoveStream(const char* hints, bool audio, bool video) {
+  void CreateOfferRemoveStream(sipcc::MediaConstraints& constraints, bool audio, bool video) {
 
     uint32_t aHintContents = 0;
 
     if (!audio) {
       aHintContents |= nsDOMMediaStream::HINT_CONTENTS_VIDEO;
     }
     if (!video) {
       aHintContents |= nsDOMMediaStream::HINT_CONTENTS_AUDIO;
@@ -554,19 +564,19 @@ class SignalingAgent {
     domMediaStream_->SetHintContents(aHintContents);
 
     // When complete RemoveStream will remove and entire stream and its tracks
     // not just disable a track as this is currently doing
     pc->RemoveStream(domMediaStream_);
 
     // Now call CreateOffer as JS would
     pObserver->state = TestObserver::stateNoResponse;
-    ASSERT_EQ(pc->CreateOffer(hints), NS_OK);
+    ASSERT_EQ(pc->CreateOffer(constraints), NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
-    SDPSanityCheck(pObserver->lastString, video, audio, true);
+    SDPSanityCheck(pObserver->lastString, audio, video, true);
     offer_ = pObserver->lastString;
   }
 
   void SetRemote(TestObserver::Action action, std::string remote) {
     pObserver->state = TestObserver::stateNoResponse;
     ASSERT_EQ(pc->SetRemoteDescription(action, remote.c_str()), NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
   }
@@ -594,41 +604,16 @@ class SignalingAgent {
     pc->GetIceState(&state);
     return state == sipcc::PeerConnectionImpl::kIceConnected;
   }
 
   void AddIceCandidate(const char* candidate, const char* mid, unsigned short level) {
     pc->AddIceCandidate(candidate, mid, level);
   }
 
-#if 0
-  void CreateOfferSetLocal(const char* hints) {
-      CreateOffer(hints);
-
-      pObserver->state = TestObserver::stateNoResponse;
-      ASSERT_EQ(pc->SetLocalDescription(sipcc::OFFER, pObserver->lastString), NS_OK);
-      ASSERT_TRUE(pObserver->WaitForObserverCall());
-      ASSERT_EQ(pObserver->state, TestObserver::stateSuccess);
-      ASSERT_EQ(pc->SetRemoteDescription(sipcc::OFFER, strSampleSdpAudioVideoNoIce), NS_OK);
-      ASSERT_TRUE(pObserver->WaitForObserverCall());
-      ASSERT_EQ(pObserver->state, TestObserver::stateSuccess);
-    }
-
-  void CreateAnswer(const char* hints, )
-    {
-      std::string offer = strSampleSdpAudioVideoNoIce;
-      std::string strHints(hints);
-
-      ASSERT_EQ(pc->CreateAnswer(strHints, offer), NS_OK);
-      ASSERT_TRUE(pObserver->WaitForObserverCall());
-      ASSERT_EQ(pObserver->state, TestObserver::stateSuccess);
-      SDPSanityCheck(pObserver->lastString, true, true, false);
-    }
-#endif
-
   int GetPacketsReceived(int stream) {
     std::vector<nsDOMMediaStream *> streams = pObserver->GetStreams();
 
     if ((int) streams.size() <= stream) {
       return 0;
     }
 
     return streams[stream]->GetStream()->AsSourceStream()->GetSegmentsAdded();
@@ -676,177 +661,292 @@ class SignalingEnvironment : public ::te
  public:
   void TearDown() {
     sipcc::PeerConnectionImpl::Shutdown();
   }
 };
 
 class SignalingTest : public ::testing::Test {
 public:
-  void CreateOffer(const char* hints) {
-    a1_.CreateOffer(hints, true, true);
+  void CreateOffer(sipcc::MediaConstraints& constraints, bool audio, bool video) {
+    a1_.CreateOffer(constraints, audio, video);
   }
 
-  void CreateSetOffer(const char* hints) {
-    a1_.CreateOffer(hints, true, true);
+  void CreateSetOffer(sipcc::MediaConstraints& constraints) {
+    a1_.CreateOffer(constraints, true, true);
     a1_.SetLocal(TestObserver::OFFER, a1_.offer());
   }
 
-  void OfferAnswer(const char* ahints, const char* bhints) {
-    a1_.CreateOffer(ahints, true, true);
+  void OfferAnswer(sipcc::MediaConstraints& aconstraints, sipcc::MediaConstraints& bconstraints,
+                       bool audio, bool video, bool finishAfterAnswer) {
+    a1_.CreateOffer(aconstraints, audio, video);
     a1_.SetLocal(TestObserver::OFFER, a1_.offer());
     a2_.SetRemote(TestObserver::OFFER, a1_.offer());
-    a2_.CreateAnswer(bhints, a1_.offer());
-    a2_.SetLocal(TestObserver::ANSWER, a2_.answer());
-    a1_.SetRemote(TestObserver::ANSWER, a2_.answer());
-    ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
-    ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
+    a2_.CreateAnswer(bconstraints, a1_.offer(), audio, video);
+    if(true == finishAfterAnswer) {
+        a2_.SetLocal(TestObserver::ANSWER, a2_.answer());
+        a1_.SetRemote(TestObserver::ANSWER, a2_.answer());
+
+        ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
+        ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
+    }
   }
 
-  void OfferModifiedAnswer(const char* ahints, const char* bhints) {
-    a1_.CreateOffer(ahints, true, true);
+  void OfferModifiedAnswer(sipcc::MediaConstraints& aconstraints, sipcc::MediaConstraints& bconstraints) {
+    a1_.CreateOffer(aconstraints, true, true);
     a1_.SetLocal(TestObserver::OFFER, a1_.offer());
     a2_.SetRemote(TestObserver::OFFER, a1_.offer());
-    a2_.CreateAnswer(bhints, a1_.offer());
+    a2_.CreateAnswer(bconstraints, a1_.offer(), true, true);
     a2_.SetLocal(TestObserver::ANSWER, a2_.answer());
     ParsedSDP sdpWrapper(a2_.answer());
     sdpWrapper.ReplaceLine("m=audio", "m=audio 65375 RTP/SAVPF 109 8 101\r\n");
     sdpWrapper.AddLine("a=rtpmap:8 PCMA/8000\r\n");
     cout << "Modified SDP " << sdpWrapper.getSdp() << endl;
     a1_.SetRemote(TestObserver::ANSWER, sdpWrapper.getSdp());
     ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
     ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
   }
 
-  void OfferAnswerTrickle(const char* ahints, const char* bhints) {
-    a1_.CreateOffer(ahints, true, true);
+  void OfferAnswerTrickle(sipcc::MediaConstraints& aconstraints, sipcc::MediaConstraints& bconstraints) {
+    a1_.CreateOffer(aconstraints, true, true);
     a1_.SetLocal(TestObserver::OFFER, a1_.offer());
     ParsedSDP a1_offer(a1_.offer());
     a2_.SetRemote(TestObserver::OFFER, a1_offer.sdp_without_ice_);
-    a2_.CreateAnswer(bhints, a1_offer.sdp_without_ice_);
+    a2_.CreateAnswer(bconstraints, a1_offer.sdp_without_ice_, true, true);
     a2_.SetLocal(TestObserver::ANSWER, a2_.answer());
     ParsedSDP a2_answer(a2_.answer());
     a1_.SetRemote(TestObserver::ANSWER, a2_answer.sdp_without_ice_);
     // Now set the trickle ICE candidates
     a1_.DoTrickleIce(a2_answer);
     a2_.DoTrickleIce(a1_offer);
     ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
     ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
   }
 
-  void CreateOfferVideoOnly(const char* hints) {
-    a1_.CreateOffer(hints, false, true);
-  }
-
-  void CreateOfferAudioOnly(const char * hints) {
-    a1_.CreateOffer(hints, true, false);
+  void CreateOfferRemoveStream(sipcc::MediaConstraints& constraints, bool audio, bool video) {
+    sipcc::MediaConstraints aconstraints;
+    aconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+    aconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+    a1_.CreateOffer(aconstraints, true, true);
+    a1_.CreateOfferRemoveStream(constraints, audio, video);
   }
 
-  void CreateOfferRemoveStream(const char * hints) {
-	a1_.CreateOffer(hints, true, true);
-    a1_.CreateOfferRemoveStream(hints, false, true);
+  void CreateOfferAudioOnly(sipcc::MediaConstraints& constraints) {
+    a1_.CreateOffer(constraints, true, false);
   }
 
-  void CreateOfferAddCandidate(const char * hints, const char * candidate, const char * mid, unsigned short level) {
-    a1_.CreateOffer(hints, true, true);
+  void CreateOfferRemoveStream(sipcc::MediaConstraints& constraints) {
+	a1_.CreateOffer(constraints, true, true);
+    a1_.CreateOfferRemoveStream(constraints, false, true);
+  }
+
+  void CreateOfferAddCandidate(sipcc::MediaConstraints& constraints, const char * candidate, const char * mid, unsigned short level) {
+    a1_.CreateOffer(constraints, true, true);
     a1_.AddIceCandidate(candidate, mid, level);
   }
 
  protected:
   SignalingAgent a1_;  // Canonically "caller"
   SignalingAgent a2_;  // Canonically "callee"
 };
 
 
 TEST_F(SignalingTest, JustInit)
 {
 }
 
-TEST_F(SignalingTest, CreateOfferNoHints)
+TEST_F(SignalingTest, CreateSetOffer)
+{
+  sipcc::MediaConstraints constraints;
+  CreateSetOffer(constraints);
+}
+
+TEST_F(SignalingTest, CreateOfferAudioVideoConstraintUndefined)
 {
-  CreateOffer("");
+  sipcc::MediaConstraints constraints;
+  CreateOffer(constraints, true, true);
+}
+
+TEST_F(SignalingTest, CreateOfferNoVideoStream)
+{
+  sipcc::MediaConstraints constraints;
+  constraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  constraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  CreateOffer(constraints, true, false);
+}
+
+TEST_F(SignalingTest, CreateOfferNoAudioStream)
+{
+  sipcc::MediaConstraints constraints;
+  constraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  constraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  CreateOffer(constraints, false, true);
 }
 
-TEST_F(SignalingTest, CreateSetOffer)
+TEST_F(SignalingTest, CreateOfferDontReceiveAudio)
+{
+  sipcc::MediaConstraints constraints;
+  constraints.setBooleanConstraint("OfferToReceiveAudio", false, false);
+  constraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  constraints.setBooleanConstraint("VoiceActivityDetection", true, true);
+  CreateOffer(constraints, true, true);
+}
+
+TEST_F(SignalingTest, CreateOfferDontReceiveVideo)
 {
-  CreateSetOffer("");
+  sipcc::MediaConstraints constraints;
+  constraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  constraints.setBooleanConstraint("OfferToReceiveVideo", false, false);
+  CreateOffer(constraints, true, true);
+}
+
+TEST_F(SignalingTest, CreateOfferRemoveAudioStream)
+{
+  sipcc::MediaConstraints constraints;
+  constraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  constraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  CreateOfferRemoveStream(constraints, false, true);
+}
+
+TEST_F(SignalingTest, CreateOfferDontReceiveAudioRemoveAudioStream)
+{
+  sipcc::MediaConstraints constraints;
+  constraints.setBooleanConstraint("OfferToReceiveAudio", false, false);
+  constraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  CreateOfferRemoveStream(constraints, false, true);
 }
 
-TEST_F(SignalingTest, CreateOfferVideoOnly)
+TEST_F(SignalingTest, CreateOfferDontReceiveVideoRemoveVideoStream)
+{
+  sipcc::MediaConstraints constraints;
+  constraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  constraints.setBooleanConstraint("OfferToReceiveVideo", false, false);
+  CreateOfferRemoveStream(constraints, true, false);
+}
+
+TEST_F(SignalingTest, OfferAnswerDontReceiveAudio)
 {
-  CreateOfferVideoOnly("");
+  sipcc::MediaConstraints aconstraints;
+  aconstraints.setBooleanConstraint("OfferToReceiveAudio", false, false);
+  aconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  sipcc::MediaConstraints bconstraints;
+  bconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  bconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  OfferAnswer(aconstraints, bconstraints, true, true, false);
+}
+
+TEST_F(SignalingTest, OfferAnswerDontReceiveVideo)
+{
+  sipcc::MediaConstraints aconstraints;
+  aconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  aconstraints.setBooleanConstraint("OfferToReceiveVideo", false, false);
+  sipcc::MediaConstraints bconstraints;
+  bconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  bconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  OfferAnswer(aconstraints, bconstraints, true, true, false);
 }
 
-TEST_F(SignalingTest, CreateOfferAudioOnly)
+TEST_F(SignalingTest, OfferAnswerDontReceiveVideoOnAnswer)
 {
-  CreateOfferAudioOnly("");
+  sipcc::MediaConstraints aconstraints;
+  aconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  aconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  sipcc::MediaConstraints bconstraints;
+  bconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  bconstraints.setBooleanConstraint("OfferToReceiveVideo", false, false);
+  OfferAnswer(aconstraints, bconstraints, true, true, false);
 }
 
-TEST_F(SignalingTest, CreateOfferRemoveStream)
+TEST_F(SignalingTest, OfferAnswerDontSendReceiveVideoNoVideoStream)
+{
+  sipcc::MediaConstraints aconstraints;
+  aconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  aconstraints.setBooleanConstraint("OfferToReceiveVideo", false, false);
+  sipcc::MediaConstraints bconstraints;
+  bconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  bconstraints.setBooleanConstraint("OfferToReceiveVideo", false, false);
+  OfferAnswer(aconstraints, bconstraints, true, false, false);
+}
+
+TEST_F(SignalingTest, OfferAnswerDontSendReceiveAudioNoAudioStream)
 {
-	CreateOfferRemoveStream("");
+  sipcc::MediaConstraints aconstraints;
+  aconstraints.setBooleanConstraint("OfferToReceiveAudio", false, false);
+  aconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  sipcc::MediaConstraints bconstraints;
+  bconstraints.setBooleanConstraint("OfferToReceiveAudio", false, false);
+  bconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  OfferAnswer(aconstraints, bconstraints, false, true, false);
+}
+
+TEST_F(SignalingTest, OfferAnswerDontReceiveAudioNoAudioStreamDontReceiveVideo)
+{
+  sipcc::MediaConstraints aconstraints;
+  aconstraints.setBooleanConstraint("OfferToReceiveAudio", false, false);
+  aconstraints.setBooleanConstraint("OfferToReceiveVideo", false, false);
+  sipcc::MediaConstraints bconstraints;
+  bconstraints.setBooleanConstraint("OfferToReceiveAudio", false, false);
+  bconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  OfferAnswer(aconstraints, bconstraints, false, true, false);
 }
 
 TEST_F(SignalingTest, CreateOfferAddCandidate)
 {
-	CreateOfferAddCandidate("", strSampleCandidate.c_str(), strSampleMid.c_str(), nSamplelevel);
+  sipcc::MediaConstraints constraints;
+  CreateOfferAddCandidate(constraints, strSampleCandidate.c_str(), strSampleMid.c_str(), nSamplelevel);
 }
 
 TEST_F(SignalingTest, OfferAnswer)
 {
-  OfferAnswer("", "");
+  sipcc::MediaConstraints constraints;
+  OfferAnswer(constraints, constraints, true, true, true);
   PR_Sleep(kDefaultTimeout * 2); // Wait for completion
 }
 
+TEST_F(SignalingTest, OfferAnswerReNegotiateOfferAnswerDontReceiveVideoNoVideoStream)
+{
+  sipcc::MediaConstraints aconstraints;
+  aconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  aconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
+  OfferAnswer(aconstraints, aconstraints, true, true, false);
+  OfferAnswer(aconstraints, aconstraints, true, true, false);
+}
+
 TEST_F(SignalingTest, OfferModifiedAnswer)
 {
-  OfferModifiedAnswer("", "");
+  sipcc::MediaConstraints constraints;
+  OfferModifiedAnswer(constraints, constraints);
   PR_Sleep(kDefaultTimeout * 2); // Wait for completion
 }
 
 TEST_F(SignalingTest, FullCall)
 {
-  OfferAnswer("", "");
+  sipcc::MediaConstraints constraints;
+  OfferAnswer(constraints, constraints, true, true, true);
+
   PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written
 
   // Check that we wrote a bunch of data
   ASSERT_GE(a1_.GetPacketsSent(0), 40);
   //ASSERT_GE(a2_.GetPacketsSent(0), 40);
   //ASSERT_GE(a1_.GetPacketsReceived(0), 40);
   ASSERT_GE(a2_.GetPacketsReceived(0), 40);
 }
 
 TEST_F(SignalingTest, FullCallTrickle)
 {
-  OfferAnswerTrickle("", "");
+  sipcc::MediaConstraints constraints;
+  OfferAnswerTrickle(constraints, constraints);
+
   PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written
 
   ASSERT_GE(a1_.GetPacketsSent(0), 40);
   ASSERT_GE(a2_.GetPacketsReceived(0), 40);
 }
 
-//TEST_F(SignalingTest, CreateOfferHints)
-//{
-//  CreateOffer("audio,video");
-//}
-
-//TEST_F(SignalingTest, CreateOfferBadHints)
-//{
-//  CreateOfferExpectError("9.uoeuhaoensthuaeugc.pdu8g");
-//}
-
-//TEST_F(SignalingTest, CreateOfferSetLocal)
-//{
-//  CreateOfferSetLocal("");
-//}
-
-//TEST_F(SignalingTest, CreateAnswerNoHints)
-//{
-//  CreateAnswer("");
-//}
 
 } // End namespace test.
 
 int main(int argc, char **argv)
 {
   test_utils.InitServices();
   NSS_NoDB_Init(NULL);
   NSS_SetDomesticPolicy();