Fix broken CVO header extension

Adds end to end unit tests for CVO.

BUG=webrtc:5621

Review URL: https://codereview.webrtc.org/1811373002

Cr-Commit-Position: refs/heads/master@{#12063}
diff --git a/webrtc/api/peerconnection_unittest.cc b/webrtc/api/peerconnection_unittest.cc
index fbaeaff..ae37069 100644
--- a/webrtc/api/peerconnection_unittest.cc
+++ b/webrtc/api/peerconnection_unittest.cc
@@ -387,6 +387,8 @@
 
   void RemoveBundleFromReceivedSdp(bool remove) { remove_bundle_ = remove; }
 
+  void RemoveCvoFromReceivedSdp(bool remove) { remove_cvo_ = remove; }
+
   bool can_receive_audio() {
     bool value;
     if (prefer_constraint_apis_) {
@@ -452,12 +454,19 @@
 
     cricket::FakeVideoCapturer* fake_capturer =
         new webrtc::FakePeriodicVideoCapturer();
+    fake_capturer->SetRotation(capture_rotation_);
     video_capturers_.push_back(fake_capturer);
     rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source =
         peer_connection_factory_->CreateVideoSource(fake_capturer,
                                                     &source_constraints);
     std::string label = stream_label + kVideoTrackLabelBase;
-    return peer_connection_factory_->CreateVideoTrack(label, source);
+
+    rtc::scoped_refptr<webrtc::VideoTrackInterface> track(
+        peer_connection_factory_->CreateVideoTrack(label, source));
+    if (!local_video_renderer_) {
+      local_video_renderer_.reset(new webrtc::FakeVideoTrackRenderer(track));
+    }
+    return track;
   }
 
   DataChannelInterface* data_channel() { return data_channel_; }
@@ -468,13 +477,16 @@
   webrtc::PeerConnectionInterface* pc() const { return peer_connection_.get(); }
 
   void StopVideoCapturers() {
-    for (std::vector<cricket::VideoCapturer*>::iterator it =
-             video_capturers_.begin();
-         it != video_capturers_.end(); ++it) {
-      (*it)->Stop();
+    for (auto* capturer : video_capturers_) {
+      capturer->Stop();
     }
   }
 
+  void SetCaptureRotation(webrtc::VideoRotation rotation) {
+    ASSERT_TRUE(video_capturers_.empty());
+    capture_rotation_ = rotation;
+  }
+
   bool AudioFramesReceivedCheck(int number_of_frames) const {
     return number_of_frames <= fake_audio_capture_module_->frames_received();
   }
@@ -705,6 +717,21 @@
         fake_video_renderers_.begin()->second->height();
   }
 
+  webrtc::VideoRotation rendered_rotation() {
+    EXPECT_FALSE(fake_video_renderers_.empty());
+    return fake_video_renderers_.empty()
+               ? webrtc::kVideoRotation_0
+               : fake_video_renderers_.begin()->second->rotation();
+  }
+
+  int local_rendered_width() {
+    return local_video_renderer_ ? local_video_renderer_->width() : 1;
+  }
+
+  int local_rendered_height() {
+    return local_video_renderer_ ? local_video_renderer_->height() : 1;
+  }
+
   size_t number_of_remote_streams() {
     if (!pc())
       return 0;
@@ -929,6 +956,10 @@
       const char kSdpSdesCryptoAttribute[] = "a=crypto";
       RemoveLinesFromSdp(kSdpSdesCryptoAttribute, sdp);
     }
+    if (remove_cvo_) {
+      const char kSdpCvoExtenstion[] = "urn:3gpp:video-orientation";
+      RemoveLinesFromSdp(kSdpCvoExtenstion, sdp);
+    }
   }
 
   std::string id_;
@@ -964,7 +995,10 @@
 
   // Store references to the video capturers we've created, so that we can stop
   // them, if required.
-  std::vector<cricket::VideoCapturer*> video_capturers_;
+  std::vector<cricket::FakeVideoCapturer*> video_capturers_;
+  webrtc::VideoRotation capture_rotation_ = webrtc::kVideoRotation_0;
+  // |local_video_renderer_| attached to the first created local video track.
+  rtc::scoped_ptr<webrtc::FakeVideoTrackRenderer> local_video_renderer_;
 
   webrtc::FakeConstraints offer_answer_constraints_;
   PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options_;
@@ -973,6 +1007,9 @@
       false;  // True if bundle should be removed in received SDP.
   bool remove_sdes_ =
       false;  // True if a=crypto should be removed in received SDP.
+  // |remove_cvo_| is true if extension urn:3gpp:video-orientation should be
+  // removed in the received SDP.
+  bool remove_cvo_ = false;
 
   rtc::scoped_refptr<DataChannelInterface> data_channel_;
   rtc::scoped_ptr<MockDataChannelObserver> data_observer_;
@@ -1047,10 +1084,22 @@
   }
 
   void VerifyRenderedSize(int width, int height) {
+    VerifyRenderedSize(width, height, webrtc::kVideoRotation_0);
+  }
+
+  void VerifyRenderedSize(int width,
+                          int height,
+                          webrtc::VideoRotation rotation) {
     EXPECT_EQ(width, receiving_client()->rendered_width());
     EXPECT_EQ(height, receiving_client()->rendered_height());
+    EXPECT_EQ(rotation, receiving_client()->rendered_rotation());
     EXPECT_EQ(width, initializing_client()->rendered_width());
     EXPECT_EQ(height, initializing_client()->rendered_height());
+    EXPECT_EQ(rotation, initializing_client()->rendered_rotation());
+
+    // Verify size of the local preview.
+    EXPECT_EQ(width, initializing_client()->local_rendered_width());
+    EXPECT_EQ(height, initializing_client()->local_rendered_height());
   }
 
   void VerifySessionDescriptions() {
@@ -1119,6 +1168,11 @@
     receiving_client_->SetVideoConstraints(recv_constraints);
   }
 
