1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5
6
7/**
8 * Get the ssrc if |report| is an ssrc report.
9 *
10 * @param {!Object} report The object contains id, type, and stats, where stats
11 *     is the object containing timestamp and values, which is an array of
12 *     strings, whose even index entry is the name of the stat, and the odd
13 *     index entry is the value.
14 * @return {?string} The ssrc.
15 */
16function GetSsrcFromReport(report) {
17  if (report.type != 'ssrc') {
18    console.warn("Trying to get ssrc from non-ssrc report.");
19    return null;
20  }
21
22  // If the 'ssrc' name-value pair exists, return the value; otherwise, return
23  // the report id.
24  // The 'ssrc' name-value pair only exists in an upcoming Libjingle change. Old
25  // versions use id to refer to the ssrc.
26  //
27  // TODO(jiayl): remove the fallback to id once the Libjingle change is rolled
28  // to Chrome.
29  if (report.stats && report.stats.values) {
30    for (var i = 0; i < report.stats.values.length - 1; i += 2) {
31      if (report.stats.values[i] == 'ssrc') {
32        return report.stats.values[i + 1];
33      }
34    }
35  }
36  return report.id;
37};
38
39/**
40 * SsrcInfoManager stores the ssrc stream info extracted from SDP.
41 */
42var SsrcInfoManager = (function() {
43  'use strict';
44
45  /**
46   * @constructor
47   */
48  function SsrcInfoManager() {
49    /**
50     * Map from ssrc id to an object containing all the stream properties.
51     * @type {!Object.<string, !Object.<string>>}
52     * @private
53     */
54    this.streamInfoContainer_ = {};
55
56    /**
57     * The string separating attibutes in an SDP.
58     * @type {string}
59     * @const
60     * @private
61     */
62    this.ATTRIBUTE_SEPARATOR_ = /[\r,\n]/;
63
64    /**
65     * The regex separating fields within an ssrc description.
66     * @type {RegExp}
67     * @const
68     * @private
69     */
70    this.FIELD_SEPARATOR_REGEX_ = / .*:/;
71
72    /**
73     * The prefix string of an ssrc description.
74     * @type {string}
75     * @const
76     * @private
77     */
78    this.SSRC_ATTRIBUTE_PREFIX_ = 'a=ssrc:';
79
80    /**
81     * The className of the ssrc info parent element.
82     * @type {string}
83     * @const
84     */
85    this.SSRC_INFO_BLOCK_CLASS = 'ssrc-info-block';
86  }
87
88  SsrcInfoManager.prototype = {
89    /**
90     * Extracts the stream information from |sdp| and saves it.
91     * For example:
92     *     a=ssrc:1234 msid:abcd
93     *     a=ssrc:1234 label:hello
94     *
95     * @param {string} sdp The SDP string.
96     */
97    addSsrcStreamInfo: function(sdp) {
98      var attributes = sdp.split(this.ATTRIBUTE_SEPARATOR_);
99      for (var i = 0; i < attributes.length; ++i) {
100        // Check if this is a ssrc attribute.
101        if (attributes[i].indexOf(this.SSRC_ATTRIBUTE_PREFIX_) != 0)
102          continue;
103
104        var nextFieldIndex = attributes[i].search(this.FIELD_SEPARATOR_REGEX_);
105
106        if (nextFieldIndex == -1)
107          continue;
108
109        var ssrc = attributes[i].substring(this.SSRC_ATTRIBUTE_PREFIX_.length,
110                                           nextFieldIndex);
111        if (!this.streamInfoContainer_[ssrc])
112          this.streamInfoContainer_[ssrc] = {};
113
114        // Make |rest| starting at the next field.
115        var rest = attributes[i].substring(nextFieldIndex + 1);
116        var name, value;
117        while (rest.length > 0) {
118          nextFieldIndex = rest.search(this.FIELD_SEPARATOR_REGEX_);
119          if (nextFieldIndex == -1)
120            nextFieldIndex = rest.length;
121
122          // The field name is the string before the colon.
123          name = rest.substring(0, rest.indexOf(':'));
124          // The field value is from after the colon to the next field.
125          value = rest.substring(rest.indexOf(':') + 1, nextFieldIndex);
126          this.streamInfoContainer_[ssrc][name] = value;
127
128          // Move |rest| to the start of the next field.
129          rest = rest.substring(nextFieldIndex + 1);
130        }
131      }
132    },
133
134    /**
135     * @param {string} sdp The ssrc id.
136     * @return {!Object.<string>} The object containing the ssrc infomation.
137     */
138    getStreamInfo: function(ssrc) {
139      return this.streamInfoContainer_[ssrc];
140    },
141
142    /**
143     * Populate the ssrc information into |parentElement|, each field as a
144     * DIV element.
145     *
146     * @param {!Element} parentElement The parent element for the ssrc info.
147     * @param {string} ssrc The ssrc id.
148     */
149    populateSsrcInfo: function(parentElement, ssrc) {
150      if (!this.streamInfoContainer_[ssrc])
151        return;
152
153      parentElement.className = this.SSRC_INFO_BLOCK_CLASS;
154
155      var fieldElement;
156      for (var property in this.streamInfoContainer_[ssrc]) {
157        fieldElement = document.createElement('div');
158        parentElement.appendChild(fieldElement);
159        fieldElement.textContent =
160            property + ':' + this.streamInfoContainer_[ssrc][property];
161      }
162    }
163  };
164
165  return SsrcInfoManager;
166})();
167