Bug 860012 - Complete hooking up errors from gsm_sdp to PeerConnectionImpl r=ehugg
authorAdam Roach [:abr] <adam@nostrum.com>
Wed, 10 Apr 2013 12:45:01 -0500
changeset 128351 58cc5c8a4e01f389528524d15e7c5deda9dcf4d4
parent 128350 e30393f6f85b8740f643cc59a13616b6825e414a
child 128352 d1c30a97d22923761769a436aaf777a4e479f8c4
push id24528
push userryanvm@gmail.com
push dateThu, 11 Apr 2013 19:19:41 +0000
treeherdermozilla-central@7b8ed29c6bc0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehugg
bugs860012
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 860012 - Complete hooking up errors from gsm_sdp to PeerConnectionImpl r=ehugg
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_call_info.c
media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c
media/webrtc/signaling/src/sipcc/core/common/ui.c
media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
media/webrtc/signaling/src/sipcc/core/includes/sessionTypes.h
media/webrtc/signaling/src/sipcc/core/includes/uiapi.h
media/webrtc/signaling/src/sipcc/include/peer_connection_types.h
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -119,17 +119,18 @@ void MediaConstraints::buildArray(cc_med
 class PeerConnectionObserverDispatch : public nsRunnable {
 
 public:
   PeerConnectionObserverDispatch(CSF::CC_CallInfoPtr aInfo,
                                  nsRefPtr<PeerConnectionImpl> aPC,
                                  IPeerConnectionObserver* aObserver)
       : mPC(aPC),
         mObserver(aObserver),
-        mCode(static_cast<StatusCode>(aInfo->getStatusCode())),
+        mCode(static_cast<PeerConnectionImpl::Error>(aInfo->getStatusCode())),
+        mReason(aInfo->getStatus()),
         mSdpStr(),
         mCallState(aInfo->getCallState()),
         mStateStr(aInfo->callStateToString(mCallState)) {
     if (mCallState == REMOTESTREAMADD) {
       MediaStreamTable *streams = NULL;
       streams = aInfo->getMediaStreams();
       mRemoteStream = mPC->media()->GetRemoteStream(streams->media_stream_id);
       MOZ_ASSERT(mRemoteStream);
@@ -141,77 +142,84 @@ public:
 
   ~PeerConnectionObserverDispatch(){}
 
   NS_IMETHOD Run() {
 
     CSFLogInfo(logTag, "PeerConnectionObserverDispatch processing "
                        "mCallState = %d (%s)", mCallState, mStateStr.c_str());
 
+    if (mCallState == SETLOCALDESCERROR || mCallState == SETREMOTEDESCERROR) {
+      const std::vector<std::string> &errors = mPC->GetSdpParseErrors();
+      std::vector<std::string>::const_iterator i;
+      for (i = errors.begin(); i != errors.end(); ++i) {
+        mReason += " | SDP Parsing Error: " + *i;
+      }
+      if (errors.size()) {
+        mCode = PeerConnectionImpl::kInvalidSessionDescription;
+      }
+      mPC->ClearSdpParseErrorMessages();
+    }
+
+    if (mReason.length()) {
+      CSFLogInfo(logTag, "Message contains error: %d: %s",
+                 mCode, mReason.c_str());
+    }
+
     switch (mCallState) {
       case CREATEOFFER:
         mObserver->OnCreateOfferSuccess(mSdpStr.c_str());
         break;
 
       case CREATEANSWER:
         mObserver->OnCreateAnswerSuccess(mSdpStr.c_str());
         break;
 
       case CREATEOFFERERROR:
-        mObserver->OnCreateOfferError(
-          PeerConnectionImpl::kInternalError,
-          "Unspecified Error processing createOffer");
+        mObserver->OnCreateOfferError(mCode, mReason.c_str());
         break;
 
       case CREATEANSWERERROR:
-        mObserver->OnCreateAnswerError(
-          PeerConnectionImpl::kInternalError,
-          "Unspecified Error processing createAnswer");
+        mObserver->OnCreateAnswerError(mCode, mReason.c_str());
         break;
 
       case SETLOCALDESC:
         // TODO: The SDP Parse error list should be copied out and sent up
-        // to the Javascript layer before being cleared here.
+        // to the Javascript layer before being cleared here. Even though
+        // there was not a failure, it is possible that the SDP parse generated
+        // warnings. The WebRTC spec does not currently have a mechanism for
+        // providing non-fatal warnings.
         mPC->ClearSdpParseErrorMessages();
         mObserver->OnSetLocalDescriptionSuccess();
         break;
 
       case SETREMOTEDESC:
         // TODO: The SDP Parse error list should be copied out and sent up
-        // to the Javascript layer before being cleared here.
+        // to the Javascript layer before being cleared here. Even though
+        // there was not a failure, it is possible that the SDP parse generated
+        // warnings. The WebRTC spec does not currently have a mechanism for
+        // providing non-fatal warnings.
         mPC->ClearSdpParseErrorMessages();
         mObserver->OnSetRemoteDescriptionSuccess();
         break;
 
       case SETLOCALDESCERROR:
-        // TODO: The SDP Parse error list should be copied out and sent up
-        // to the Javascript layer before being cleared here.
-        mPC->ClearSdpParseErrorMessages();
-        mObserver->OnSetLocalDescriptionError(
-          PeerConnectionImpl::kInternalError,
-          "Unspecified Error processing setLocalDescription");
+        mObserver->OnSetLocalDescriptionError(mCode, mReason.c_str());
         break;
 
       case SETREMOTEDESCERROR:
-        // TODO: The SDP Parse error list should be copied out and sent up
-        // to the Javascript layer before being cleared here.
-        mPC->ClearSdpParseErrorMessages();
-        mObserver->OnSetRemoteDescriptionError(
-          PeerConnectionImpl::kInternalError,
-          "Unspecified Error processing setRemoteDescription");
+        mObserver->OnSetRemoteDescriptionError(mCode, mReason.c_str());
         break;
 
       case ADDICECANDIDATE:
         mObserver->OnAddIceCandidateSuccess();
         break;
 
       case ADDICECANDIDATEERROR:
-        mObserver->OnAddIceCandidateError(
-          PeerConnectionImpl::kInternalError,
-          "Unspecified Error processing addIceCandidate");
+        mObserver->OnAddIceCandidateError(mCode, mReason.c_str());
         break;
 
       case REMOTESTREAMADD:
         {
           DOMMediaStream* stream = nullptr;
 
           if (!mRemoteStream) {
             CSFLogError(logTag, "%s: GetRemoteStream returned NULL", __FUNCTION__);
@@ -245,17 +253,18 @@ public:
     }
 
     return NS_OK;
   }
 
 private:
   nsRefPtr<PeerConnectionImpl> mPC;
   nsCOMPtr<IPeerConnectionObserver> mObserver;
-  StatusCode mCode;
+  PeerConnectionImpl::Error mCode;
+  std::string mReason;
   std::string mSdpStr;
   cc_call_state_t mCallState;
   std::string mStateStr;
   nsRefPtr<RemoteSourceStreamInfo> mRemoteStream;
 };
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(PeerConnectionImpl, IPeerConnection)
 
@@ -1437,16 +1446,21 @@ PeerConnectionImpl::OnSdpParseError(cons
   mSDPParseErrorMessages.push_back(message);
 }
 
 void
 PeerConnectionImpl::ClearSdpParseErrorMessages() {
   mSDPParseErrorMessages.clear();
 }
 
+const std::vector<std::string> &
+PeerConnectionImpl::GetSdpParseErrors() {
+  return mSDPParseErrorMessages;
+}
+
 
 #ifdef MOZILLA_INTERNAL_API
 static nsresult
 GetStreams(JSContext* cx, PeerConnectionImpl* peerConnection,
            MediaStreamList::StreamType type, JS::Value* streams)
 {
   nsAutoPtr<MediaStreamList> list(new MediaStreamList(peerConnection, type));
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -260,16 +260,19 @@ public:
   // May be called more than once and does not necessarily mean
   // that parsing was stopped, only that something was unrecognized.
   void OnSdpParseError(const char* errorMessage);
 
   // Called when OnLocal/RemoteDescriptionSuccess/Error
   // is called to start the list over.
   void ClearSdpParseErrorMessages();
 
+  // Called to retreive the list of parsing errors.
+  const std::vector<std::string> &GetSdpParseErrors();
+
 private:
   PeerConnectionImpl(const PeerConnectionImpl&rhs);
   PeerConnectionImpl& operator=(PeerConnectionImpl);
   nsresult Initialize(IPeerConnectionObserver* aObserver,
                       nsIDOMWindow* aWindow,
                       const IceConfiguration* aConfiguration,
                       const JS::Value* aRTCConfiguration,
                       nsIThread* aThread,
--- a/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_call_info.c
+++ b/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_call_info.c
@@ -305,17 +305,17 @@ cc_int32_t CCAPI_CallInfo_getCallInstanc
  * @param handle - call handle
  * @return call status
  */
 cc_string_t CCAPI_CallInfo_getStatus(cc_callinfo_ref_t handle){
   static const char *fname="CCAPI_CallInfo_getStatus";
   session_data_t *data = (session_data_t *)handle;
   CCAPP_DEBUG(DEB_F_PREFIX"Entering\n", DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname));
 
-  if ( data != NULL){
+  if (data && data->status){
      CCAPP_DEBUG(DEB_F_PREFIX"returned %s\n", DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname), data->status);
      return data->status;
   }
 
   return strlib_empty();
 
 }
 
--- a/media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c
+++ b/media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c
@@ -1075,41 +1075,41 @@ session_data_t * getDeepCopyOfSessionDat
  * @return  ptr to session data
  *
  * @pre     None
  */
 
 void cleanSessionData(session_data_t *data)
 {
    if ( data != NULL ) {
-	strlib_free(data->clg_name);
+        strlib_free(data->clg_name);
         data->clg_name = strlib_empty();
-	strlib_free(data->clg_number);
+        strlib_free(data->clg_number);
         data->clg_number = strlib_empty();
-	strlib_free(data->alt_number);
+        strlib_free(data->alt_number);
         data->alt_number = strlib_empty();
-	strlib_free(data->cld_name);
+        strlib_free(data->cld_name);
         data->cld_name = strlib_empty();
-	strlib_free(data->cld_number);
+        strlib_free(data->cld_number);
         data->cld_number = strlib_empty();
-	strlib_free(data->orig_called_name);
+        strlib_free(data->orig_called_name);
         data->orig_called_name = strlib_empty();
-	strlib_free(data->orig_called_number);
+        strlib_free(data->orig_called_number);
         data->orig_called_number = strlib_empty();
-	strlib_free(data->last_redir_name);
+        strlib_free(data->last_redir_name);
         data->last_redir_name = strlib_empty();
-	strlib_free(data->last_redir_number);
+        strlib_free(data->last_redir_number);
         data->last_redir_number = strlib_empty();
-	strlib_free(data->plcd_name);
+        strlib_free(data->plcd_name);
         data->plcd_name = strlib_empty();
-	strlib_free(data->plcd_number);
+        strlib_free(data->plcd_number);
         data->plcd_number = strlib_empty();
-	strlib_free(data->status);
+        strlib_free(data->status);
         data->status = strlib_empty();
-	strlib_free(data->sdp);
+        strlib_free(data->sdp);
         data->sdp = strlib_empty();
         calllogger_free_call_log(&data->call_log);
     }
 }
 
 /**
  *
  * CCApp Provider check for CONNECTED calls for preservation
@@ -1456,16 +1456,18 @@ static void ccappUpdateSessionData (sess
                 /* Fall through to the next case... */
             case REMOTE_STREAM_ADD:
                 data->cause =
                     sessUpd->update.ccSessionUpd.data.state_data.cause;
                 data->media_stream_track_id = sessUpd->update.ccSessionUpd.data.
                     state_data.media_stream_track_id;
                 data->media_stream_id = sessUpd->update.ccSessionUpd.data.
                     state_data.media_stream_id;
+                data->status =
+                  sessUpd->update.ccSessionUpd.data.state_data.reason_text;
                 break;
             default:
                 break;
         }
 
         /*
          * If phone was idle, we not going to active state
          * send notification to resetmanager that we
--- a/media/webrtc/signaling/src/sipcc/core/common/ui.c
+++ b/media/webrtc/signaling/src/sipcc/core/common/ui.c
@@ -1,16 +1,17 @@
 /* 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/. */
 
 /** @file tnp_ui.c
  * API provided by Platform to the Call Control for User Interface activities
  */
 
+#include <stdarg.h>
 #include "cpr.h"
 #include "cpr_in.h"
 #include "phone.h"
 #include "time2.h"
 #include "debug.h"
 #include "phone_debug.h"
 #include "dialplan.h"
 #include "ccapi.h"
@@ -1549,153 +1550,202 @@ ui_control_feature (line_t line_id, call
  */
 static void post_message_helper(
     group_call_event_t eventId,
     call_events event,
     line_t nLine,
     callid_t nCallId,
     uint16_t call_instance_id,
     string_t sdp,
-    cc_int32_t status)
+    pc_error error,
+    const char *format,
+    va_list args)
 {
+    flex_string fs;
     session_update_t msg;
     memset( &msg, 0, sizeof(session_update_t));
 
     if (nCallId == CC_NO_CALL_ID) {
         /* no operation when no call ID */
         return;
     }
 
     msg.sessionID = createSessionId(nLine, nCallId);
 
     msg.eventID = eventId;
     msg.update.ccSessionUpd.data.state_data.state = event;
     msg.update.ccSessionUpd.data.state_data.inst = call_instance_id;
     msg.update.ccSessionUpd.data.state_data.line_id = nLine;
     msg.update.ccSessionUpd.data.state_data.sdp = sdp;
-    if (eventId == SET_LOCAL_DESC || eventId == SET_REMOTE_DESC) {
-        msg.update.ccSessionUpd.data.state_data.cause = status;
+    msg.update.ccSessionUpd.data.state_data.cause = error;
+
+    if (format) {
+      flex_string_init(&fs);
+      flex_string_vsprintf(&fs, format, args);
+      msg.update.ccSessionUpd.data.state_data.reason_text =
+        strlib_malloc(fs.buffer, -1);
+      flex_string_free(&fs);
+    } else {
+      msg.update.ccSessionUpd.data.state_data.reason_text = strlib_empty();
     }
 
-    if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
-        CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATE(%d) msg \n", __FUNCTION__, event);
+    if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t),
+                          CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+        CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATE(%d) msg \n",
+                    __FUNCTION__, event);
     }
 
     return;
 }
 
 /**
  *  Send data from createOffer to the UI, can send success with SDP string
  *  or can send error
  *
  *  @return none
  */
 void ui_create_offer(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp)
+                     uint16_t call_instance_id, string_t sdp,
+                     pc_error error, const char *format, ...)
 {
+    va_list ap;
+
     TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d attr=%d call_instance=%d\n",
-              DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
+              DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__),
+              event, call_instance_id);
+
 
-    post_message_helper(CREATE_OFFER, event, nLine, nCallID, call_instance_id, sdp, 0);
+    va_start(ap, format);
+    post_message_helper(CREATE_OFFER, event, nLine, nCallID, call_instance_id,
+                        sdp, error, format, ap);
+    va_end(ap);
 
     return;
 }
 
 /**
  *  Send data from createAnswer to the UI, can send success with SDP string
  *  or can send error
  *
  *  @return none
  */
 void ui_create_answer(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp)
