1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/video_engine/encoder_state_feedback.h"
12
13#include <assert.h>
14
15#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
16#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
17#include "webrtc/video_engine/vie_encoder.h"
18
19namespace webrtc {
20
21// Helper class registered at the RTP module relaying callbacks to
22// EncoderStatFeedback.
23class EncoderStateFeedbackObserver : public  RtcpIntraFrameObserver {
24 public:
25  explicit EncoderStateFeedbackObserver(EncoderStateFeedback* owner)
26      : owner_(owner) {}
27  ~EncoderStateFeedbackObserver() {}
28
29  // Implements RtcpIntraFrameObserver.
30  virtual void OnReceivedIntraFrameRequest(uint32_t ssrc) {
31    owner_->OnReceivedIntraFrameRequest(ssrc);
32  }
33  virtual void OnReceivedSLI(uint32_t ssrc, uint8_t picture_id) {
34    owner_->OnReceivedSLI(ssrc, picture_id);
35  }
36  virtual void OnReceivedRPSI(uint32_t ssrc, uint64_t picture_id) {
37    owner_->OnReceivedRPSI(ssrc, picture_id);
38  }
39
40  virtual void OnLocalSsrcChanged(uint32_t old_ssrc, uint32_t new_ssrc) {
41    owner_->OnLocalSsrcChanged(old_ssrc, new_ssrc);
42  }
43
44 private:
45  EncoderStateFeedback* owner_;
46};
47
48EncoderStateFeedback::EncoderStateFeedback()
49    : crit_(CriticalSectionWrapper::CreateCriticalSection()),
50      observer_(new EncoderStateFeedbackObserver(this)) {}
51
52EncoderStateFeedback::~EncoderStateFeedback() {
53  assert(encoders_.empty());
54}
55
56bool EncoderStateFeedback::AddEncoder(uint32_t ssrc, ViEEncoder* encoder)  {
57  CriticalSectionScoped lock(crit_.get());
58  if (encoders_.find(ssrc) != encoders_.end()) {
59    // Two encoders must not have the same ssrc.
60    return false;
61  }
62
63  encoders_[ssrc] = encoder;
64  return true;
65}
66
67void EncoderStateFeedback::RemoveEncoder(const ViEEncoder* encoder)  {
68  CriticalSectionScoped lock(crit_.get());
69  SsrcEncoderMap::iterator it = encoders_.begin();
70  while (it != encoders_.end()) {
71    if (it->second == encoder) {
72      encoders_.erase(it++);
73    } else {
74      ++it;
75    }
76  }
77}
78
79RtcpIntraFrameObserver* EncoderStateFeedback::GetRtcpIntraFrameObserver() {
80  return observer_.get();
81}
82
83void EncoderStateFeedback::OnReceivedIntraFrameRequest(uint32_t ssrc) {
84  CriticalSectionScoped lock(crit_.get());
85  SsrcEncoderMap::iterator it = encoders_.find(ssrc);
86  if (it == encoders_.end())
87    return;
88
89  it->second->OnReceivedIntraFrameRequest(ssrc);
90}
91
92void EncoderStateFeedback::OnReceivedSLI(uint32_t ssrc, uint8_t picture_id) {
93  CriticalSectionScoped lock(crit_.get());
94  SsrcEncoderMap::iterator it = encoders_.find(ssrc);
95  if (it == encoders_.end())
96    return;
97
98  it->second->OnReceivedSLI(ssrc, picture_id);
99}
100
101void EncoderStateFeedback::OnReceivedRPSI(uint32_t ssrc, uint64_t picture_id) {
102  CriticalSectionScoped lock(crit_.get());
103  SsrcEncoderMap::iterator it = encoders_.find(ssrc);
104  if (it == encoders_.end())
105    return;
106
107  it->second->OnReceivedRPSI(ssrc, picture_id);
108}
109
110void EncoderStateFeedback::OnLocalSsrcChanged(uint32_t old_ssrc,
111                                              uint32_t new_ssrc) {
112  CriticalSectionScoped lock(crit_.get());
113  SsrcEncoderMap::iterator it = encoders_.find(old_ssrc);
114  if (it == encoders_.end() || encoders_.find(new_ssrc) != encoders_.end()) {
115    return;
116  }
117
118  ViEEncoder* encoder = it->second;
119  encoders_.erase(it);
120  encoders_[new_ssrc] = encoder;
121  encoder->OnLocalSsrcChanged(old_ssrc, new_ssrc);
122}
123
124}  // namespace webrtc
125