Bug 818714: Set media enabled to FALSE unless added using addStream, r=ehugg
authorAdam Roach [:abr] <adam@nostrum.com>
Thu, 20 Dec 2012 16:05:28 -0600
changeset 125978 8667a82f1bf2fc117a86dbe3abbedcd81335c175
parent 125977 4ad96e42102e208dd49476786cb080ff38423968
child 125979 6fe65eeaa2b4c988400c28a2c4476ed4d209d636
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehugg
bugs818714
milestone20.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 818714: Set media enabled to FALSE unless added using addStream, r=ehugg
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
media/webrtc/signaling/src/sipcc/core/gsm/lsm.c
media/webrtc/signaling/test/signaling_unittests.cpp
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -503,16 +503,19 @@ PeerConnectionImpl::CreateDataChannel(co
     aType == mozilla::DataChannelConnection::PARTIAL_RELIABLE_REXMIT ? aMaxNum :
     (aType == mozilla::DataChannelConnection::PARTIAL_RELIABLE_TIMED ? aMaxTime : 0),
     nullptr, nullptr
   );
   NS_ENSURE_TRUE(dataChannel,NS_ERROR_FAILURE);
 
   CSFLogDebugS(logTag, __FUNCTION__ << ": making DOMDataChannel");
 
+  // TODO -- need something like "mCall->addStream(stream_id, 0, DATA);" so
+  // the SDP can be generated correctly
+
   return NS_NewDOMDataChannel(dataChannel.forget(), mWindow, aRetval);
 #else
   return NS_OK;
 #endif
 }
 
 void
 PeerConnectionImpl::NotifyConnection()
--- a/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
@@ -3053,29 +3053,33 @@ fsmdef_ev_createanswer (sm_event_t *even
      * for negotiation.
      */
     gsmsdp_get_offered_media_types(fcb, dcb->sdp, &has_audio, &has_video, &has_data);
 
     /*
      * The sdp member of the dcb has local and remote sdp
      * this next function fills in the local part
      */
-    cause = gsmsdp_create_local_sdp(dcb, FALSE, 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_create_answer(evCreateAnswerError, line, call_id,
             dcb->caller_id.call_instance_id, strlib_empty());
         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, TRUE, TRUE, FALSE, TRUE);
+    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());
         return (fsmdef_release(fcb, cause, FALSE));
     }
 
     cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -117,25 +117,43 @@ static const cc_media_cap_table_t *gsmsd
              GSM_ERR_MSG(GSM_L_C_F_PREFIX"media table malloc failed.\n",
                     dcb_p->line, dcb_p->call_id, fname);
              return NULL;
          }
     }
 
     *(dcb_p->media_cap_tbl) = g_media_table;
 
