Bug 784519 - Part 1: Enforce State Transition Rules in SIPCC r=ehugg
authorAdam Roach [:abr] <adam@nostrum.com>
Tue, 07 May 2013 21:13:41 -0500
changeset 142152 9b321cd729e5b4edb7f9fcbcb20b96edd8f8dbe1
parent 142146 b980d32c366f82691e99f065b1743e535df64843
child 142153 6d5ff743bb6bfe3db8b0de28af080122256f6ac6
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehugg
bugs784519
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 784519 - Part 1: Enforce State Transition Rules in SIPCC r=ehugg
media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
media/webrtc/signaling/src/sipcc/core/gsm/h/fsm.h
--- a/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
@@ -52,42 +52,53 @@ void escalateDeescalate();
 // Minimum and maximum hold reversion timer in seconds
 #define MIN_HOLD_REVERSION_INTERVAL_TIMER 10
 #define MAX_HOLD_REVERSION_INTERVAL_TIMER 1200
 
 fsmdef_dcb_t *fsmdef_dcbs;
 
 static const char *fsmdef_state_names[] = {
     "IDLE",
+
+    /* SIP states */
     "COLLECTING_INFO",
     "CALL_SENT",
     "OUTGOING_PROCEEDING",
     "KPML_COLLECTING_INFO",
     "OUTGOING_ALERTING",
     "INCOMING_ALERTING",
     "CONNECTING",
     "JOINING",
     "CONNECTED",
     "CONNECTED MEDIA PEND",
     "RELEASING",
     "HOLD_PENDING",
     "HOLDING",
     "RESUME_PENDING",
-    "PRESERVED"
+    "PRESERVED",
+
+    /* WebRTC States */
+    "STABLE",
+    "HAVE_LOCAL_OFFER",
+    "HAVE_REMOTE_OFFER",
+    "HAVE_REMOTE_PRANSWER",
+    "HAVE_LOCAL_PRANSWER",
+    "CLOSED"
 };
 
 
 static sm_rcs_t fsmdef_ev_createoffer(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_createanswer(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_setlocaldesc(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_setremotedesc(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_setpeerconnection(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_addstream(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_removestream(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_addcandidate(sm_event_t *event);
+
 static sm_rcs_t fsmdef_ev_default(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_default_feature_ack(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_idle_setup(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_idle_feature(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_idle_offhook(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_idle_dialstring(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_onhook(sm_event_t *event);
 static sm_rcs_t fsmdef_ev_collectinginfo_release(sm_event_t *event);
@@ -179,24 +190,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_idle_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_default,
     /* CC_MSG_LINE             */ fsmdef_ev_idle_offhook,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_idle_dialstring,  // new outgoing
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
     /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_COLLECT_INFO ---------------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -209,24 +220,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_digit_begin,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_dialstring,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_CALL_SENT ------------------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_proceeding,
     /* CC_MSG_ALERTING         */ fsmdef_ev_out_alerting,
@@ -239,24 +250,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_OUTGOING_PROCEEDING --------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_out_alerting,
@@ -269,24 +280,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_KPML_COLLECT_INFO ----------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_out_alerting,
@@ -299,24 +310,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_digit_begin,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_OUTGOING_ALERTING ----------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_out_alerting,
@@ -329,24 +340,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_INCOMING_ALERTING ----------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -359,24 +370,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_inalerting_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_inalerting_offhook,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_CONNECTING ------------------------------------------------------ */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -389,24 +400,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_connected_line,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_JOINING --------------------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -419,24 +430,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_joining_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_connected_line,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_CONNECTED ------------------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -449,24 +460,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_connected_line,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_CONNECTED_MEDIA_PEND  ------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -479,24 +490,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_connected_line,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_RELEASING ------------------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -509,24 +520,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_releasing_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_connected_line,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_HOLD_PENDING ---------------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -539,24 +550,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_HOLDING --------------------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -569,24 +580,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_holding_offhook,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_holding_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_RESUME_PENDING -------------------------------------------------- */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -599,24 +610,24 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
-    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
-    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
-    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
-    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
-    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
-    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
-    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     },
 
 /* FSMDEF_S_PRESERVED  ------------------------------------------------------ */
     {
     /* CC_MSG_SETUP            */ fsmdef_ev_default,
     /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
     /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
     /* CC_MSG_ALERTING         */ fsmdef_ev_default,
@@ -629,24 +640,206 @@ static sm_function_t fsmdef_function_tab
     /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
     /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
     /* CC_MSG_LINE             */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
     /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
     /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
     /* CC_MSG_MWI              */ fsmdef_ev_default,
     /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_session_audit,
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
+    },
+
+
+/* FSMDEF_S_STABLE  --------------------------------------------------------- */
+    {
+    /* CC_MSG_SETUP            */ fsmdef_ev_default,
+    /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
+    /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
+    /* CC_MSG_ALERTING         */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED        */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED_ACK    */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE          */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE          */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE_ACK      */ fsmdef_ev_default,
+    /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
+    /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
+    /* CC_MSG_LINE             */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
+    /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
+    /* CC_MSG_MWI              */ fsmdef_ev_default,
+    /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_default,
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    },
+
+/* FSMDEF_S_HAVE_LOCAL_OFFER  ----------------------------------------------- */
+    {
+    /* CC_MSG_SETUP            */ fsmdef_ev_default,
+    /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
+    /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
+    /* CC_MSG_ALERTING         */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED        */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED_ACK    */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE          */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE          */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE_ACK      */ fsmdef_ev_default,
+    /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
+    /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
+    /* CC_MSG_LINE             */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
+    /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
+    /* CC_MSG_MWI              */ fsmdef_ev_default,
+    /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_default,
     /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
     /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
     /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
     /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
-    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default /* Reject lame-duck
+                                                       candidates */
+    },
+
+/* FSMDEF_S_HAVE_REMOTE_OFFER  ---------------------------------------------- */
+    {
+    /* CC_MSG_SETUP            */ fsmdef_ev_default,
+    /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
+    /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
+    /* CC_MSG_ALERTING         */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED        */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED_ACK    */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE          */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE          */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE_ACK      */ fsmdef_ev_default,
+    /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
+    /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
+    /* CC_MSG_LINE             */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
+    /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
+    /* CC_MSG_MWI              */ fsmdef_ev_default,
+    /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_default,
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
     /* CC_MSG_ADDSTREAM        */ fsmdef_ev_addstream,
     /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_removestream,
     /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    },
+
+/* FSMDEF_S_HAVE_REMOTE_PRANSWER  ------------------------------------------- */
+    {
+    /* CC_MSG_SETUP            */ fsmdef_ev_default,
+    /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
+    /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
+    /* CC_MSG_ALERTING         */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED        */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED_ACK    */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE          */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE          */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE_ACK      */ fsmdef_ev_default,
+    /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
+    /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
+    /* CC_MSG_LINE             */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
+    /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
+    /* CC_MSG_MWI              */ fsmdef_ev_default,
+    /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_default,
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default, /* Should not happen */
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_setremotedesc,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    },
+
+/* FSMDEF_S_HAVE_LOCAL_PRANSWER  -------------------------------------------- */
+    {
+    /* CC_MSG_SETUP            */ fsmdef_ev_default,
+    /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
+    /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
+    /* CC_MSG_ALERTING         */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED        */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED_ACK    */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE          */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE          */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE_ACK      */ fsmdef_ev_default,
+    /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
+    /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
+    /* CC_MSG_LINE             */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
+    /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
+    /* CC_MSG_MWI              */ fsmdef_ev_default,
+    /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_default,
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_createoffer,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_createanswer,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_setlocaldesc,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default, /* Should not happen */
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_addcandidate
+    },
+
+/* FSMDEF_S_CLOSED  --------------------------------------------------------- */
+    {
+    /* CC_MSG_SETUP            */ fsmdef_ev_default,
+    /* CC_MSG_SETUP_ACK        */ fsmdef_ev_default,
+    /* CC_MSG_PROCEEDING       */ fsmdef_ev_default,
+    /* CC_MSG_ALERTING         */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED        */ fsmdef_ev_default,
+    /* CC_MSG_CONNECTED_ACK    */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE          */ fsmdef_ev_default,
+    /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE          */ fsmdef_ev_default,
+    /* CC_MSG_FEATURE_ACK      */ fsmdef_ev_default,
+    /* CC_MSG_OFFHOOK          */ fsmdef_ev_default,
+    /* CC_MSG_ONHOOK           */ fsmdef_ev_onhook,
+    /* CC_MSG_LINE             */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_BEGIN      */ fsmdef_ev_default,
+    /* CC_MSG_DIGIT_END        */ fsmdef_ev_default,
+    /* CC_MSG_DIALSTRING       */ fsmdef_ev_default,
+    /* CC_MSG_MWI              */ fsmdef_ev_default,
+    /* CC_MSG_SESSION_AUDIT    */ fsmdef_ev_default,
+    /* CC_MSG_CREATEOFFER      */ fsmdef_ev_default,
+    /* CC_MSG_CREATEANSWER     */ fsmdef_ev_default,
+    /* CC_MSG_SETLOCALDESC     */ fsmdef_ev_default,
+    /* CC_MSG_SETREMOTEDESC    */ fsmdef_ev_default,
+    /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_default,
+    /* CC_MSG_ADDSTREAM        */ fsmdef_ev_default,
+    /* CC_MSG_REMOVESTREAM     */ fsmdef_ev_default,
+    /* CC_MSG_ADDCANDIDATE     */ fsmdef_ev_default
     }
 };
 
 static sm_table_t fsmdef_sm_table;
 sm_table_t *pfsmdef_sm_table = &fsmdef_sm_table;
 
 /*--------------------------------------------------------------------------
  * Global data
@@ -1756,16 +1949,17 @@ fsmdef_get_cause (boolean data_valid, cc
 sm_rcs_t
 fsmdef_release (fsm_fcb_t *fcb, cc_causes_t cause, boolean send_release)
 {
     fsmdef_dcb_t   *dcb = fcb->dcb;
     cc_state_data_t state_data;
     cc_kfact_t      kfactor;
     fsmdef_media_t *media;
     char tmp_str[STATUS_LINE_MAX_LEN];
+    int             sdpmode = 0;
 
     if (!dcb) {
       /* Already been released */
       return SM_RC_CLEANUP;
     }
 
     FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Entered. cause= %s",
 		DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, dcb->call_id, __FUNCTION__), cc_cause_name(cause));
@@ -1840,17 +2034,20 @@ fsmdef_release (fsm_fcb_t *fcb, cc_cause
          * have received a release.
          */
         if (FSM_CHK_FLAGS(dcb->msgs_sent, FSMDEF_MSG_PROCEEDING) ||
             FSM_CHK_FLAGS(dcb->msgs_rcvd, FSMDEF_MSG_RELEASE)) {
             cc_int_release_complete(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
                                     dcb->line, cause, &kfactor);
         }
 
-        fsm_change_state(fcb, __LINE__, FSMDEF_S_IDLE);
+        config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+        fsm_change_state(fcb, __LINE__,
+                         sdpmode ? FSMDEF_S_CLOSED : FSMDEF_S_IDLE);
+
         fsmdef_free_dcb(dcb);
         fsm_release(fcb, __LINE__, cause);
         /*
          * fsmdef has been released, indiate cleanup FSM chain.
          */
         return (SM_RC_CLEANUP);
     }
 }
@@ -2196,23 +2393,84 @@ fsmdef_set_ringback_delay_timer (fsmdef_
 }
 
 /*******************************************************************
  * event functions
  */
 static sm_rcs_t
 fsmdef_ev_default (sm_event_t *event)
 {
-    fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+    fsm_fcb_t    *fcb = (fsm_fcb_t *) event->data;
+    fsmdef_dcb_t *dcb = fcb->dcb;
+    cc_feature_t *msg = (cc_feature_t *) event->msg;
 
     FSM_DEBUG_SM("%s", get_debug_string(FSM_DBG_SM_DEFAULT_EVENT));
-    if (fcb->dcb) {
-        cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
-                      NULL);
-    }
+
+    if (!dcb) {
+      return (SM_RC_END);
+    }
+
+    /*
+     * For WebRTC events, we must send back a message to enable the
+     * corresponding error callback to be called. Arguably, these
+     * should always be caught by the PeerConnection and thrown as exceptions,
+     * but this enusres that the behavior is water-tight.
+     */
+    switch (event->event) {
+      case CC_MSG_CREATEOFFER:
+          ui_create_offer(evCreateOfferError, msg->line, msg->call_id,
+              dcb->caller_id.call_instance_id, strlib_empty(),
+              PC_INVALID_STATE, "Cannot create offer in state %s",
+              fsmdef_state_name(event->state));
+        break;
+
+      case CC_MSG_CREATEANSWER:
+          ui_create_answer(evCreateAnswerError, msg->line, msg->call_id,
+              dcb->caller_id.call_instance_id, strlib_empty(),
+              PC_INVALID_STATE, "Cannot create answer in state %s",
+              fsmdef_state_name(event->state));
+        break;
+
+      case CC_MSG_SETLOCALDESC:
+          ui_set_local_description(evSetLocalDescError, msg->line,
+              msg->call_id, dcb->caller_id.call_instance_id, strlib_empty(),
+              PC_INVALID_STATE, "Cannot set local description in state %s",
+              fsmdef_state_name(event->state));
+        break;
+
+      case CC_MSG_SETREMOTEDESC:
+          ui_set_remote_description(evSetRemoteDescError, msg->line,
+              msg->call_id, dcb->caller_id.call_instance_id, strlib_empty(),
+              PC_INVALID_STATE, "Cannot set remote description in state %s",
+              fsmdef_state_name(event->state));
+        break;
+
+      case CC_MSG_ADDCANDIDATE:
+          ui_ice_candidate_add(evAddIceCandidateError, msg->line, msg->call_id,
+              dcb->caller_id.call_instance_id, strlib_empty(),
+              PC_INVALID_STATE, "Cannot add ICE candidate in state %s",
+              fsmdef_state_name(event->state));
+        break;
+
+      case CC_MSG_ADDSTREAM:
+      case CC_MSG_REMOVESTREAM:
+          /* This shouldn't happen, since PeerConnection should check
+           * the state before sending these events to us. The debug message
+           * here is to catch the unexpected situation of such an event
+           * getting through anyway. */
+          FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Cannot add or remove streams "
+              "in state %s", DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line,
+              msg->call_id, __FUNCTION__), fsmdef_state_name(event->state));
+        break;
+
+      default:
+          cc_call_state(dcb->call_id, dcb->line, CC_STATE_UNKNOWN, NULL);
+        break;
+    }
+
     return (SM_RC_END);
 }
 
 /*
  * Default event handler for feature_ack event
  */
 static sm_rcs_t
 fsmdef_ev_default_feature_ack (sm_event_t *event)
@@ -3014,17 +3272,18 @@ fsmdef_ev_createanswer (sm_event_t *even
     FSM_DEBUG_SM(DEB_F_PREFIX"Entered.", 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.", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+        FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.",
+            DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         return SM_RC_CLEANUP;
     }
 
     /* For now, if the local SDP has been set, we don't allow it to be set
        again. This will change when we allow renegotiation of ongoing
        sessions. See bug 840728. */
     if (dcb->local_sdp_complete) {
         FSM_DEBUG_SM(DEB_F_PREFIX"local SDP already created: returning "
@@ -3146,105 +3405,95 @@ fsmdef_ev_createanswer (sm_event_t *even
 
     return (SM_RC_END);
 }
 
 
 /**
  * SetLocalDescription
  *
+ * Because the PeerConnection relies on receiving either a success or
+ * an error callback, there must be no paths that return from this
+ * function without first calling ui_set_local_description.
  */
 static sm_rcs_t
 fsmdef_ev_setlocaldesc(sm_event_t *event) {
     fsm_fcb_t           *fcb = (fsm_fcb_t *) event->data;
     fsmdef_dcb_t        *dcb = fcb->dcb;
     cc_feature_t        *msg = (cc_feature_t *) event->msg;
     cc_causes_t         cause = CC_CAUSE_NORMAL;
-    cc_msgbody_info_t   msg_body;
     int                 action = msg->action;
     string_t            sdp = msg->sdp;
     int                 sdpmode = 0;
     callid_t            call_id = msg->call_id;
     line_t              line = msg->line;
     cc_causes_t         lsm_rc;
     char                *local_sdp = NULL;
     uint32_t            local_sdp_len = 0;
 
     FSM_DEBUG_SM(DEB_F_PREFIX"Entered.", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
+    if (dcb == NULL) {
+        FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.",
+          DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+        ui_set_local_description(evSetLocalDescError, line, call_id,
+            0, strlib_empty(),
+            PC_INTERNAL_ERROR, "Unrecoverable error: dcb is NULL.");
+        fsm_change_state(fcb, __LINE__, FSMDEF_S_CLOSED);
+        return (SM_RC_CLEANUP);
+    }
+
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
     if (!sdpmode) {
         ui_set_local_description(evSetLocalDescError, line, call_id,
             dcb->caller_id.call_instance_id, strlib_empty(),
             PC_INTERNAL_ERROR, "'sdpmode' configuration is false. This should "
             "never ever happen. Run for your lives!");
+        fsm_change_state(fcb, __LINE__, FSMDEF_S_CLOSED);
         return (SM_RC_END);
     }
 
-    if (dcb == NULL) {
-        FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
-        return SM_RC_CLEANUP;
-    }
-
-    if (JSEP_OFFER == action) {
-        cause = gsmsdp_encode_sdp(dcb->sdp, &msg_body);
-        if (cause != CC_CAUSE_OK) {
-            FSM_DEBUG_SM("%s", get_debug_string(FSM_DBG_SDP_BUILD_ERR));
-            ui_set_local_description(evSetLocalDescError, line, call_id,
-                dcb->caller_id.call_instance_id, strlib_empty(),
-                PC_INTERNAL_ERROR, "Could not encode SDP for local description"
-                " (offer) -- did you forget to call createOffer?"
-                " cause = %s", cc_cause_name(cause));
-            return (SM_RC_END);
-        }
-
-        /* compare and fail if different:
-         * anant: Why? The JS should be able to modify the SDP. Commenting out for now (same for answer)
-        if (strcmp(msg_body.parts[0].body, sdp) != 0) {
+    if (!dcb->sdp) {
+        ui_set_local_description(evSetLocalDescError, line, call_id,
+           dcb->caller_id.call_instance_id, strlib_empty(),
+           PC_INTERNAL_ERROR, "Setting of local SDP before calling "
+           "createOffer or createAnswer is not currently supported.");
+        return (SM_RC_END);
+    }
+
+    switch (action) {
+
+    case JSEP_OFFER:
+        if (event->state != FSMDEF_S_STABLE &&
+            event->state != FSMDEF_S_HAVE_LOCAL_OFFER) {
             ui_set_local_description(evSetLocalDescError, line, call_id,
                 dcb->caller_id.call_instance_id, strlib_empty(),
-                PC_INVALID_STATE, "SDP changes are not supported");
-            cc_free_msg_body_parts(&msg_body);
+                PC_INVALID_STATE, "Cannot set local offer in state %s",
+                fsmdef_state_name(event->state));
             return (SM_RC_END);
         }
-        */
-
-        fsm_change_state(fcb, __LINE__, FSMDEF_S_CALL_SENT);
-
-    } else if (JSEP_ANSWER == action) {
-
-        /* compare SDP generated from CreateAnswer */
-        cause = gsmsdp_encode_sdp(dcb->sdp, &msg_body);
-        if (cause != CC_CAUSE_OK) {
-            FSM_DEBUG_SM("%s", get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+        /* TODO: Parse incoming SDP and act on it. */
+        fsm_change_state(fcb, __LINE__, FSMDEF_S_HAVE_LOCAL_OFFER);
+        break;
+
+    case JSEP_ANSWER:
+        if (event->state != FSMDEF_S_HAVE_REMOTE_OFFER &&
+            event->state != FSMDEF_S_HAVE_LOCAL_PRANSWER) {
             ui_set_local_description(evSetLocalDescError, line, call_id,
                 dcb->caller_id.call_instance_id, strlib_empty(),
-                PC_INTERNAL_ERROR, "Could not encode SDP for local description"
-                " (answer) -- did you forget to call createAnswer?"
-                " cause = %s", cc_cause_name(cause));
+                PC_INVALID_STATE, "Cannot set local answer in state %s",
+                fsmdef_state_name(event->state));
             return (SM_RC_END);
         }
-
-        /* compare and fail if different
-        if (strcmp(msg_body.parts[0].body, sdp) != 0) {
-            cc_free_msg_body_parts(&msg_body);
-            ui_set_local_description(evSetLocalDescError, line, call_id,
-                dcb->caller_id.call_instance_id, strlib_empty(),
-                PC_INVALID_STATE, "SDP changes are not supported");
-            return (SM_RC_END);
-        }*/
-
+        /* TODO: Parse incoming SDP and act on it. */
         FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_CONNECTED);
 
-
         cc_call_state(dcb->call_id, dcb->line, CC_STATE_ANSWERED,
                       FSMDEF_CC_CALLER_ID);
 
-        fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTING);
-
         /*
          * 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_local_description(evSetLocalDescError, line, call_id,
                 dcb->caller_id.call_instance_id, strlib_empty(),
@@ -3255,51 +3504,76 @@ fsmdef_ev_setlocaldesc(sm_event_t *event
 
         /* taken from fsmdef_ev_connected_ack start rx and tx  */
         cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
                   FSMDEF_CC_CALLER_ID);
         /*
          * If DSP is not able to start rx/tx channels, release the call
          */
         if (dcb->dsp_out_of_resources == TRUE) {
-            cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN, NULL);
+            cc_call_state(fcb->dcb->call_id, fcb->dcb->line,
+                CC_STATE_UNKNOWN, NULL);
+            ui_set_local_description(evSetLocalDescError, line, call_id,
+                dcb->caller_id.call_instance_id, strlib_empty(),
+                PC_INTERNAL_ERROR, "Cannot start media channels; cause = %s",
+                cc_cause_name(cause));
             return (SM_RC_END);
         }
-
         /* we may want to use the functionality in the following method
          *  to handle media capability changes, needs discussion
          * fsmdef_transition_to_connected(fcb);
          */
-        fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTED);
-
-    }
-    /* We're done with the msg_body contents -- free them.*/
-    cc_free_msg_body_parts(&msg_body);
+        fsm_change_state(fcb, __LINE__, FSMDEF_S_STABLE);
+        break;
+
+    case JSEP_PRANSWER:
+        if (event->state != FSMDEF_S_HAVE_REMOTE_OFFER &&
+            event->state != FSMDEF_S_HAVE_LOCAL_PRANSWER) {
+            ui_set_local_description(evSetLocalDescError, line, call_id,
+                dcb->caller_id.call_instance_id, strlib_empty(),
+                PC_INVALID_STATE, "Cannot set local pranswer in state %s",
+                fsmdef_state_name(event->state));
+            return (SM_RC_END);
+        }
+        ui_set_local_description(evSetLocalDescError, msg->line,
+            msg->call_id, dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "Provisional answers are not yet supported");
+        return (SM_RC_END);
+
+    default:
+        ui_set_local_description(evSetLocalDescError, msg->line,
+            msg->call_id, dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "Unknown session description type: %d",action);
+        return (SM_RC_END);
+    }
 
     /* Encode the current local SDP structure into a char buffer */
     local_sdp = sipsdp_write_to_buf(dcb->sdp->src_sdp, &local_sdp_len);
     if (!local_sdp) {
-        ui_set_local_description(evSetLocalDescError, line, call_id,
+        ui_set_local_description(evSetLocalDescError, msg->line, msg->call_id,
             dcb->caller_id.call_instance_id, strlib_empty(),
             PC_INTERNAL_ERROR, "Could not encode local SDP for local "
             "description");
         return (SM_RC_END);
     }
-    ui_set_local_description(evSetLocalDesc, line, call_id,
+
+    ui_set_local_description(evSetLocalDesc, msg->line, msg->call_id,
         dcb->caller_id.call_instance_id, strlib_malloc(local_sdp,-1),
         PC_NO_ERROR, NULL);
+
     free(local_sdp);
-
     return (SM_RC_END);
 }
 
-
 /**
  * SetRemoteDescription
  *
+ * Because the PeerConnection relies on receiving either a success or
+ * an error callback, there must be no paths that return from this
+ * function without first calling ui_set_remote_description.
  */
 static sm_rcs_t
 fsmdef_ev_setremotedesc(sm_event_t *event) {
     fsm_fcb_t           *fcb = (fsm_fcb_t *) event->data;
     fsmdef_dcb_t        *dcb = fcb->dcb;
     cc_feature_t        *msg = (cc_feature_t *) event->msg;
     cc_causes_t         cause = CC_CAUSE_NORMAL;
     int                 action = msg->action;
@@ -3313,44 +3587,49 @@ fsmdef_ev_setremotedesc(sm_event_t *even
     boolean             has_audio;
     boolean             has_video;
     boolean             has_data;
     char                *remote_sdp = 0;
     uint32_t            remote_sdp_len = 0;
 
     FSM_DEBUG_SM(DEB_F_PREFIX"Entered.", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
+    if (dcb == NULL) {
+        FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.",
+          DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+        ui_set_remote_description(evSetRemoteDescError, line, call_id,
+            0, strlib_empty(),
+            PC_INTERNAL_ERROR, "Unrecoverable error: dcb is NULL.");
+        fsm_change_state(fcb, __LINE__, FSMDEF_S_CLOSED);
+        return (SM_RC_CLEANUP);
+    }
+
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
     if (!sdpmode) {
         ui_set_remote_description(evSetRemoteDescError, line, call_id,
             dcb->caller_id.call_instance_id, strlib_empty(),
             PC_INTERNAL_ERROR, "'sdpmode' configuration is false. This should "
             "never ever happen. Run for your lives!");
+        fsm_change_state(fcb, __LINE__, FSMDEF_S_CLOSED);
         return (SM_RC_END);
     }
 
     // XXX We don't currently support renegotiation. If the remote SDP
     // has already been set, return an error to the application. This is
     // temporary until Bug 840728 is implemented.
     if (dcb->sdp && dcb->sdp->dest_sdp) {
         FSM_DEBUG_SM(DEB_F_PREFIX"Renegotiation not currently supported.",
                      DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         ui_set_remote_description(evSetRemoteDescError, line, call_id,
             dcb->caller_id.call_instance_id, strlib_empty(),
             PC_INVALID_STATE, "Renegotiation of session description is not "
             "currently supported. See Bug 840728 for status.");
         return (SM_RC_END);
     }
 
-
-    if (dcb == NULL) {
-        FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
-        return SM_RC_CLEANUP;
-    }
-
     cc_initialize_msg_body_parts_info(&msg_body);
 
     /* !!! NOTE !!! The following code sets up the pointers inside
        msg_body.parts[0] to point directly to the buffers from the
        event->msg structure. While this is more efficient than
        copying them, we must take exceptional care not to call
        cc_free_msg_body_parts() on this particular msg_body, since
        doing so would result in the buffers being freed twice. */
@@ -3361,63 +3640,82 @@ fsmdef_ev_setremotedesc(sm_event_t *even
     body_length = strlen(msg->sdp);
     part->body = msg->sdp;
     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) {
-
+    switch (action) {
+    case JSEP_OFFER:
+        if (event->state != FSMDEF_S_STABLE &&
+            event->state != FSMDEF_S_HAVE_REMOTE_OFFER) {
+            ui_set_remote_description(evSetRemoteDescError, line, call_id,
+                dcb->caller_id.call_instance_id, strlib_empty(),
+                PC_INVALID_STATE, "Cannot set remote offer in state %s",
+                fsmdef_state_name(event->state));
+            return (SM_RC_END);
+        }
         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, strlib_empty(),
-                PC_INTERNAL_ERROR, "Could not process offer SDP; cause = %s",
-                cc_cause_name(cause));
+                PC_INTERNAL_ERROR, "Could not process offer SDP; "
+                "cause = %s", cc_cause_name(cause));
             return (SM_RC_END);
         }
 
         /*
-         * Determine what media types are offered, used to create matching local SDP
-         * for negotiation.
+         * 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);
+        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, has_audio, has_video, has_data, FALSE);
+        cause = gsmsdp_create_local_sdp(dcb, TRUE, has_audio, has_video,
+            has_data, FALSE);
         if (cause != CC_CAUSE_OK) {
             ui_set_remote_description(evSetRemoteDescError, line, call_id,
               dcb->caller_id.call_instance_id, strlib_empty(),
               PC_INTERNAL_ERROR, "Could not create local SDP; cause = %s",
               cc_cause_name(cause));
             FSM_DEBUG_SM("%s", get_debug_string(FSM_DBG_SDP_BUILD_ERR));
             // Force clean up call without sending release
             return (fsmdef_release(fcb, cause, FALSE));
         }
 
-        cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp, TRUE, TRUE, TRUE, FALSE);
+        cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp,
+            TRUE, TRUE, TRUE, FALSE);
         if (cause != CC_CAUSE_OK) {
             ui_set_remote_description(evSetRemoteDescError, line, call_id,
               dcb->caller_id.call_instance_id, strlib_empty(),
               PC_INTERNAL_ERROR, "Could not negotiate media lines; cause = %s",
               cc_cause_name(cause));
             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) {
-
+        fsm_change_state(fcb, __LINE__, FSMDEF_S_HAVE_REMOTE_OFFER);
+        break;
+
+    case JSEP_ANSWER:
+        if (event->state != FSMDEF_S_HAVE_LOCAL_OFFER &&
+            event->state != FSMDEF_S_HAVE_REMOTE_PRANSWER) {
+            ui_set_remote_description(evSetRemoteDescError, line, call_id,
+                dcb->caller_id.call_instance_id, strlib_empty(),
+                PC_INVALID_STATE, "Cannot set remote answer in state %s",
+                fsmdef_state_name(event->state));
+            return (SM_RC_END);
+        }
         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, strlib_empty(),
                 PC_INTERNAL_ERROR, "Could not negotiate answer SDP; cause = %s",
                 cc_cause_name(cause));
             return (SM_RC_END);
         }
@@ -3430,25 +3728,46 @@ fsmdef_ev_setremotedesc(sm_event_t *even
         if (cause != CC_CAUSE_OK) {
             ui_set_remote_description(evSetRemoteDescError, line, call_id,
                 dcb->caller_id.call_instance_id, strlib_empty(),
                 PC_INTERNAL_ERROR, "Could not configure local ICE state"
                 " from SDP; cause = %s", cc_cause_name(cause));
             return (SM_RC_END);
         }
 
-        cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED, FSMDEF_CC_CALLER_ID);
+        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);
-         * fsmdef_transition_to_connected(fcb);
          */
 
-        fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTED);
+        fsm_change_state(fcb, __LINE__, FSMDEF_S_STABLE);
+        break;
+
+    case JSEP_PRANSWER:
+        if (event->state != FSMDEF_S_HAVE_LOCAL_OFFER &&
+            event->state != FSMDEF_S_HAVE_REMOTE_PRANSWER) {
+            ui_set_remote_description(evSetRemoteDescError, line, call_id,
+                dcb->caller_id.call_instance_id, strlib_empty(),
+                PC_INVALID_STATE, "Cannot set remote pranswer in state %s",
+                fsmdef_state_name(event->state));
+            return (SM_RC_END);
+        }
+        ui_set_local_description(evSetLocalDescError, msg->line,
+            msg->call_id, dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "Provisional answers are not yet supported");
+        return (SM_RC_END);
+
+    default:
+        ui_set_local_description(evSetLocalDescError, msg->line,
+            msg->call_id, dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "Unknown session description type: %d",action);
+        return (SM_RC_END);
     }
 
     /* For the sake of accuracy, we regenerate the SDP text from our parsed
        version: if we have any local variation in how we've interpreted the
        received SDP, then remoteDescription will reflect that variation. In
        practice, this shouldn't happen; but, if it does, at least this will
        allow the WebRTC application to figure out what's going on. */
 
@@ -3481,16 +3800,18 @@ fsmdef_ev_setpeerconnection(sm_event_t *
     callid_t            call_id = msg->call_id;
     int                 sdpmode = 0;
     line_t              line = msg->line;
     cc_causes_t         lsm_rc;
 
     FSM_DEBUG_SM(DEB_F_PREFIX"Entered.", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
     if (!sdpmode) {
+        FSM_DEBUG_SM(DEB_F_PREFIX"sdpmode is false; cannot set peerconnection.",
+            DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         return (SM_RC_END);
     }
 
     if (!msg)
       return SM_RC_END;
 
     if (!msg->data_valid)
       return SM_RC_END;
@@ -3498,29 +3819,34 @@ fsmdef_ev_setpeerconnection(sm_event_t *
     if (dcb == NULL) {
       dcb = fsmdef_get_new_dcb(call_id);
       if (dcb == NULL) {
         return SM_RC_ERROR;
       }
 
       lsm_rc = lsm_get_facility_by_line(call_id, line, FALSE, dcb);
       if (lsm_rc != CC_CAUSE_OK) {
-          FSM_DEBUG_SM(DEB_F_PREFIX"lsm_get_facility_by_line failed.", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+          FSM_DEBUG_SM(DEB_F_PREFIX"lsm_get_facility_by_line failed.",
+              DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
           return SM_RC_END;
       }
 
       fsmdef_init_dcb(dcb, call_id, FSMDEF_CALL_TYPE_NONE, NULL, line, fcb);
 
       fsm_set_fcb_dcbs(dcb);
     }
 
     PR_ASSERT(strlen(msg->data.pc.pc_handle) < PC_HANDLE_SIZE);
-    sstrncpy(dcb->peerconnection, msg->data.pc.pc_handle, sizeof(dcb->peerconnection));
+    sstrncpy(dcb->peerconnection, msg->data.pc.pc_handle,
+        sizeof(dcb->peerconnection));
     dcb->peerconnection_set = TRUE;
 
+    /* WebRTC connections always start in state "STABLE". */
+    fsm_change_state(fcb, __LINE__, FSMDEF_S_STABLE);
+
     return (SM_RC_END);
 }
 
 
 static sm_rcs_t
 fsmdef_ev_addstream(sm_event_t *event) {
     fsm_fcb_t           *fcb = (fsm_fcb_t *) event->data;
     fsmdef_dcb_t        *dcb = fcb->dcb;
@@ -3607,17 +3933,17 @@ fsmdef_ev_removestream(sm_event_t *event
         dcb->video_pref = SDP_DIRECTION_SENDRECV;
     } else if (msg->data.track.media_type == VIDEO) {
         PR_ASSERT(dcb->media_cap_tbl->cap[CC_VIDEO_1].enabled);
         dcb->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_RECVONLY;
     } else {
         return (SM_RC_END);
     }
 
-	return (SM_RC_END);
+    return (SM_RC_END);
 }
 
 static sm_rcs_t
 fsmdef_ev_addcandidate(sm_event_t *event) {
     fsm_fcb_t           *fcb = (fsm_fcb_t *) event->data;
     fsmdef_dcb_t        *dcb = fcb->dcb;
     cc_causes_t         cause = CC_CAUSE_NORMAL;
     cc_feature_t        *msg = (cc_feature_t *) event->msg;
@@ -6133,21 +6459,21 @@ fsmdef_ev_onhook (sm_event_t *event)
     if (dcb->onhook_received) {
         dcb->onhook_received = FALSE;
         return SM_RC_END;
     }
 
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
 
     if (sdpmode) {
-    	if(dcb->ice_ufrag)
-    		cpr_free(dcb->ice_ufrag);
-
-    	if(dcb->ice_pwd)
-    		cpr_free(dcb->ice_pwd);
+        if(dcb->ice_ufrag)
+          cpr_free(dcb->ice_ufrag);
+
+        if(dcb->ice_pwd)
+          cpr_free(dcb->ice_pwd);
     }
 
     /*
      * If the user presses the ENDCALL softkey for an
      * incoming call set the release cause to Busy.
      */
     if (fcb->state == FSMDEF_S_INCOMING_ALERTING) {
         sm_rc = fsmdef_release(fcb, CC_CAUSE_BUSY, dcb->send_release);
--- a/media/webrtc/signaling/src/sipcc/core/gsm/h/fsm.h
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/h/fsm.h
@@ -62,32 +62,44 @@ typedef enum {
     FSMDEF_CALL_TYPE_INCOMING = CC_CALL_TYPE_INCOMING,
     FSMDEF_CALL_TYPE_OUTGOING = CC_CALL_TYPE_OUTGOING,
     FSMDEF_CALL_TYPE_FORWARD = CC_CALL_TYPE_FORWARDED,
     FSMDEF_CALL_TYPE_MAX
 } fsmdef_call_types_t;
 
 typedef enum {
     FSMDEF_S_MIN = -1,
+
     FSMDEF_S_IDLE,
+
+    /* SIP States */
     FSMDEF_S_COLLECT_INFO,
     FSMDEF_S_CALL_SENT,
     FSMDEF_S_OUTGOING_PROCEEDING,
     FSMDEF_S_KPML_COLLECT_INFO,
     FSMDEF_S_OUTGOING_ALERTING,
     FSMDEF_S_INCOMING_ALERTING,
     FSMDEF_S_CONNECTING,
     FSMDEF_S_JOINING,
     FSMDEF_S_CONNECTED,
     FSMDEF_S_CONNECTED_MEDIA_PEND,
     FSMDEF_S_RELEASING,
     FSMDEF_S_HOLD_PENDING,
     FSMDEF_S_HOLDING,
     FSMDEF_S_RESUME_PENDING,
     FSMDEF_S_PRESERVED,
+
+    /* WebRTC States */
+    FSMDEF_S_STABLE,
+    FSMDEF_S_HAVE_LOCAL_OFFER,
+    FSMDEF_S_HAVE_REMOTE_OFFER,
+    FSMDEF_S_HAVE_REMOTE_PRANSWER,
+    FSMDEF_S_HAVE_LOCAL_PRANSWER,
+    FSMDEF_S_CLOSED,
+
     FSMDEF_S_MAX
 } fsmdef_states_t;
 
 typedef enum {
     FSMDEF_MRTONE_NO_ACTION = 0,
     FSMDEF_MRTONE_PLAYED_MONITOR_TONE,
     FSMDEF_MRTONE_PLAYED_RECORDER_TONE,
     FSMDEF_MRTONE_PLAYED_BOTH_TONES,