1/*
2 * Copyright (C) 2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26#include "LibWebRTCUtils.h"
27
28#if USE(LIBWEBRTC)
29
30#include "LibWebRTCMacros.h"
31#include "RTCPeerConnection.h"
32#include "RTCRtpSendParameters.h"
33#include <wtf/text/WTFString.h>
34
35ALLOW_UNUSED_PARAMETERS_BEGIN
36
37#include <webrtc/api/rtpparameters.h>
38#include <webrtc/api/rtptransceiverinterface.h>
39
40ALLOW_UNUSED_PARAMETERS_END
41
42namespace WebCore {
43
44static inline RTCRtpEncodingParameters toRTCEncodingParameters(const webrtc::RtpEncodingParameters& rtcParameters)
45{
46 RTCRtpEncodingParameters parameters;
47
48 if (rtcParameters.ssrc)
49 parameters.ssrc = *rtcParameters.ssrc;
50 if (rtcParameters.rtx && rtcParameters.rtx->ssrc)
51 parameters.rtx.ssrc = *rtcParameters.rtx->ssrc;
52 if (rtcParameters.fec && rtcParameters.fec->ssrc)
53 parameters.fec.ssrc = *rtcParameters.fec->ssrc;
54 if (rtcParameters.dtx) {
55 switch (*rtcParameters.dtx) {
56 case webrtc::DtxStatus::DISABLED:
57 parameters.dtx = RTCDtxStatus::Disabled;
58 break;
59 case webrtc::DtxStatus::ENABLED:
60 parameters.dtx = RTCDtxStatus::Enabled;
61 }
62 }
63 parameters.active = rtcParameters.active;
64 if (rtcParameters.max_bitrate_bps)
65 parameters.maxBitrate = *rtcParameters.max_bitrate_bps;
66 if (rtcParameters.max_framerate)
67 parameters.maxFramerate = *rtcParameters.max_framerate;
68 parameters.rid = fromStdString(rtcParameters.rid);
69 if (rtcParameters.scale_resolution_down_by)
70 parameters.scaleResolutionDownBy = *rtcParameters.scale_resolution_down_by;
71
72 return parameters;
73}
74
75static inline RTCRtpHeaderExtensionParameters toRTCHeaderExtensionParameters(const webrtc::RtpHeaderExtensionParameters& rtcParameters)
76{
77 RTCRtpHeaderExtensionParameters parameters;
78
79 parameters.uri = fromStdString(rtcParameters.uri);
80 parameters.id = rtcParameters.id;
81
82 return parameters;
83}
84
85static inline webrtc::RtpHeaderExtensionParameters fromRTCHeaderExtensionParameters(const RTCRtpHeaderExtensionParameters& parameters)
86{
87 webrtc::RtpHeaderExtensionParameters rtcParameters;
88
89 rtcParameters.uri = parameters.uri.utf8().data();
90 rtcParameters.id = parameters.id;
91
92 return rtcParameters;
93}
94
95static inline RTCRtpCodecParameters toRTCCodecParameters(const webrtc::RtpCodecParameters& rtcParameters)
96{
97 RTCRtpCodecParameters parameters;
98
99 parameters.payloadType = rtcParameters.payload_type;
100 parameters.mimeType = fromStdString(rtcParameters.mime_type());
101 if (rtcParameters.clock_rate)
102 parameters.clockRate = *rtcParameters.clock_rate;
103 if (rtcParameters.num_channels)
104 parameters.channels = *rtcParameters.num_channels;
105
106 StringBuilder sdpFmtpLineBuilder;
107 sdpFmtpLineBuilder.appendLiteral("a=fmtp:");
108 sdpFmtpLineBuilder.appendNumber(parameters.payloadType);
109 sdpFmtpLineBuilder.append(' ');
110
111 bool isFirst = true;
112 for (auto& keyValue : rtcParameters.parameters) {
113 if (!isFirst)
114 sdpFmtpLineBuilder.append(';');
115 else
116 isFirst = false;
117
118 sdpFmtpLineBuilder.append(StringView { keyValue.first.c_str() });
119 sdpFmtpLineBuilder.append('=');
120 sdpFmtpLineBuilder.append(StringView { keyValue.second.c_str() });
121 }
122 parameters.sdpFmtpLine = sdpFmtpLineBuilder.toString();
123
124 return parameters;
125}
126
127RTCRtpParameters toRTCRtpParameters(const webrtc::RtpParameters& rtcParameters)
128{
129 RTCRtpParameters parameters;
130
131 for (auto& extension : rtcParameters.header_extensions)
132 parameters.headerExtensions.append(toRTCHeaderExtensionParameters(extension));
133 for (auto& codec : rtcParameters.codecs)
134 parameters.codecs.append(toRTCCodecParameters(codec));
135
136 return parameters;
137}
138
139RTCRtpSendParameters toRTCRtpSendParameters(const webrtc::RtpParameters& rtcParameters)
140{
141 RTCRtpSendParameters parameters { toRTCRtpParameters(rtcParameters) };
142
143 parameters.transactionId = fromStdString(rtcParameters.transaction_id);
144 for (auto& rtcEncoding : rtcParameters.encodings)
145 parameters.encodings.append(toRTCEncodingParameters(rtcEncoding));
146
147 switch (rtcParameters.degradation_preference) {
148 // FIXME: Support DegradationPreference::DISABLED.
149 case webrtc::DegradationPreference::DISABLED:
150 case webrtc::DegradationPreference::MAINTAIN_FRAMERATE:
151 parameters.degradationPreference = RTCDegradationPreference::MaintainFramerate;
152 break;
153 case webrtc::DegradationPreference::MAINTAIN_RESOLUTION:
154 parameters.degradationPreference = RTCDegradationPreference::MaintainResolution;
155 break;
156 case webrtc::DegradationPreference::BALANCED:
157 parameters.degradationPreference = RTCDegradationPreference::Balanced;
158 break;
159 };
160 return parameters;
161}
162
163void updateRTCRtpSendParameters(const RTCRtpSendParameters& parameters, webrtc::RtpParameters& rtcParameters)
164{
165 rtcParameters.transaction_id = parameters.transactionId.utf8().data();
166
167 if (parameters.encodings.size() != rtcParameters.encodings.size()) {
168 // If encodings size is different, setting parameters will fail. Let's make it so.
169 rtcParameters.encodings.clear();
170 return;
171 }
172
173 // We copy all current encodings parameters and only update parameters that can actually be usefully updated.
174 for (size_t i = 0; i < parameters.encodings.size(); ++i) {
175 rtcParameters.encodings[i].active = parameters.encodings[i].active;
176 if (parameters.encodings[i].maxBitrate)
177 rtcParameters.encodings[i].max_bitrate_bps = parameters.encodings[i].maxBitrate;
178 if (parameters.encodings[i].maxFramerate)
179 rtcParameters.encodings[i].max_framerate = parameters.encodings[i].maxFramerate;
180 }
181
182 rtcParameters.header_extensions.clear();
183 for (auto& extension : parameters.headerExtensions)
184 rtcParameters.header_extensions.push_back(fromRTCHeaderExtensionParameters(extension));
185 // Codecs parameters are readonly
186
187 switch (parameters.degradationPreference) {
188 case RTCDegradationPreference::MaintainFramerate:
189 rtcParameters.degradation_preference = webrtc::DegradationPreference::MAINTAIN_FRAMERATE;
190 break;
191 case RTCDegradationPreference::MaintainResolution:
192 rtcParameters.degradation_preference = webrtc::DegradationPreference::MAINTAIN_RESOLUTION;
193 break;
194 case RTCDegradationPreference::Balanced:
195 rtcParameters.degradation_preference = webrtc::DegradationPreference::BALANCED;
196 break;
197 }
198}
199
200RTCRtpTransceiverDirection toRTCRtpTransceiverDirection(webrtc::RtpTransceiverDirection rtcDirection)
201{
202 switch (rtcDirection) {
203 case webrtc::RtpTransceiverDirection::kSendRecv:
204 return RTCRtpTransceiverDirection::Sendrecv;
205 case webrtc::RtpTransceiverDirection::kSendOnly:
206 return RTCRtpTransceiverDirection::Sendonly;
207 case webrtc::RtpTransceiverDirection::kRecvOnly:
208 return RTCRtpTransceiverDirection::Recvonly;
209 case webrtc::RtpTransceiverDirection::kInactive:
210 return RTCRtpTransceiverDirection::Inactive;
211 };
212
213 RELEASE_ASSERT_NOT_REACHED();
214}
215
216webrtc::RtpTransceiverDirection fromRTCRtpTransceiverDirection(RTCRtpTransceiverDirection direction)
217{
218 switch (direction) {
219 case RTCRtpTransceiverDirection::Sendrecv:
220 return webrtc::RtpTransceiverDirection::kSendRecv;
221 case RTCRtpTransceiverDirection::Sendonly:
222 return webrtc::RtpTransceiverDirection::kSendOnly;
223 case RTCRtpTransceiverDirection::Recvonly:
224 return webrtc::RtpTransceiverDirection::kRecvOnly;
225 case RTCRtpTransceiverDirection::Inactive:
226 return webrtc::RtpTransceiverDirection::kInactive;
227 };
228
229 RELEASE_ASSERT_NOT_REACHED();
230}
231
232webrtc::RtpTransceiverInit fromRtpTransceiverInit(const RTCRtpTransceiverInit& init)
233{
234 webrtc::RtpTransceiverInit rtcInit;
235 rtcInit.direction = fromRTCRtpTransceiverDirection(init.direction);
236 for (auto& stream : init.streams)
237 rtcInit.stream_ids.push_back(stream->id().utf8().data());
238 return rtcInit;
239}
240
241} // namespace WebCore
242
243#endif // USE(LIBWEBRTC)
244