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; 19 20 import mock.*; 21 import mock.muc.*; 22 import mock.util.*; 23 24 import org.jitsi.xmpp.extensions.colibri.*; 25 import org.jitsi.xmpp.extensions.jitsimeet.*; 26 27 import net.java.sip.communicator.util.*; 28 29 import org.jitsi.protocol.xmpp.util.*; 30 import org.junit.*; 31 import org.junit.runner.*; 32 import org.junit.runners.*; 33 import org.jxmpp.jid.*; 34 import org.jxmpp.jid.impl.*; 35 36 import java.util.*; 37 38 import static org.junit.Assert.*; 39 40 /** 41 * 42 */ 43 @RunWith(JUnit4.class) 44 public class AdvertiseSSRCsTest 45 { 46 private static final Logger logger 47 = Logger.getLogger(AdvertiseSSRCsTest.class); 48 49 private OSGiHandler osgi = OSGiHandler.getInstance(); 50 51 @Before setUpClass()52 public void setUpClass() 53 throws Exception 54 { 55 osgi.init(); 56 } 57 58 @After tearDownClass()59 public void tearDownClass() 60 throws Exception 61 { 62 osgi.shutdown(); 63 } 64 65 @Test testOneToOneConference()66 public void testOneToOneConference() 67 throws Exception 68 { 69 //FIXME: test when there is participant without contents 70 71 EntityBareJid roomName = JidCreate.entityBareFrom( 72 "testSSRCs@conference.pawel.jitsi.net"); 73 String serverName = "test-server"; 74 75 TestConference testConf 76 = TestConference.allocate(osgi.bc, serverName, roomName); 77 78 MockProtocolProvider pps 79 = testConf.getFocusProtocolProvider(); 80 81 MockMultiUserChatOpSet mucOpSet = pps.getMockChatOpSet(); 82 83 MockMultiUserChat chat 84 = (MockMultiUserChat) mucOpSet.findRoom(roomName.toString()); 85 86 // Join with all users 87 MockParticipant user1 = new MockParticipant("User1"); 88 user1.setSsrcVideoType(SSRCInfoPacketExtension.CAMERA_VIDEO_TYPE); 89 user1.join(chat); 90 91 MockParticipant user2 = new MockParticipant("User2"); 92 user2.setSsrcVideoType(SSRCInfoPacketExtension.SCREEN_VIDEO_TYPE); 93 user2.join(chat); 94 95 // Accept invite with all users 96 assertNotNull(user1.acceptInvite(4000)); 97 assertNotNull(user2.acceptInvite(4000)); 98 99 user1.waitForAddSource(2000); 100 user2.waitForAddSource(2000); 101 102 assertEquals(2, user1.getRemoteSSRCs("audio").size()); 103 // No groups 104 assertEquals(0, user1.getRemoteSSRCGroups("audio").size()); 105 106 // Verify SSRC owners and video types 107 // From user 1 perspective 108 assertEquals( 109 user2.getMyJid(), 110 SSRCSignaling.getSSRCOwner(user1.getRemoteSSRCs("audio").get(1))); 111 assertEquals( 112 user2.getMyJid(), 113 SSRCSignaling.getSSRCOwner(user1.getRemoteSSRCs("video").get(1))); 114 assertEquals( 115 user2.getSsrcVideoType(), 116 SSRCSignaling.getVideoType(user1.getRemoteSSRCs("video").get(1))); 117 // From user 2 perspective 118 assertEquals( 119 user1.getMyJid(), 120 SSRCSignaling.getSSRCOwner(user2.getRemoteSSRCs("audio").get(1))); 121 assertEquals( 122 user1.getMyJid(), 123 SSRCSignaling.getSSRCOwner(user2.getRemoteSSRCs("video").get(1))); 124 assertEquals( 125 user1.getSsrcVideoType(), 126 SSRCSignaling.getVideoType(user2.getRemoteSSRCs("video").get(1))); 127 128 user2.leave(); 129 130 assertNotNull(user1.waitForRemoveSource(500)); 131 132 assertEquals(1, user1.getRemoteSSRCs("audio").size()); 133 // No groups 134 assertEquals(0, user1.getRemoteSSRCGroups("audio").size()); 135 136 MockParticipant user3 = new MockParticipant("User3"); 137 user3.join(chat); 138 assertNotNull(user3.acceptInvite(4000)); 139 140 user1.waitForAddSource(2000); 141 142 assertEquals(2, user1.getRemoteSSRCs("audio").size()); 143 assertEquals(2, user3.getRemoteSSRCs("audio").size()); 144 // No groups 145 assertEquals(0, user1.getRemoteSSRCGroups("audio").size()); 146 assertEquals(0, user3.getRemoteSSRCGroups("audio").size()); 147 148 user3.leave(); 149 user1.leave(); 150 151 testConf.stop(); 152 } 153 154 @Test testSourceRemoval()155 public void testSourceRemoval() 156 throws Exception 157 { 158 EntityBareJid roomName = JidCreate.entityBareFrom( 159 "testSSRCremoval@conference.pawel.jitsi.net"); 160 String serverName = "test-server"; 161 162 TestConference testConf 163 = TestConference.allocate(osgi.bc, serverName, roomName); 164 165 MockProtocolProvider pps 166 = testConf.getFocusProtocolProvider(); 167 168 MockMultiUserChatOpSet mucOpSet = pps.getMockChatOpSet(); 169 170 MockMultiUserChat chat 171 = (MockMultiUserChat) mucOpSet.findRoom(roomName.toString()); 172 173 // Join with all users 174 MockParticipant user1 = new MockParticipant("User1"); 175 user1.setSsrcVideoType(SSRCInfoPacketExtension.CAMERA_VIDEO_TYPE); 176 user1.join(chat); 177 178 MockParticipant user2 = new MockParticipant("User2"); 179 user2.setSsrcVideoType(SSRCInfoPacketExtension.SCREEN_VIDEO_TYPE); 180 user2.join(chat); 181 182 // Accept invite with all users 183 assertNotNull(user1.acceptInvite(4000)); 184 assertNotNull(user2.acceptInvite(4000)); 185 186 user1.waitForAddSource(2000); 187 user2.waitForAddSource(2000); 188 189 user2.audioSourceRemove(1); 190 191 assertNotNull(user1.waitForRemoveSource(500)); 192 193 assertEquals(1, user1.getRemoteSSRCs("audio").size()); 194 assertEquals(0, user1.getRemoteSSRCGroups("audio").size()); 195 196 MockParticipant user3 = new MockParticipant("User3"); 197 user3.join(chat); 198 assertNotNull(user3.acceptInvite(4000)); 199 200 user1.waitForAddSource(2000); 201 202 assertEquals(2, user1.getRemoteSSRCs("audio").size()); 203 assertEquals(2, user3.getRemoteSSRCs("audio").size()); 204 // No groups 205 assertEquals(0, user1.getRemoteSSRCGroups("audio").size()); 206 assertEquals(0, user3.getRemoteSSRCGroups("audio").size()); 207 208 user3.leave(); 209 user2.leave(); 210 user1.leave(); 211 212 testConf.stop(); 213 } 214 215 @Test testDuplicatedSSRCs()216 public void testDuplicatedSSRCs() 217 throws Exception 218 { 219 EntityBareJid roomName = JidCreate.entityBareFrom( 220 "testSSRCs@conference.pawel.jitsi.net"); 221 String serverName = "test-server"; 222 223 TestConference testConf 224 = TestConference.allocate(osgi.bc, serverName, roomName); 225 226 MockProtocolProvider pps 227 = testConf.getFocusProtocolProvider(); 228 229 MockMultiUserChatOpSet mucOpSet = pps.getMockChatOpSet(); 230 231 MockMultiUserChat chat 232 = (MockMultiUserChat) mucOpSet.findRoom(roomName.toString()); 233 234 // Join with all users 235 MockParticipant user1 = new MockParticipant("User1"); 236 user1.join(chat); 237 238 MockParticipant user2 = new MockParticipant("User2"); 239 user2.join(chat); 240 241 // Accept invite with all users 242 long u1VideoSSRC = MockParticipant.nextSSRC(); 243 user1.addLocalVideoSSRC(u1VideoSSRC, null); 244 245 long u1VideoSSRC2 = MockParticipant.nextSSRC(); 246 user1.addLocalVideoSSRC(u1VideoSSRC2, null); 247 248 assertNotNull(user1.acceptInvite(4000)); 249 250 assertNotNull(user2.acceptInvite(4000)); 251 252 assertNotNull(user1.waitForAddSource(1000)); 253 assertNotNull(user2.waitForAddSource(1000)); 254 255 // There is 1 + 2 extra we've created here in the test 256 assertEquals(1 /* jvb */ + 3, user2.getRemoteSSRCs("video").size()); 257 // No groups 258 assertEquals(0, user2.getRemoteSSRCGroups("video").size()); 259 260 user1.videoSourceAdd(new long[]{ u1VideoSSRC }, false); 261 262 user1.videoSourceAdd( 263 new long[]{ 264 u1VideoSSRC, u1VideoSSRC2, u1VideoSSRC, 265 u1VideoSSRC, u1VideoSSRC, u1VideoSSRC2 266 }, false); 267 268 user1.videoSourceAdd(new long[]{ u1VideoSSRC2, u1VideoSSRC }, false); 269 270 // There should be no source-add notifications sent 271 assertEquals(null, user2.waitForAddSource(500)); 272 273 assertEquals(1 + /* jvb */ + 1, user2.getRemoteSSRCs("audio").size()); 274 // There is 1 + 2 extra we've created here in the test 275 assertEquals(1 + /* jvb */ + 3, user2.getRemoteSSRCs("video").size()); 276 277 user2.leave(); 278 user1.leave(); 279 280 testConf.stop(); 281 } 282 283 @Test testSSRCLimit()284 public void testSSRCLimit() 285 throws Exception 286 { 287 EntityBareJid roomName = JidCreate.entityBareFrom( 288 "testSSRCs@conference.pawel.jitsi.net"); 289 String serverName = "test-server"; 290 291 TestConference testConf 292 = TestConference.allocate(osgi.bc, serverName, roomName); 293 294 JitsiMeetGlobalConfig globalConfig 295 = ServiceUtils.getService(osgi.bc, JitsiMeetGlobalConfig.class); 296 297 assertNotNull(globalConfig); 298 299 MockProtocolProvider pps 300 = testConf.getFocusProtocolProvider(); 301 302 MockMultiUserChatOpSet mucOpSet = pps.getMockChatOpSet(); 303 304 MockMultiUserChat chat 305 = (MockMultiUserChat) mucOpSet.findRoom(roomName.toString()); 306 307 // Join with all users 308 MockParticipant user1 = new MockParticipant("User1"); 309 user1.join(chat); 310 user1.waitForJoinThread(5000); 311 312 MockParticipant user2 = new MockParticipant("User2"); 313 user2.join(chat); 314 user2.waitForJoinThread(5000); 315 316 int maxSSRCs = globalConfig.getMaxSourcesPerUser(); 317 318 // Accept invite with all users 319 // Add many SSRCs to both users 320 321 // Video: 322 // User 1 will fit into the limit on accept, but we'll try to exceed 323 // it later 324 int user1ExtraVideoSSRCCount = maxSSRCs / 2; 325 // User 2 will exceed SSRC limit on accept already 326 int user2ExtraVideoSSRCCount = maxSSRCs + 3; 327 user1.addMultipleVideoSSRCs(user1ExtraVideoSSRCCount); 328 user2.addMultipleVideoSSRCs(user2ExtraVideoSSRCCount); 329 330 // Audio: the opposite scenario 331 int user1ExtraAudioSSRCCount = maxSSRCs + 5; 332 int user2ExtraAudioSSRCCount = maxSSRCs / 2; 333 user1.addMultipleAudioSSRCs(user1ExtraAudioSSRCCount); 334 user2.addMultipleAudioSSRCs(user2ExtraAudioSSRCCount); 335 336 assertNotNull(user1.acceptInvite(10000)); 337 assertNotNull(user2.acceptInvite(10000)); 338 339 assertNotNull(user1.waitForAddSource(4000)); 340 assertNotNull(user2.waitForAddSource(4000)); 341 342 int expectedMax 343 = 1 /* jvb's mixed */ 344 + maxSSRCs /* max that can come from 1 participant */; 345 346 // Verify User1's SSRCs seen by User2 347 assertEquals(1 /* jvb's mixed */ + 1 + user1ExtraVideoSSRCCount, 348 user2.getRemoteSSRCs("video").size()); 349 assertEquals(expectedMax, 350 user2.getRemoteSSRCs("audio").size()); 351 // Verify User1's SSRCs seen by User1 352 assertEquals(expectedMax, 353 user1.getRemoteSSRCs("video").size()); 354 assertEquals(1 /* jvb's mixed */ + 1 + user2ExtraAudioSSRCCount, 355 user1.getRemoteSSRCs("audio").size()); 356 357 // No groups 358 assertEquals(0, user2.getRemoteSSRCGroups("video").size()); 359 assertEquals(0, user1.getRemoteSSRCGroups("video").size()); 360 assertEquals(0, user2.getRemoteSSRCGroups("audio").size()); 361 assertEquals(0, user1.getRemoteSSRCGroups("audio").size()); 362 363 // Now let's test the limits for source-add 364 // User1 will have video SSRCs filled and audio are filled already 365 user1.videoSourceAdd(maxSSRCs / 2); 366 assertNotNull(user2.waitForAddSource(300)); 367 assertEquals(expectedMax, user2.getRemoteSSRCs("video").size()); 368 369 user1.audioSourceAdd(5); 370 assertTrue(null == user2.waitForAddSource(300)); 371 assertEquals(expectedMax, user2.getRemoteSSRCs("audio").size()); 372 373 // User2 has video SSRCs filled already and audio will be filled 374 user2.videoSourceAdd(maxSSRCs / 2); 375 assertNull(user1.waitForAddSource(300)); 376 assertEquals(expectedMax, user1.getRemoteSSRCs("video").size()); 377 378 user2.audioSourceAdd(maxSSRCs / 2); 379 assertNotNull(user1.waitForAddSource(300)); 380 assertEquals(expectedMax, user1.getRemoteSSRCs("audio").size()); 381 382 user2.leave(); 383 user1.leave(); 384 385 // stopping the conference also stops the bridge, 386 // but the users leaving still want the bridge to disconnect properly 387 Thread.sleep(5000); 388 389 testConf.stop(); 390 } 391 392 // FIXME the test is broken 393 //@Test testOneToOneSSRCGroupsConference()394 public void testOneToOneSSRCGroupsConference() 395 throws Exception 396 { 397 EntityBareJid roomName = JidCreate.entityBareFrom( 398 "testSSRCs@conference.pawel.jitsi.net"); 399 String serverName = "test-server"; 400 401 TestConference testConf 402 = TestConference.allocate(osgi.bc, serverName, roomName); 403 404 MockProtocolProvider pps 405 = testConf.getFocusProtocolProvider(); 406 407 MockMultiUserChatOpSet mucOpSet = pps.getMockChatOpSet(); 408 409 MockMultiUserChat chat 410 = (MockMultiUserChat) mucOpSet.findRoom(roomName.toString()); 411 412 // Join with all users 413 final MockParticipant user1 = new MockParticipant("User1"); 414 user1.setUseSsrcGroups(true); 415 416 MockParticipant user2 = new MockParticipant("User2"); 417 user2.setUseSsrcGroups(true); 418 419 user1.join(chat); 420 user2.join(chat); 421 422 // Accept invite with all users 423 assertNotNull(user1.acceptInvite(4000)); 424 assertNotNull(user2.acceptInvite(4000)); 425 426 user1.waitForAddSource(2000); 427 428 assertEquals(1, user1.getRemoteSSRCs("audio").size()); 429 assertEquals(2, user1.getRemoteSSRCs("video").size()); 430 // groups 431 assertEquals(0, user1.getRemoteSSRCGroups("audio").size()); 432 assertEquals(1, user1.getRemoteSSRCGroups("video").size()); 433 434 // Check if layers are up-to-date on the bridge 435 verifySimulcastLayersOnTheBridge(testConf, user1); 436 verifySimulcastLayersOnTheBridge(testConf, user2); 437 438 logger.info("Switching to desktop stream"); 439 440 // Test video stream switch(for desktop sharing) 441 long [] desktopSSRC = new long[1]; 442 desktopSSRC[0] = MockParticipant.nextSSRC(); 443 user2.switchVideoSSRCs(desktopSSRC, false); 444 // Wait for update 445 user1.waitForAddSource(1000); 446 user1.waitForRemoveSource(1000); 447 // Check one SSRC is received and no groups 448 assertEquals(1, user1.getRemoteSSRCs("video").size()); 449 assertEquals(0, user1.getRemoteSSRCGroups("video").size()); 450 // Verify on the bridge 451 verifyNOSimulcastLayersOnTheBridge(testConf, user2); 452 453 logger.info("Switching back to camera stream"); 454 455 // Restore video stream 456 long[] videoSSRCs = new long[2]; 457 videoSSRCs[0] = MockParticipant.nextSSRC(); 458 videoSSRCs[1] = MockParticipant.nextSSRC(); 459 user2.switchVideoSSRCs(videoSSRCs, true); 460 // Wait for update 461 user1.waitForAddSource(1000); 462 user1.waitForRemoveSource(1000); 463 // Check 2 SSRCs are received and 1 group 464 assertEquals(2, user1.getRemoteSSRCs("video").size()); 465 assertEquals(1, user1.getRemoteSSRCGroups("video").size()); 466 // Verify on the bridge 467 verifySimulcastLayersOnTheBridge(testConf, user2); 468 469 // User2 - quit 470 user2.leave(); 471 472 assertNotNull(user1.waitForRemoveSource(1000)); 473 474 assertEquals(0, user1.getRemoteSSRCs("audio").size()); 475 // No groups 476 assertEquals(0, user1.getRemoteSSRCGroups("audio").size()); 477 478 // This one has no groups 479 MockParticipant user3 = new MockParticipant("User3"); 480 user3.join(chat); 481 assertNotNull(user3.acceptInvite(4000)); 482 483 user1.waitForAddSource(2000); 484 485 assertEquals(1, user1.getRemoteSSRCs("audio").size()); 486 assertEquals(1, user1.getRemoteSSRCs("video").size()); 487 // No groups 488 assertEquals(0, user1.getRemoteSSRCGroups("audio").size()); 489 assertEquals(0, user1.getRemoteSSRCGroups("video").size()); 490 491 user3.leave(); 492 user1.leave(); 493 494 testConf.stop(); 495 } 496 497 /** 498 * Verifies if number of simulcast layers on the bridge matches the SSRCs 499 * count in local video group. Also checks if primary SSRCs of particular 500 * layers do match local video SSRCs. 501 * @param testConference instance of <tt>TestConference</tt> that will be 502 * used for obtaining videobridge backend. 503 * @param peer the <tt>MockParticipant</tt> for which simulcast layers will 504 * be verified. 505 */ verifySimulcastLayersOnTheBridge(TestConference testConference, MockParticipant peer)506 private void verifySimulcastLayersOnTheBridge(TestConference testConference, 507 MockParticipant peer) 508 { 509 long[] simulcastLayersSSRCs 510 = testConference.getSimulcastLayersSSRCs(peer.getMyJid()); 511 List<SourcePacketExtension> videoSSRCs = peer.getVideoSSRCS(); 512 513 assertEquals(videoSSRCs.size(), simulcastLayersSSRCs.length); 514 515 for (int i=0; i<videoSSRCs.size(); i++) 516 { 517 assertEquals( 518 "idx: " + i, 519 videoSSRCs.get(i).getSSRC(), 520 simulcastLayersSSRCs[i]); 521 } 522 } 523 524 /** 525 * Verifies if the are 0 simulcast layers on the bridge for given 526 * <tt>peer</tt>. 527 * @param testConference instance of <tt>TestConference</tt> that will be 528 * used for obtaining videobridge backend. 529 * @param peer the <tt>MockParticipant</tt> for which simulcast layers will 530 * be verified. 531 */ verifyNOSimulcastLayersOnTheBridge( TestConference testConference, MockParticipant peer)532 private void verifyNOSimulcastLayersOnTheBridge( 533 TestConference testConference, MockParticipant peer) 534 { 535 long[] simulcastLayersSSRCs 536 = testConference.getSimulcastLayersSSRCs(peer.getMyJid()); 537 538 assertEquals(1, simulcastLayersSSRCs.length); 539 } 540 } 541