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 mock; 19 20 import mock.muc.*; 21 import mock.util.*; 22 import mock.xmpp.*; 23 24 import org.jitsi.xmpp.extensions.colibri.*; 25 import org.jitsi.xmpp.extensions.jingle.*; 26 import org.jitsi.xmpp.extensions.jitsimeet.*; 27 import net.java.sip.communicator.util.*; 28 29 import org.jitsi.impl.protocol.xmpp.*; 30 import org.jitsi.protocol.xmpp.*; 31 import org.jitsi.protocol.xmpp.util.*; 32 import org.jivesoftware.smack.packet.*; 33 import org.jivesoftware.smack.packet.id.*; 34 import org.jxmpp.jid.*; 35 import org.jxmpp.jid.impl.*; 36 import org.jxmpp.stringprep.*; 37 38 import java.util.*; 39 import java.util.concurrent.*; 40 41 /** 42 * 43 */ 44 public class MockParticipant 45 { 46 /** 47 * The logger. 48 */ 49 private final static Logger logger 50 = Logger.getLogger(MockParticipant.class); 51 52 private final static Random random = new Random(System.nanoTime()); 53 54 private final String nick; 55 56 private final boolean useBundle; 57 58 private XmppPeer xmppPeer; 59 60 private MockRoomMember user; 61 62 private XmppConnection mockConnection; 63 64 private UtilityJingleOpSet jingle; 65 66 private ArrayList<ContentPacketExtension> myContents; 67 68 private final Object sourceLock = new Object(); 69 70 private final Object joinLock = new Object(); 71 72 private MediaSourceMap remoteSSRCs = new MediaSourceMap(); 73 74 private MediaSourceGroupMap remoteSSRCgroups = new MediaSourceGroupMap(); 75 76 private HashMap<String, IceUdpTransportPacketExtension> transportMap; 77 78 private JingleSession jingleSession; 79 80 private JingleHandler jingleHandler = new JingleHandler(); 81 82 private Jid myJid; 83 84 private Jid remoteJid; 85 86 private MediaSourceMap localSSRCs = new MediaSourceMap(); 87 88 private MediaSourceGroupMap localSSRCGroups = new MediaSourceGroupMap(); 89 90 private String ssrcVideoType = SSRCInfoPacketExtension.CAMERA_VIDEO_TYPE; 91 92 private boolean useSsrcGroups; 93 94 private BlockingQueue<JingleIQ> ssrcAddQueue 95 = new LinkedBlockingQueue<>(); 96 97 private BlockingQueue<JingleIQ> ssrcRemoveQueue 98 = new LinkedBlockingQueue<>(); 99 MockParticipant(String nick)100 public MockParticipant(String nick) 101 { 102 this(nick, true); 103 } 104 MockParticipant(String nick, boolean useBundle)105 public MockParticipant(String nick, boolean useBundle) 106 { 107 this.nick = nick; 108 this.useBundle = useBundle; 109 } 110 getChatMember()111 public MockRoomMember getChatMember() 112 { 113 return user; 114 } 115 joinInNewThread(final MockMultiUserChat chat)116 public void joinInNewThread(final MockMultiUserChat chat) 117 { 118 new Thread(new Runnable() 119 { 120 @Override 121 public void run() 122 { 123 join(chat); 124 } 125 }).start(); 126 } 127 waitForJoinThread(long timeout)128 public void waitForJoinThread(long timeout) 129 throws InterruptedException 130 { 131 synchronized (joinLock) 132 { 133 if (xmppPeer == null) 134 { 135 joinLock.wait(timeout); 136 } 137 if (xmppPeer == null) 138 { 139 throw new RuntimeException( 140 "Failed to join the room within" + 141 " the time limit specified: " + timeout); 142 } 143 } 144 } 145 join(MockMultiUserChat chat)146 public void join(MockMultiUserChat chat) 147 { 148 try 149 { 150 user = chat.createMockRoomMember(nick); 151 } 152 catch (XmppStringprepException e) 153 { 154 throw new RuntimeException(e); 155 } 156 157 user.setupFeatures(useBundle); 158 159 160 try 161 { 162 myJid = JidCreate.entityFullFrom(chat.getName() + "/" + user.getName()); 163 } 164 catch (XmppStringprepException e) 165 { 166 throw new RuntimeException(e); 167 } 168 169 mockConnection = new MockXmppConnection(myJid); 170 jingle = new UtilityJingleOpSet(mockConnection); 171 jingle.mockParticipant = this; 172 mockConnection.registerIQRequestHandler(jingle); 173 174 chat.mockJoin(user); 175 synchronized (joinLock) 176 { 177 xmppPeer = new XmppPeer(user.getJid(), mockConnection); 178 xmppPeer.start(); 179 joinLock.notifyAll(); 180 } 181 } 182 nextSSRC()183 public static long nextSSRC() 184 { 185 return random.nextInt(Integer.MAX_VALUE); 186 } 187 newSSRC(long ssrc, String ssrcVideoType)188 private SourcePacketExtension newSSRC(long ssrc, String ssrcVideoType) 189 { 190 SourcePacketExtension ssrcPe = new SourcePacketExtension(); 191 192 ssrcPe.setSSRC(ssrc); 193 194 SSRCSignaling.setSSRCOwner(ssrcPe, myJid); 195 196 if (ssrcVideoType != null) 197 SSRCSignaling.setSSRCVideoType(ssrcPe, ssrcVideoType); 198 199 return ssrcPe; 200 } 201 initContents()202 private void initContents() 203 { 204 myContents = new ArrayList<>(); 205 206 // AUDIO 207 ContentPacketExtension audio = new ContentPacketExtension(); 208 audio.setName("audio"); 209 210 RtpDescriptionPacketExtension audioRtpDesc 211 = new RtpDescriptionPacketExtension(); 212 audioRtpDesc.setMedia("audio"); 213 audio.addChildExtension(audioRtpDesc); 214 215 addLocalAudioSSRC(nextSSRC()); 216 217 for (SourcePacketExtension ssrc : localSSRCs.getSourcesForMedia("audio")) 218 { 219 audioRtpDesc.addChildExtension(ssrc); 220 } 221 222 myContents.add(audio); 223 224 // VIDEO 225 ContentPacketExtension video = new ContentPacketExtension(); 226 video.setName("video"); 227 228 RtpDescriptionPacketExtension videoRtpDesc 229 = new RtpDescriptionPacketExtension(); 230 videoRtpDesc.setMedia("video"); 231 video.addChildExtension(videoRtpDesc); 232 233 // Add video SSRC 234 addLocalVideoSSRC(nextSSRC(), ssrcVideoType); 235 if (useSsrcGroups) 236 { 237 // 2nd video SSRC 238 addLocalVideoSSRC(nextSSRC(), ssrcVideoType); 239 } 240 241 for (SourcePacketExtension videoSSRC : getVideoSSRCS()) 242 { 243 videoRtpDesc.addChildExtension(videoSSRC); 244 } 245 246 if (useSsrcGroups) 247 { 248 // Video SSRC group 249 SourceGroup videoGroup = getLocalSSRCGroup("video"); 250 videoGroup.addSources(getVideoSSRCS()); 251 252 videoRtpDesc.addChildExtension(videoGroup.getExtensionCopy()); 253 } 254 255 myContents.add(video); 256 } 257 acceptInviteInBg()258 public void acceptInviteInBg() 259 { 260 new Thread(new Runnable() 261 { 262 @Override 263 public void run() 264 { 265 try 266 { 267 acceptInvite(5000); 268 } 269 catch (InterruptedException e) 270 { 271 logger.error(e, e); 272 Thread.currentThread().interrupt(); 273 } 274 } 275 },"Accept invite " + nick).start(); 276 } 277 acceptInvite(long timeout)278 public JingleIQ[] acceptInvite(long timeout) 279 throws InterruptedException 280 { 281 JingleIQ invite = jingle.acceptSession(timeout, jingleHandler); 282 if (invite == null) 283 { 284 throw new RuntimeException(nick + " - wait for invite timeout"); 285 } 286 287 logger.info(nick + " invite: " + invite.toXML()); 288 289 // ACK invite 290 IQ inviteAck = JingleIQ.createResultIQ(invite); 291 mockConnection.sendStanza(inviteAck); 292 293 initContents(); 294 295 processStanza(invite); 296 297 JingleIQ user1Accept = generateSessionAccept( 298 invite, 299 createTransportMap(invite)); 300 301 logger.info(nick + " accept: " + user1Accept.toXML()); 302 303 mockConnection.sendStanza(user1Accept); 304 305 this.myJid = user1Accept.getFrom(); 306 this.remoteJid = user1Accept.getTo(); 307 this.jingleSession = jingle.getSession(invite.getSID()); 308 309 return new JingleIQ[] { invite, user1Accept }; 310 } 311 leave()312 public void leave() 313 { 314 xmppPeer.stop(); 315 316 user.leave(); 317 } 318 createTransportMap( JingleIQ user1Invite)319 private Map<String, IceUdpTransportPacketExtension> createTransportMap( 320 JingleIQ user1Invite) 321 { 322 this.transportMap = new HashMap<>(); 323 324 for (ContentPacketExtension content : user1Invite.getContentList()) 325 { 326 IceUdpTransportPacketExtension transport 327 = new IceUdpTransportPacketExtension(); 328 329 if (useBundle) 330 { 331 // Bundle uses RTCP mux 332 transport.addChildExtension(new RtcpmuxPacketExtension()); 333 } 334 335 DtlsFingerprintPacketExtension dtlsFingerprint 336 = new DtlsFingerprintPacketExtension(); 337 338 IceUdpTransportPacketExtension offerTransport 339 = content.getFirstChildOfType( 340 IceUdpTransportPacketExtension.class); 341 342 DtlsFingerprintPacketExtension offerFingerprint 343 = offerTransport.getFirstChildOfType( 344 DtlsFingerprintPacketExtension.class); 345 346 dtlsFingerprint.setHash(offerFingerprint.getHash()); 347 dtlsFingerprint.setFingerprint( 348 offerFingerprint.getFingerprint() 349 .replace("A", "B") 350 .replace("1", "2") 351 .replace("C", "D") 352 ); 353 354 transport.addChildExtension(dtlsFingerprint); 355 356 transportMap.put(content.getName(), transport); 357 } 358 359 return transportMap; 360 } 361 generateFakeCandidates()362 public Map<String, IceUdpTransportPacketExtension> generateFakeCandidates() 363 { 364 for (ContentPacketExtension content : myContents) 365 { 366 IceUdpTransportPacketExtension iceTransport 367 = transportMap.get(content.getName()); 368 369 CandidatePacketExtension fakeCandidate 370 = new CandidatePacketExtension(); 371 372 fakeCandidate.setIP("127.0.0.1"); 373 fakeCandidate.setPort(60000); 374 fakeCandidate.setType(CandidateType.host); 375 376 iceTransport.addCandidate(fakeCandidate); 377 } 378 return transportMap; 379 } 380 sendTransportInfo()381 public JingleIQ sendTransportInfo() 382 { 383 List<ContentPacketExtension> contents = new ArrayList<>(); 384 385 for (ContentPacketExtension myContent : myContents) 386 { 387 ContentPacketExtension content = new ContentPacketExtension(); 388 content.setName(myContent.getName()); 389 390 try 391 { 392 IceUdpTransportPacketExtension transportCopy 393 = IceUdpTransportPacketExtension 394 .cloneTransportAndCandidates( 395 transportMap.get(content.getName()), true); 396 397 content.addChildExtension(transportCopy); 398 399 contents.add(content); 400 } 401 catch (Exception e) 402 { 403 throw new RuntimeException(e); 404 } 405 } 406 407 JingleIQ transportInfoIq 408 = JinglePacketFactory.createTransportInfo( 409 myJid, remoteJid, jingleSession.getSessionID(), contents); 410 411 mockConnection.sendStanza(transportInfoIq); 412 413 return transportInfoIq; 414 } 415 generateSessionAccept( JingleIQ sessionInit, Map<String, IceUdpTransportPacketExtension> transportMap)416 private JingleIQ generateSessionAccept( 417 JingleIQ sessionInit, 418 Map<String, IceUdpTransportPacketExtension> transportMap) 419 { 420 JingleIQ accept = new JingleIQ( 421 JingleAction.SESSION_ACCEPT, 422 sessionInit.getSID()); 423 424 accept.setStanzaId(StanzaIdUtil.newStanzaId()); 425 accept.setType(IQ.Type.set); 426 accept.setFrom(sessionInit.getTo()); 427 accept.setTo(sessionInit.getFrom()); 428 429 // Jingle BUNDLE extension 430 accept.addExtension( 431 GroupPacketExtension.createBundleGroup( 432 sessionInit.getContentList())); 433 434 for (ContentPacketExtension contentOffer : myContents) 435 { 436 ContentPacketExtension acceptContent 437 = new ContentPacketExtension(); 438 439 acceptContent.setName(contentOffer.getName()); 440 441 acceptContent.setCreator( 442 ContentPacketExtension.CreatorEnum.responder); 443 444 acceptContent.setSenders(contentOffer.getSenders()); 445 446 acceptContent.addChildExtension( 447 transportMap.get(contentOffer.getName())); 448 449 // Copy RTPDescription 450 acceptContent.addChildExtension( 451 contentOffer.getFirstChildOfType( 452 RtpDescriptionPacketExtension.class)); 453 454 accept.addContent(acceptContent); 455 } 456 457 return accept; 458 } 459 getNickname()460 public String getNickname() 461 { 462 return nick; 463 } 464 processStanza(IQ packet)465 public void processStanza(IQ packet) 466 { 467 JingleIQ modifySSRcIq = (JingleIQ) packet; 468 JingleAction action = modifySSRcIq.getAction(); 469 470 if (JingleAction.SESSION_INITIATE.equals(action)) 471 { 472 synchronized (sourceLock) 473 { 474 MediaSourceMap ssrcMap 475 = MediaSourceMap.getSourcesFromContent( 476 modifySSRcIq.getContentList()); 477 478 remoteSSRCs.add(ssrcMap); 479 480 MediaSourceGroupMap ssrcGroupMap 481 = MediaSourceGroupMap.getSourceGroupsForContents( 482 modifySSRcIq.getContentList()); 483 484 remoteSSRCgroups.add(ssrcGroupMap); 485 486 logger.info(nick + " received session-initiate: " + ssrcMap + " groups: " + ssrcGroupMap); 487 488 sourceLock.notifyAll(); 489 } 490 } 491 else if (JingleAction.SOURCEADD.equals(action) 492 || JingleAction.ADDSOURCE.equals(action)) 493 { 494 synchronized (sourceLock) 495 { 496 MediaSourceMap ssrcMap 497 = MediaSourceMap.getSourcesFromContent( 498 modifySSRcIq.getContentList()); 499 500 remoteSSRCs.add(ssrcMap); 501 502 MediaSourceGroupMap ssrcGroupMap 503 = MediaSourceGroupMap.getSourceGroupsForContents( 504 modifySSRcIq.getContentList()); 505 506 remoteSSRCgroups.add(ssrcGroupMap); 507 508 logger.info(nick + " received source-add " + ssrcMap); 509 510 try 511 { 512 ssrcAddQueue.put(modifySSRcIq); 513 } 514 catch (InterruptedException e) 515 { 516 throw new RuntimeException(e); 517 } 518 519 sourceLock.notifyAll(); 520 } 521 } 522 else if (JingleAction.SOURCEREMOVE.equals(action) 523 || JingleAction.REMOVESOURCE.equals(action)) 524 { 525 synchronized (sourceLock) 526 { 527 MediaSourceMap ssrcsToRemove 528 = MediaSourceMap.getSourcesFromContent( 529 modifySSRcIq.getContentList()); 530 531 remoteSSRCs.remove(ssrcsToRemove); 532 533 MediaSourceGroupMap ssrcGroupsToRemove 534 = MediaSourceGroupMap.getSourceGroupsForContents( 535 modifySSRcIq.getContentList()); 536 537 remoteSSRCgroups.remove(ssrcGroupsToRemove); 538 539 logger.info(nick + " source-remove received " + ssrcsToRemove); 540 541 try 542 { 543 ssrcRemoveQueue.put(modifySSRcIq); 544 } 545 catch (InterruptedException e) 546 { 547 throw new RuntimeException(e); 548 } 549 550 sourceLock.notifyAll(); 551 } 552 } 553 } 554 switchVideoSSRCs(long[] newVideoSSRCs, boolean useSsrcGroups)555 public void switchVideoSSRCs(long[] newVideoSSRCs, boolean useSsrcGroups) 556 { 557 MediaSourceMap toRemove = new MediaSourceMap(); 558 toRemove.addSources("video", localSSRCs.getSourcesForMedia("video")); 559 560 // Send source-remove 561 jingle.sendRemoveSourceIQ( 562 toRemove, localSSRCGroups.copy(), jingleSession); 563 564 // Remove old ssrcs(and clear groups) 565 localSSRCs.remove(toRemove); 566 localSSRCGroups = new MediaSourceGroupMap(); 567 568 videoSourceAdd(newVideoSSRCs, useSsrcGroups); 569 } 570 getLocalSSRCGroup(String media)571 private SourceGroup getLocalSSRCGroup(String media) 572 { 573 List<SourceGroup> videoGroups 574 = localSSRCGroups.getSourceGroupsForMedia(media); 575 SourceGroup group = null; 576 if (videoGroups.size() > 0) 577 { 578 group = videoGroups.get(0); 579 } 580 if (videoGroups.size() == 0) 581 { 582 SourceGroupPacketExtension ssrcGroup 583 = SourceGroupPacketExtension.createSimulcastGroup(); 584 585 group = new SourceGroup(ssrcGroup); 586 587 localSSRCGroups.addSourceGroup(media, group); 588 } 589 return group; 590 } 591 videoSourceAdd(int count)592 public List<SourcePacketExtension> videoSourceAdd(int count) 593 { 594 return sourceAdd("video", count, false, null); 595 } 596 audioSourceAdd(int count)597 public List<SourcePacketExtension> audioSourceAdd(int count) 598 { 599 return sourceAdd("audio", count, false, null); 600 } 601 audioSourceRemove(int count)602 public void audioSourceRemove(int count) 603 { 604 List<SourcePacketExtension> audioSources 605 = this.localSSRCs.getSourcesForMedia("audio"); 606 607 if (audioSources.size() < count) 608 { 609 throw new IllegalArgumentException( 610 "audio source size(" + audioSources.size() 611 + ") < count(" + count + ")"); 612 } 613 614 List<SourcePacketExtension> toRemove = new ArrayList<>(count); 615 616 for(int i = 0; i < count; i++) 617 { 618 toRemove.add(audioSources.remove(0)); 619 } 620 621 MediaSourceMap removeMap = new MediaSourceMap(); 622 623 removeMap.addSources("audio", toRemove); 624 625 jingle.sendRemoveSourceIQ(removeMap, null, jingleSession); 626 } 627 sourceAdd( String media, int count, boolean useGroups, String[] videoTypes)628 private List<SourcePacketExtension> sourceAdd( 629 String media, int count, boolean useGroups, String[] videoTypes) 630 { 631 long[] ssrcs = new long[count]; 632 for (int i=0; i<count; i++) 633 { 634 ssrcs[i] = nextSSRC(); 635 } 636 return sourceAdd(media, ssrcs, useGroups, videoTypes); 637 } 638 videoSourceAdd( long[] newSSRCs, boolean useSsrcGroups)639 public List<SourcePacketExtension> videoSourceAdd( 640 long[] newSSRCs, boolean useSsrcGroups) 641 { 642 return sourceAdd("video", newSSRCs, useSsrcGroups, null); 643 } 644 sourceAdd( String media, long[] newSSRCs, boolean useSsrcGroups, String[] ssrcsVideoTypes)645 public List<SourcePacketExtension> sourceAdd( 646 String media, long[] newSSRCs, boolean useSsrcGroups, String[] ssrcsVideoTypes) 647 { 648 List<SourcePacketExtension> addedSSRCs 649 = new ArrayList<>(newSSRCs.length); 650 MediaSourceMap toAdd = new MediaSourceMap(); 651 SourceGroup sourceGroup = getLocalSSRCGroup(media); 652 653 // Create new SSRCs 654 for (int i=0; i<newSSRCs.length; i++) 655 { 656 String videoType = null; 657 if (ssrcsVideoTypes != null) 658 { 659 videoType = ssrcsVideoTypes[i]; 660 } 661 662 SourcePacketExtension ssrcPe 663 = addLocalSSRC(media, newSSRCs[i], videoType); 664 665 toAdd.addSource(media, ssrcPe); 666 addedSSRCs.add(ssrcPe); 667 668 if (useSsrcGroups) 669 { 670 sourceGroup.addSource(ssrcPe); 671 } 672 } 673 674 // Send source-add 675 jingle.sendAddSourceIQ(toAdd, localSSRCGroups, jingleSession); 676 677 return addedSSRCs; 678 } 679 getRemoteSSRCs(String media)680 public List<SourcePacketExtension> getRemoteSSRCs(String media) 681 { 682 return remoteSSRCs.getSourcesForMedia(media); 683 } 684 getRemoteSSRCGroups(String media)685 public List<SourceGroup> getRemoteSSRCGroups(String media) 686 { 687 return remoteSSRCgroups.getSourceGroupsForMedia(media); 688 } 689 waitForAddSource(long timeout)690 public JingleIQ waitForAddSource(long timeout) 691 throws InterruptedException 692 { 693 return ssrcAddQueue.poll(timeout, TimeUnit.MILLISECONDS); 694 } 695 waitForRemoveSource(long timeout)696 public JingleIQ waitForRemoveSource(long timeout) 697 throws InterruptedException 698 { 699 return ssrcRemoveQueue.poll(timeout, TimeUnit.MILLISECONDS); 700 } 701 waitForSSRCCondition( SSRCCondition condition, long timeout)702 public void waitForSSRCCondition( SSRCCondition condition, 703 long timeout) 704 throws InterruptedException 705 { 706 synchronized (sourceLock) 707 { 708 long start = System.currentTimeMillis(); 709 long end = start + timeout; 710 711 while (!condition.checkCondition(this) && 712 System.currentTimeMillis() < end) 713 { 714 long wait = end - System.currentTimeMillis(); 715 if (wait > 0) 716 { 717 sourceLock.wait(wait); 718 } 719 } 720 721 //if (!condition.checkCondition(this)) 722 // fail(errorMsg); 723 } 724 } 725 isUseSsrcGroups()726 public boolean isUseSsrcGroups() 727 { 728 return useSsrcGroups; 729 } 730 setUseSsrcGroups(boolean useSsrcGroups)731 public void setUseSsrcGroups(boolean useSsrcGroups) 732 { 733 this.useSsrcGroups = useSsrcGroups; 734 } 735 getMyJid()736 public Jid getMyJid() 737 { 738 return myJid; 739 } 740 getVideoSSRCS()741 public List<SourcePacketExtension> getVideoSSRCS() 742 { 743 return localSSRCs.getSourcesForMedia("video"); 744 } 745 getSsrcVideoType()746 public String getSsrcVideoType() 747 { 748 return ssrcVideoType; 749 } 750 setSsrcVideoType(String ssrcVideoType)751 public void setSsrcVideoType(String ssrcVideoType) 752 { 753 this.ssrcVideoType = ssrcVideoType; 754 } 755 addMultipleAudioSSRCs(int count)756 public List<SourcePacketExtension> addMultipleAudioSSRCs(int count) 757 { 758 List<SourcePacketExtension> newSSRCs = new ArrayList<>(count); 759 for (int i=0; i<count; i++) 760 { 761 newSSRCs.add(addLocalAudioSSRC(nextSSRC())); 762 } 763 return newSSRCs; 764 } 765 addMultipleVideoSSRCs(int count)766 public List<SourcePacketExtension> addMultipleVideoSSRCs(int count) 767 { 768 List<SourcePacketExtension> newSSRCs = new ArrayList<>(count); 769 for (int i=0; i<count; i++) 770 { 771 newSSRCs.add(addLocalVideoSSRC(nextSSRC(), null)); 772 } 773 return newSSRCs; 774 } 775 addLocalSSRC( String media, long ssrc, String videoType)776 public SourcePacketExtension addLocalSSRC( 777 String media, long ssrc, String videoType) 778 { 779 SourcePacketExtension newSSRC = newSSRC(ssrc, videoType); 780 781 localSSRCs.addSource(media, newSSRC); 782 783 return newSSRC; 784 } 785 addLocalVideoSSRC(long ssrc, String videoType)786 public SourcePacketExtension addLocalVideoSSRC(long ssrc, String videoType) 787 { 788 return addLocalSSRC("video", ssrc, videoType); 789 } 790 addLocalAudioSSRC(long ssrc)791 public SourcePacketExtension addLocalAudioSSRC(long ssrc) 792 { 793 return addLocalSSRC("audio", ssrc, null); 794 } 795 796 class JingleHandler extends DefaultJingleRequestHandler 797 { 798 799 } 800 801 public interface SSRCCondition 802 { checkCondition(MockParticipant me)803 boolean checkCondition(MockParticipant me); 804 } 805 } 806