-    /*
-     * Turn off two default streams, this is temporary
-     * until we can handle multiple streams properly
-     */
     if (sdpmode) {
-        dcb_p->media_cap_tbl->cap[CC_AUDIO_1].enabled = TRUE;
-        dcb_p->media_cap_tbl->cap[CC_VIDEO_1].enabled = TRUE;
-        dcb_p->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_RECVONLY;
-        dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_RECVONLY;
+        /* This needs to change when we handle more than one stream
+           of each media type at a time. */
+
+        dcb_p->media_cap_tbl->cap[CC_AUDIO_1].enabled = FALSE;
+        dcb_p->media_cap_tbl->cap[CC_VIDEO_1].enabled = FALSE;
+
+        /* We initialize as RECVONLY to allow the application to
+           display incoming media streams, even if it doesn't
+           plan to send media for those streams. This will be
+           upgraded to SENDRECV when and if a stream is added. */
+
+        dcb_p->media_cap_tbl->cap[CC_AUDIO_1].support_direction =
+          SDP_DIRECTION_RECVONLY;
+
+        dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction =
+          SDP_DIRECTION_RECVONLY;
+
+        /*
+         * This really should be set to FALSE unless we have added
+         * a data channel using createDataChannel(). Right now,
+         * though, those operations are not queued (and, in fact,
+         * the W3C hasn't specified the proper behavior here anyway, so
+         * we would only be implementing speculatively) -- so we'll
+         * always offer data channels until the standard is
+         * a bit more set.
+         */
         dcb_p->media_cap_tbl->cap[CC_DATACHANNEL_1].enabled = TRUE;
     } else {
         dcb_p->media_cap_tbl->cap[CC_DATACHANNEL_1].enabled = FALSE;
 
         if ( dcb_p->video_pref == SDP_DIRECTION_INACTIVE) {
             // do not enable video
             dcb_p->media_cap_tbl->cap[CC_VIDEO_1].enabled = FALSE;
         }
--- a/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c
@@ -970,27 +970,34 @@ lsm_rx_start (lsm_lcb_t *lcb, const char
                 media->rcv_chan = TRUE; /* recevied channel is created */
                 /* save the source RX port */
                 if (media->is_multicast) {
                     media->multicast_port = open_rcv.port;
                 } else {
                     media->src_port = open_rcv.port;
                 }
 
-                /* TODO(ekr@rtfm.com): Needs changing for when we have > 2 streams */
+                /* TODO(ekr@rtfm.com): Needs changing for when we
+                   have > 2 streams. (adam@nostrum.com): For now,
+                   we know that the stream IDs are assigned in the
+                   same order as things appear in the media objects.
+                   The "level" in the media objects are indexed
+                   starting from one, while pc_stream_id is
+                   zero-indexed.  This means that the stream ID
+                   will (for now) be equal to media->level-1. */
                 if ( media->cap_index == CC_VIDEO_1 ) {
                     attrs.video.opaque = media->video;
-                    pc_stream_id = 1;
+                    pc_stream_id = media->level - 1;
                 } else {
                     attrs.audio.packetization_period = media->packetization_period;
                     attrs.audio.max_packetization_period = media->max_packetization_period;
                     attrs.audio.avt_payload_type = media->avt_payload_type;
                     attrs.audio.mixing_mode = mix_mode;
                     attrs.audio.mixing_party = mix_party;
-                    pc_stream_id = 0;
+                    pc_stream_id = media->level - 1;
                 }
                 pc_track_id = 0;
                 dcb->cur_video_avail &= ~CC_ATTRIB_CAST;
 
                 config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
                 if (dcb->peerconnection) {
                     ret_val = vcmRxStartICE(media->cap_index, group_id, media->refid,
                     media->level,
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -72,34 +72,37 @@ static const std::string strSampleMid = 
 static const unsigned short nSamplelevel = 2;
 
 enum sdpTestFlags
 {
   SHOULD_SEND_AUDIO     = (1<<0),
   SHOULD_RECV_AUDIO     = (1<<1),
   SHOULD_INACTIVE_AUDIO = (1<<2),
   SHOULD_REJECT_AUDIO   = (1<<3),
-  SHOULD_SEND_VIDEO     = (1<<4),
-  SHOULD_RECV_VIDEO     = (1<<5),
-  SHOULD_INACTIVE_VIDEO = (1<<6),
-  SHOULD_REJECT_VIDEO   = (1<<7),
-  DONT_CHECK_AUDIO      = (1<<8),
-  DONT_CHECK_VIDEO      = (1<<9),
+  SHOULD_OMIT_AUDIO     = (1<<4),
+  DONT_CHECK_AUDIO      = (1<<5),
+
+  SHOULD_SEND_VIDEO     = (1<<8),
+  SHOULD_RECV_VIDEO     = (1<<9),
+  SHOULD_INACTIVE_VIDEO = (1<<10),
+  SHOULD_REJECT_VIDEO   = (1<<11),
+  SHOULD_OMIT_VIDEO     = (1<<12),
+  DONT_CHECK_VIDEO      = (1<<13),
 
   SHOULD_SENDRECV_AUDIO = SHOULD_SEND_AUDIO | SHOULD_RECV_AUDIO,
   SHOULD_SENDRECV_VIDEO = SHOULD_SEND_VIDEO | SHOULD_RECV_VIDEO,
   SHOULD_SENDRECV_AV = SHOULD_SENDRECV_AUDIO | SHOULD_SENDRECV_VIDEO,
 
   AUDIO_FLAGS = SHOULD_SEND_AUDIO | SHOULD_RECV_AUDIO
                 | SHOULD_INACTIVE_AUDIO | SHOULD_REJECT_AUDIO
-                | DONT_CHECK_AUDIO,
+                | DONT_CHECK_AUDIO | SHOULD_OMIT_AUDIO,
 
   VIDEO_FLAGS = SHOULD_SEND_VIDEO | SHOULD_RECV_VIDEO
                 | SHOULD_INACTIVE_VIDEO | SHOULD_REJECT_VIDEO
-                | DONT_CHECK_VIDEO
+                | DONT_CHECK_VIDEO | SHOULD_OMIT_VIDEO
 };
 
 enum offerAnswerFlags
 {
   OFFER_NONE  = 0, // Sugar to make function calls clearer.
   OFFER_AUDIO = (1<<0),
   OFFER_VIDEO = (1<<1),
   // Leaving some room here for other media types
@@ -725,56 +728,73 @@ public:
 
 private:
   void SDPSanityCheck(std::string sdp, uint32_t flags, bool offer)
   {
     ASSERT_NE(sdp.find("v=0"), std::string::npos);
     ASSERT_NE(sdp.find("c=IN IP4"), std::string::npos);
     ASSERT_NE(sdp.find("a=fingerprint:sha-256"), std::string::npos);
 
-    cout << "SDPSanityCheck flags = " << std::hex << std::showbase
+    cout << "SDPSanityCheck flags for "
+         << (offer ? "offer" : "answer")
+         << " = " << std::hex << std::showbase
          << flags << std::dec
+
          << ((flags & SHOULD_SEND_AUDIO)?" SHOULD_SEND_AUDIO":"")
          << ((flags & SHOULD_RECV_AUDIO)?" SHOULD_RECV_AUDIO":"")
          << ((flags & SHOULD_INACTIVE_AUDIO)?" SHOULD_INACTIVE_AUDIO":"")
          << ((flags & SHOULD_REJECT_AUDIO)?" SHOULD_REJECT_AUDIO":"")
+         << ((flags & SHOULD_OMIT_AUDIO)?" SHOULD_OMIT_AUDIO":"")
+         << ((flags & DONT_CHECK_AUDIO)?" DONT_CHECK_AUDIO":"")
+
          << ((flags & SHOULD_SEND_VIDEO)?" SHOULD_SEND_VIDEO":"")
          << ((flags & SHOULD_RECV_VIDEO)?" SHOULD_RECV_VIDEO":"")
          << ((flags & SHOULD_INACTIVE_VIDEO)?" SHOULD_INACTIVE_VIDEO":"")
          << ((flags & SHOULD_REJECT_VIDEO)?" SHOULD_REJECT_VIDEO":"")
-         << endl;
+         << ((flags & SHOULD_OMIT_VIDEO)?" SHOULD_OMIT_VIDEO":"")
+         << ((flags & DONT_CHECK_VIDEO)?" DONT_CHECK_VIDEO":"")
 
-    if ((flags & AUDIO_FLAGS) && offer) {
-      ASSERT_NE(sdp.find("a=rtpmap:0 PCMU/8000"), std::string::npos);
-    }
+         << endl;
 
     switch(flags & AUDIO_FLAGS) {
       case 0:
             ASSERT_EQ(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos);
         break;
       case SHOULD_SEND_AUDIO:
             ASSERT_NE(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos);
             ASSERT_NE(sdp.find(" 0-15\r\na=sendonly"), std::string::npos);
+            if (offer) {
+              ASSERT_NE(sdp.find("a=rtpmap:0 PCMU/8000"), std::string::npos);
+            }
         break;
       case SHOULD_RECV_AUDIO:
             ASSERT_NE(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos);
             ASSERT_NE(sdp.find(" 0-15\r\na=recvonly"), std::string::npos);
+            if (offer) {
+              ASSERT_NE(sdp.find("a=rtpmap:0 PCMU/8000"), std::string::npos);
+            }
         break;
       case SHOULD_SENDRECV_AUDIO:
             ASSERT_NE(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos);
             ASSERT_NE(sdp.find(" 0-15\r\na=sendrecv"), std::string::npos);
+            if (offer) {
+              ASSERT_NE(sdp.find("a=rtpmap:0 PCMU/8000"), std::string::npos);
+            }
         break;
       case SHOULD_INACTIVE_AUDIO:
             ASSERT_NE(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos);
             ASSERT_NE(sdp.find(" 0-15\r\na=inactive"), std::string::npos);
         break;
       case SHOULD_REJECT_AUDIO:
             ASSERT_EQ(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos);
             ASSERT_NE(sdp.find("m=audio 0 "), std::string::npos);
         break;
+      case SHOULD_OMIT_AUDIO:
+            ASSERT_EQ(sdp.find("m=audio"), std::string::npos);
+        break;
       case DONT_CHECK_AUDIO:
         break;
       default:
             ASSERT_FALSE("Missing case in switch statement");
     }
 
     switch(flags & VIDEO_FLAGS) {
       case 0:
@@ -794,16 +814,19 @@ private:
         break;
       case SHOULD_INACTIVE_VIDEO:
             ASSERT_NE(sdp.find("a=rtpmap:120 VP8/90000\r\na=inactive"),
                       std::string::npos);
         break;
       case SHOULD_REJECT_VIDEO:
             ASSERT_NE(sdp.find("m=video 0 "), std::string::npos);
         break;
+      case SHOULD_OMIT_VIDEO:
+            ASSERT_EQ(sdp.find("m=video"), std::string::npos);
+        break;
       case DONT_CHECK_VIDEO:
         break;
       default:
             ASSERT_FALSE("Missing case in switch statement");
     }
   }
 };
 
@@ -947,26 +970,26 @@ TEST_F(SignalingTest, CreateOfferAudioVi
 }
 
 TEST_F(SignalingTest, CreateOfferNoVideoStream)
 {
   sipcc::MediaConstraints constraints;
   constraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   constraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   CreateOffer(constraints, OFFER_AUDIO,
-              SHOULD_SENDRECV_AUDIO | SHOULD_RECV_VIDEO);
+              SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO);
 }
 
 TEST_F(SignalingTest, CreateOfferNoAudioStream)
 {
   sipcc::MediaConstraints constraints;
   constraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   constraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   CreateOffer(constraints, OFFER_VIDEO,
-              SHOULD_RECV_AUDIO | SHOULD_SENDRECV_VIDEO);
+              SHOULD_OMIT_AUDIO | SHOULD_SENDRECV_VIDEO);
 }
 
 TEST_F(SignalingTest, CreateOfferDontReceiveAudio)
 {
   sipcc::MediaConstraints constraints;
   constraints.setBooleanConstraint("OfferToReceiveAudio", false, false);
   constraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   constraints.setBooleanConstraint("VoiceActivityDetection", true, true);
@@ -1073,31 +1096,31 @@ TEST_F(SignalingTest, OfferAnswerDontAdd
 {
   sipcc::MediaConstraints offerconstraints;
   offerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   offerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   sipcc::MediaConstraints answerconstraints;
   answerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   answerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   OfferAnswer(offerconstraints, answerconstraints, OFFER_VIDEO | ANSWER_AV,
-              false, SHOULD_RECV_AUDIO | SHOULD_SENDRECV_VIDEO,
-              SHOULD_SEND_AUDIO | SHOULD_SENDRECV_VIDEO);
+              false, SHOULD_OMIT_AUDIO | SHOULD_SENDRECV_VIDEO,
+              SHOULD_OMIT_AUDIO | SHOULD_SENDRECV_VIDEO);
 }
 
 TEST_F(SignalingTest, OfferAnswerDontAddVideoStreamOnOffer)
 {
   sipcc::MediaConstraints offerconstraints;
   offerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   offerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   sipcc::MediaConstraints answerconstraints;
   answerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   answerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   OfferAnswer(offerconstraints, answerconstraints, OFFER_AUDIO | ANSWER_AV,
-              false, SHOULD_SENDRECV_AUDIO | SHOULD_RECV_VIDEO,
-              SHOULD_SENDRECV_AUDIO | SHOULD_SEND_VIDEO);
+              false, SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO,
+              SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO);
 }
 
 TEST_F(SignalingTest, OfferAnswerDontAddAudioStreamOnAnswer)
 {
   sipcc::MediaConstraints offerconstraints;
   offerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   offerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   sipcc::MediaConstraints answerconstraints;
@@ -1162,17 +1185,18 @@ TEST_F(SignalingTest, OfferAnswerDontAdd
 {
   sipcc::MediaConstraints offerconstraints;
   offerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   offerconstraints.setBooleanConstraint("OfferToReceiveVideo", false, false);
   sipcc::MediaConstraints answerconstraints;
   answerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   answerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   OfferAnswer(offerconstraints, answerconstraints, OFFER_AUDIO | ANSWER_AV,
-              false, SHOULD_SENDRECV_AUDIO, SHOULD_SENDRECV_AUDIO);
+              false, SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO,
+              SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO);
 }
 
 TEST_F(SignalingTest, OfferAnswerDontReceiveAudioNoAudioStreamOnOfferDontReceiveVideoOnAnswer)
 {
   sipcc::MediaConstraints offerconstraints;
   offerconstraints.setBooleanConstraint("OfferToReceiveAudio", false, false);
   offerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   sipcc::MediaConstraints answerconstraints;
@@ -1237,26 +1261,16 @@ TEST_F(SignalingTest, OfferAnswerDontAdd
   offerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
   offerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false);
   sipcc::MediaConstraints answerconstraints;
   OfferAnswer(offerconstraints, answerconstraints, OFFER_AV | ANSWER_NONE,
               false, SHOULD_SENDRECV_AV,
               SHOULD_RECV_AUDIO | SHOULD_RECV_VIDEO);
 }
 
-TEST_F(SignalingTest, OfferModifiedAnswer)
-{
-  sipcc::MediaConstraints constraints;
-  OfferModifiedAnswer(constraints, constraints, SHOULD_SENDRECV_AV,
-                      SHOULD_SENDRECV_AV);
-  PR_Sleep(kDefaultTimeout * 2); // Wait for completion
-  a1_.CloseSendStreams();
-  a2_.CloseReceiveStreams();
-}
-
 TEST_F(SignalingTest, FullCall)
 {
   sipcc::MediaConstraints constraints;
   OfferAnswer(constraints, constraints, OFFER_AV | ANSWER_AV,
               true, SHOULD_SENDRECV_AV, SHOULD_SENDRECV_AV);
 
   PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written
 
@@ -1264,16 +1278,65 @@ TEST_F(SignalingTest, FullCall)
   a2_.CloseReceiveStreams();
   // Check that we wrote a bunch of data
   ASSERT_GE(a1_.GetPacketsSent(0), 40);
   //ASSERT_GE(a2_.GetPacketsSent(0), 40);
   //ASSERT_GE(a1_.GetPacketsReceived(0), 40);
   ASSERT_GE(a2_.GetPacketsReceived(0), 40);
 }
 
+TEST_F(SignalingTest, FullCallAudioOnly)
+{
+  sipcc::MediaConstraints constraints;
+  OfferAnswer(constraints, constraints, OFFER_AUDIO | ANSWER_AUDIO,
+              true, SHOULD_SENDRECV_AUDIO, SHOULD_SENDRECV_AUDIO);
+
+  PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written
+
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+  // Check that we wrote a bunch of data
+  ASSERT_GE(a1_.GetPacketsSent(0), 40);
+  //ASSERT_GE(a2_.GetPacketsSent(0), 40);
+  //ASSERT_GE(a1_.GetPacketsReceived(0), 40);
+  ASSERT_GE(a2_.GetPacketsReceived(0), 40);
+}
+
+TEST_F(SignalingTest, FullCallVideoOnly)
+{
+  sipcc::MediaConstraints constraints;
+  OfferAnswer(constraints, constraints, OFFER_VIDEO | ANSWER_VIDEO,
+              true, SHOULD_SENDRECV_VIDEO, SHOULD_SENDRECV_VIDEO);
+
+  PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written
+
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+
+  // FIXME -- Ideally we would check that packets were sent
+  // and received; however, the test driver setup does not
+  // currently support sending/receiving with Fake_VideoStreamSource.
+  //
+  // Check that we wrote a bunch of data
+  // ASSERT_GE(a1_.GetPacketsSent(0), 40);
+  //ASSERT_GE(a2_.GetPacketsSent(0), 40);
+  //ASSERT_GE(a1_.GetPacketsReceived(0), 40);
+  // ASSERT_GE(a2_.GetPacketsReceived(0), 40);
+}
+
+TEST_F(SignalingTest, OfferModifiedAnswer)
+{
+  sipcc::MediaConstraints constraints;
+  OfferModifiedAnswer(constraints, constraints, SHOULD_SENDRECV_AV,
+                      SHOULD_SENDRECV_AV);
+  PR_Sleep(kDefaultTimeout * 2); // Wait for completion
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+}
+
 TEST_F(SignalingTest, FullCallTrickle)
 {
   sipcc::MediaConstraints constraints;
   OfferAnswerTrickle(constraints, constraints,
                      SHOULD_SENDRECV_AV, SHOULD_SENDRECV_AV);
 
   std::cerr << "ICE handshake completed" << std::endl;
   PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written