| Index: webrtc/video/end_to_end_tests.cc
 | 
| diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
 | 
| index 416c8dd5d8b868c917c6d2945e478244a021e092..36206fae9cd2e7a58bf09fa190dbe9b6594cbb6e 100644
 | 
| --- a/webrtc/video/end_to_end_tests.cc
 | 
| +++ b/webrtc/video/end_to_end_tests.cc
 | 
| @@ -1133,120 +1133,304 @@ TEST_F(EndToEndTest, UsesRtcpReducedSizeMode) {
 | 
|  
 | 
|  // Test sets up a Call multiple senders with different resolutions and SSRCs.
 | 
|  // Another is set up to receive all three of these with different renderers.
 | 
| +class MultiStreamTest {
 | 
| + public:
 | 
| +  static const size_t kNumStreams = 3;
 | 
| +  struct CodecSettings {
 | 
| +    uint32_t ssrc;
 | 
| +    int width;
 | 
| +    int height;
 | 
| +  } codec_settings[kNumStreams];
 | 
| +
 | 
| +  MultiStreamTest() {
 | 
| +    // TODO(sprang): Cleanup when msvc supports explicit initializers for array.
 | 
| +    codec_settings[0] = {1, 640, 480};
 | 
| +    codec_settings[1] = {2, 320, 240};
 | 
| +    codec_settings[2] = {3, 240, 160};
 | 
| +  }
 | 
| +
 | 
| +  virtual ~MultiStreamTest() {}
 | 
| +
 | 
| +  void RunTest() {
 | 
| +    rtc::scoped_ptr<test::DirectTransport> sender_transport(
 | 
| +        CreateSendTransport());
 | 
| +    rtc::scoped_ptr<test::DirectTransport> receiver_transport(
 | 
| +        CreateReceiveTransport());
 | 
| +
 | 
| +    rtc::scoped_ptr<Call> sender_call(
 | 
| +        Call::Create(Call::Config(sender_transport.get())));
 | 
| +    rtc::scoped_ptr<Call> receiver_call(
 | 
| +        Call::Create(Call::Config(receiver_transport.get())));
 | 
| +    sender_transport->SetReceiver(receiver_call->Receiver());
 | 
| +    receiver_transport->SetReceiver(sender_call->Receiver());
 | 
| +
 | 
| +    rtc::scoped_ptr<VideoEncoder> encoders[kNumStreams];
 | 
| +    for (size_t i = 0; i < kNumStreams; ++i)
 | 
| +      encoders[i].reset(VideoEncoder::Create(VideoEncoder::kVp8));
 | 
| +
 | 
| +    VideoSendStream* send_streams[kNumStreams];
 | 
| +    VideoReceiveStream* receive_streams[kNumStreams];
 | 
| +
 | 
| +    test::FrameGeneratorCapturer* frame_generators[kNumStreams];
 | 
| +    ScopedVector<VideoDecoder> allocated_decoders;
 | 
| +    for (size_t i = 0; i < kNumStreams; ++i) {
 | 
| +      uint32_t ssrc = codec_settings[i].ssrc;
 | 
| +      int width = codec_settings[i].width;
 | 
| +      int height = codec_settings[i].height;
 | 
| +
 | 
| +      VideoSendStream::Config send_config;
 | 
| +      send_config.rtp.ssrcs.push_back(ssrc);
 | 
| +      send_config.encoder_settings.encoder = encoders[i].get();
 | 
| +      send_config.encoder_settings.payload_name = "VP8";
 | 
| +      send_config.encoder_settings.payload_type = 124;
 | 
| +      VideoEncoderConfig encoder_config;
 | 
| +      encoder_config.streams = test::CreateVideoStreams(1);
 | 
| +      VideoStream* stream = &encoder_config.streams[0];
 | 
| +      stream->width = width;
 | 
| +      stream->height = height;
 | 
| +      stream->max_framerate = 5;
 | 
| +      stream->min_bitrate_bps = stream->target_bitrate_bps =
 | 
| +          stream->max_bitrate_bps = 100000;
 | 
| +
 | 
| +      UpdateSendConfig(i, &send_config, &encoder_config, &frame_generators[i]);
 | 
| +
 | 
| +      send_streams[i] =
 | 
| +          sender_call->CreateVideoSendStream(send_config, encoder_config);
 | 
| +      send_streams[i]->Start();
 | 
| +
 | 
| +      VideoReceiveStream::Config receive_config;
 | 
| +      receive_config.rtp.remote_ssrc = ssrc;
 | 
| +      receive_config.rtp.local_ssrc = test::CallTest::kReceiverLocalSsrc;
 | 
| +      VideoReceiveStream::Decoder decoder =
 | 
| +          test::CreateMatchingDecoder(send_config.encoder_settings);
 | 
| +      allocated_decoders.push_back(decoder.decoder);
 | 
| +      receive_config.decoders.push_back(decoder);
 | 
| +
 | 
| +      UpdateReceiveConfig(i, &receive_config);
 | 
| +
 | 
| +      receive_streams[i] =
 | 
| +          receiver_call->CreateVideoReceiveStream(receive_config);
 | 
| +      receive_streams[i]->Start();
 | 
| +
 | 
| +      frame_generators[i] = test::FrameGeneratorCapturer::Create(
 | 
| +          send_streams[i]->Input(), width, height, 30,
 | 
| +          Clock::GetRealTimeClock());
 | 
| +      frame_generators[i]->Start();
 | 
| +    }
 | 
| +
 | 
| +    Wait();
 | 
| +
 | 
| +    for (size_t i = 0; i < kNumStreams; ++i) {
 | 
| +      frame_generators[i]->Stop();
 | 
| +      sender_call->DestroyVideoSendStream(send_streams[i]);
 | 
| +      receiver_call->DestroyVideoReceiveStream(receive_streams[i]);
 | 
| +      delete frame_generators[i];
 | 
| +    }
 | 
| +
 | 
| +    sender_transport->StopSending();
 | 
| +    receiver_transport->StopSending();
 | 
| +  }
 | 
| +
 | 
| + protected:
 | 
| +  virtual void Wait() = 0;
 | 
| +  // Note: frame_generator is a point-to-pointer, since the actual instance
 | 
| +  // hasn't been created at the time of this call. Only when packets/frames
 | 
| +  // start flowing should this be dereferenced.
 | 
| +  virtual void UpdateSendConfig(
 | 
| +      size_t stream_index,
 | 
| +      VideoSendStream::Config* send_config,
 | 
| +      VideoEncoderConfig* encoder_config,
 | 
| +      test::FrameGeneratorCapturer** frame_generator) {}
 | 
| +  virtual void UpdateReceiveConfig(size_t stream_index,
 | 
| +                                   VideoReceiveStream::Config* receive_config) {
 | 
| +  }
 | 
| +  virtual test::DirectTransport* CreateSendTransport() {
 | 
| +    return new test::DirectTransport();
 | 
| +  }
 | 
| +  virtual test::DirectTransport* CreateReceiveTransport() {
 | 
| +    return new test::DirectTransport();
 | 
| +  }
 | 
| +};
 | 
| +
 | 
|  // Each renderer verifies that it receives the expected resolution, and as soon
 | 
|  // as every renderer has received a frame, the test finishes.
 | 
|  TEST_F(EndToEndTest, SendsAndReceivesMultipleStreams) {
 | 
| -  static const size_t kNumStreams = 3;
 | 
| -
 | 
|    class VideoOutputObserver : public VideoRenderer {
 | 
|     public:
 | 
| -    VideoOutputObserver(test::FrameGeneratorCapturer** capturer,
 | 
| -                        int width,
 | 
| -                        int height)
 | 
| -        : capturer_(capturer),
 | 
| -          width_(width),
 | 
| -          height_(height),
 | 
| +    VideoOutputObserver(const MultiStreamTest::CodecSettings& settings,
 | 
| +                        uint32_t ssrc,
 | 
| +                        test::FrameGeneratorCapturer** frame_generator)
 | 
| +        : settings_(settings),
 | 
| +          ssrc_(ssrc),
 | 
| +          frame_generator_(frame_generator),
 | 
|            done_(EventWrapper::Create()) {}
 | 
|  
 | 
|      void RenderFrame(const VideoFrame& video_frame,
 | 
|                       int time_to_render_ms) override {
 | 
| -      EXPECT_EQ(width_, video_frame.width());
 | 
| -      EXPECT_EQ(height_, video_frame.height());
 | 
| -      (*capturer_)->Stop();
 | 
| +      EXPECT_EQ(settings_.width, video_frame.width());
 | 
| +      EXPECT_EQ(settings_.height, video_frame.height());
 | 
| +      (*frame_generator_)->Stop();
 | 
|        done_->Set();
 | 
|      }
 | 
|  
 | 
| +    uint32_t Ssrc() { return ssrc_; }
 | 
| +
 | 
|      bool IsTextureSupported() const override { return false; }
 | 
|  
 | 
|      EventTypeWrapper Wait() { return done_->Wait(kDefaultTimeoutMs); }
 | 
|  
 | 
|     private:
 | 
| -    test::FrameGeneratorCapturer** capturer_;
 | 
| -    int width_;
 | 
| -    int height_;
 | 
| +    const MultiStreamTest::CodecSettings& settings_;
 | 
| +    const uint32_t ssrc_;
 | 
| +    test::FrameGeneratorCapturer** const frame_generator_;
 | 
|      rtc::scoped_ptr<EventWrapper> done_;
 | 
|    };
 | 
|  
 | 
| -  struct {
 | 
| -    uint32_t ssrc;
 | 
| -    int width;
 | 
| -    int height;
 | 
| -  } codec_settings[kNumStreams] = {{1, 640, 480}, {2, 320, 240}, {3, 240, 160}};
 | 
| +  class Tester : public MultiStreamTest {
 | 
| +   public:
 | 
| +    Tester() {}
 | 
| +    virtual ~Tester() {}
 | 
| +
 | 
| +   protected:
 | 
| +    void Wait() override {
 | 
| +      for (const auto& observer : observers_) {
 | 
| +        EXPECT_EQ(EventTypeWrapper::kEventSignaled, observer->Wait())
 | 
| +            << "Time out waiting for from on ssrc " << observer->Ssrc();
 | 
| +      }
 | 
| +    }
 | 
|  
 | 
| -  test::DirectTransport sender_transport, receiver_transport;
 | 
| -  rtc::scoped_ptr<Call> sender_call(
 | 
| -      Call::Create(Call::Config(&sender_transport)));
 | 
| -  rtc::scoped_ptr<Call> receiver_call(
 | 
| -      Call::Create(Call::Config(&receiver_transport)));
 | 
| -  sender_transport.SetReceiver(receiver_call->Receiver());
 | 
| -  receiver_transport.SetReceiver(sender_call->Receiver());
 | 
| -
 | 
| -  VideoSendStream* send_streams[kNumStreams];
 | 
| -  VideoReceiveStream* receive_streams[kNumStreams];
 | 
| -
 | 
| -  VideoOutputObserver* observers[kNumStreams];
 | 
| -  test::FrameGeneratorCapturer* frame_generators[kNumStreams];
 | 
| -
 | 
| -  rtc::scoped_ptr<VideoEncoder> encoders[kNumStreams];
 | 
| -  for (size_t i = 0; i < kNumStreams; ++i)
 | 
| -    encoders[i].reset(VideoEncoder::Create(VideoEncoder::kVp8));
 | 
| -
 | 
| -  ScopedVector<VideoDecoder> allocated_decoders;
 | 
| -  for (size_t i = 0; i < kNumStreams; ++i) {
 | 
| -    uint32_t ssrc = codec_settings[i].ssrc;
 | 
| -    int width = codec_settings[i].width;
 | 
| -    int height = codec_settings[i].height;
 | 
| -    observers[i] = new VideoOutputObserver(&frame_generators[i], width, height);
 | 
| +    void UpdateSendConfig(
 | 
| +        size_t stream_index,
 | 
| +        VideoSendStream::Config* send_config,
 | 
| +        VideoEncoderConfig* encoder_config,
 | 
| +        test::FrameGeneratorCapturer** frame_generator) override {
 | 
| +      observers_[stream_index].reset(new VideoOutputObserver(
 | 
| +          codec_settings[stream_index], send_config->rtp.ssrcs.front(),
 | 
| +          frame_generator));
 | 
| +    }
 | 
|  
 | 
| -    VideoSendStream::Config send_config;
 | 
| -    send_config.rtp.ssrcs.push_back(ssrc);
 | 
| -    send_config.encoder_settings.encoder = encoders[i].get();
 | 
| -    send_config.encoder_settings.payload_name = "VP8";
 | 
| -    send_config.encoder_settings.payload_type = 124;
 | 
| -    VideoEncoderConfig encoder_config;
 | 
| -    encoder_config.streams = test::CreateVideoStreams(1);
 | 
| -    VideoStream* stream = &encoder_config.streams[0];
 | 
| -    stream->width = width;
 | 
| -    stream->height = height;
 | 
| -    stream->max_framerate = 5;
 | 
| -    stream->min_bitrate_bps = stream->target_bitrate_bps =
 | 
| -        stream->max_bitrate_bps = 100000;
 | 
| -    send_streams[i] =
 | 
| -        sender_call->CreateVideoSendStream(send_config, encoder_config);
 | 
| -    send_streams[i]->Start();
 | 
| +    void UpdateReceiveConfig(
 | 
| +        size_t stream_index,
 | 
| +        VideoReceiveStream::Config* receive_config) override {
 | 
| +      receive_config->renderer = observers_[stream_index].get();
 | 
| +    }
 | 
|  
 | 
| -    VideoReceiveStream::Config receive_config;
 | 
| -    receive_config.renderer = observers[i];
 | 
| -    receive_config.rtp.remote_ssrc = ssrc;
 | 
| -    receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
 | 
| -    VideoReceiveStream::Decoder decoder =
 | 
| -        test::CreateMatchingDecoder(send_config.encoder_settings);
 | 
| -    allocated_decoders.push_back(decoder.decoder);
 | 
| -    receive_config.decoders.push_back(decoder);
 | 
| -    receive_streams[i] =
 | 
| -        receiver_call->CreateVideoReceiveStream(receive_config);
 | 
| -    receive_streams[i]->Start();
 | 
| +   private:
 | 
| +    rtc::scoped_ptr<VideoOutputObserver> observers_[kNumStreams];
 | 
| +  } tester;
 | 
|  
 | 
| -    frame_generators[i] = test::FrameGeneratorCapturer::Create(
 | 
| -        send_streams[i]->Input(), width, height, 30, Clock::GetRealTimeClock());
 | 
| -    frame_generators[i]->Start();
 | 
| -  }
 | 
| +  tester.RunTest();
 | 
| +}
 | 
|  
 | 
| -  for (size_t i = 0; i < kNumStreams; ++i) {
 | 
| -    EXPECT_EQ(kEventSignaled, observers[i]->Wait())
 | 
| -        << "Timed out while waiting for observer " << i << " to render.";
 | 
| -  }
 | 
| +TEST_F(EndToEndTest, AssignsTransportSequenceNumbers) {
 | 
| +  // TODO(sprang): Extend this to verify received values once send-side BWE
 | 
| +  // is in place.
 | 
|  
 | 
| -  for (size_t i = 0; i < kNumStreams; ++i) {
 | 
| -    frame_generators[i]->Stop();
 | 
| -    sender_call->DestroyVideoSendStream(send_streams[i]);
 | 
| -    receiver_call->DestroyVideoReceiveStream(receive_streams[i]);
 | 
| -    delete frame_generators[i];
 | 
| -    delete observers[i];
 | 
| -  }
 | 
| +  static const int kExtensionId = 5;
 | 
|  
 | 
| -  sender_transport.StopSending();
 | 
| -  receiver_transport.StopSending();
 | 
| +  class RtpExtensionHeaderObserver : public test::DirectTransport {
 | 
| +   public:
 | 
| +    RtpExtensionHeaderObserver()
 | 
| +        : done_(EventWrapper::Create()),
 | 
| +          parser_(RtpHeaderParser::Create()),
 | 
| +          last_seq_(0),
 | 
| +          padding_observed_(false),
 | 
| +          rtx_padding_observed_(false) {
 | 
| +      parser_->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber,
 | 
| +                                          kExtensionId);
 | 
| +    }
 | 
| +    virtual ~RtpExtensionHeaderObserver() {}
 | 
| +
 | 
| +    bool SendRtp(const uint8_t* data, size_t length) override {
 | 
| +      RTPHeader header;
 | 
| +      EXPECT_TRUE(parser_->Parse(data, length, &header));
 | 
| +      if (header.extension.hasTransportSequenceNumber) {
 | 
| +        if (!streams_observed_.empty()) {
 | 
| +          EXPECT_EQ(static_cast<uint16_t>(last_seq_ + 1),
 | 
| +                    header.extension.transportSequenceNumber);
 | 
| +        }
 | 
| +        last_seq_ = header.extension.transportSequenceNumber;
 | 
| +
 | 
| +        size_t payload_length =
 | 
| +            length - (header.headerLength + header.paddingLength);
 | 
| +        if (payload_length == 0) {
 | 
| +          padding_observed_ = true;
 | 
| +        } else if (header.payloadType == kSendRtxPayloadType) {
 | 
| +          rtx_padding_observed_ = true;
 | 
| +        } else {
 | 
| +          streams_observed_.insert(header.ssrc);
 | 
| +        }
 | 
| +
 | 
| +        if (streams_observed_.size() == MultiStreamTest::kNumStreams &&
 | 
| +            padding_observed_ && rtx_padding_observed_) {
 | 
| +          done_->Set();
 | 
| +        }
 | 
| +      }
 | 
| +      return test::DirectTransport::SendRtp(data, length);
 | 
| +    }
 | 
| +
 | 
| +    EventTypeWrapper Wait() { return done_->Wait(kDefaultTimeoutMs); }
 | 
| +
 | 
| +    rtc::scoped_ptr<EventWrapper> done_;
 | 
| +    rtc::scoped_ptr<RtpHeaderParser> parser_;
 | 
| +    uint16_t last_seq_;
 | 
| +    std::set<uint32_t> streams_observed_;
 | 
| +    bool padding_observed_;
 | 
| +    bool rtx_padding_observed_;
 | 
| +  };
 | 
| +
 | 
| +  class TransportSequenceNumberTester : public MultiStreamTest {
 | 
| +   public:
 | 
| +    TransportSequenceNumberTester() : observer_(nullptr) {}
 | 
| +    virtual ~TransportSequenceNumberTester() {}
 | 
| +
 | 
| +   protected:
 | 
| +    void Wait() override {
 | 
| +      DCHECK(observer_ != nullptr);
 | 
| +      EXPECT_EQ(EventTypeWrapper::kEventSignaled, observer_->Wait());
 | 
| +    }
 | 
| +
 | 
| +    void UpdateSendConfig(
 | 
| +        size_t stream_index,
 | 
| +        VideoSendStream::Config* send_config,
 | 
| +        VideoEncoderConfig* encoder_config,
 | 
| +        test::FrameGeneratorCapturer** frame_generator) override {
 | 
| +      send_config->rtp.extensions.clear();
 | 
| +      send_config->rtp.extensions.push_back(
 | 
| +          RtpExtension(RtpExtension::kTransportSequenceNumber, kExtensionId));
 | 
| +
 | 
| +      // Force some padding to be sent.
 | 
| +      const int kPaddingBitrateBps = 50000;
 | 
| +      int total_target_bitrate = 0;
 | 
| +      for (const VideoStream& stream : encoder_config->streams)
 | 
| +        total_target_bitrate += stream.target_bitrate_bps;
 | 
| +      encoder_config->min_transmit_bitrate_bps =
 | 
| +          total_target_bitrate + kPaddingBitrateBps;
 | 
| +
 | 
| +      // Configure RTX for redundant payload padding.
 | 
| +      send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
 | 
| +      send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
 | 
| +      send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
 | 
| +    }
 | 
| +
 | 
| +    void UpdateReceiveConfig(
 | 
| +        size_t stream_index,
 | 
| +        VideoReceiveStream::Config* receive_config) override {
 | 
| +      receive_config->rtp.extensions.clear();
 | 
| +      receive_config->rtp.extensions.push_back(
 | 
| +          RtpExtension(RtpExtension::kTransportSequenceNumber, kExtensionId));
 | 
| +    }
 | 
| +
 | 
| +    virtual test::DirectTransport* CreateSendTransport() {
 | 
| +      observer_ = new RtpExtensionHeaderObserver();
 | 
| +      return observer_;
 | 
| +    }
 | 
| +
 | 
| +   private:
 | 
| +    RtpExtensionHeaderObserver* observer_;
 | 
| +  } tester;
 | 
| +
 | 
| +  tester.RunTest();
 | 
|  }
 | 
