Clone sample token server
preferably in an linux machine and run the steps provided in that repo's README.md
If the machine has domain name then it will be accessed using it's domain
If the machine is local to the phone running the app. Then get the ip address of the machine
running token server along with the port of the sample server
Running the app
Build and run the app
Pass the ip_address:port (eg: 192.168.0.1:8080) or the domain name of the token server setup in
above step in the "Base Url" and pass a random value in "User Name". Remember to note the
username value it will be used during invite user
classCallerActivityextendsAppCompatActivity {
privateMediaSessionsession;
@OverrideprotectedvoidonCreate(@NullableBundlesavedInstanceState) {
session = newMediaSession.JoinBuilder(this)
.setSessionId("<Session Id>")
.build();
session.start();
session.getConnectionStatus().observe(this, status -> {
// wait till session is connected, else sendMessage will fail.
});
// send message to every one in the networksession.sendMessage("hello world");
// send data to nodes with node id 1, 2session.sendMessage("hello world", 1, 2);
// send content info to all nodes in the networksession.sendContentInfoMessage("hello world", (int) System.currentTimeMillis());
// send data to nodes with node id 1, 2session.sendContentInfoMessage("hello world", (int) System.currentTimeMillis(), 1, 2);
}
@OverrideprotectedvoidonDestroy() {
session.stop();
}
}
Listening for messages, content info
classCallerActivityextendsAppCompatActivity {
@OverrideprotectedvoidonCreate(@NullableBundlesavedInstanceState) {
// Join or create a sessionsession.setMessageReceivedListener((message, sourceNodeId) -> {
// triggered on receiving a new message from sourceNodeId// NOTE: This code will be executed on a background thread.// and this listener will be cleared during stop()
});
session.setContentInfoReceivedListener((message, sourceNodeId, contentTime) -> {
// triggered on receiving a new content info message from sourceNodeId// NOTE: This code will be executed on a background thread.// and this listener will be cleared during stop()
});
session.setNodeStatusListener((nodeId, isOnline) -> {
// triggered when nodeId becomes online / offline// NOTE: This code will be executed on a background thread.// and this listener will be cleared during stop()
});
}
}
Listening for connection status
classCallerActivityextendsAppCompatActivity {
@OverrideprotectedvoidonCreate(@NullableBundlesavedInstanceState) {
MediaSessionsession = newMediaSession.JoinBuilder(this)
.setSessionId("<Session Id>")
.build();
session.start();
session.getConnectionStatus().observe(this, status -> {
// wait till session is connected, else sendMessage will fail.
});
}
}
Adding Mic and Camera Streams to a given channel
classCallerActivityextendsAppCompatActivity {
@OverrideprotectedvoidonCreate(@NullableBundlesavedInstanceState) {
MediaSessionsession = newMediaSession.JoinBuilder(this)
.setSessionId("<Session Id>")
.build();
// Hard-coding channel names would be a best practice.// adding camera streamsession
.addStream(newCameraStreamHandler.Builder(
"<CHANNEL NAME>",
CameraStreamHandler.VideoQuality.SD,
CameraSelector.DEFAULT_FRONT_CAMERA))
.observe(this, videoHandler -> {
if (null == videoHandler) {
// errorreturn;
}
videoHandler.start();
videoHandler.bindToLifecycle(this, this, binding.pvSelf);
});
// adding microphone streamsession
.addStream(newMicStreamHandler.Builder("<CHANNEL NAME>"))
.observe(this, audioHandler -> {
if (null == audioHandler) {
// errorreturn;
}
audioHandler.start();
audioHandler.bindToLifecycle(this);
});
}
}
Listening for streams and setting up views for each player
classCallerActivityextendsAppCompatActivity {
@OverrideprotectedvoidonCreate(@NullableBundlesavedInstanceState) {
MediaSessionsession = newMediaSession.JoinBuilder(this)
.setSessionId("<Session Id>")
.build();
// binding each participant to their corresponding viewsession
.start()
.observe(this, response -> {
if (null != response.getError()) {
// errorreturn;
}
MediaSession.ChannelNodesContainernodesContainer = response
.getValue()
.stream()
.filter(container -> container.getChannelName().equals("<CHANNEL NAME>"))
.findFirst()
.orElse(null);
if (null == nodesContainer) {
// ignorereturn;
}
this.participants = nodesContainer.getNodes();
if (participants.size() > playerViews.size()) {
// for sake of simplicity.// Better with a recycler view ?participants = participants.subList(0, playerViews.size());
}
// binding each participant to their corresponding viewfor (inti = 0; i < participants.size(); i++) {
NodePlayerViewpv = playerViews.get(i);
if (null == pv.getPlayer()) {
SimpleExoPlayerplayer = MediaSession.getLowLatencyPlayer(this);
players.add(player);
pv.setPlayer(player);
}
pv.bindToNode(participants.get(i));
}
// unbinding each view from participantfor (inti = participants.size(); i < playerViews.size(); i++) {
SimpleExoPlayerplayer;
NodePlayerViewpv = playerViews.get(i);
if (null != (player = pv.getPlayer())) {
player.release();
}
pv.setPlayer(null);
}
});
}
}
Rules for proguard and r8 will be added soon here.
Gist of using the api
classCallerActivityextendsAppCompatActivity {
privateMediaSessionsession;
@OverrideprotectedvoidonCreate(@NullableBundlesavedInstanceState) {
session = newMediaSession.CreateBuilder(this)
.setName("whatever")
.setMetadata("anything")
.addChannel(newMediaSession.ChannelBuilder("channel name", "channel metadata"))
.build();
session.start().observe(this, container -> {
// bind participant to the corresponding view
});
// adding camera streamsession
.addStream(newCameraStreamHandler.Builder(
"channel name",
CameraStreamHandler.VideoQuality.SD,
CameraSelector.DEFAULT_FRONT_CAMERA))
.observe(this, videoHandler -> {
// start the handler
});
// adding microphone streamsession
.addStream(newMicStreamHandler.Builder("channel name"))
.observe(this, audioHandler -> {
// start the handler
});
session.getConnectionStatus().observe(this, status -> {
// don't sendMessage() until status = connected, else it will fail.
});
// send message to every one in the networksession.sendMessage("hello world");
// send data to nodes with node id 1, 2session.sendMessage("hello world", 1, 2);
// send content info to all nodes in the networksession.sendContentInfoMessage("hello world", (int) System.currentTimeMillis());
// send data to nodes with node id 1, 2session.sendContentInfoMessage("hello world", (int) System.currentTimeMillis(), 1, 2);
session.delete().observe(this, response -> {
if (null != response.getError()) {
// success
}
});
}
@OverrideprotectedvoidonDestroy() {
session.stop();
}
}
cocomediasdk-android-video-conference-sample-app's People