summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/transportbridge/MediaPipelineFilter.cpp
blob: 1acb73e9f278e500ab6b4493fd2b1feaed282015 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: softtabstop=2:shiftwidth=2:expandtab
 * */
/* 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/. */

// Original author: bcampen@mozilla.com

#include "MediaPipelineFilter.h"

#include "api/rtp_headers.h"
#include "api/rtp_parameters.h"
#include "mozilla/Logging.h"

// defined in MediaPipeline.cpp
extern mozilla::LazyLogModule gMediaPipelineLog;

#define DEBUG_LOG(x) MOZ_LOG(gMediaPipelineLog, LogLevel::Debug, x)

namespace mozilla {
MediaPipelineFilter::MediaPipelineFilter(
    const std::vector<webrtc::RtpExtension>& aExtMap)
    : mExtMap(aExtMap) {}

void MediaPipelineFilter::SetRemoteMediaStreamId(
    const Maybe<std::string>& aMid) {
  if (aMid != mRemoteMid) {
    DEBUG_LOG(("MediaPipelineFilter added new remote RTP MID: '%s'.",
               aMid.valueOr("").c_str()));
    mRemoteMid = aMid;
    mRemoteMidBindings.clear();
  }
}

bool MediaPipelineFilter::Filter(const webrtc::RTPHeader& header) {
  DEBUG_LOG(("MediaPipelineFilter inspecting seq# %u SSRC: %u",
             header.sequenceNumber, header.ssrc));

  auto fromStreamId = [](const std::string& aId) {
    return Maybe<std::string>(aId.empty() ? Nothing() : Some(aId));
  };

  //
  //  MID Based Filtering
  //

  const auto mid = fromStreamId(header.extension.mid);

  // Check to see if a bound SSRC is moved to a new MID
  if (mRemoteMidBindings.count(header.ssrc) == 1 && mid && mRemoteMid != mid) {
    mRemoteMidBindings.erase(header.ssrc);
  }
  // Bind an SSRC if a matching MID is found
  if (mid && mRemoteMid == mid) {
    DEBUG_LOG(("MediaPipelineFilter learned SSRC: %u for MID: '%s'",
               header.ssrc, mRemoteMid.value().c_str()));
    mRemoteMidBindings.insert(header.ssrc);
  }
  // Check for matching MID
  if (!mRemoteMidBindings.empty()) {
    MOZ_ASSERT(mRemoteMid != Nothing());
    if (mRemoteMidBindings.count(header.ssrc) == 1) {
      DEBUG_LOG(
          ("MediaPipelineFilter SSRC: %u matched for MID: '%s'."
           " passing packet",
           header.ssrc, mRemoteMid.value().c_str()));
      return true;
    }
    DEBUG_LOG(
        ("MediaPipelineFilter SSRC: %u did not match bound SSRC(s) for"
         " MID: '%s'. ignoring packet",
         header.ssrc, mRemoteMid.value().c_str()));
    for (const uint32_t ssrc : mRemoteMidBindings) {
      DEBUG_LOG(("MID %s is associated with SSRC: %u",
                 mRemoteMid.value().c_str(), ssrc));
    }
    return false;
  }

  //
  // RTP-STREAM-ID based filtering (for tests only)
  //

  //
  // Remote SSRC based filtering
  //

  if (remote_ssrc_set_.count(header.ssrc)) {
    DEBUG_LOG(
        ("MediaPipelineFilter SSRC: %u matched remote SSRC set."
         " passing packet",
         header.ssrc));
    return true;
  }
  DEBUG_LOG(
      ("MediaPipelineFilter SSRC: %u did not match any of %zu"
       " remote SSRCS.",
       header.ssrc, remote_ssrc_set_.size()));

  //
  // PT, payload type, last ditch effort filtering
  //

  if (payload_type_set_.count(header.payloadType)) {
    DEBUG_LOG(
        ("MediaPipelineFilter payload-type: %u matched %zu"
         " unique payload type. learning ssrc. passing packet",
         header.ssrc, remote_ssrc_set_.size()));
    // Actual match. We need to update the ssrc map so we can route rtcp
    // sender reports correctly (these use a different payload-type field)
    AddRemoteSSRC(header.ssrc);
    return true;
  }
  DEBUG_LOG(
      ("MediaPipelineFilter payload-type: %u did not match any of %zu"
       " unique payload-types.",
       header.payloadType, payload_type_set_.size()));
  DEBUG_LOG(
      ("MediaPipelineFilter packet failed to match any criteria."
       " ignoring packet"));
  return false;
}

void MediaPipelineFilter::AddRemoteSSRC(uint32_t ssrc) {
  remote_ssrc_set_.insert(ssrc);
}

void MediaPipelineFilter::AddUniquePT(uint8_t payload_type) {
  payload_type_set_.insert(payload_type);
}

void MediaPipelineFilter::Update(const MediaPipelineFilter& filter_update) {
  // We will not stomp the remote_ssrc_set_ if the update has no ssrcs,
  // because we don't want to unlearn any remote ssrcs unless the other end
  // has explicitly given us a new set.
  if (!filter_update.remote_ssrc_set_.empty()) {
    remote_ssrc_set_ = filter_update.remote_ssrc_set_;
  }
  // We don't want to overwrite the learned binding unless we have changed MIDs
  // or the update contains a MID binding.
  if (!filter_update.mRemoteMidBindings.empty() ||
      (filter_update.mRemoteMid && filter_update.mRemoteMid != mRemoteMid)) {
    mRemoteMid = filter_update.mRemoteMid;
    mRemoteMidBindings = filter_update.mRemoteMidBindings;
  }
  payload_type_set_ = filter_update.payload_type_set_;

  // Use extmapping from new filter
  mExtMap = filter_update.mExtMap;
}

}  // end namespace mozilla