+                      uint16_t call_instance_id, string_t sdp,
+                      pc_error error, const char *format, ...)
 {
+    va_list ap;
     TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n",
               DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
 
-    post_message_helper(CREATE_ANSWER, event, nLine, nCallID, call_instance_id, sdp, 0);
+    va_start(ap, format);
+    post_message_helper(CREATE_ANSWER, event, nLine, nCallID, call_instance_id,
+                        sdp, error, format, ap);
+    va_end(ap);
 
     return;
 }
 
 /**
  *  Send data from setLocalDescription to the UI
  *
  *  @return none
  */
 
 void ui_set_local_description(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp, cc_int32_t status)
+                              uint16_t call_instance_id, string_t sdp,
+                              pc_error error, const char *format, ...)
 {
+    va_list ap;
     TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n",
               DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
 
-    post_message_helper(SET_LOCAL_DESC, event, nLine, nCallID, call_instance_id, sdp, status);
+    va_start(ap, format);
+    post_message_helper(SET_LOCAL_DESC, event, nLine, nCallID, call_instance_id,
+                        sdp, error, format, ap);
+    va_end(ap);
 
     return;
 }
 
 /**
  *  Send data from setRemoteDescription to the UI
  *
  *  @return none
  */
 
-void ui_set_remote_description(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp, cc_int32_t status)
+void ui_set_remote_description(call_events event, line_t nLine,
+                               callid_t nCallID, uint16_t call_instance_id,
+                               string_t sdp, pc_error error,
+                               const char *format, ...)
 {
+    va_list ap;
     TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n",
               DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
 
-    post_message_helper(SET_REMOTE_DESC, event, nLine, nCallID, call_instance_id, sdp, status);
+    va_start(ap, format);
+    post_message_helper(SET_REMOTE_DESC, event, nLine, nCallID,
+                        call_instance_id, sdp, error, format, ap);
+    va_end(ap);
 
     return;
 }
 
 /**
  *  Let PeerConnection know about an updated local session description
  *
  *  @return none
  */
 
