/*
* (C) Copyright 2016 Kurento (http://kurento.org/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.kurento.test.functional.ice;
import static org.kurento.commons.PropertiesManager.getProperty;
import static org.kurento.test.config.TestConfiguration.TEST_ICE_CANDIDATE_KMS_TYPE;
import static org.kurento.test.config.TestConfiguration.TEST_ICE_CANDIDATE_SELENIUM_TYPE;
import static org.kurento.test.config.TestConfiguration.TEST_KMS_TRANSPORT;
import static org.kurento.test.config.TestConfiguration.TEST_SELENIUM_TRANSPORT;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.kurento.client.EventListener;
import org.kurento.client.IceComponentStateChangeEvent;
import org.kurento.client.MediaFlowInStateChangeEvent;
import org.kurento.client.MediaFlowOutStateChangeEvent;
import org.kurento.client.MediaFlowState;
import org.kurento.client.MediaPipeline;
import org.kurento.client.NewCandidatePairSelectedEvent;
import org.kurento.client.PlayerEndpoint;
import org.kurento.client.WebRtcEndpoint;
import org.kurento.test.browser.WebRtcCandidateType;
import org.kurento.test.browser.WebRtcChannel;
import org.kurento.test.browser.WebRtcIpvMode;
import org.kurento.test.browser.WebRtcMode;
import org.kurento.test.config.Protocol;
import org.kurento.test.docker.TransportMode;
import org.kurento.test.functional.player.FunctionalPlayerTest;
/**
* Base for player tests.
*
* @author Raul Benitez (rbenitez@gsyc.es)
* @since 6.3.1
*/
public class SimpleIceTest extends FunctionalPlayerTest {
private List<Candidate> localCandidate;
private List<Candidate> remoteCandidate;
private List<Candidate> kmsCandidateType;
private List<Candidate> seleniumCandidateType;
protected WebRtcCandidateType getCandidateType(String candidate) {
String candidateType = candidate.split("typ")[1].split(" ")[1];
return WebRtcCandidateType.find(candidateType);
}
protected TransportMode getTransportMode(String candidate) {
if (candidate.toUpperCase().contains(TransportMode.UDP.toString())) {
return TransportMode.UDP;
} else if (candidate.toUpperCase().contains(TransportMode.TCP.toString())) {
return TransportMode.TCP;
}
return null;
}
protected void addCandidates(NewCandidatePairSelectedEvent event) {
Candidate lCandidate =
new Candidate(getCandidateType(event.getCandidatePair().getLocalCandidate()),
getTransportMode(event.getCandidatePair().getLocalCandidate()));
Candidate rCandidate =
new Candidate(getCandidateType(event.getCandidatePair().getRemoteCandidate()),
getTransportMode(event.getCandidatePair().getRemoteCandidate()));
if (WebRtcCandidateType.PRFLX.equals(lCandidate.getWebRtcCandidateType())) {
lCandidate.setWebRtcCandidateType(WebRtcCandidateType.SRFLX);
}
if (WebRtcCandidateType.PRFLX.equals(rCandidate.getWebRtcCandidateType())) {
rCandidate.setWebRtcCandidateType(WebRtcCandidateType.SRFLX);
}
localCandidate.add(lCandidate);
remoteCandidate.add(rCandidate);
if (getProperty(TEST_ICE_CANDIDATE_KMS_TYPE) != null) {
kmsCandidateType.add(new Candidate(
WebRtcCandidateType.find(getProperty(TEST_ICE_CANDIDATE_KMS_TYPE).toLowerCase()),
TransportMode.find(getProperty(TEST_KMS_TRANSPORT))));
}
if (getProperty(TEST_ICE_CANDIDATE_SELENIUM_TYPE) != null) {
seleniumCandidateType.add(new Candidate(
WebRtcCandidateType.find(getProperty(TEST_ICE_CANDIDATE_SELENIUM_TYPE).toLowerCase()),
TransportMode.find(getProperty(TEST_SELENIUM_TRANSPORT))));
}
}
protected void initLists() {
localCandidate = new ArrayList<Candidate>();
remoteCandidate = new ArrayList<Candidate>();
kmsCandidateType = new ArrayList<Candidate>();
seleniumCandidateType = new ArrayList<Candidate>();
}
protected void saveGstreamerDot(String prefix, MediaPipeline mp) {
if (mp != null) {
String gstreamerDot = mp.getGstreamerDot();
String pipelineName = mp.getName();
String gstreamerDotFile = getDefaultOutputFile(prefix + pipelineName);
try {
FileUtils.writeStringToFile(new File(gstreamerDotFile), gstreamerDot);
} catch (IOException e) {
log.error("Problem saving GstreamerDot with prefix: {} and pipeline: {} in path: {} ",
prefix, pipelineName, gstreamerDotFile);
e.printStackTrace();
}
}
}
public void initTestSendRecv(WebRtcChannel webRtcChannel, WebRtcIpvMode webRtcIpvMode,
WebRtcCandidateType webRtcCandidateType) throws InterruptedException {
initLists();
// Media Pipeline
MediaPipeline mp = kurentoClient.createMediaPipeline();
WebRtcEndpoint webRtcEndpoint = new WebRtcEndpoint.Builder(mp).build();
webRtcEndpoint.connect(webRtcEndpoint);
final CountDownLatch eosLatch = new CountDownLatch(1);
webRtcEndpoint
.addIceComponentStateChangeListener(new EventListener<IceComponentStateChangeEvent>() {
@Override
public void onEvent(IceComponentStateChangeEvent event) {
log.debug("OnIceComponentStateChanged State: {} Source: {} Type: {} StreamId: {}",
event.getState(), event.getSource(), event.getType(), event.getStreamId());
}
});
webRtcEndpoint
.addMediaFlowOutStateChangeListener(new EventListener<MediaFlowOutStateChangeEvent>() {
@Override
public void onEvent(MediaFlowOutStateChangeEvent event) {
if (event.getState().equals(MediaFlowState.FLOWING)) {
eosLatch.countDown();
}
}
});
webRtcEndpoint
.addNewCandidatePairSelectedListener(new EventListener<NewCandidatePairSelectedEvent>() {
@Override
public void onEvent(NewCandidatePairSelectedEvent event) {
log.debug(
"SendRecv -> New Candidate Pair Selected: \nStream: {} \nLocal: {} \nRemote: {}",
event.getCandidatePair().getStreamID(),
event.getCandidatePair().getLocalCandidate(),
event.getCandidatePair().getRemoteCandidate());
addCandidates(event);
}
});
// Test execution
getPage(0).subscribeEvents("playing");
getPage(0).initWebRtc(webRtcEndpoint, webRtcChannel, WebRtcMode.SEND_RCV, webRtcIpvMode,
webRtcCandidateType);
// Assertions
saveGstreamerDot("-before-waiting-FlowingOut-event-", mp);
Assert.assertTrue("Not received FLOWING OUT event in webRtcEp:" + webRtcChannel,
eosLatch.await(getPage(0).getTimeout(), TimeUnit.SECONDS));
saveGstreamerDot("-before-waiting-player-event-", mp);
Assert.assertTrue("Not received media (timeout waiting playing event)",
getPage(0).waitForEvent("playing"));
// For the moment, these assertions are not necessary
// Assert.assertEquals("Local candidate type (KMS) is wrong. It waits "
// + kmsCandidateType.get(0).getWebRtcCandidateType() + " and finds "
// + localCandidate.get(0).getWebRtcCandidateType(), kmsCandidateType.get(0)
// .getWebRtcCandidateType(), localCandidate.get(0).getWebRtcCandidateType());
//
// if (WebRtcCandidateType.RELAY.toString().equals(webRtcCandidateType)) {
// Assert.assertEquals("Local candidate transport (KMS) is wrong. It waits "
// + kmsCandidateType.get(0).getTransportMode() + " and finds "
// + localCandidate.get(0).getTransportMode(), kmsCandidateType.get(0).getTransportMode(),
// localCandidate.get(0).getTransportMode());
// }
//
// Assert.assertEquals("Remote candidate type (SELENIUM) is wrong. It waits "
// + seleniumCandidateType.get(0).getWebRtcCandidateType() + " and finds "
// + remoteCandidate.get(0).getWebRtcCandidateType(), seleniumCandidateType.get(0)
// .getWebRtcCandidateType(), remoteCandidate.get(0).getWebRtcCandidateType());
//
// if (WebRtcCandidateType.RELAY.toString().equals(webRtcCandidateType)) {
// Assert.assertEquals("Remote candidate transport (SELENIUM) is wrong. It waits "
// + seleniumCandidateType.get(0).getTransportMode() + " and finds "
// + remoteCandidate.get(0).getTransportMode(), seleniumCandidateType.get(0)
// .getTransportMode(), remoteCandidate.get(0).getTransportMode());
// }
// Release Media Pipeline
mp.release();
}
public void initTestRcvOnly(WebRtcChannel webRtcChannel, WebRtcIpvMode webRtcIpvMode,
WebRtcCandidateType webRtcCandidateType, String nameMedia) throws InterruptedException {
initLists();
String mediaUrl = getMediaUrl(Protocol.FILE, nameMedia);
MediaPipeline mp = kurentoClient.createMediaPipeline();
PlayerEndpoint playerEp = new PlayerEndpoint.Builder(mp, mediaUrl).build();
WebRtcEndpoint webRtcEp = new WebRtcEndpoint.Builder(mp).build();
playerEp.connect(webRtcEp);
final CountDownLatch eosLatch = new CountDownLatch(1);
webRtcEp.addIceComponentStateChangeListener(new EventListener<IceComponentStateChangeEvent>() {
@Override
public void onEvent(IceComponentStateChangeEvent event) {
log.debug("OnIceComponentStateChanged State: {} Source: {} Type: {} StreamId: {}",
event.getState(), event.getSource(), event.getType(), event.getStreamId());
}
});
webRtcEp.addMediaFlowInStateChangeListener(new EventListener<MediaFlowInStateChangeEvent>() {
@Override
public void onEvent(MediaFlowInStateChangeEvent event) {
if (event.getState().equals(MediaFlowState.FLOWING)) {
eosLatch.countDown();
}
}
});
webRtcEp
.addNewCandidatePairSelectedListener(new EventListener<NewCandidatePairSelectedEvent>() {
@Override
public void onEvent(NewCandidatePairSelectedEvent event) {
log.debug(
"RecvOnly -> New Candidate Pair Selected: \nStream: {} \nLocal: {} \nRemote: {}",
event.getCandidatePair().getStreamID(),
event.getCandidatePair().getLocalCandidate(),
event.getCandidatePair().getRemoteCandidate());
addCandidates(event);
}
});
// Test execution
getPage(0).subscribeEvents("playing");
getPage(0).initWebRtc(webRtcEp, webRtcChannel, WebRtcMode.RCV_ONLY, webRtcIpvMode,
webRtcCandidateType);
playerEp.play();
// Assertions
saveGstreamerDot("-before-waiting-FlowingIn-event-", mp);
Assert.assertTrue(
"Not received FLOWING IN event in webRtcEp: " + mediaUrl + " " + webRtcChannel,
eosLatch.await(getPage(0).getTimeout(), TimeUnit.SECONDS));
saveGstreamerDot("-before-waiting-player-event-", mp);
Assert.assertTrue(
"Not received media (timeout waiting playing event): " + mediaUrl + " " + webRtcChannel,
getPage(0).waitForEvent("playing"));
// For the moment, these assertions are not necessary
// Assert.assertEquals("Local candidate type (KMS) is wrong. It waits "
// + kmsCandidateType.get(0).getWebRtcCandidateType() + " and finds "
// + localCandidate.get(0).getWebRtcCandidateType(), kmsCandidateType.get(0)
// .getWebRtcCandidateType(), localCandidate.get(0).getWebRtcCandidateType());
//
// if (WebRtcCandidateType.RELAY.toString().equals(webRtcCandidateType)) {
// Assert.assertEquals("Local candidate transport (KMS) is wrong. It waits "
// + kmsCandidateType.get(0).getTransportMode() + " and finds "
// + localCandidate.get(0).getTransportMode(), kmsCandidateType.get(0).getTransportMode(),
// localCandidate.get(0).getTransportMode());
// }
//
// Assert.assertEquals("Remote candidate type (SELENIUM) is wrong. It waits "
// + seleniumCandidateType.get(0).getWebRtcCandidateType() + " and finds "
// + remoteCandidate.get(0).getWebRtcCandidateType(), seleniumCandidateType.get(0)
// .getWebRtcCandidateType(), remoteCandidate.get(0).getWebRtcCandidateType());
//
// if (WebRtcCandidateType.RELAY.toString().equals(webRtcCandidateType)) {
// Assert.assertEquals("Remote candidate transport (SELENIUM) is wrong. It waits "
// + seleniumCandidateType.get(0).getTransportMode() + " and finds "
// + remoteCandidate.get(0).getTransportMode(), seleniumCandidateType.get(0)
// .getTransportMode(), remoteCandidate.get(0).getTransportMode());
// }
// Release Media Pipeline
mp.release();
}
public void initTestSendOnly(WebRtcChannel webRtcChannel, WebRtcIpvMode webRtcIpvMode,
WebRtcCandidateType webRtcCandidateType) throws InterruptedException {
initLists();
MediaPipeline mp = kurentoClient.createMediaPipeline();
WebRtcEndpoint webRtcEpSendOnly = new WebRtcEndpoint.Builder(mp).build();
WebRtcEndpoint webRtcEpRcvOnly = new WebRtcEndpoint.Builder(mp).build();
webRtcEpSendOnly.connect(webRtcEpRcvOnly);
final CountDownLatch eosLatch = new CountDownLatch(1);
webRtcEpSendOnly
.addIceComponentStateChangeListener(new EventListener<IceComponentStateChangeEvent>() {
@Override
public void onEvent(IceComponentStateChangeEvent event) {
log.debug(
"webRtcEpSendOnly: OnIceComponentStateChanged State: {} Source: {} Type: {} StreamId: {}",
event.getState(), event.getSource(), event.getType(), event.getStreamId());
}
});
webRtcEpSendOnly
.addNewCandidatePairSelectedListener(new EventListener<NewCandidatePairSelectedEvent>() {
@Override
public void onEvent(NewCandidatePairSelectedEvent event) {
log.debug(
"SendOnly (webRtcEpSendOnly) -> New Candidate Pair Selected: \nStream: {} \nLocal: {} \nRemote: {}",
event.getCandidatePair().getStreamID(),
event.getCandidatePair().getLocalCandidate(),
event.getCandidatePair().getRemoteCandidate());
}
});
webRtcEpRcvOnly
.addIceComponentStateChangeListener(new EventListener<IceComponentStateChangeEvent>() {
@Override
public void onEvent(IceComponentStateChangeEvent event) {
log.debug(
"webRtcEpRcvOnly: OnIceComponentStateChanged State: {} Source: {} Type: {} StreamId: {}",
event.getState(), event.getSource(), event.getType(), event.getStreamId());
}
});
webRtcEpRcvOnly
.addMediaFlowInStateChangeListener(new EventListener<MediaFlowInStateChangeEvent>() {
@Override
public void onEvent(MediaFlowInStateChangeEvent event) {
if (event.getState().equals(MediaFlowState.FLOWING)) {
eosLatch.countDown();
}
}
});
webRtcEpRcvOnly
.addNewCandidatePairSelectedListener(new EventListener<NewCandidatePairSelectedEvent>() {
@Override
public void onEvent(NewCandidatePairSelectedEvent event) {
log.debug(
"SendOnly (webRtcEpRcvOnly) -> New Candidate Pair Selected: \nStream: {} \nLocal: {} \nRemote: {}",
event.getCandidatePair().getStreamID(),
event.getCandidatePair().getLocalCandidate(),
event.getCandidatePair().getRemoteCandidate());
addCandidates(event);
}
});
// Test execution
getPage(1).subscribeEvents("playing");
getPage(0).initWebRtc(webRtcEpSendOnly, webRtcChannel, WebRtcMode.SEND_ONLY, webRtcIpvMode,
webRtcCandidateType);
getPage(1).initWebRtc(webRtcEpRcvOnly, webRtcChannel, WebRtcMode.RCV_ONLY, webRtcIpvMode,
webRtcCandidateType);
// Assertions
saveGstreamerDot("-before-waiting-FlowingIn-event-", mp);
Assert.assertTrue("Not received FLOWING IN event in webRtcEpRcvOnly: " + webRtcChannel,
eosLatch.await(getPage(1).getTimeout(), TimeUnit.SECONDS));
saveGstreamerDot("-before-waiting-player-event-", mp);
Assert.assertTrue("Not received media (timeout waiting playing event)",
getPage(1).waitForEvent("playing"));
// For the moment, these assertions are not necessary
// Assert.assertEquals("Local candidate type (KMS) is wrong. It waits "
// + kmsCandidateType.get(0).getWebRtcCandidateType() + " and finds "
// + localCandidate.get(0).getWebRtcCandidateType(), kmsCandidateType.get(0)
// .getWebRtcCandidateType(), localCandidate.get(0).getWebRtcCandidateType());
//
// if (WebRtcCandidateType.RELAY.toString().equals(webRtcCandidateType)) {
// Assert.assertEquals("Local candidate transport (KMS) is wrong. It waits "
// + kmsCandidateType.get(0).getTransportMode() + " and finds "
// + localCandidate.get(0).getTransportMode(), kmsCandidateType.get(0).getTransportMode(),
// localCandidate.get(0).getTransportMode());
// }
//
// Assert.assertEquals("Remote candidate type (SELENIUM) is wrong. It waits "
// + seleniumCandidateType.get(0).getWebRtcCandidateType() + " and finds "
// + remoteCandidate.get(0).getWebRtcCandidateType(), seleniumCandidateType.get(0)
// .getWebRtcCandidateType(), remoteCandidate.get(0).getWebRtcCandidateType());
//
// if (WebRtcCandidateType.RELAY.toString().equals(webRtcCandidateType)) {
// Assert.assertEquals("Remote candidate transport (SELENIUM) is wrong. It waits "
// + seleniumCandidateType.get(0).getTransportMode() + " and finds "
// + remoteCandidate.get(0).getTransportMode(), seleniumCandidateType.get(0)
// .getTransportMode(), remoteCandidate.get(0).getTransportMode());
// }
// Release Media Pipeline
mp.release();
}
private class Candidate {
private WebRtcCandidateType webRtcCandidateType;
private TransportMode transportMode;
public Candidate(WebRtcCandidateType webRtcCandidateType, TransportMode transportMode) {
this.webRtcCandidateType = webRtcCandidateType;
this.transportMode = transportMode;
}
public WebRtcCandidateType getWebRtcCandidateType() {
return webRtcCandidateType;
}
public void setWebRtcCandidateType(WebRtcCandidateType webRtcCandidateType) {
this.webRtcCandidateType = webRtcCandidateType;
}
public TransportMode getTransportMode() {
return transportMode;
}
}
}