1 /* 2 * Jicofo, the Jitsi Conference Focus. 3 * 4 * Copyright @ 2015 Atlassian Pty Ltd 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.jitsi.jicofo.util; 19 20 import org.jitsi.xmpp.extensions.jingle.*; 21 22 import org.jitsi.service.configuration.*; 23 import org.jitsi.service.neomedia.*; 24 import org.jitsi.service.neomedia.codec.*; 25 import org.jitsi.utils.*; 26 27 import java.net.*; 28 import java.util.*; 29 30 /** 31 * Contains factory methods for creating Jingle offer sent in 'session-invite' 32 * by Jitsi Meet conference focus. 33 * 34 * @author Pawel Domas 35 * @author George Politis 36 * @author Boris Grozev 37 * @author Lyubomir Marinov 38 */ 39 public class JingleOfferFactory 40 { 41 /** 42 * The property name of the VP8 payload type to include in the Jingle 43 * session-invite. 44 */ 45 public static final String VP8_PT_PNAME = "org.jitsi.jicofo.VP8_PT"; 46 47 /** 48 * The name of the property which enables VP8. 49 */ 50 public static final String ENABLE_VP8_PNAME 51 = "org.jitsi.jicofo.ENABLE_VP8"; 52 53 /** 54 * The property name of the VP8 RTX payload type to include in the Jingle 55 * session-invite. 56 */ 57 public static final String VP8_RTX_PT_PNAME = "org.jitsi.jicofo.VP8_RTX_PT"; 58 59 /** 60 * The property name of the VP9 payload type to include in the Jingle 61 * session-invite. 62 */ 63 public static final String VP9_PT_PNAME = "org.jitsi.jicofo.VP9_PT"; 64 65 /** 66 * The name of the property which enables VP9. 67 */ 68 public static final String ENABLE_VP9_PNAME 69 = "org.jitsi.jicofo.ENABLE_VP9"; 70 71 /** 72 * The property name of the VP9 RTX payload type to include in the Jingle 73 * session-invite. 74 */ 75 public static final String VP9_RTX_PT_PNAME 76 = "org.jitsi.jicofo.VP9_RTX_PT"; 77 78 /** 79 * The property name of the H264 payload type to include in the Jingle 80 * session-invite. 81 */ 82 public static final String H264_PT_PNAME = "org.jitsi.jicofo.H264_PT"; 83 84 /** 85 * The name of the property which enables H264. 86 */ 87 public static final String ENABLE_H264_PNAME 88 = "org.jitsi.jicofo.ENABLE_H264"; 89 90 /** 91 * The property name of the H264 RTX payload type to include in the Jingle 92 * session-invite. 93 */ 94 public static final String H264_RTX_PT_PNAME 95 = "org.jitsi.jicofo.H264_RTX_PT"; 96 97 /** 98 * The name of the property which enables the inclusion of the 99 * framemarking RTP header extension in the offer. 100 */ 101 public static final String ENABLE_FRAMEMARKING_PNAME 102 = "org.jitsi.jicofo.ENABLE_FRAMEMARKING"; 103 104 /** 105 * The name of the property which enables the inclusion of the AST RTP 106 * header extension in the offer. 107 */ 108 public static final String ENABLE_AST_PNAME = "org.jitsi.jicofo.ENABLE_AST"; 109 110 /** 111 * The name of the property which enables the inclusion of the TOF RTP 112 * header extension in the offer. 113 */ 114 public static final String ENABLE_TOF_PNAME = "org.jitsi.jicofo.ENABLE_TOF"; 115 116 /** 117 * The name of the property which enables the inclusion of the video content 118 * type RTP header extension. 119 */ 120 public static final String ENABLE_VIDEO_CONTENT_TYPE_PNAME 121 = "org.jitsi.jicofo.ENABLE_VIDEO_CONTENT_TYPE"; 122 123 /** 124 * The name of the property which enables the inclusion of the RID RTP 125 * header extension. 126 */ 127 public static final String ENABLE_RID_PNAME = "org.jitsi.jicofo.ENABLE_RID"; 128 129 /** 130 * The ID of the transport-cc header extension. 131 */ 132 private static final String TRANSPORT_CC_ID = "5"; 133 134 /** 135 * The VP8 payload type to include in the Jingle session-invite. 136 */ 137 private final int VP8_PT; 138 139 /** 140 * Whether VP8 is enabled. 141 */ 142 private final boolean ENABLE_VP8; 143 144 /** 145 * The VP8 RTX payload type to include in the Jingle session-invite. 146 */ 147 private final int VP8_RTX_PT; 148 149 /** 150 * The VP9 payload type to include in the Jingle session-invite. 151 */ 152 private final int VP9_PT; 153 154 /** 155 * Whether VP9 is enabled. 156 */ 157 private final boolean ENABLE_VP9; 158 159 /** 160 * The VP9 RTX payload type to include in the Jingle session-invite. 161 */ 162 private final int VP9_RTX_PT; 163 164 /** 165 * The H264 payload type to include in the Jingle session-invite. 166 */ 167 private final int H264_PT; 168 169 /** 170 * Whether H264 is enabled. 171 */ 172 private final boolean ENABLE_H264; 173 174 /** 175 * The H264 RTX payload type to include in the Jingle session-invite. 176 */ 177 private final int H264_RTX_PT; 178 179 /** 180 * Whether to enable the framemarking RTP header extension in created 181 * offers. 182 */ 183 private final boolean enableFrameMarking; 184 185 /** 186 * Whether to enable the AST RTP header extension in created offers. 187 */ 188 private final boolean enableAst; 189 190 /** 191 * Whether to enable the TOF RTP header extension in created offers. 192 */ 193 private final boolean enableTof; 194 195 /** 196 * Whether to enable the video content type header extension in created 197 * offers. 198 */ 199 private final boolean enableVideoContentType; 200 201 /** 202 * Whether to enable the RID header extension in created offers. 203 */ 204 private final boolean enableRid; 205 206 /** 207 * Ctor. 208 * 209 * @param cfg the {@link ConfigurationService} to pull config options from. 210 */ JingleOfferFactory(ConfigurationService cfg)211 public JingleOfferFactory(ConfigurationService cfg) 212 { 213 VP8_PT = cfg != null ? cfg.getInt(VP8_PT_PNAME, 100) : 100; 214 ENABLE_VP8 = cfg != null ? cfg.getBoolean(ENABLE_VP8_PNAME, true) : true; 215 VP8_RTX_PT = cfg != null ? cfg.getInt(VP8_RTX_PT_PNAME, 96) : 96; 216 VP9_PT = cfg != null ? cfg.getInt(VP9_PT_PNAME, 101) : 101; 217 ENABLE_VP9 = cfg != null ? cfg.getBoolean(ENABLE_VP9_PNAME, true) : true; 218 VP9_RTX_PT = cfg != null ? cfg.getInt(VP9_RTX_PT_PNAME, 97) : 97; 219 H264_PT = cfg != null ? cfg.getInt(H264_PT_PNAME, 107) : 107; 220 ENABLE_H264 = cfg != null ? cfg.getBoolean(ENABLE_H264_PNAME, true) : true; 221 H264_RTX_PT = cfg != null ? cfg.getInt(H264_RTX_PT_PNAME, 99) : 99; 222 enableFrameMarking 223 = cfg != null && cfg.getBoolean(ENABLE_FRAMEMARKING_PNAME, false); 224 225 enableAst = cfg != null && cfg.getBoolean(ENABLE_AST_PNAME, true); 226 227 // TOF is currently disabled, because we don't support it in the bridge 228 // (and currently clients seem to not use it when abs-send-time is 229 // available). 230 enableTof = cfg != null && cfg.getBoolean(ENABLE_TOF_PNAME, false); 231 232 enableVideoContentType = cfg != null 233 && cfg.getBoolean(ENABLE_VIDEO_CONTENT_TYPE_PNAME, false); 234 235 enableRid = cfg != null && cfg.getBoolean(ENABLE_RID_PNAME, false); 236 } 237 238 /** 239 * Creates a {@link ContentPacketExtension} for the audio media type that 240 * will be included in initial conference offer. 241 * 242 * @param disableIce pass <tt>true</tt> if RAW transport instead of ICE 243 * should be indicated in the offer. 244 * @param useDtls whether to add a DTLS element under the transport 245 * elements in the offer. 246 * 247 * @return <tt>ContentPacketExtension</tt> for given media type that will be 248 * used in initial conference offer. 249 */ createAudioContent( boolean disableIce, boolean useDtls, boolean stereo, boolean enableRemb, boolean enableTcc)250 public ContentPacketExtension createAudioContent( 251 boolean disableIce, boolean useDtls, boolean stereo, 252 boolean enableRemb, boolean enableTcc) 253 { 254 ContentPacketExtension content 255 = createContentPacketExtension( 256 MediaType.AUDIO, disableIce, useDtls); 257 258 addAudioToContent(content, stereo, enableRemb, enableTcc); 259 260 return content; 261 } 262 263 /** 264 * Creates a {@link ContentPacketExtension} for the data media type that 265 * will be included in initial conference offer. 266 * 267 * @param disableIce pass <tt>true</tt> if RAW transport instead of ICE 268 * should be indicated in the offer. 269 * @param useDtls whether to add a DTLS element under the transport 270 * elements in the offer. 271 * 272 * @return <tt>ContentPacketExtension</tt> for given media type that will be 273 * used in initial conference offer. 274 */ createDataContent( boolean disableIce, boolean useDtls)275 public ContentPacketExtension createDataContent( 276 boolean disableIce, boolean useDtls) 277 { 278 ContentPacketExtension content 279 = createContentPacketExtension( 280 MediaType.DATA, disableIce, useDtls); 281 282 addDataToContent(content); 283 284 return content; 285 } 286 287 /** 288 * Creates a {@link ContentPacketExtension} for the video media type that 289 * will be included in initial conference offer. 290 * 291 * @param disableIce pass <tt>true</tt> if RAW transport instead of ICE 292 * should be indicated in the offer. 293 * @param useDtls whether to add a DTLS element under the transport 294 * elements in the offer. 295 * @param useRtx whether RTX should be included in the offer. 296 * @param minBitrate the value to set to the "x-google-min-bitrate" fmtp 297 * line for video, or -1 to not add such a line. 298 * @param startBitrate the value to set to the "x-google-start-bitrate" fmtp 299 * line for video, or -1 to not add such a line. 300 * 301 * @return <tt>ContentPacketExtension</tt> for given media type that will be 302 * used in initial conference offer. 303 */ createVideoContent( boolean disableIce, boolean useDtls, boolean useRtx, boolean enableRemb, boolean enableTcc, int minBitrate, int startBitrate)304 public ContentPacketExtension createVideoContent( 305 boolean disableIce, boolean useDtls, boolean useRtx, 306 boolean enableRemb, boolean enableTcc, 307 int minBitrate, int startBitrate) 308 { 309 ContentPacketExtension videoContentPe 310 = createContentPacketExtension( 311 MediaType.VIDEO, disableIce, useDtls); 312 313 addVideoToContent(videoContentPe, useRtx, enableRemb, enableTcc, 314 minBitrate, startBitrate); 315 316 return videoContentPe; 317 } 318 319 /** 320 * Creates <tt>ContentPacketExtension</tt> initialized with type of 321 * the media and basic transport information based on given parameters. 322 * The creator attribute is set to "initiator" and "senders" to "both". 323 * 324 * @param mediaType the <tt>MediaType</tt> for the content 325 * @param disableIce <tt>true</tt> if ICE transport should be disabled 326 * @param useDtls <tt>true</tt> if DTLS should be used on top of ICE 327 * transport(will have effect only if <tt>disableIce</tt></tt> is 328 * <tt>false</tt>) 329 * 330 * @return new, parametrized instance of <tt>ContentPacketExtension</tt>. 331 */ createContentPacketExtension( MediaType mediaType, boolean disableIce, boolean useDtls)332 private static ContentPacketExtension createContentPacketExtension( 333 MediaType mediaType, boolean disableIce, boolean useDtls) 334 { 335 ContentPacketExtension content 336 = new ContentPacketExtension( 337 ContentPacketExtension.CreatorEnum.initiator, 338 mediaType.name().toLowerCase()); 339 340 content.setSenders(ContentPacketExtension.SendersEnum.both); 341 342 if (!disableIce) 343 { 344 IceUdpTransportPacketExtension iceUdpTransportPacketExtension 345 = new IceUdpTransportPacketExtension(); 346 347 if (useDtls) 348 { 349 iceUdpTransportPacketExtension 350 .addChildExtension(new DtlsFingerprintPacketExtension()); 351 } 352 353 content.addChildExtension(iceUdpTransportPacketExtension); 354 } 355 else 356 { 357 content.addChildExtension(new RawUdpTransportPacketExtension()); 358 } 359 360 return content; 361 } 362 363 /** 364 * Adds the audio-related extensions for an offer to a 365 * {@link ContentPacketExtension}. 366 * @param content the {@link ContentPacketExtension} to add extensions to. 367 */ addVideoToContent(ContentPacketExtension content, boolean useRtx, boolean enableRemb, boolean enableTcc, int minBitrate, int startBitrate)368 private void addVideoToContent(ContentPacketExtension content, 369 boolean useRtx, 370 boolean enableRemb, 371 boolean enableTcc, 372 int minBitrate, 373 int startBitrate) 374 { 375 RtpDescriptionPacketExtension rtpDesc 376 = new RtpDescriptionPacketExtension(); 377 378 rtpDesc.setMedia("video"); 379 380 if (enableTof) 381 { 382 // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset 383 RTPHdrExtPacketExtension toOffset = new RTPHdrExtPacketExtension(); 384 toOffset.setID("2"); 385 toOffset.setURI(URI.create(RTPExtension.TOF_URN)); 386 rtpDesc.addExtmap(toOffset); 387 } 388 389 if (enableAst) 390 { 391 // a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time 392 RTPHdrExtPacketExtension absSendTime 393 = new RTPHdrExtPacketExtension(); 394 absSendTime.setID("3"); 395 absSendTime.setURI(URI.create(RTPExtension.ABS_SEND_TIME_URN)); 396 rtpDesc.addExtmap(absSendTime); 397 } 398 399 if (enableFrameMarking) 400 { 401 // a=extmap:9 urn:ietf:params:rtp-hdrext:framemarking 402 RTPHdrExtPacketExtension framemarking 403 = new RTPHdrExtPacketExtension(); 404 framemarking.setID("9"); 405 framemarking.setURI(URI.create(RTPExtension.FRAME_MARKING_URN)); 406 rtpDesc.addExtmap(framemarking); 407 } 408 409 if (enableVideoContentType) 410 { 411 // http://www.webrtc.org/experiments/rtp-hdrext/video-content-type 412 RTPHdrExtPacketExtension videoContentType 413 = new RTPHdrExtPacketExtension(); 414 videoContentType.setID("7"); 415 videoContentType.setURI(URI.create(RTPExtension.VIDEO_CONTENT_TYPE_URN)); 416 rtpDesc.addExtmap(videoContentType); 417 } 418 419 if (enableRid) 420 { 421 RTPHdrExtPacketExtension rtpStreamId = new RTPHdrExtPacketExtension(); 422 rtpStreamId.setID("4"); 423 rtpStreamId.setURI(URI.create(RTPExtension.RTP_STREAM_ID_URN)); 424 rtpDesc.addExtmap(rtpStreamId); 425 } 426 427 if (ENABLE_VP8 && VP8_PT > 0) 428 { 429 // a=rtpmap:XXX VP8/90000 430 PayloadTypePacketExtension vp8 431 = addPayloadTypeExtension(rtpDesc, VP8_PT, Constants.VP8, 90000); 432 433 addExtensionsToVideoPayloadType( 434 vp8, minBitrate, startBitrate, enableRemb, enableTcc); 435 } 436 437 if (ENABLE_H264 && H264_PT > 0) 438 { 439 // a=rtpmap:XXX H264/90000 440 PayloadTypePacketExtension h264 = addPayloadTypeExtension( 441 // XXX(gp): older Chrome versions (users have reported 53/55/61) 442 // fail to enable h264, if the encoding name is in lower case. 443 rtpDesc, H264_PT, Constants.H264.toUpperCase(), 90000); 444 445 addExtensionsToVideoPayloadType( 446 h264, minBitrate, startBitrate, enableRemb, enableTcc); 447 addParameterExtension( 448 h264, 449 "profile-level-id", 450 "42e01f;level-asymmetry-allowed=1;packetization-mode=1;"); 451 } 452 453 if (ENABLE_VP9 && VP9_PT > 0) 454 { 455 // a=rtpmap:XXX VP9/90000 456 PayloadTypePacketExtension vp9 457 = addPayloadTypeExtension(rtpDesc, VP9_PT, Constants.VP9, 90000); 458 459 addExtensionsToVideoPayloadType( 460 vp9, minBitrate, startBitrate, enableRemb, enableTcc); 461 } 462 463 464 if (enableTcc) 465 { 466 // a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 467 RTPHdrExtPacketExtension tcc = new RTPHdrExtPacketExtension(); 468 tcc.setID(TRANSPORT_CC_ID); 469 tcc.setURI(URI.create(RTPExtension.TRANSPORT_CC_URN)); 470 rtpDesc.addExtmap(tcc); 471 } 472 473 474 if (useRtx) 475 { 476 if (ENABLE_VP8 && VP8_RTX_PT > 0 && VP8_PT > 0) 477 { 478 // a=rtpmap:96 rtx/90000 479 PayloadTypePacketExtension rtx = addPayloadTypeExtension( 480 rtpDesc, VP8_RTX_PT, Constants.RTX, 90000); 481 482 // a=fmtp:96 apt=100 483 addParameterExtension(rtx, "apt", String.valueOf(VP8_PT)); 484 485 // Chrome doesn't have these when it creates an offer, but they were 486 // observed in a hangouts conference. Not sure whether they have any 487 // effect. 488 // a=rtcp-fb:96 ccm fir 489 rtx.addRtcpFeedbackType(createRtcpFbPacketExtension("ccm", "fir")); 490 491 // a=rtcp-fb:96 nack 492 rtx.addRtcpFeedbackType(createRtcpFbPacketExtension("nack", null)); 493 494 // a=rtcp-fb:96 nack pli 495 rtx.addRtcpFeedbackType(createRtcpFbPacketExtension("nack", "pli")); 496 } 497 498 if (ENABLE_VP9 && VP9_RTX_PT > 0 && VP9_PT > 0) 499 { 500 // a=rtpmap:97 rtx/90000 501 PayloadTypePacketExtension rtxVP9 = addPayloadTypeExtension( 502 rtpDesc, VP9_RTX_PT, Constants.RTX, 90000); 503 504 // a=fmtp:97 apt=101 505 addParameterExtension(rtxVP9, "apt", String.valueOf(VP9_PT)); 506 } 507 508 if (ENABLE_H264 && H264_RTX_PT > 0 && H264_PT > 0) 509 { 510 // a=rtpmap:99 rtx/90000 511 PayloadTypePacketExtension rtxH264 = addPayloadTypeExtension( 512 rtpDesc, H264_RTX_PT, Constants.RTX, 90000); 513 514 // a=fmtp:99 apt=107 515 addParameterExtension(rtxH264, "apt", String.valueOf(H264_PT)); 516 } 517 } 518 519 // a=rtpmap:116 red/90000 520 //addPayloadTypeExtension(rtpDesc, 116, Constants.RED, 90000); 521 522 // a=rtpmap:117 ulpfec/90000 523 //addPayloadTypeExtension(rtpDesc, 117, Constants.ULPFEC, 90000); 524 525 content.addChildExtension(rtpDesc); 526 } 527 528 /** 529 * Adds a {@link ParameterPacketExtension} with a given name and value 530 * to a given {@link PayloadTypePacketExtension}. 531 * @param ptExt the extension to add to. 532 * @param name the name of the parameter to add. 533 * @param value the value of the parameter to add. 534 * @return the added extension. 535 */ addParameterExtension( PayloadTypePacketExtension ptExt, String name, String value)536 private static ParameterPacketExtension addParameterExtension( 537 PayloadTypePacketExtension ptExt, 538 String name, String value) 539 { 540 ParameterPacketExtension parameterPacketExtension 541 = new ParameterPacketExtension(); 542 parameterPacketExtension.setName(name); 543 parameterPacketExtension.setValue(value); 544 ptExt.addParameter(parameterPacketExtension); 545 546 return parameterPacketExtension; 547 } 548 addExtensionsToVideoPayloadType( PayloadTypePacketExtension pt, int minBitrate, int startBitrate, boolean enableRemb, boolean enableTcc)549 private static void addExtensionsToVideoPayloadType( 550 PayloadTypePacketExtension pt, 551 int minBitrate, 552 int startBitrate, 553 boolean enableRemb, 554 boolean enableTcc) 555 { 556 // a=rtcp-fb:XXX ccm fir 557 pt.addRtcpFeedbackType(createRtcpFbPacketExtension("ccm", "fir")); 558 559 // a=rtcp-fb:XXX nack 560 pt.addRtcpFeedbackType(createRtcpFbPacketExtension("nack", null)); 561 562 // a=rtcp-fb:XXX nack pli 563 pt.addRtcpFeedbackType(createRtcpFbPacketExtension("nack", "pli")); 564 565 566 if (minBitrate != -1) 567 { 568 addParameterExtension( 569 pt, "x-google-min-bitrate", String.valueOf(minBitrate)); 570 } 571 572 if (startBitrate != -1) 573 { 574 addParameterExtension( 575 pt, "x-google-start-bitrate", String.valueOf(startBitrate)); 576 } 577 578 if (enableRemb) 579 { 580 // a=rtcp-fb:XXX goog-remb 581 pt.addRtcpFeedbackType( 582 createRtcpFbPacketExtension("goog-remb", null)); 583 } 584 585 if (enableTcc) 586 { 587 // a=rtcp-fb:XXX transport-cc 588 pt.addRtcpFeedbackType( 589 createRtcpFbPacketExtension("transport-cc", null)); 590 } 591 592 } 593 594 /** 595 * Creates an {@link RtcpFbPacketExtension} with the given type and subtype. 596 * @return the created extension. 597 */ createRtcpFbPacketExtension( String type, String subtype)598 private static RtcpFbPacketExtension createRtcpFbPacketExtension( 599 String type, String subtype) 600 { 601 RtcpFbPacketExtension rtcpFb = new RtcpFbPacketExtension(); 602 if (type != null) 603 { 604 rtcpFb.setFeedbackType(type); 605 } 606 if (subtype != null) 607 { 608 rtcpFb.setFeedbackSubtype(subtype); 609 } 610 611 return rtcpFb; 612 } 613 614 /** 615 * Adds a {@link PayloadTypePacketExtension} to a 616 * {@link RtpDescriptionPacketExtension}. 617 * @param rtpDesc the {@link RtpDescriptionPacketExtension} to add to. 618 * @param id the ID of the {@link PayloadTypePacketExtension}. 619 * @param name the name of the {@link PayloadTypePacketExtension}. 620 * @param clockRate the clock rate of the {@link PayloadTypePacketExtension}. 621 * @return the added {@link PayloadTypePacketExtension}. 622 */ addPayloadTypeExtension( RtpDescriptionPacketExtension rtpDesc, int id, String name, int clockRate)623 private static PayloadTypePacketExtension addPayloadTypeExtension( 624 RtpDescriptionPacketExtension rtpDesc, int id, String name, 625 int clockRate) 626 { 627 PayloadTypePacketExtension payloadTypePacketExtension 628 = new PayloadTypePacketExtension(); 629 payloadTypePacketExtension.setId(id); 630 payloadTypePacketExtension.setName(name); 631 payloadTypePacketExtension.setClockrate(clockRate); 632 633 rtpDesc.addPayloadType(payloadTypePacketExtension); 634 return payloadTypePacketExtension; 635 } 636 637 /** 638 * Adds the video-related extensions for an offer to a 639 * {@link ContentPacketExtension}. 640 * @param content the {@link ContentPacketExtension} to add extensions to. 641 * @param stereo Whether to enable stereo for opus. 642 * @param enableRemb Whether to enable REMB. 643 * @param enableTcc Whether to enable transport-cc. 644 */ addAudioToContent(ContentPacketExtension content, boolean stereo, boolean enableRemb, boolean enableTcc)645 private static void addAudioToContent(ContentPacketExtension content, 646 boolean stereo, boolean enableRemb, 647 boolean enableTcc) 648 { 649 RtpDescriptionPacketExtension rtpDesc 650 = new RtpDescriptionPacketExtension(); 651 652 rtpDesc.setMedia("audio"); 653 654 RTPHdrExtPacketExtension ssrcAudioLevel 655 = new RTPHdrExtPacketExtension(); 656 ssrcAudioLevel.setID("1"); 657 ssrcAudioLevel.setURI(URI.create(RTPExtension.SSRC_AUDIO_LEVEL_URN)); 658 rtpDesc.addExtmap(ssrcAudioLevel); 659 660 // a=rtpmap:111 opus/48000/2 661 PayloadTypePacketExtension opus 662 = addPayloadTypeExtension(rtpDesc, 111, Constants.OPUS, 48000); 663 opus.setChannels(2); 664 665 // fmtp:111 minptime=10 666 addParameterExtension(opus, "minptime", "10"); 667 668 if (stereo) 669 { 670 // fmtp: 111 stereo=1 671 addParameterExtension(opus, "stereo", "1"); 672 } 673 674 // fmtp:111 useinbandfec=1 675 addParameterExtension(opus, "useinbandfec", "1"); 676 677 if (enableTcc) 678 { 679 // a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 680 RTPHdrExtPacketExtension tcc = new RTPHdrExtPacketExtension(); 681 tcc.setID(TRANSPORT_CC_ID); 682 tcc.setURI(URI.create(RTPExtension.TRANSPORT_CC_URN)); 683 rtpDesc.addExtmap(tcc); 684 685 // a=rtcp-fb:111 transport-cc 686 opus.addRtcpFeedbackType( 687 createRtcpFbPacketExtension("transport-cc", null)); 688 } 689 690 // a=rtpmap:103 ISAC/16000 691 addPayloadTypeExtension(rtpDesc, 103, "ISAC", 16000); 692 693 // a=rtpmap:104 ISAC/32000 694 addPayloadTypeExtension(rtpDesc, 104, "ISAC", 32000); 695 696 // rtpmap:126 telephone-event/8000 697 addPayloadTypeExtension(rtpDesc, 126, Constants.TELEPHONE_EVENT, 8000); 698 699 // a=maxptime:60 700 rtpDesc.setAttribute("maxptime", "60"); 701 content.addChildExtension(rtpDesc); 702 } 703 704 /** 705 * Adds the data-related extensions for an offer to a 706 * {@link ContentPacketExtension}. 707 * @param content the {@link ContentPacketExtension} to add extensions to. 708 */ addDataToContent(ContentPacketExtension content)709 private static void addDataToContent(ContentPacketExtension content) 710 { 711 //SctpMapExtension sctpMap = new SctpMapExtension(); 712 //sctpMap.setPort(5000); 713 //sctpMap.setProtocol(SctpMapExtension.Protocol.WEBRTC_CHANNEL); 714 //sctpMap.setStreams(1024); 715 //content.addChildExtension(sctpMap); 716 717 RtpDescriptionPacketExtension rdpe 718 = new RtpDescriptionPacketExtension(); 719 rdpe.setMedia("application"); 720 721 content.addChildExtension(rdpe); 722 } 723 724 /** 725 * Check if given offer contains video contents. 726 * @param contents the list of <tt>ContentPacketExtension</tt> describing 727 * Jingle offer. 728 * @return <tt>true</tt> if given offer has video content. 729 */ containsVideoContent( List<ContentPacketExtension> contents)730 public static boolean containsVideoContent( 731 List<ContentPacketExtension> contents) 732 { 733 for (ContentPacketExtension content : contents) 734 { 735 if (content.getName().equalsIgnoreCase("video")) 736 { 737 return true; 738 } 739 } 740 return false; 741 } 742 } 743