-void ui_update_local_description(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp)
+void ui_update_local_description(call_events event, line_t nLine,
+                                 callid_t nCallID, uint16_t call_instance_id,
+                                 string_t sdp, pc_error error,
+                                 const char *format, ...)
 {
+    va_list ap;
     TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n",
               DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__),
               event, call_instance_id);
 
-    post_message_helper(UPDATE_LOCAL_DESC, event, nLine, nCallID, call_instance_id,
-                        sdp, PC_OK);
+    va_start(ap, format);
+    post_message_helper(UPDATE_LOCAL_DESC, event, nLine, nCallID,
+                        call_instance_id, sdp, error, format, ap);
+    va_end(ap);
 
     return;
 }
 
 /**
  * Send data from addIceCandidate to the UI
  *
  * @return none
  */
 
 void ui_ice_candidate_add(call_events event, line_t nLine, callid_t nCallID,
-                 	  uint16_t call_instance_id, string_t sdp)
+                          uint16_t call_instance_id, string_t sdp,
+                          pc_error error, const char *format, ...)
 {
+    va_list ap;
     TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n",
               DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
 
-    post_message_helper(ICE_CANDIDATE_ADD, event, nLine, nCallID, call_instance_id, sdp, PC_OK);
+    va_start(ap, format);
+    post_message_helper(ICE_CANDIDATE_ADD, event, nLine, nCallID,
+                        call_instance_id, sdp, error, format, ap);
+    va_end(ap);
 }
 
 /**
  *  Send Remote Stream data to the UI
  *
  *  @return none
  */
 