+  void SetCaptureRotation(webrtc::VideoRotation rotation) {
+    initiating_client_->SetCaptureRotation(rotation);
+    receiving_client_->SetCaptureRotation(rotation);
+  }
+
   void EnableVideoDecoderFactory() {
     initiating_client_->EnableVideoDecoderFactory();
     receiving_client_->EnableVideoDecoderFactory();
@@ -1389,6 +1443,21 @@
   VerifyRenderedSize(640, 480);
 }
 
+TEST_F(P2PTestConductor, LocalP2PTestCVO) {
+  ASSERT_TRUE(CreateTestClients());
+  SetCaptureRotation(webrtc::kVideoRotation_90);
+  LocalP2PTest();
+  VerifyRenderedSize(640, 480, webrtc::kVideoRotation_90);
+}
+
+TEST_F(P2PTestConductor, LocalP2PTestReceiverDoesntSupportCVO) {
+  ASSERT_TRUE(CreateTestClients());
+  SetCaptureRotation(webrtc::kVideoRotation_90);
+  receiving_client()->RemoveCvoFromReceivedSdp(true);
+  LocalP2PTest();
+  VerifyRenderedSize(480, 640, webrtc::kVideoRotation_0);
+}
+
 // This test sets up a call between two endpoints that are configured to use
 // DTLS key agreement. The offerer don't support SDES. As a result, DTLS is
 // negotiated and used for transport.
diff --git a/webrtc/api/test/fakevideotrackrenderer.h b/webrtc/api/test/fakevideotrackrenderer.h
index 387ce51..312cf64 100644
--- a/webrtc/api/test/fakevideotrackrenderer.h
+++ b/webrtc/api/test/fakevideotrackrenderer.h
@@ -32,6 +32,7 @@
   int errors() const { return fake_renderer_.errors(); }
   int width() const { return fake_renderer_.width(); }
   int height() const { return fake_renderer_.height(); }
+  webrtc::VideoRotation rotation() const { return fake_renderer_.rotation(); }
   bool black_frame() const { return fake_renderer_.black_frame(); }
 
   int num_rendered_frames() const {
diff --git a/webrtc/media/base/fakevideorenderer.h b/webrtc/media/base/fakevideorenderer.h
index 05e285b..5cc1a59 100644
--- a/webrtc/media/base/fakevideorenderer.h
+++ b/webrtc/media/base/fakevideorenderer.h
@@ -59,7 +59,7 @@
     rtc::CritScope cs(&crit_);
     return height_;
   }
-  int rotation() const {
+  webrtc::VideoRotation rotation() const {
     rtc::CritScope cs(&crit_);
     return rotation_;
   }
diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc
index 122edfe..2d8cf00 100644
--- a/webrtc/media/engine/webrtcvideoengine2.cc
+++ b/webrtc/media/engine/webrtcvideoengine2.cc
@@ -1800,10 +1800,10 @@
     // Set codecs and options.
     if (params.codec) {
       SetCodec(*params.codec);
-      return;
+      recreate_stream = false;  // SetCodec has already recreated the stream.
     } else if (params.conference_mode && parameters_.codec_settings) {
       SetCodec(*parameters_.codec_settings);
-      return;
+      recreate_stream = false;  // SetCodec has already recreated the stream.
     }
     if (recreate_stream) {
       LOG(LS_INFO)
diff --git a/webrtc/media/engine/webrtcvideoengine2_unittest.cc b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
index fc18721..21c4fd2 100644
--- a/webrtc/media/engine/webrtcvideoengine2_unittest.cc
+++ b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
@@ -282,8 +282,10 @@
 
   cricket::FakeWebRtcVideoEncoderFactory encoder_factory;
   encoder_factory.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
+  encoder_factory.AddSupportedVideoCodecType(webrtc::kVideoCodecVP9, "VP9");
   cricket::VideoSendParameters parameters;
   parameters.codecs.push_back(kVp8Codec);
+  parameters.codecs.push_back(kVp9Codec);
 
   std::unique_ptr<VideoMediaChannel> channel(
       SetUpForExternalEncoderFactory(&encoder_factory, parameters.codecs));
@@ -292,10 +294,15 @@
   // Set capturer.
   EXPECT_TRUE(channel->SetCapturer(kSsrc, &capturer));
 
+  // Verify capturer has turned on applying rotation.
+  EXPECT_TRUE(capturer.GetApplyRotation());
+
   // Add CVO extension.
   const int id = 1;
   parameters.extensions.push_back(
       cricket::RtpHeaderExtension(kRtpVideoRotationHeaderExtension, id));
+  // Also remove the first codec to trigger a codec change as well.
+  parameters.codecs.erase(parameters.codecs.begin());
   EXPECT_TRUE(channel->SetSendParameters(parameters));
 
   // Verify capturer has turned off applying rotation.