|  
 | 
|  TEST_F(EndToEndTest, ObserversEncodedFrames) {
 | 
| @@ -1806,7 +1990,8 @@ void EndToEndTest::TestSendsSetSsrcs(size_t num_ssrcs,
 | 
|            num_ssrcs_(num_ssrcs),
 | 
|            send_single_ssrc_first_(send_single_ssrc_first),
 | 
|            ssrcs_to_observe_(num_ssrcs),
 | 
| -          expect_single_ssrc_(send_single_ssrc_first) {
 | 
| +          expect_single_ssrc_(send_single_ssrc_first),
 | 
| +          send_stream_(nullptr) {
 | 
|        for (size_t i = 0; i < num_ssrcs; ++i)
 | 
|          valid_ssrcs_[ssrcs[i]] = true;
 | 
|      }
 | 
| @@ -1898,7 +2083,9 @@ TEST_F(EndToEndTest, ReportsSetEncoderRates) {
 | 
|     public:
 | 
|      EncoderRateStatsTest()
 | 
|          : EndToEndTest(kDefaultTimeoutMs),
 | 
| -          FakeEncoder(Clock::GetRealTimeClock()) {}
 | 
| +          FakeEncoder(Clock::GetRealTimeClock()),
 | 
| +          send_stream_(nullptr),
 | 
| +          bitrate_kbps_(0) {}
 | 
|  
 | 
|      void OnStreamsCreated(
 | 
|          VideoSendStream* send_stream,
 | 
| @@ -2534,6 +2721,8 @@ TEST_F(EndToEndTest, RespectsNetworkState) {
 | 
|            FakeEncoder(Clock::GetRealTimeClock()),
 | 
|            encoded_frames_(EventWrapper::Create()),
 | 
|            packet_event_(EventWrapper::Create()),
 | 
| +          sender_call_(nullptr),
 | 
| +          receiver_call_(nullptr),
 | 
|            sender_state_(kNetworkUp),
 | 
|            sender_rtp_(0),
 | 
|            sender_rtcp_(0),
 | 
| 
 |