-void ui_on_remote_stream_added(call_events event, line_t nLine, callid_t nCallID, uint16_t call_instance_id, cc_media_remote_track_table_t media_track)
+void ui_on_remote_stream_added(call_events event, line_t nLine,
+                               callid_t nCallID, uint16_t call_instance_id,
+                               cc_media_remote_track_table_t media_track)
 {
     session_update_t msg;
     fsmdef_dcb_t *dcb = fsmdef_get_dcb_by_call_id(nCallID);
     memset( &msg, 0, sizeof(session_update_t));
 
     if (nCallID == CC_NO_CALL_ID || dcb == NULL) {
         /* no operation when no call ID */
         return;
@@ -1708,15 +1758,16 @@ void ui_on_remote_stream_added(call_even
     msg.sessionID = createSessionId(nLine, nCallID);
 
     msg.eventID = REMOTE_STREAM_ADD;
     msg.update.ccSessionUpd.data.state_data.state = event;
     msg.update.ccSessionUpd.data.state_data.inst = call_instance_id;
     msg.update.ccSessionUpd.data.state_data.line_id = nLine;
     msg.update.ccSessionUpd.data.state_data.media_stream_track_id = media_track.track[0].media_stream_track_id;
     msg.update.ccSessionUpd.data.state_data.media_stream_id = (unsigned int)media_track.media_stream_id;
+    msg.update.ccSessionUpd.data.state_data.cause = PC_NO_ERROR;
 
     if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
         CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATE(%d) msg \n", __FUNCTION__, event);
     }
 
     return;
 }
--- a/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
@@ -2887,24 +2887,25 @@ fsmdef_ev_createoffer (sm_event_t *event
        sessions. See bug 840728. */
     if (dcb->local_sdp_complete) {
         FSM_DEBUG_SM(DEB_F_PREFIX"local SDP already created: returning "
         "prevously created SDP.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
         local_sdp = sipsdp_write_to_buf(dcb->sdp->src_sdp, &local_sdp_len);
         if (!local_sdp) {
             ui_create_offer(evCreateOfferError, line, call_id,
-                dcb->caller_id.call_instance_id, strlib_empty());
+                dcb->caller_id.call_instance_id, strlib_empty(),
+                PC_INTERNAL_ERROR, "Could not re-create local SDP for offer");
             FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
             return (fsmdef_release(fcb, cause, FALSE));
         }
 
         ui_create_offer(evCreateOffer, line, call_id,
             dcb->caller_id.call_instance_id,
-            strlib_malloc(local_sdp,-1));
+            strlib_malloc(local_sdp,-1), PC_NO_ERROR, NULL);
         free(local_sdp);
         return (SM_RC_END);
     }
 
     dcb->inbound = FALSE;
 
     if (msg->data.session.constraints) {
        gsmsdp_process_cap_constraints(dcb, msg->data.session.constraints);
@@ -2912,17 +2913,18 @@ fsmdef_ev_createoffer (sm_event_t *event
        msg->data.session.constraints = 0;
     }
 
     vcm_res = vcmGetIceParams(dcb->peerconnection, &ufrag, &ice_pwd);
     if (vcm_res) {
     	FSM_DEBUG_SM(DEB_F_PREFIX"vcmGetIceParams returned an error\n",
             DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
       ui_create_offer(evCreateOfferError, line, call_id,
-          dcb->caller_id.call_instance_id, strlib_empty());
+          dcb->caller_id.call_instance_id, strlib_empty(),
+          PC_INTERNAL_ERROR, "Failed to get ICE parameters for local SDP");
       return (fsmdef_release(fcb, cause, FALSE));
     }
 
     dcb->ice_ufrag = (char *)cpr_malloc(strlen(ufrag) + 1);
     if (!dcb->ice_ufrag)
     	return SM_RC_END;
 
     sstrncpy(dcb->ice_ufrag, ufrag, strlen(ufrag) + 1);
@@ -2943,35 +2945,39 @@ fsmdef_ev_createoffer (sm_event_t *event
     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, TRUE, TRUE, TRUE, TRUE);
     if (cause != CC_CAUSE_OK) {
         ui_create_offer(evCreateOfferError, line, call_id,
-            dcb->caller_id.call_instance_id, strlib_empty());
+            dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "Could not create local SDP for offer;"
+                " cause = %s", cc_cause_name(cause));
         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) {
         ui_create_offer(evCreateOfferError, line, call_id,
-            dcb->caller_id.call_instance_id, strlib_empty());
+            dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "Could not encode local SDP for offer;"
+                " cause = %s", cc_cause_name(cause));
         FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
         return (fsmdef_release(fcb, cause, FALSE));
     }
 
     dcb->local_sdp_complete = TRUE;
 
     /* Pass offer SDP back to UI */
     ui_create_offer(evCreateOffer, line, call_id,
         dcb->caller_id.call_instance_id,
-        strlib_malloc(msg_body.parts[0].body, -1));
+        strlib_malloc(msg_body.parts[0].body, -1), PC_NO_ERROR, NULL);
     cc_free_msg_body_parts(&msg_body);
 
     return (SM_RC_END);
 }
 
 
 /**
  * fsmdef_ev_createanswer
@@ -3022,42 +3028,44 @@ fsmdef_ev_createanswer (sm_event_t *even
        sessions. See bug 840728. */
     if (dcb->local_sdp_complete) {
         FSM_DEBUG_SM(DEB_F_PREFIX"local SDP already created: returning "
         "prevously created SDP.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
         local_sdp = sipsdp_write_to_buf(dcb->sdp->src_sdp, &local_sdp_len);
         if (!local_sdp) {
             ui_create_answer(evCreateAnswerError, line, call_id,
-                dcb->caller_id.call_instance_id, strlib_empty());
+                dcb->caller_id.call_instance_id, strlib_empty(),
+                PC_INTERNAL_ERROR, "Could not re-create local SDP for answer");
             FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
             return (fsmdef_release(fcb, cause, FALSE));
         }
 
         ui_create_answer(evCreateAnswer, line, call_id,
             dcb->caller_id.call_instance_id,
-            strlib_malloc(local_sdp,-1));
+            strlib_malloc(local_sdp,-1), PC_NO_ERROR, NULL);
         free(local_sdp);
         return (SM_RC_END);
     }
 
     dcb->inbound = TRUE;
 
     if (msg->data.session.constraints) {
        gsmsdp_process_cap_constraints(dcb, msg->data.session.constraints);
        fsmdef_free_constraints(msg->data.session.constraints);
        msg->data.session.constraints = 0;
     }
 
     vcm_res = vcmGetIceParams(dcb->peerconnection, &ufrag, &ice_pwd);
     if (vcm_res) {
     	FSM_DEBUG_SM(DEB_F_PREFIX"vcmGetIceParams returned an error\n",
             DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
-      ui_create_offer(evCreateAnswerError, line, call_id,
-          dcb->caller_id.call_instance_id, strlib_empty());
+      ui_create_answer(evCreateAnswerError, line, call_id,
+          dcb->caller_id.call_instance_id, strlib_empty(),
+          PC_INTERNAL_ERROR, "Could not get ICE parameters for answer");
       return (fsmdef_release(fcb, cause, FALSE));
     }
 
     dcb->ice_ufrag = (char *)cpr_malloc(strlen(ufrag) + 1);
     if (!dcb->ice_ufrag)
         return SM_RC_END;
 
     sstrncpy(dcb->ice_ufrag, ufrag, strlen(ufrag) + 1);
@@ -3088,51 +3096,57 @@ fsmdef_ev_createanswer (sm_event_t *even
 
     /*
      * 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);
     if (cause != CC_CAUSE_OK) {
         ui_create_answer(evCreateAnswerError, line, call_id,
-            dcb->caller_id.call_instance_id, strlib_empty());
+            dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "Could not create local SDP for answer;"
+                " cause = %s", cc_cause_name(cause));
         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
        processing an offer. The first, however, is for an initial offer and we may
        want to set that conditionally. */
     cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp,
             /* initial_offer */       TRUE,
             /* offer */               TRUE,
             /* notify_stream_added */ FALSE,
             /* create_answer */       TRUE);
 
     if (cause != CC_CAUSE_OK) {
         ui_create_answer(evCreateAnswerError, line, call_id,
-            dcb->caller_id.call_instance_id, strlib_empty());
+            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));
     }
 
     cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
     if (cause != CC_CAUSE_OK) {
         ui_create_answer(evCreateAnswerError, line, call_id,
-            dcb->caller_id.call_instance_id, strlib_empty());
+            dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "Could not encode SDP for answer; cause = %s",
+                cc_cause_name(cause));
         FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
         return (fsmdef_release(fcb, cause, FALSE));
     }
 
     dcb->local_sdp_complete = TRUE;
 
     /* Pass SDP back to UI */
     ui_create_answer(evCreateAnswer, line, call_id,
         dcb->caller_id.call_instance_id,
-        strlib_malloc(msg_body.parts[0].body, -1));
+        strlib_malloc(msg_body.parts[0].body, -1), PC_NO_ERROR, NULL);
     cc_free_msg_body_parts(&msg_body);
 
     return (SM_RC_END);
 }
 
 
 /**
  * SetLocalDescription
@@ -3155,64 +3169,71 @@ fsmdef_ev_setlocaldesc(sm_event_t *event
     uint32_t            local_sdp_len = 0;
 
     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_local_description(evSetLocalDescError, line, call_id,
             dcb->caller_id.call_instance_id, strlib_empty(),
-            PC_SETLOCALDESCERROR);
+            PC_INTERNAL_ERROR, "'sdpmode' configuration is false. This should "
+            "never ever happen. Run for your lives!");
         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;
     }
 
     if (JSEP_OFFER == action) {
         cause = gsmsdp_encode_sdp(dcb->sdp, &msg_body);
         if (cause != CC_CAUSE_OK) {
             FSM_DEBUG_SM(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_SETLOCALDESCERROR);
+                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) {
             ui_set_local_description(evSetLocalDescError, line, call_id,
-                dcb->caller_id.call_instance_id, strlib_empty(), PC_SDPCHANGED);
+                dcb->caller_id.call_instance_id, strlib_empty(),
+                PC_INVALID_STATE, "SDP changes are not supported");
             cc_free_msg_body_parts(&msg_body);
             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(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_SETLOCALDESCERROR);
+                PC_INTERNAL_ERROR, "Could not encode SDP for local description"
+                " (answer) -- did you forget to call createAnswer?"
+                " cause = %s", cc_cause_name(cause));
             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_SDPCHANGED);
+                dcb->caller_id.call_instance_id, strlib_empty(),
+                PC_INVALID_STATE, "SDP changes are not supported");
             return (SM_RC_END);
         }*/
 
         FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_CONNECTED);
 
 
         cc_call_state(dcb->call_id, dcb->line, CC_STATE_ANSWERED,
                       FSMDEF_CC_CALLER_ID);
@@ -3221,17 +3242,19 @@ fsmdef_ev_setlocaldesc(sm_event_t *event
 
         /*
          * 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(), PC_SDPCHANGED);
+                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);
         }
 
         /* 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
@@ -3251,21 +3274,23 @@ fsmdef_ev_setlocaldesc(sm_event_t *event
     /* We're done with the msg_body contents -- free them.*/
     cc_free_msg_body_parts(&msg_body);
 
     /* 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,
             dcb->caller_id.call_instance_id, strlib_empty(),
-            PC_SETLOCALDESCERROR);
+            PC_INTERNAL_ERROR, "Could not encode local SDP for local "
+            "description");
         return (SM_RC_END);
     }
     ui_set_local_description(evSetLocalDesc, line, call_id,
-        dcb->caller_id.call_instance_id, strlib_malloc(local_sdp,-1), PC_OK);
+        dcb->caller_id.call_instance_id, strlib_malloc(local_sdp,-1),
+        PC_NO_ERROR, NULL);
     free(local_sdp);
 
     return (SM_RC_END);
 }
 
 
 /**
  * SetRemoteDescription
@@ -3292,29 +3317,31 @@ fsmdef_ev_setremotedesc(sm_event_t *even
     uint32_t            remote_sdp_len = 0;
 
     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, strlib_empty(),
-            PC_SETREMOTEDESCERROR);
+            PC_INTERNAL_ERROR, "'sdpmode' configuration is false. This should "
+            "never ever happen. Run for your lives!");
         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.\n",
                      DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         ui_set_remote_description(evSetRemoteDescError, line, call_id,
             dcb->caller_id.call_instance_id, strlib_empty(),
-            PC_SETREMOTEDESCERROR);
+            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.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         return SM_RC_CLEANUP;
     }
@@ -3340,17 +3367,18 @@ fsmdef_ev_setremotedesc(sm_event_t *even
     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, strlib_empty(),
-                PC_SETREMOTEDESCERROR);
+                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.
          */
         gsmsdp_get_offered_media_types(fcb, dcb->sdp, &has_audio, &has_video, &has_data);
@@ -3358,85 +3386,90 @@ fsmdef_ev_setremotedesc(sm_event_t *even
         /*
          * 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);
         if (cause != CC_CAUSE_OK) {
             ui_set_remote_description(evSetRemoteDescError, line, call_id,
               dcb->caller_id.call_instance_id, strlib_empty(),
-              PC_SETREMOTEDESCERROR);
+              PC_INTERNAL_ERROR, "Could not create local SDP; cause = %s",
+              cc_cause_name(cause));
             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_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_SETREMOTEDESCERROR);
+              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) {
 
         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_SETREMOTEDESCERROR);
+                PC_INTERNAL_ERROR, "Could not negotiate answer SDP; cause = %s",
+                cc_cause_name(cause));
             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, strlib_empty(),
-                PC_SETREMOTEDESCERROR);
+                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);
 
         /* 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);
     }
 
     /* 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 localDescription will reflect that variation. In
+       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. */
 
     remote_sdp = sipsdp_write_to_buf(dcb->sdp->dest_sdp, &remote_sdp_len);
 
     if (!remote_sdp) {
         ui_set_remote_description(evSetRemoteDescError, line, call_id,
             dcb->caller_id.call_instance_id, strlib_empty(),
-            PC_SETREMOTEDESCERROR);
+            PC_INTERNAL_ERROR, "Could not serialize remote description;"
+            " cause = %s",  cc_cause_name(cause));
         return (SM_RC_END);
     }
 
     ui_set_remote_description(evSetRemoteDesc, line, call_id,
         dcb->caller_id.call_instance_id, strlib_malloc(remote_sdp,-1),
-        PC_OK);
+        PC_NO_ERROR, NULL);
 
     free(remote_sdp);
 
     return (SM_RC_END);
 }
 
 
 static sm_rcs_t
@@ -3598,34 +3631,38 @@ fsmdef_ev_addcandidate(sm_event_t *event
     char                *candidate = 0;
     char                candidate_tmp[CANDIDATE_SIZE];
 
     FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
     if (!dcb) {
         FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
         ui_ice_candidate_add(evAddIceCandidateError, line, call_id,
-            0, strlib_empty());
+            0, strlib_empty(), PC_INTERNAL_ERROR, "DCB has not been created.");
         return SM_RC_CLEANUP;
     }
 
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
     if (sdpmode == FALSE) {
         ui_ice_candidate_add(evAddIceCandidateError, line, call_id,
-            dcb->caller_id.call_instance_id, strlib_empty());
+            dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "'sdpmode' configuration is false. This should "
+            "never ever happen. Run for your lives!");
         return (SM_RC_END);
     }
 
     if (!dcb->sdp) {
         FSM_DEBUG_SM(DEB_F_PREFIX"dcb->sdp is NULL. Has the "
             "remote description been set yet?\n",
             DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
 
         ui_ice_candidate_add(evAddIceCandidateError, line, call_id,
-            dcb->caller_id.call_instance_id, strlib_empty());
+            dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INVALID_STATE, "Cannot add remote ICE candidates before "
+                              "setting remote SDP.");
 
         return SM_RC_END;
     }
 
     /* Perform level lookup based on mid value */
     /* comment until mid is properly updated
     cause = gsmsdp_find_level_from_mid(dcb, (const char *)msg->data.candidate.mid, &level);
     */
@@ -3660,22 +3697,25 @@ fsmdef_ev_addcandidate(sm_event_t *event
 
     /* Serialize the updated SDP and inform the PeerConnection of the
        new SDP contents. */
 
     remote_sdp = sipsdp_write_to_buf(dcb->sdp->dest_sdp, &remote_sdp_len);
 
     if (!remote_sdp) {
         ui_ice_candidate_add(evAddIceCandidateError, line, call_id,
-            dcb->caller_id.call_instance_id, strlib_empty());
+            dcb->caller_id.call_instance_id, strlib_empty(),
+            PC_INTERNAL_ERROR, "Could not serialize new SDP after adding ICE "
+            "candidate.");
         return (SM_RC_END);
     }
 
     ui_ice_candidate_add(evAddIceCandidate, line, call_id,
-        dcb->caller_id.call_instance_id, strlib_malloc(remote_sdp,-1));
+        dcb->caller_id.call_instance_id, strlib_malloc(remote_sdp,-1),
+        PC_NO_ERROR, NULL);
 
     free(remote_sdp);
     return (SM_RC_END);
 }
 
 static void
 fsmdef_check_active_feature (fsmdef_dcb_t *dcb, cc_features_t ftr_id)
 {
--- a/media/webrtc/signaling/src/sipcc/core/includes/sessionTypes.h
+++ b/media/webrtc/signaling/src/sipcc/core/includes/sessionTypes.h
@@ -51,17 +51,18 @@ typedef struct {
 } ccSession_feature_t;
 
 typedef struct {
   int          state;
   int          attr;
   int          inst;
   line_t       line_id;
   int          cause;
-  string_t 	   sdp;
+  string_t     reason_text;
+  string_t     sdp;
   unsigned int media_stream_id;
   unsigned int media_stream_track_id;
 } cc_call_state_data_t;
 /* CALL_SESSION_CREATED shall use the call_state as data*/
 
 typedef struct
 {
   string_t      cldNum;
--- a/media/webrtc/signaling/src/sipcc/core/includes/uiapi.h
+++ b/media/webrtc/signaling/src/sipcc/core/includes/uiapi.h
@@ -41,16 +41,40 @@ typedef enum {
     evSetLocalDescError = SETLOCALDESCERROR,
     evSetRemoteDescError = SETREMOTEDESCERROR,
     evOnRemoteStreamAdd = REMOTESTREAMADD,
     evAddIceCandidate = ADDICECANDIDATE,
     evAddIceCandidateError = ADDICECANDIDATEERROR,
     evMaxEvent
 } call_events;
 
+/* These values must be kept in sync with the equivalent values in:
+ *
+ *   PeerConnectionImpl.h
+ *   Peerconnection.js
+ *   nsIDOMPeerConnection.idl
+ *
+ * Yes, this is far from ideal, but there isn't an obviously cleaner
+ * way to deal with the situation within the constraints imposed on us
+ * by IDL.
+ */
+
+typedef enum {
+    PC_NO_ERROR                          = 0,
+    PC_INVALID_CONSTRAINTS_TYPE          = 1,
+    PC_INVALID_CANDIDATE_TYPE            = 2,
+    PC_INVALID_MEDIASTREAM_TRACK         = 3,
+    PC_INVALID_STATE                     = 4,
+    PC_INVALID_SESSION_DESCRIPTION       = 5,
+    PC_INCOMPATIBLE_SESSION_DESCRIPTION  = 6,
+    PC_INCOMPATIBLE_CONSTRAINTS          = 7,
+    PC_INCOMPATIBLE_MEDIA_STREAM_TRACK   = 8,
+    PC_INTERNAL_ERROR                    = 9
+} pc_error;
+
 #define MWI_STATUS_YES 1
 
 /* call operations : dialing, state change and info related */
 void ui_new_call(call_events event, line_t nLine, callid_t nCallID,
                  int call_attr, uint16_t call_instance_id, boolean dialed_digits);
 void ui_set_call_attr(line_t line_id, callid_t call_id, call_attr_t attr);
 void ui_call_info(string_t clgName, string_t clgNumber, string_t altClgNumber, boolean dispClgNumber,
                   string_t cldName, string_t cldNumber, boolean dispCldNumber,
@@ -147,28 +171,67 @@ void ui_log_status_msg(char *msg);
 
 void ui_init_ccm_conn_status(void);
 void ui_update_video_avail (line_t line, callid_t call_id, int avail);
 void ui_update_video_offered (line_t line, callid_t call_id, int dir);
 void ui_call_stop_ringer(line_t line, callid_t call_id);
 void ui_call_start_ringer(vcm_ring_mode_t ringMode, short once, line_t line, callid_t call_id);
 void ui_BLF_notification (int request_id, cc_blf_state_t blf_state, int app_id);
 void ui_update_media_interface_change(line_t line, callid_t call_id, group_call_event_t event);
-void ui_create_offer(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp);
-void ui_create_answer(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp);
-void ui_set_local_description(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp, cc_int32_t status);
-void ui_set_remote_description(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp, cc_int32_t status);
+
+/* WebRTC upcalls for PeerConnectionImpl */
+
+void ui_create_offer(call_events event,
+                     line_t nLine,
+                     callid_t nCallID,
+                     uint16_t call_instance_id,
+                     string_t sdp,
+                     pc_error error,
+                     const char *format, ...);
+
+void ui_create_answer(call_events event,
+                      line_t nLine,
+                      callid_t nCallID,
+                      uint16_t call_instance_id,
+                      string_t sdp,
+                      pc_error error,
+                      const char *format, ...);
+
+void ui_set_local_description(call_events event,
+                              line_t nLine,
+                              callid_t nCallID,
+                              uint16_t call_instance_id,
+                              string_t sdp,
+                              pc_error error,
+                              const char *format, ...);
 
-void ui_update_local_description(call_events event, line_t nLine, callid_t nCallID,
-                 	 uint16_t call_instance_id, string_t sdp);
+void ui_set_remote_description(call_events event,
+                               line_t nLine,
+                               callid_t nCallID,
+                               uint16_t call_instance_id,
+                               string_t sdp,
+                               pc_error error,
+                               const char *format, ...);
 
-void ui_ice_candidate_add(call_events event, line_t nLine, callid_t nCallID,
-                         uint16_t call_instance_id, string_t sdp);
+void ui_update_local_description(call_events event,
+                                 line_t nLine,
+                                 callid_t nCallID,
+                                 uint16_t call_instance_id,
+                                 string_t sdp,
+                                 pc_error error,
+                                 const char *format, ...);
 
-void ui_on_remote_stream_added(call_events event, line_t nLine, callid_t nCallID,
-                     uint16_t call_instance_id, cc_media_remote_track_table_t media_tracks);
+void ui_ice_candidate_add(call_events event,
+                          line_t nLine,
+                          callid_t nCallID,
+                          uint16_t call_instance_id,
+                          string_t sdp,
+                          pc_error error,
+                          const char *format, ...);
+
+void ui_on_remote_stream_added(call_events event,
+                               line_t nLine,
+                               callid_t nCallID,
+                               uint16_t call_instance_id,
+                               cc_media_remote_track_table_t media_tracks);
 
 
 #endif
--- a/media/webrtc/signaling/src/sipcc/include/peer_connection_types.h
+++ b/media/webrtc/signaling/src/sipcc/include/peer_connection_types.h
@@ -2,29 +2,16 @@
  * 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/. */
 
 #ifndef _PEER_CONNECTION_TYPES_H_
 #define _PEER_CONNECTION_TYPES_H_
 
 #define MAX_TRACKS 8
 
-enum StatusCode {
-    PC_OK = 0,
-    PC_INVALID_HINTS,
-    PC_INVALID_OFFER,
-    PC_INVALID_REMOTE_SDP,
-    PC_INVALID_LOCAL_SDP,
-    PC_NO_OBSERVER,
-    PC_SDPCHANGED,
-    PC_SETLOCALDESCERROR,
-    PC_SETREMOTEDESCERROR,
-    PC_INTERNAL_ERROR
-};
-
 typedef struct MediaTrack {
     unsigned int    media_stream_track_id;
     int             video;
 } MediaTrack;
 
 typedef struct MediaStreamTable {
     unsigned int    media_stream_id;
     unsigned int    num_tracks;