Implementing group call(many 2 many) kurento-room-client-android





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















I am able to achieve one 2 one video call using nubomedia(kurento-room-client-android).But not able to implement multiple video group call. Please guide me with it. I am able to get multiple video stream on onRemoteStreamAdded method. I check the onIceCandiate state for different users. Only one local and one remote iceCandidate state is connected and completed, rest remote users are still on checking. Just for testing purpose I wrote onRemoteStreamAdded code. Please don't judge it.



public class PeerVideoActivity extends AppCompatActivity
implements NBMWebRTCPeer.Observer, RoomListener {
private static final String TAG = "PeerVideoActivity";
private String usrArr;
private NBMWebRTCPeer nbmWebRTCPeer;
private SurfaceViewRenderer masterViewFirst, masterViewSecond;
private boolean masterViewFirstAdded=false, masterViewSecondAdded=false;
private SurfaceViewRenderer localView;
private Map<Integer, String> videoRequestUserMapping;
private int publishVideoRequestId;
private TextView mCallStatus;
private String username;
private boolean isAdded = false;
private HorizontalVideoStreamAdapter horizontalAdapter;
private RecyclerView horizontal_recycler_view;
private boolean isRemoteStreamAdded = false;
private boolean backPressed = false;
private Thread backPressedThread = null;
private HashMap<String, Boolean> generateOfferMap, sendOfferMap, iceCandidtateMap;
private ArrayList<MediaStream> remoteStreamList;
private Handler mHandler = null;
private CallState callState;

private enum CallState {
IDLE,
PUBLISHING,
PUBLISHED,
WAITING_REMOTE_USER,
RECEIVING_REMOTE_USER
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_conference);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mHandler = new Handler();
masterViewFirst = (SurfaceViewRenderer) findViewById(R.id.gl_surface_first);
masterViewSecond= (SurfaceViewRenderer) findViewById(R.id.gl_surface_second);
horizontal_recycler_view = (RecyclerView) findViewById(R.id.horizontal_recycler_view);
remoteStreamList = new ArrayList<>();
localView = (SurfaceViewRenderer) findViewById(R.id.gl_surface_local);
this.mCallStatus = (TextView) findViewById(R.id.call_status);
callState = CallState.IDLE;
MainActivity.getKurentoRoomAPIInstance().addObserver(this);
}

@Override
protected void onStart() {
super.onStart();

Bundle extras = getIntent().getExtras();
this.username = extras.getString(Constants.USER_NAME, "");
usrArr = extras.getString("usrArr");
Log.i(TAG, "username: " + username);
generateOfferMap = getUserMap();
iceCandidtateMap = getUserMap();
sendOfferMap = getUserMap();
EglBase rootEglBase = EglBase.create();
masterViewFirst.init(rootEglBase.getEglBaseContext(), null);
masterViewFirst.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
masterViewSecond.init(rootEglBase.getEglBaseContext(), null);
masterViewSecond.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
localView.init(rootEglBase.getEglBaseContext(), null);
localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);

NBMMediaConfiguration peerConnectionParameters =
new NBMMediaConfiguration(NBMMediaConfiguration.NBMRendererType.OPENGLES,
NBMMediaConfiguration.NBMAudioCodec.OPUS, 0, NBMMediaConfiguration.NBMVideoCodec.VP8, 0,
new NBMMediaConfiguration.NBMVideoFormat(320, 240, PixelFormat.RGB_888, 30),
NBMMediaConfiguration.NBMCameraPosition.FRONT);

videoRequestUserMapping = new HashMap<>();
nbmWebRTCPeer = new NBMWebRTCPeer(peerConnectionParameters, this, localView, this);
//nbmWebRTCPeer.registerMasterRenderer(masterViewFirst);
//nbmWebRTCPeer.registerMasterRenderer(masterViewSecond);
horizontalAdapter = new HorizontalVideoStreamAdapter(remoteStreamList, this, nbmWebRTCPeer,
masterViewFirst, masterViewSecond);
LinearLayoutManager horizontalLayoutManager =
new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
horizontal_recycler_view.setLayoutManager(horizontalLayoutManager);
horizontal_recycler_view.setAdapter(horizontalAdapter);
Log.i(TAG, "Initializing nbmWebRTCPeer...");
nbmWebRTCPeer.initialize();
callState = CallState.PUBLISHING;
mCallStatus.setText("Publishing...");
}

@Override
protected void onStop() {
//endCall();
super.onStop();
}

@Override
protected void onPause() {
//nbmWebRTCPeer.stopLocalMedia();
super.onPause();
}

@Override
protected void onResume() {
super.onResume();
nbmWebRTCPeer.startLocalMedia();
}

@Override
protected void onDestroy() {
super.onDestroy();
}

/* @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_video_chat, menu);
return true;
}*/

/* @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();

//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}

return super.onOptionsItemSelected(item);
}*/

@Override
public void onBackPressed() {
// If back button has not been pressed in a while then trigger thread and toast notification
if (!this.backPressed) {
this.backPressed = true;
Toast.makeText(this, "Press back again to end.", Toast.LENGTH_SHORT).show();
this.backPressedThread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
backPressed = false;
} catch (InterruptedException e) {
Log.d("VCA-oBP", "Successfully interrupted");
}
}
});
this.backPressedThread.start();
}
// If button pressed the second time then call super back pressed
// (eventually calls onDestroy)
else {
if (this.backPressedThread != null) this.backPressedThread.interrupt();
super.onBackPressed();
}
}

public void hangup(View view) {
finish();
}

private void GenerateOfferForRemote(String remote_name) {
nbmWebRTCPeer.generateOffer(remote_name, false);
callState = CallState.WAITING_REMOTE_USER;
runOnUiThread(new Runnable() {
@Override
public void run() {
mCallStatus.setText(R.string.waiting_remote_stream);
}
});
}

public void receiveFromRemote(View view) {
//GenerateOfferForRemote();
}

/**
* Terminates the current call and ends activity
*/
/* private void endCall() {
callState = CallState.IDLE;
try
{
if (nbmWebRTCPeer != null) {
nbmWebRTCPeer.close();
nbmWebRTCPeer = null;
}
}
catch (Exception e){e.printStackTrace();}
}*/
@Override
public void onInitialize() {
if (nbmWebRTCPeer != null) nbmWebRTCPeer.generateOffer("local", true);
}

@Override
public void onLocalSdpOfferGenerated(final SessionDescription sessionDescription,
final NBMPeerConnection nbmPeerConnection) {
if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
Log.d(TAG, "local " + sessionDescription.type);
//publishVideoRequestId = ++Constants.id;
Log.i("sendPublishVideo", username);
MainActivity.getKurentoRoomAPIInstance()
.sendPublishVideo(sessionDescription.description, username);
} else { // Asking for remote user video
Log.d(TAG, "remote " + sessionDescription.type);
if (sendOfferMap != null) {
for (Map.Entry<String, Boolean> entry : sendOfferMap.entrySet()) {
if (entry.getValue()) {
MainActivity.getKurentoRoomAPIInstance()
.sendPublishVideo(sessionDescription.description, entry.getKey());
entry.setValue(false);
}
}
}
}
}

@Override
public void onLocalSdpAnswerGenerated(SessionDescription sessionDescription,
NBMPeerConnection nbmPeerConnection) {
}

@Override
public void onIceCandidate(IceCandidate iceCandidate, NBMPeerConnection nbmPeerConnection) {
int sendIceCandidateRequestId = ++Constants.id;
if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
MainActivity.getKurentoRoomAPIInstance()
.sendOnIceCandidate(this.username, iceCandidate.sdp, iceCandidate.sdpMid,
Integer.toString(iceCandidate.sdpMLineIndex));
} else {
if (iceCandidtateMap != null) {
for (Map.Entry<String, Boolean> entry : iceCandidtateMap.entrySet()) {
if (entry.getValue()) {
MainActivity.getKurentoRoomAPIInstance()
.sendOnIceCandidate(entry.getKey(), iceCandidate.sdp, iceCandidate.sdpMid,
Integer.toString(iceCandidate.sdpMLineIndex));
entry.setValue(false);
}
}
}
//MainActivity.getKurentoRoomAPIInstance().sendOnIceCandidate(nbmPeerConnection.getConnectionId(), iceCandidate.sdp,
// iceCandidate.sdpMid, Integer.toString(iceCandidate.sdpMLineIndex), sendIceCandidateRequestId);
}
}

@Override
public void onIceStatusChanged(PeerConnection.IceConnectionState iceConnectionState,
NBMPeerConnection nbmPeerConnection) {
Log.i(TAG, "onIceStatusChanged");
}

@Override
public void onRemoteStreamAdded(final MediaStream mediaStream,
final NBMPeerConnection nbmPeerConnection) {
Log.i(TAG, "Enter onRemoteStreamAdded");
if (!nbmPeerConnection.getConnectionId().equalsIgnoreCase("local")) {
remoteStreamList.add(mediaStream);

runOnUiThread(new Runnable() {
@Override
public void run() {
mCallStatus.setText("");

if(remoteStreamList != null) {
if (remoteStreamList.size() == 1) {
//nbmWebRTCPeer.attachRendererToRemoteStream(masterViewFirst, remoteStreamList.get(0));
remoteStreamList.get(0).videoTracks.get(0).addRenderer(new VideoRenderer(masterViewFirst));
} else if (remoteStreamList.size() ==2) {
remoteStreamList.get(1).videoTracks.get(0).addRenderer(new VideoRenderer(masterViewSecond));
}
}
}
});
}
Log.i(TAG, "onRemoteStreamAdded :" + remoteStreamList.size());
Log.i(TAG, "Exit onRemoteStreamAdded");
}

@Override public void onRemoteStreamRemoved (MediaStream mediaStream, NBMPeerConnection
nbmPeerConnection){
Log.i(TAG, "onRemoteStreamRemoved");
}

@Override public void onPeerConnectionError (String s){
Log.i(TAG, "onPeerConnectionError:" + s);
}

@Override public void onDataChannel (DataChannel dataChannel, NBMPeerConnection connection){
Log.i(TAG, "[datachannel] Peer opened data channel");
}

@Override public void onBufferedAmountChange ( long l, NBMPeerConnection connection, DataChannel
channel){

}

public void sendHelloMessage (DataChannel channel){
/*byte rawMessage = "Hello Peer!".getBytes(Charset.forName("UTF-8"));
ByteBuffer directData = ByteBuffer.allocateDirect(rawMessage.length);
directData.put(rawMessage);
directData.flip();
DataChannel.Buffer data = new DataChannel.Buffer(directData, false);
channel.send(data);*/
}

@Override public void onStateChange (NBMPeerConnection connection, DataChannel channel){
Log.i(TAG, "[datachannel] DataChannel onStateChange: " + channel.state());
/* if (channel.state() == DataChannel.State.OPEN) {
sendHelloMessage(channel);
Log.i(TAG, "[datachannel] Datachannel open, sending first hello");
}*/
}

@Override public void onMessage (DataChannel.Buffer buffer, NBMPeerConnection
connection, DataChannel channel){
Log.i(TAG, "[datachannel] Message received: " + buffer.toString());
//sendHelloMessage(channel);
}

/* private Runnable offerWhenReady = new Runnable() {
@Override
public void run() {
// Generate offers to receive video from all peers in the room
if (generateOfferMap != null) {
for (Map.Entry<String, Boolean> entry : generateOfferMap.entrySet()) {
if (entry.getValue()) {
GenerateOfferForRemote(entry.getKey());
Log.i(TAG, "I'm " + username + " DERP: Generating offer for peer " + entry.getKey());
// Set value to false so that if this function is called again we won't
// generate another offer for this user
entry.setValue(false);
}
}
}
}
};*/

private void offerWhenReady(){
if (generateOfferMap != null) {
for (Map.Entry<String, Boolean> entry : generateOfferMap.entrySet()) {
if (entry.getValue()) {
GenerateOfferForRemote(entry.getKey());
Log.i(TAG, "I'm " + username + " DERP: Generating offer for peer " + entry.getKey());
// Set value to false so that if this function is called again we won't
// generate another offer for this user
entry.setValue(false);
}
}
}
}

@Override public void onRoomResponse (/*RoomResponse*/ String response){
Log.d(TAG, "OnRoomResponse:" + response);
if (response != null) {
try {
JSONObject obj = new JSONObject(response);
if (obj.getString("rsp").equals("answer")) {
if (obj.getString("answer") != null) {
SessionDescription sd =
new SessionDescription(SessionDescription.Type.ANSWER, obj.getString("answer"));

// Check if we are waiting for publication of our own vide
if (callState == CallState.PUBLISHING) {
callState = CallState.PUBLISHED;
nbmWebRTCPeer.processAnswer(sd, "local");
//mHandler.postDelayed(offerWhenReady, 2000);
offerWhenReady();

// Check if we are waiting for the video publication of the other peer
} else if (callState == CallState.WAITING_REMOTE_USER) {
//String user_name = Integer.toString(publishVideoRequestId);
callState = CallState.RECEIVING_REMOTE_USER;
//String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
String connectionId = obj.getString("userId");
nbmWebRTCPeer.processAnswer(sd, connectionId);
} else {
callState = CallState.RECEIVING_REMOTE_USER;
//String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
String connectionId = obj.getString("userId");
nbmWebRTCPeer.processAnswer(sd, connectionId);
}
}
} else if (obj.getString("rsp") != null) {
if (obj.getString("rsp").equals(RoomListener.METHOD_ICE_CANDIDATE)) {
JSONObject childObj = obj.getJSONObject("candidate");
String sdpMid = childObj.getString("sdpMid");
int sdpMLineIndex = Integer.valueOf(childObj.get("sdpMLineIndex").toString());
String sdp = childObj.getString("candidate");
String userId = obj.getString("userId");
IceCandidate ic = new IceCandidate(sdpMid, sdpMLineIndex, sdp);

if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
nbmWebRTCPeer.addRemoteIceCandidate(ic, "local");
} else {
nbmWebRTCPeer.addRemoteIceCandidate(ic, userId);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
/* int requestId =response.getId();

if (requestId == publishVideoRequestId){

SessionDescription sd = new SessionDescription(SessionDescription.Type.ANSWER,
response.getValue("sdpAnswer").get(0));

// Check if we are waiting for publication of our own vide
if (callState == CallState.PUBLISHING){
callState = CallState.PUBLISHED;
nbmWebRTCPeer.processAnswer(sd, "local");
mHandler.postDelayed(offerWhenReady, 2000);

// Check if we are waiting for the video publication of the other peer
} else if (callState == CallState.WAITING_REMOTE_USER){
//String user_name = Integer.toString(publishVideoRequestId);
callState = CallState.RECEIVING_REMOTE_USER;
String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
nbmWebRTCPeer.processAnswer(sd, connectionId);
}
}*/

}

@Override public void onRoomError (RoomError error){
Log.e(TAG, "OnRoomError:" + error);
}

@Override public void onRoomNotification (RoomNotification notification){
Log.i(TAG, "OnRoomNotification (state=" + callState.toString() + "):" + notification);
/* Map<String, Object> map = notification.getParams();

if(notification.getMethod().equals(RoomListener.METHOD_ICE_CANDIDATE)) {
String sdpMid = map.get("sdpMid").toString();
int sdpMLineIndex = Integer.valueOf(map.get("sdpMLineIndex").toString());
String sdp = map.get("candidate").toString();
IceCandidate ic = new IceCandidate(sdpMid, sdpMLineIndex, sdp);

if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
nbmWebRTCPeer.addRemoteIceCandidate(ic, "local");
} else {
nbmWebRTCPeer.addRemoteIceCandidate(ic, "remote");
}
}

// Somebody in the room published their video
else if(notification.getMethod().equals(RoomListener.METHOD_PARTICIPANT_PUBLISHED)) {
mHandler.postDelayed(offerWhenReady, 2000);
}*/
}

@Override public void onRoomConnected () {
}

@Override public void onRoomDisconnected () {
Utils.showFinishingError(this, "Disconnected", "You have been disconnected from room.");
}

private HashMap<String, Boolean> getUserMap () {
HashMap<String, Boolean> map = new HashMap<>();
if (usrArr != null) {
try {
JSONArray arr = new JSONArray(usrArr);
if (arr.length() > 0) {
map = new HashMap();
for (int i = 0; i < arr.length(); i++) {
JSONObject obj = (JSONObject) arr.get(i);
map.put(obj.getString("userId"), true);
//GenerateOfferForRemote(obj.getString("userId"));
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return map;
}
}









share|improve this question































    0















    I am able to achieve one 2 one video call using nubomedia(kurento-room-client-android).But not able to implement multiple video group call. Please guide me with it. I am able to get multiple video stream on onRemoteStreamAdded method. I check the onIceCandiate state for different users. Only one local and one remote iceCandidate state is connected and completed, rest remote users are still on checking. Just for testing purpose I wrote onRemoteStreamAdded code. Please don't judge it.



    public class PeerVideoActivity extends AppCompatActivity
    implements NBMWebRTCPeer.Observer, RoomListener {
    private static final String TAG = "PeerVideoActivity";
    private String usrArr;
    private NBMWebRTCPeer nbmWebRTCPeer;
    private SurfaceViewRenderer masterViewFirst, masterViewSecond;
    private boolean masterViewFirstAdded=false, masterViewSecondAdded=false;
    private SurfaceViewRenderer localView;
    private Map<Integer, String> videoRequestUserMapping;
    private int publishVideoRequestId;
    private TextView mCallStatus;
    private String username;
    private boolean isAdded = false;
    private HorizontalVideoStreamAdapter horizontalAdapter;
    private RecyclerView horizontal_recycler_view;
    private boolean isRemoteStreamAdded = false;
    private boolean backPressed = false;
    private Thread backPressedThread = null;
    private HashMap<String, Boolean> generateOfferMap, sendOfferMap, iceCandidtateMap;
    private ArrayList<MediaStream> remoteStreamList;
    private Handler mHandler = null;
    private CallState callState;

    private enum CallState {
    IDLE,
    PUBLISHING,
    PUBLISHED,
    WAITING_REMOTE_USER,
    RECEIVING_REMOTE_USER
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_conference);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    mHandler = new Handler();
    masterViewFirst = (SurfaceViewRenderer) findViewById(R.id.gl_surface_first);
    masterViewSecond= (SurfaceViewRenderer) findViewById(R.id.gl_surface_second);
    horizontal_recycler_view = (RecyclerView) findViewById(R.id.horizontal_recycler_view);
    remoteStreamList = new ArrayList<>();
    localView = (SurfaceViewRenderer) findViewById(R.id.gl_surface_local);
    this.mCallStatus = (TextView) findViewById(R.id.call_status);
    callState = CallState.IDLE;
    MainActivity.getKurentoRoomAPIInstance().addObserver(this);
    }

    @Override
    protected void onStart() {
    super.onStart();

    Bundle extras = getIntent().getExtras();
    this.username = extras.getString(Constants.USER_NAME, "");
    usrArr = extras.getString("usrArr");
    Log.i(TAG, "username: " + username);
    generateOfferMap = getUserMap();
    iceCandidtateMap = getUserMap();
    sendOfferMap = getUserMap();
    EglBase rootEglBase = EglBase.create();
    masterViewFirst.init(rootEglBase.getEglBaseContext(), null);
    masterViewFirst.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
    masterViewSecond.init(rootEglBase.getEglBaseContext(), null);
    masterViewSecond.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
    localView.init(rootEglBase.getEglBaseContext(), null);
    localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);

    NBMMediaConfiguration peerConnectionParameters =
    new NBMMediaConfiguration(NBMMediaConfiguration.NBMRendererType.OPENGLES,
    NBMMediaConfiguration.NBMAudioCodec.OPUS, 0, NBMMediaConfiguration.NBMVideoCodec.VP8, 0,
    new NBMMediaConfiguration.NBMVideoFormat(320, 240, PixelFormat.RGB_888, 30),
    NBMMediaConfiguration.NBMCameraPosition.FRONT);

    videoRequestUserMapping = new HashMap<>();
    nbmWebRTCPeer = new NBMWebRTCPeer(peerConnectionParameters, this, localView, this);
    //nbmWebRTCPeer.registerMasterRenderer(masterViewFirst);
    //nbmWebRTCPeer.registerMasterRenderer(masterViewSecond);
    horizontalAdapter = new HorizontalVideoStreamAdapter(remoteStreamList, this, nbmWebRTCPeer,
    masterViewFirst, masterViewSecond);
    LinearLayoutManager horizontalLayoutManager =
    new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
    horizontal_recycler_view.setLayoutManager(horizontalLayoutManager);
    horizontal_recycler_view.setAdapter(horizontalAdapter);
    Log.i(TAG, "Initializing nbmWebRTCPeer...");
    nbmWebRTCPeer.initialize();
    callState = CallState.PUBLISHING;
    mCallStatus.setText("Publishing...");
    }

    @Override
    protected void onStop() {
    //endCall();
    super.onStop();
    }

    @Override
    protected void onPause() {
    //nbmWebRTCPeer.stopLocalMedia();
    super.onPause();
    }

    @Override
    protected void onResume() {
    super.onResume();
    nbmWebRTCPeer.startLocalMedia();
    }

    @Override
    protected void onDestroy() {
    super.onDestroy();
    }

    /* @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_video_chat, menu);
    return true;
    }*/

    /* @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
    return true;
    }

    return super.onOptionsItemSelected(item);
    }*/

    @Override
    public void onBackPressed() {
    // If back button has not been pressed in a while then trigger thread and toast notification
    if (!this.backPressed) {
    this.backPressed = true;
    Toast.makeText(this, "Press back again to end.", Toast.LENGTH_SHORT).show();
    this.backPressedThread = new Thread(new Runnable() {
    @Override
    public void run() {
    try {
    Thread.sleep(1000);
    backPressed = false;
    } catch (InterruptedException e) {
    Log.d("VCA-oBP", "Successfully interrupted");
    }
    }
    });
    this.backPressedThread.start();
    }
    // If button pressed the second time then call super back pressed
    // (eventually calls onDestroy)
    else {
    if (this.backPressedThread != null) this.backPressedThread.interrupt();
    super.onBackPressed();
    }
    }

    public void hangup(View view) {
    finish();
    }

    private void GenerateOfferForRemote(String remote_name) {
    nbmWebRTCPeer.generateOffer(remote_name, false);
    callState = CallState.WAITING_REMOTE_USER;
    runOnUiThread(new Runnable() {
    @Override
    public void run() {
    mCallStatus.setText(R.string.waiting_remote_stream);
    }
    });
    }

    public void receiveFromRemote(View view) {
    //GenerateOfferForRemote();
    }

    /**
    * Terminates the current call and ends activity
    */
    /* private void endCall() {
    callState = CallState.IDLE;
    try
    {
    if (nbmWebRTCPeer != null) {
    nbmWebRTCPeer.close();
    nbmWebRTCPeer = null;
    }
    }
    catch (Exception e){e.printStackTrace();}
    }*/
    @Override
    public void onInitialize() {
    if (nbmWebRTCPeer != null) nbmWebRTCPeer.generateOffer("local", true);
    }

    @Override
    public void onLocalSdpOfferGenerated(final SessionDescription sessionDescription,
    final NBMPeerConnection nbmPeerConnection) {
    if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
    Log.d(TAG, "local " + sessionDescription.type);
    //publishVideoRequestId = ++Constants.id;
    Log.i("sendPublishVideo", username);
    MainActivity.getKurentoRoomAPIInstance()
    .sendPublishVideo(sessionDescription.description, username);
    } else { // Asking for remote user video
    Log.d(TAG, "remote " + sessionDescription.type);
    if (sendOfferMap != null) {
    for (Map.Entry<String, Boolean> entry : sendOfferMap.entrySet()) {
    if (entry.getValue()) {
    MainActivity.getKurentoRoomAPIInstance()
    .sendPublishVideo(sessionDescription.description, entry.getKey());
    entry.setValue(false);
    }
    }
    }
    }
    }

    @Override
    public void onLocalSdpAnswerGenerated(SessionDescription sessionDescription,
    NBMPeerConnection nbmPeerConnection) {
    }

    @Override
    public void onIceCandidate(IceCandidate iceCandidate, NBMPeerConnection nbmPeerConnection) {
    int sendIceCandidateRequestId = ++Constants.id;
    if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
    MainActivity.getKurentoRoomAPIInstance()
    .sendOnIceCandidate(this.username, iceCandidate.sdp, iceCandidate.sdpMid,
    Integer.toString(iceCandidate.sdpMLineIndex));
    } else {
    if (iceCandidtateMap != null) {
    for (Map.Entry<String, Boolean> entry : iceCandidtateMap.entrySet()) {
    if (entry.getValue()) {
    MainActivity.getKurentoRoomAPIInstance()
    .sendOnIceCandidate(entry.getKey(), iceCandidate.sdp, iceCandidate.sdpMid,
    Integer.toString(iceCandidate.sdpMLineIndex));
    entry.setValue(false);
    }
    }
    }
    //MainActivity.getKurentoRoomAPIInstance().sendOnIceCandidate(nbmPeerConnection.getConnectionId(), iceCandidate.sdp,
    // iceCandidate.sdpMid, Integer.toString(iceCandidate.sdpMLineIndex), sendIceCandidateRequestId);
    }
    }

    @Override
    public void onIceStatusChanged(PeerConnection.IceConnectionState iceConnectionState,
    NBMPeerConnection nbmPeerConnection) {
    Log.i(TAG, "onIceStatusChanged");
    }

    @Override
    public void onRemoteStreamAdded(final MediaStream mediaStream,
    final NBMPeerConnection nbmPeerConnection) {
    Log.i(TAG, "Enter onRemoteStreamAdded");
    if (!nbmPeerConnection.getConnectionId().equalsIgnoreCase("local")) {
    remoteStreamList.add(mediaStream);

    runOnUiThread(new Runnable() {
    @Override
    public void run() {
    mCallStatus.setText("");

    if(remoteStreamList != null) {
    if (remoteStreamList.size() == 1) {
    //nbmWebRTCPeer.attachRendererToRemoteStream(masterViewFirst, remoteStreamList.get(0));
    remoteStreamList.get(0).videoTracks.get(0).addRenderer(new VideoRenderer(masterViewFirst));
    } else if (remoteStreamList.size() ==2) {
    remoteStreamList.get(1).videoTracks.get(0).addRenderer(new VideoRenderer(masterViewSecond));
    }
    }
    }
    });
    }
    Log.i(TAG, "onRemoteStreamAdded :" + remoteStreamList.size());
    Log.i(TAG, "Exit onRemoteStreamAdded");
    }

    @Override public void onRemoteStreamRemoved (MediaStream mediaStream, NBMPeerConnection
    nbmPeerConnection){
    Log.i(TAG, "onRemoteStreamRemoved");
    }

    @Override public void onPeerConnectionError (String s){
    Log.i(TAG, "onPeerConnectionError:" + s);
    }

    @Override public void onDataChannel (DataChannel dataChannel, NBMPeerConnection connection){
    Log.i(TAG, "[datachannel] Peer opened data channel");
    }

    @Override public void onBufferedAmountChange ( long l, NBMPeerConnection connection, DataChannel
    channel){

    }

    public void sendHelloMessage (DataChannel channel){
    /*byte rawMessage = "Hello Peer!".getBytes(Charset.forName("UTF-8"));
    ByteBuffer directData = ByteBuffer.allocateDirect(rawMessage.length);
    directData.put(rawMessage);
    directData.flip();
    DataChannel.Buffer data = new DataChannel.Buffer(directData, false);
    channel.send(data);*/
    }

    @Override public void onStateChange (NBMPeerConnection connection, DataChannel channel){
    Log.i(TAG, "[datachannel] DataChannel onStateChange: " + channel.state());
    /* if (channel.state() == DataChannel.State.OPEN) {
    sendHelloMessage(channel);
    Log.i(TAG, "[datachannel] Datachannel open, sending first hello");
    }*/
    }

    @Override public void onMessage (DataChannel.Buffer buffer, NBMPeerConnection
    connection, DataChannel channel){
    Log.i(TAG, "[datachannel] Message received: " + buffer.toString());
    //sendHelloMessage(channel);
    }

    /* private Runnable offerWhenReady = new Runnable() {
    @Override
    public void run() {
    // Generate offers to receive video from all peers in the room
    if (generateOfferMap != null) {
    for (Map.Entry<String, Boolean> entry : generateOfferMap.entrySet()) {
    if (entry.getValue()) {
    GenerateOfferForRemote(entry.getKey());
    Log.i(TAG, "I'm " + username + " DERP: Generating offer for peer " + entry.getKey());
    // Set value to false so that if this function is called again we won't
    // generate another offer for this user
    entry.setValue(false);
    }
    }
    }
    }
    };*/

    private void offerWhenReady(){
    if (generateOfferMap != null) {
    for (Map.Entry<String, Boolean> entry : generateOfferMap.entrySet()) {
    if (entry.getValue()) {
    GenerateOfferForRemote(entry.getKey());
    Log.i(TAG, "I'm " + username + " DERP: Generating offer for peer " + entry.getKey());
    // Set value to false so that if this function is called again we won't
    // generate another offer for this user
    entry.setValue(false);
    }
    }
    }
    }

    @Override public void onRoomResponse (/*RoomResponse*/ String response){
    Log.d(TAG, "OnRoomResponse:" + response);
    if (response != null) {
    try {
    JSONObject obj = new JSONObject(response);
    if (obj.getString("rsp").equals("answer")) {
    if (obj.getString("answer") != null) {
    SessionDescription sd =
    new SessionDescription(SessionDescription.Type.ANSWER, obj.getString("answer"));

    // Check if we are waiting for publication of our own vide
    if (callState == CallState.PUBLISHING) {
    callState = CallState.PUBLISHED;
    nbmWebRTCPeer.processAnswer(sd, "local");
    //mHandler.postDelayed(offerWhenReady, 2000);
    offerWhenReady();

    // Check if we are waiting for the video publication of the other peer
    } else if (callState == CallState.WAITING_REMOTE_USER) {
    //String user_name = Integer.toString(publishVideoRequestId);
    callState = CallState.RECEIVING_REMOTE_USER;
    //String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
    String connectionId = obj.getString("userId");
    nbmWebRTCPeer.processAnswer(sd, connectionId);
    } else {
    callState = CallState.RECEIVING_REMOTE_USER;
    //String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
    String connectionId = obj.getString("userId");
    nbmWebRTCPeer.processAnswer(sd, connectionId);
    }
    }
    } else if (obj.getString("rsp") != null) {
    if (obj.getString("rsp").equals(RoomListener.METHOD_ICE_CANDIDATE)) {
    JSONObject childObj = obj.getJSONObject("candidate");
    String sdpMid = childObj.getString("sdpMid");
    int sdpMLineIndex = Integer.valueOf(childObj.get("sdpMLineIndex").toString());
    String sdp = childObj.getString("candidate");
    String userId = obj.getString("userId");
    IceCandidate ic = new IceCandidate(sdpMid, sdpMLineIndex, sdp);

    if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
    nbmWebRTCPeer.addRemoteIceCandidate(ic, "local");
    } else {
    nbmWebRTCPeer.addRemoteIceCandidate(ic, userId);
    }
    }
    }
    } catch (JSONException e) {
    e.printStackTrace();
    }
    }
    /* int requestId =response.getId();

    if (requestId == publishVideoRequestId){

    SessionDescription sd = new SessionDescription(SessionDescription.Type.ANSWER,
    response.getValue("sdpAnswer").get(0));

    // Check if we are waiting for publication of our own vide
    if (callState == CallState.PUBLISHING){
    callState = CallState.PUBLISHED;
    nbmWebRTCPeer.processAnswer(sd, "local");
    mHandler.postDelayed(offerWhenReady, 2000);

    // Check if we are waiting for the video publication of the other peer
    } else if (callState == CallState.WAITING_REMOTE_USER){
    //String user_name = Integer.toString(publishVideoRequestId);
    callState = CallState.RECEIVING_REMOTE_USER;
    String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
    nbmWebRTCPeer.processAnswer(sd, connectionId);
    }
    }*/

    }

    @Override public void onRoomError (RoomError error){
    Log.e(TAG, "OnRoomError:" + error);
    }

    @Override public void onRoomNotification (RoomNotification notification){
    Log.i(TAG, "OnRoomNotification (state=" + callState.toString() + "):" + notification);
    /* Map<String, Object> map = notification.getParams();

    if(notification.getMethod().equals(RoomListener.METHOD_ICE_CANDIDATE)) {
    String sdpMid = map.get("sdpMid").toString();
    int sdpMLineIndex = Integer.valueOf(map.get("sdpMLineIndex").toString());
    String sdp = map.get("candidate").toString();
    IceCandidate ic = new IceCandidate(sdpMid, sdpMLineIndex, sdp);

    if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
    nbmWebRTCPeer.addRemoteIceCandidate(ic, "local");
    } else {
    nbmWebRTCPeer.addRemoteIceCandidate(ic, "remote");
    }
    }

    // Somebody in the room published their video
    else if(notification.getMethod().equals(RoomListener.METHOD_PARTICIPANT_PUBLISHED)) {
    mHandler.postDelayed(offerWhenReady, 2000);
    }*/
    }

    @Override public void onRoomConnected () {
    }

    @Override public void onRoomDisconnected () {
    Utils.showFinishingError(this, "Disconnected", "You have been disconnected from room.");
    }

    private HashMap<String, Boolean> getUserMap () {
    HashMap<String, Boolean> map = new HashMap<>();
    if (usrArr != null) {
    try {
    JSONArray arr = new JSONArray(usrArr);
    if (arr.length() > 0) {
    map = new HashMap();
    for (int i = 0; i < arr.length(); i++) {
    JSONObject obj = (JSONObject) arr.get(i);
    map.put(obj.getString("userId"), true);
    //GenerateOfferForRemote(obj.getString("userId"));
    }
    }
    } catch (JSONException e) {
    e.printStackTrace();
    }
    }
    return map;
    }
    }









    share|improve this question



























      0












      0








      0








      I am able to achieve one 2 one video call using nubomedia(kurento-room-client-android).But not able to implement multiple video group call. Please guide me with it. I am able to get multiple video stream on onRemoteStreamAdded method. I check the onIceCandiate state for different users. Only one local and one remote iceCandidate state is connected and completed, rest remote users are still on checking. Just for testing purpose I wrote onRemoteStreamAdded code. Please don't judge it.



      public class PeerVideoActivity extends AppCompatActivity
      implements NBMWebRTCPeer.Observer, RoomListener {
      private static final String TAG = "PeerVideoActivity";
      private String usrArr;
      private NBMWebRTCPeer nbmWebRTCPeer;
      private SurfaceViewRenderer masterViewFirst, masterViewSecond;
      private boolean masterViewFirstAdded=false, masterViewSecondAdded=false;
      private SurfaceViewRenderer localView;
      private Map<Integer, String> videoRequestUserMapping;
      private int publishVideoRequestId;
      private TextView mCallStatus;
      private String username;
      private boolean isAdded = false;
      private HorizontalVideoStreamAdapter horizontalAdapter;
      private RecyclerView horizontal_recycler_view;
      private boolean isRemoteStreamAdded = false;
      private boolean backPressed = false;
      private Thread backPressedThread = null;
      private HashMap<String, Boolean> generateOfferMap, sendOfferMap, iceCandidtateMap;
      private ArrayList<MediaStream> remoteStreamList;
      private Handler mHandler = null;
      private CallState callState;

      private enum CallState {
      IDLE,
      PUBLISHING,
      PUBLISHED,
      WAITING_REMOTE_USER,
      RECEIVING_REMOTE_USER
      }

      @Override
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_conference);
      getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
      mHandler = new Handler();
      masterViewFirst = (SurfaceViewRenderer) findViewById(R.id.gl_surface_first);
      masterViewSecond= (SurfaceViewRenderer) findViewById(R.id.gl_surface_second);
      horizontal_recycler_view = (RecyclerView) findViewById(R.id.horizontal_recycler_view);
      remoteStreamList = new ArrayList<>();
      localView = (SurfaceViewRenderer) findViewById(R.id.gl_surface_local);
      this.mCallStatus = (TextView) findViewById(R.id.call_status);
      callState = CallState.IDLE;
      MainActivity.getKurentoRoomAPIInstance().addObserver(this);
      }

      @Override
      protected void onStart() {
      super.onStart();

      Bundle extras = getIntent().getExtras();
      this.username = extras.getString(Constants.USER_NAME, "");
      usrArr = extras.getString("usrArr");
      Log.i(TAG, "username: " + username);
      generateOfferMap = getUserMap();
      iceCandidtateMap = getUserMap();
      sendOfferMap = getUserMap();
      EglBase rootEglBase = EglBase.create();
      masterViewFirst.init(rootEglBase.getEglBaseContext(), null);
      masterViewFirst.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
      masterViewSecond.init(rootEglBase.getEglBaseContext(), null);
      masterViewSecond.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
      localView.init(rootEglBase.getEglBaseContext(), null);
      localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);

      NBMMediaConfiguration peerConnectionParameters =
      new NBMMediaConfiguration(NBMMediaConfiguration.NBMRendererType.OPENGLES,
      NBMMediaConfiguration.NBMAudioCodec.OPUS, 0, NBMMediaConfiguration.NBMVideoCodec.VP8, 0,
      new NBMMediaConfiguration.NBMVideoFormat(320, 240, PixelFormat.RGB_888, 30),
      NBMMediaConfiguration.NBMCameraPosition.FRONT);

      videoRequestUserMapping = new HashMap<>();
      nbmWebRTCPeer = new NBMWebRTCPeer(peerConnectionParameters, this, localView, this);
      //nbmWebRTCPeer.registerMasterRenderer(masterViewFirst);
      //nbmWebRTCPeer.registerMasterRenderer(masterViewSecond);
      horizontalAdapter = new HorizontalVideoStreamAdapter(remoteStreamList, this, nbmWebRTCPeer,
      masterViewFirst, masterViewSecond);
      LinearLayoutManager horizontalLayoutManager =
      new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
      horizontal_recycler_view.setLayoutManager(horizontalLayoutManager);
      horizontal_recycler_view.setAdapter(horizontalAdapter);
      Log.i(TAG, "Initializing nbmWebRTCPeer...");
      nbmWebRTCPeer.initialize();
      callState = CallState.PUBLISHING;
      mCallStatus.setText("Publishing...");
      }

      @Override
      protected void onStop() {
      //endCall();
      super.onStop();
      }

      @Override
      protected void onPause() {
      //nbmWebRTCPeer.stopLocalMedia();
      super.onPause();
      }

      @Override
      protected void onResume() {
      super.onResume();
      nbmWebRTCPeer.startLocalMedia();
      }

      @Override
      protected void onDestroy() {
      super.onDestroy();
      }

      /* @Override
      public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.menu_video_chat, menu);
      return true;
      }*/

      /* @Override
      public boolean onOptionsItemSelected(MenuItem item) {
      // Handle action bar item clicks here. The action bar will
      // automatically handle clicks on the Home/Up button, so long
      // as you specify a parent activity in AndroidManifest.xml.
      int id = item.getItemId();

      //noinspection SimplifiableIfStatement
      if (id == R.id.action_settings) {
      return true;
      }

      return super.onOptionsItemSelected(item);
      }*/

      @Override
      public void onBackPressed() {
      // If back button has not been pressed in a while then trigger thread and toast notification
      if (!this.backPressed) {
      this.backPressed = true;
      Toast.makeText(this, "Press back again to end.", Toast.LENGTH_SHORT).show();
      this.backPressedThread = new Thread(new Runnable() {
      @Override
      public void run() {
      try {
      Thread.sleep(1000);
      backPressed = false;
      } catch (InterruptedException e) {
      Log.d("VCA-oBP", "Successfully interrupted");
      }
      }
      });
      this.backPressedThread.start();
      }
      // If button pressed the second time then call super back pressed
      // (eventually calls onDestroy)
      else {
      if (this.backPressedThread != null) this.backPressedThread.interrupt();
      super.onBackPressed();
      }
      }

      public void hangup(View view) {
      finish();
      }

      private void GenerateOfferForRemote(String remote_name) {
      nbmWebRTCPeer.generateOffer(remote_name, false);
      callState = CallState.WAITING_REMOTE_USER;
      runOnUiThread(new Runnable() {
      @Override
      public void run() {
      mCallStatus.setText(R.string.waiting_remote_stream);
      }
      });
      }

      public void receiveFromRemote(View view) {
      //GenerateOfferForRemote();
      }

      /**
      * Terminates the current call and ends activity
      */
      /* private void endCall() {
      callState = CallState.IDLE;
      try
      {
      if (nbmWebRTCPeer != null) {
      nbmWebRTCPeer.close();
      nbmWebRTCPeer = null;
      }
      }
      catch (Exception e){e.printStackTrace();}
      }*/
      @Override
      public void onInitialize() {
      if (nbmWebRTCPeer != null) nbmWebRTCPeer.generateOffer("local", true);
      }

      @Override
      public void onLocalSdpOfferGenerated(final SessionDescription sessionDescription,
      final NBMPeerConnection nbmPeerConnection) {
      if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
      Log.d(TAG, "local " + sessionDescription.type);
      //publishVideoRequestId = ++Constants.id;
      Log.i("sendPublishVideo", username);
      MainActivity.getKurentoRoomAPIInstance()
      .sendPublishVideo(sessionDescription.description, username);
      } else { // Asking for remote user video
      Log.d(TAG, "remote " + sessionDescription.type);
      if (sendOfferMap != null) {
      for (Map.Entry<String, Boolean> entry : sendOfferMap.entrySet()) {
      if (entry.getValue()) {
      MainActivity.getKurentoRoomAPIInstance()
      .sendPublishVideo(sessionDescription.description, entry.getKey());
      entry.setValue(false);
      }
      }
      }
      }
      }

      @Override
      public void onLocalSdpAnswerGenerated(SessionDescription sessionDescription,
      NBMPeerConnection nbmPeerConnection) {
      }

      @Override
      public void onIceCandidate(IceCandidate iceCandidate, NBMPeerConnection nbmPeerConnection) {
      int sendIceCandidateRequestId = ++Constants.id;
      if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
      MainActivity.getKurentoRoomAPIInstance()
      .sendOnIceCandidate(this.username, iceCandidate.sdp, iceCandidate.sdpMid,
      Integer.toString(iceCandidate.sdpMLineIndex));
      } else {
      if (iceCandidtateMap != null) {
      for (Map.Entry<String, Boolean> entry : iceCandidtateMap.entrySet()) {
      if (entry.getValue()) {
      MainActivity.getKurentoRoomAPIInstance()
      .sendOnIceCandidate(entry.getKey(), iceCandidate.sdp, iceCandidate.sdpMid,
      Integer.toString(iceCandidate.sdpMLineIndex));
      entry.setValue(false);
      }
      }
      }
      //MainActivity.getKurentoRoomAPIInstance().sendOnIceCandidate(nbmPeerConnection.getConnectionId(), iceCandidate.sdp,
      // iceCandidate.sdpMid, Integer.toString(iceCandidate.sdpMLineIndex), sendIceCandidateRequestId);
      }
      }

      @Override
      public void onIceStatusChanged(PeerConnection.IceConnectionState iceConnectionState,
      NBMPeerConnection nbmPeerConnection) {
      Log.i(TAG, "onIceStatusChanged");
      }

      @Override
      public void onRemoteStreamAdded(final MediaStream mediaStream,
      final NBMPeerConnection nbmPeerConnection) {
      Log.i(TAG, "Enter onRemoteStreamAdded");
      if (!nbmPeerConnection.getConnectionId().equalsIgnoreCase("local")) {
      remoteStreamList.add(mediaStream);

      runOnUiThread(new Runnable() {
      @Override
      public void run() {
      mCallStatus.setText("");

      if(remoteStreamList != null) {
      if (remoteStreamList.size() == 1) {
      //nbmWebRTCPeer.attachRendererToRemoteStream(masterViewFirst, remoteStreamList.get(0));
      remoteStreamList.get(0).videoTracks.get(0).addRenderer(new VideoRenderer(masterViewFirst));
      } else if (remoteStreamList.size() ==2) {
      remoteStreamList.get(1).videoTracks.get(0).addRenderer(new VideoRenderer(masterViewSecond));
      }
      }
      }
      });
      }
      Log.i(TAG, "onRemoteStreamAdded :" + remoteStreamList.size());
      Log.i(TAG, "Exit onRemoteStreamAdded");
      }

      @Override public void onRemoteStreamRemoved (MediaStream mediaStream, NBMPeerConnection
      nbmPeerConnection){
      Log.i(TAG, "onRemoteStreamRemoved");
      }

      @Override public void onPeerConnectionError (String s){
      Log.i(TAG, "onPeerConnectionError:" + s);
      }

      @Override public void onDataChannel (DataChannel dataChannel, NBMPeerConnection connection){
      Log.i(TAG, "[datachannel] Peer opened data channel");
      }

      @Override public void onBufferedAmountChange ( long l, NBMPeerConnection connection, DataChannel
      channel){

      }

      public void sendHelloMessage (DataChannel channel){
      /*byte rawMessage = "Hello Peer!".getBytes(Charset.forName("UTF-8"));
      ByteBuffer directData = ByteBuffer.allocateDirect(rawMessage.length);
      directData.put(rawMessage);
      directData.flip();
      DataChannel.Buffer data = new DataChannel.Buffer(directData, false);
      channel.send(data);*/
      }

      @Override public void onStateChange (NBMPeerConnection connection, DataChannel channel){
      Log.i(TAG, "[datachannel] DataChannel onStateChange: " + channel.state());
      /* if (channel.state() == DataChannel.State.OPEN) {
      sendHelloMessage(channel);
      Log.i(TAG, "[datachannel] Datachannel open, sending first hello");
      }*/
      }

      @Override public void onMessage (DataChannel.Buffer buffer, NBMPeerConnection
      connection, DataChannel channel){
      Log.i(TAG, "[datachannel] Message received: " + buffer.toString());
      //sendHelloMessage(channel);
      }

      /* private Runnable offerWhenReady = new Runnable() {
      @Override
      public void run() {
      // Generate offers to receive video from all peers in the room
      if (generateOfferMap != null) {
      for (Map.Entry<String, Boolean> entry : generateOfferMap.entrySet()) {
      if (entry.getValue()) {
      GenerateOfferForRemote(entry.getKey());
      Log.i(TAG, "I'm " + username + " DERP: Generating offer for peer " + entry.getKey());
      // Set value to false so that if this function is called again we won't
      // generate another offer for this user
      entry.setValue(false);
      }
      }
      }
      }
      };*/

      private void offerWhenReady(){
      if (generateOfferMap != null) {
      for (Map.Entry<String, Boolean> entry : generateOfferMap.entrySet()) {
      if (entry.getValue()) {
      GenerateOfferForRemote(entry.getKey());
      Log.i(TAG, "I'm " + username + " DERP: Generating offer for peer " + entry.getKey());
      // Set value to false so that if this function is called again we won't
      // generate another offer for this user
      entry.setValue(false);
      }
      }
      }
      }

      @Override public void onRoomResponse (/*RoomResponse*/ String response){
      Log.d(TAG, "OnRoomResponse:" + response);
      if (response != null) {
      try {
      JSONObject obj = new JSONObject(response);
      if (obj.getString("rsp").equals("answer")) {
      if (obj.getString("answer") != null) {
      SessionDescription sd =
      new SessionDescription(SessionDescription.Type.ANSWER, obj.getString("answer"));

      // Check if we are waiting for publication of our own vide
      if (callState == CallState.PUBLISHING) {
      callState = CallState.PUBLISHED;
      nbmWebRTCPeer.processAnswer(sd, "local");
      //mHandler.postDelayed(offerWhenReady, 2000);
      offerWhenReady();

      // Check if we are waiting for the video publication of the other peer
      } else if (callState == CallState.WAITING_REMOTE_USER) {
      //String user_name = Integer.toString(publishVideoRequestId);
      callState = CallState.RECEIVING_REMOTE_USER;
      //String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
      String connectionId = obj.getString("userId");
      nbmWebRTCPeer.processAnswer(sd, connectionId);
      } else {
      callState = CallState.RECEIVING_REMOTE_USER;
      //String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
      String connectionId = obj.getString("userId");
      nbmWebRTCPeer.processAnswer(sd, connectionId);
      }
      }
      } else if (obj.getString("rsp") != null) {
      if (obj.getString("rsp").equals(RoomListener.METHOD_ICE_CANDIDATE)) {
      JSONObject childObj = obj.getJSONObject("candidate");
      String sdpMid = childObj.getString("sdpMid");
      int sdpMLineIndex = Integer.valueOf(childObj.get("sdpMLineIndex").toString());
      String sdp = childObj.getString("candidate");
      String userId = obj.getString("userId");
      IceCandidate ic = new IceCandidate(sdpMid, sdpMLineIndex, sdp);

      if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
      nbmWebRTCPeer.addRemoteIceCandidate(ic, "local");
      } else {
      nbmWebRTCPeer.addRemoteIceCandidate(ic, userId);
      }
      }
      }
      } catch (JSONException e) {
      e.printStackTrace();
      }
      }
      /* int requestId =response.getId();

      if (requestId == publishVideoRequestId){

      SessionDescription sd = new SessionDescription(SessionDescription.Type.ANSWER,
      response.getValue("sdpAnswer").get(0));

      // Check if we are waiting for publication of our own vide
      if (callState == CallState.PUBLISHING){
      callState = CallState.PUBLISHED;
      nbmWebRTCPeer.processAnswer(sd, "local");
      mHandler.postDelayed(offerWhenReady, 2000);

      // Check if we are waiting for the video publication of the other peer
      } else if (callState == CallState.WAITING_REMOTE_USER){
      //String user_name = Integer.toString(publishVideoRequestId);
      callState = CallState.RECEIVING_REMOTE_USER;
      String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
      nbmWebRTCPeer.processAnswer(sd, connectionId);
      }
      }*/

      }

      @Override public void onRoomError (RoomError error){
      Log.e(TAG, "OnRoomError:" + error);
      }

      @Override public void onRoomNotification (RoomNotification notification){
      Log.i(TAG, "OnRoomNotification (state=" + callState.toString() + "):" + notification);
      /* Map<String, Object> map = notification.getParams();

      if(notification.getMethod().equals(RoomListener.METHOD_ICE_CANDIDATE)) {
      String sdpMid = map.get("sdpMid").toString();
      int sdpMLineIndex = Integer.valueOf(map.get("sdpMLineIndex").toString());
      String sdp = map.get("candidate").toString();
      IceCandidate ic = new IceCandidate(sdpMid, sdpMLineIndex, sdp);

      if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
      nbmWebRTCPeer.addRemoteIceCandidate(ic, "local");
      } else {
      nbmWebRTCPeer.addRemoteIceCandidate(ic, "remote");
      }
      }

      // Somebody in the room published their video
      else if(notification.getMethod().equals(RoomListener.METHOD_PARTICIPANT_PUBLISHED)) {
      mHandler.postDelayed(offerWhenReady, 2000);
      }*/
      }

      @Override public void onRoomConnected () {
      }

      @Override public void onRoomDisconnected () {
      Utils.showFinishingError(this, "Disconnected", "You have been disconnected from room.");
      }

      private HashMap<String, Boolean> getUserMap () {
      HashMap<String, Boolean> map = new HashMap<>();
      if (usrArr != null) {
      try {
      JSONArray arr = new JSONArray(usrArr);
      if (arr.length() > 0) {
      map = new HashMap();
      for (int i = 0; i < arr.length(); i++) {
      JSONObject obj = (JSONObject) arr.get(i);
      map.put(obj.getString("userId"), true);
      //GenerateOfferForRemote(obj.getString("userId"));
      }
      }
      } catch (JSONException e) {
      e.printStackTrace();
      }
      }
      return map;
      }
      }









      share|improve this question
















      I am able to achieve one 2 one video call using nubomedia(kurento-room-client-android).But not able to implement multiple video group call. Please guide me with it. I am able to get multiple video stream on onRemoteStreamAdded method. I check the onIceCandiate state for different users. Only one local and one remote iceCandidate state is connected and completed, rest remote users are still on checking. Just for testing purpose I wrote onRemoteStreamAdded code. Please don't judge it.



      public class PeerVideoActivity extends AppCompatActivity
      implements NBMWebRTCPeer.Observer, RoomListener {
      private static final String TAG = "PeerVideoActivity";
      private String usrArr;
      private NBMWebRTCPeer nbmWebRTCPeer;
      private SurfaceViewRenderer masterViewFirst, masterViewSecond;
      private boolean masterViewFirstAdded=false, masterViewSecondAdded=false;
      private SurfaceViewRenderer localView;
      private Map<Integer, String> videoRequestUserMapping;
      private int publishVideoRequestId;
      private TextView mCallStatus;
      private String username;
      private boolean isAdded = false;
      private HorizontalVideoStreamAdapter horizontalAdapter;
      private RecyclerView horizontal_recycler_view;
      private boolean isRemoteStreamAdded = false;
      private boolean backPressed = false;
      private Thread backPressedThread = null;
      private HashMap<String, Boolean> generateOfferMap, sendOfferMap, iceCandidtateMap;
      private ArrayList<MediaStream> remoteStreamList;
      private Handler mHandler = null;
      private CallState callState;

      private enum CallState {
      IDLE,
      PUBLISHING,
      PUBLISHED,
      WAITING_REMOTE_USER,
      RECEIVING_REMOTE_USER
      }

      @Override
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_conference);
      getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
      mHandler = new Handler();
      masterViewFirst = (SurfaceViewRenderer) findViewById(R.id.gl_surface_first);
      masterViewSecond= (SurfaceViewRenderer) findViewById(R.id.gl_surface_second);
      horizontal_recycler_view = (RecyclerView) findViewById(R.id.horizontal_recycler_view);
      remoteStreamList = new ArrayList<>();
      localView = (SurfaceViewRenderer) findViewById(R.id.gl_surface_local);
      this.mCallStatus = (TextView) findViewById(R.id.call_status);
      callState = CallState.IDLE;
      MainActivity.getKurentoRoomAPIInstance().addObserver(this);
      }

      @Override
      protected void onStart() {
      super.onStart();

      Bundle extras = getIntent().getExtras();
      this.username = extras.getString(Constants.USER_NAME, "");
      usrArr = extras.getString("usrArr");
      Log.i(TAG, "username: " + username);
      generateOfferMap = getUserMap();
      iceCandidtateMap = getUserMap();
      sendOfferMap = getUserMap();
      EglBase rootEglBase = EglBase.create();
      masterViewFirst.init(rootEglBase.getEglBaseContext(), null);
      masterViewFirst.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
      masterViewSecond.init(rootEglBase.getEglBaseContext(), null);
      masterViewSecond.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
      localView.init(rootEglBase.getEglBaseContext(), null);
      localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);

      NBMMediaConfiguration peerConnectionParameters =
      new NBMMediaConfiguration(NBMMediaConfiguration.NBMRendererType.OPENGLES,
      NBMMediaConfiguration.NBMAudioCodec.OPUS, 0, NBMMediaConfiguration.NBMVideoCodec.VP8, 0,
      new NBMMediaConfiguration.NBMVideoFormat(320, 240, PixelFormat.RGB_888, 30),
      NBMMediaConfiguration.NBMCameraPosition.FRONT);

      videoRequestUserMapping = new HashMap<>();
      nbmWebRTCPeer = new NBMWebRTCPeer(peerConnectionParameters, this, localView, this);
      //nbmWebRTCPeer.registerMasterRenderer(masterViewFirst);
      //nbmWebRTCPeer.registerMasterRenderer(masterViewSecond);
      horizontalAdapter = new HorizontalVideoStreamAdapter(remoteStreamList, this, nbmWebRTCPeer,
      masterViewFirst, masterViewSecond);
      LinearLayoutManager horizontalLayoutManager =
      new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
      horizontal_recycler_view.setLayoutManager(horizontalLayoutManager);
      horizontal_recycler_view.setAdapter(horizontalAdapter);
      Log.i(TAG, "Initializing nbmWebRTCPeer...");
      nbmWebRTCPeer.initialize();
      callState = CallState.PUBLISHING;
      mCallStatus.setText("Publishing...");
      }

      @Override
      protected void onStop() {
      //endCall();
      super.onStop();
      }

      @Override
      protected void onPause() {
      //nbmWebRTCPeer.stopLocalMedia();
      super.onPause();
      }

      @Override
      protected void onResume() {
      super.onResume();
      nbmWebRTCPeer.startLocalMedia();
      }

      @Override
      protected void onDestroy() {
      super.onDestroy();
      }

      /* @Override
      public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.menu_video_chat, menu);
      return true;
      }*/

      /* @Override
      public boolean onOptionsItemSelected(MenuItem item) {
      // Handle action bar item clicks here. The action bar will
      // automatically handle clicks on the Home/Up button, so long
      // as you specify a parent activity in AndroidManifest.xml.
      int id = item.getItemId();

      //noinspection SimplifiableIfStatement
      if (id == R.id.action_settings) {
      return true;
      }

      return super.onOptionsItemSelected(item);
      }*/

      @Override
      public void onBackPressed() {
      // If back button has not been pressed in a while then trigger thread and toast notification
      if (!this.backPressed) {
      this.backPressed = true;
      Toast.makeText(this, "Press back again to end.", Toast.LENGTH_SHORT).show();
      this.backPressedThread = new Thread(new Runnable() {
      @Override
      public void run() {
      try {
      Thread.sleep(1000);
      backPressed = false;
      } catch (InterruptedException e) {
      Log.d("VCA-oBP", "Successfully interrupted");
      }
      }
      });
      this.backPressedThread.start();
      }
      // If button pressed the second time then call super back pressed
      // (eventually calls onDestroy)
      else {
      if (this.backPressedThread != null) this.backPressedThread.interrupt();
      super.onBackPressed();
      }
      }

      public void hangup(View view) {
      finish();
      }

      private void GenerateOfferForRemote(String remote_name) {
      nbmWebRTCPeer.generateOffer(remote_name, false);
      callState = CallState.WAITING_REMOTE_USER;
      runOnUiThread(new Runnable() {
      @Override
      public void run() {
      mCallStatus.setText(R.string.waiting_remote_stream);
      }
      });
      }

      public void receiveFromRemote(View view) {
      //GenerateOfferForRemote();
      }

      /**
      * Terminates the current call and ends activity
      */
      /* private void endCall() {
      callState = CallState.IDLE;
      try
      {
      if (nbmWebRTCPeer != null) {
      nbmWebRTCPeer.close();
      nbmWebRTCPeer = null;
      }
      }
      catch (Exception e){e.printStackTrace();}
      }*/
      @Override
      public void onInitialize() {
      if (nbmWebRTCPeer != null) nbmWebRTCPeer.generateOffer("local", true);
      }

      @Override
      public void onLocalSdpOfferGenerated(final SessionDescription sessionDescription,
      final NBMPeerConnection nbmPeerConnection) {
      if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
      Log.d(TAG, "local " + sessionDescription.type);
      //publishVideoRequestId = ++Constants.id;
      Log.i("sendPublishVideo", username);
      MainActivity.getKurentoRoomAPIInstance()
      .sendPublishVideo(sessionDescription.description, username);
      } else { // Asking for remote user video
      Log.d(TAG, "remote " + sessionDescription.type);
      if (sendOfferMap != null) {
      for (Map.Entry<String, Boolean> entry : sendOfferMap.entrySet()) {
      if (entry.getValue()) {
      MainActivity.getKurentoRoomAPIInstance()
      .sendPublishVideo(sessionDescription.description, entry.getKey());
      entry.setValue(false);
      }
      }
      }
      }
      }

      @Override
      public void onLocalSdpAnswerGenerated(SessionDescription sessionDescription,
      NBMPeerConnection nbmPeerConnection) {
      }

      @Override
      public void onIceCandidate(IceCandidate iceCandidate, NBMPeerConnection nbmPeerConnection) {
      int sendIceCandidateRequestId = ++Constants.id;
      if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
      MainActivity.getKurentoRoomAPIInstance()
      .sendOnIceCandidate(this.username, iceCandidate.sdp, iceCandidate.sdpMid,
      Integer.toString(iceCandidate.sdpMLineIndex));
      } else {
      if (iceCandidtateMap != null) {
      for (Map.Entry<String, Boolean> entry : iceCandidtateMap.entrySet()) {
      if (entry.getValue()) {
      MainActivity.getKurentoRoomAPIInstance()
      .sendOnIceCandidate(entry.getKey(), iceCandidate.sdp, iceCandidate.sdpMid,
      Integer.toString(iceCandidate.sdpMLineIndex));
      entry.setValue(false);
      }
      }
      }
      //MainActivity.getKurentoRoomAPIInstance().sendOnIceCandidate(nbmPeerConnection.getConnectionId(), iceCandidate.sdp,
      // iceCandidate.sdpMid, Integer.toString(iceCandidate.sdpMLineIndex), sendIceCandidateRequestId);
      }
      }

      @Override
      public void onIceStatusChanged(PeerConnection.IceConnectionState iceConnectionState,
      NBMPeerConnection nbmPeerConnection) {
      Log.i(TAG, "onIceStatusChanged");
      }

      @Override
      public void onRemoteStreamAdded(final MediaStream mediaStream,
      final NBMPeerConnection nbmPeerConnection) {
      Log.i(TAG, "Enter onRemoteStreamAdded");
      if (!nbmPeerConnection.getConnectionId().equalsIgnoreCase("local")) {
      remoteStreamList.add(mediaStream);

      runOnUiThread(new Runnable() {
      @Override
      public void run() {
      mCallStatus.setText("");

      if(remoteStreamList != null) {
      if (remoteStreamList.size() == 1) {
      //nbmWebRTCPeer.attachRendererToRemoteStream(masterViewFirst, remoteStreamList.get(0));
      remoteStreamList.get(0).videoTracks.get(0).addRenderer(new VideoRenderer(masterViewFirst));
      } else if (remoteStreamList.size() ==2) {
      remoteStreamList.get(1).videoTracks.get(0).addRenderer(new VideoRenderer(masterViewSecond));
      }
      }
      }
      });
      }
      Log.i(TAG, "onRemoteStreamAdded :" + remoteStreamList.size());
      Log.i(TAG, "Exit onRemoteStreamAdded");
      }

      @Override public void onRemoteStreamRemoved (MediaStream mediaStream, NBMPeerConnection
      nbmPeerConnection){
      Log.i(TAG, "onRemoteStreamRemoved");
      }

      @Override public void onPeerConnectionError (String s){
      Log.i(TAG, "onPeerConnectionError:" + s);
      }

      @Override public void onDataChannel (DataChannel dataChannel, NBMPeerConnection connection){
      Log.i(TAG, "[datachannel] Peer opened data channel");
      }

      @Override public void onBufferedAmountChange ( long l, NBMPeerConnection connection, DataChannel
      channel){

      }

      public void sendHelloMessage (DataChannel channel){
      /*byte rawMessage = "Hello Peer!".getBytes(Charset.forName("UTF-8"));
      ByteBuffer directData = ByteBuffer.allocateDirect(rawMessage.length);
      directData.put(rawMessage);
      directData.flip();
      DataChannel.Buffer data = new DataChannel.Buffer(directData, false);
      channel.send(data);*/
      }

      @Override public void onStateChange (NBMPeerConnection connection, DataChannel channel){
      Log.i(TAG, "[datachannel] DataChannel onStateChange: " + channel.state());
      /* if (channel.state() == DataChannel.State.OPEN) {
      sendHelloMessage(channel);
      Log.i(TAG, "[datachannel] Datachannel open, sending first hello");
      }*/
      }

      @Override public void onMessage (DataChannel.Buffer buffer, NBMPeerConnection
      connection, DataChannel channel){
      Log.i(TAG, "[datachannel] Message received: " + buffer.toString());
      //sendHelloMessage(channel);
      }

      /* private Runnable offerWhenReady = new Runnable() {
      @Override
      public void run() {
      // Generate offers to receive video from all peers in the room
      if (generateOfferMap != null) {
      for (Map.Entry<String, Boolean> entry : generateOfferMap.entrySet()) {
      if (entry.getValue()) {
      GenerateOfferForRemote(entry.getKey());
      Log.i(TAG, "I'm " + username + " DERP: Generating offer for peer " + entry.getKey());
      // Set value to false so that if this function is called again we won't
      // generate another offer for this user
      entry.setValue(false);
      }
      }
      }
      }
      };*/

      private void offerWhenReady(){
      if (generateOfferMap != null) {
      for (Map.Entry<String, Boolean> entry : generateOfferMap.entrySet()) {
      if (entry.getValue()) {
      GenerateOfferForRemote(entry.getKey());
      Log.i(TAG, "I'm " + username + " DERP: Generating offer for peer " + entry.getKey());
      // Set value to false so that if this function is called again we won't
      // generate another offer for this user
      entry.setValue(false);
      }
      }
      }
      }

      @Override public void onRoomResponse (/*RoomResponse*/ String response){
      Log.d(TAG, "OnRoomResponse:" + response);
      if (response != null) {
      try {
      JSONObject obj = new JSONObject(response);
      if (obj.getString("rsp").equals("answer")) {
      if (obj.getString("answer") != null) {
      SessionDescription sd =
      new SessionDescription(SessionDescription.Type.ANSWER, obj.getString("answer"));

      // Check if we are waiting for publication of our own vide
      if (callState == CallState.PUBLISHING) {
      callState = CallState.PUBLISHED;
      nbmWebRTCPeer.processAnswer(sd, "local");
      //mHandler.postDelayed(offerWhenReady, 2000);
      offerWhenReady();

      // Check if we are waiting for the video publication of the other peer
      } else if (callState == CallState.WAITING_REMOTE_USER) {
      //String user_name = Integer.toString(publishVideoRequestId);
      callState = CallState.RECEIVING_REMOTE_USER;
      //String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
      String connectionId = obj.getString("userId");
      nbmWebRTCPeer.processAnswer(sd, connectionId);
      } else {
      callState = CallState.RECEIVING_REMOTE_USER;
      //String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
      String connectionId = obj.getString("userId");
      nbmWebRTCPeer.processAnswer(sd, connectionId);
      }
      }
      } else if (obj.getString("rsp") != null) {
      if (obj.getString("rsp").equals(RoomListener.METHOD_ICE_CANDIDATE)) {
      JSONObject childObj = obj.getJSONObject("candidate");
      String sdpMid = childObj.getString("sdpMid");
      int sdpMLineIndex = Integer.valueOf(childObj.get("sdpMLineIndex").toString());
      String sdp = childObj.getString("candidate");
      String userId = obj.getString("userId");
      IceCandidate ic = new IceCandidate(sdpMid, sdpMLineIndex, sdp);

      if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
      nbmWebRTCPeer.addRemoteIceCandidate(ic, "local");
      } else {
      nbmWebRTCPeer.addRemoteIceCandidate(ic, userId);
      }
      }
      }
      } catch (JSONException e) {
      e.printStackTrace();
      }
      }
      /* int requestId =response.getId();

      if (requestId == publishVideoRequestId){

      SessionDescription sd = new SessionDescription(SessionDescription.Type.ANSWER,
      response.getValue("sdpAnswer").get(0));

      // Check if we are waiting for publication of our own vide
      if (callState == CallState.PUBLISHING){
      callState = CallState.PUBLISHED;
      nbmWebRTCPeer.processAnswer(sd, "local");
      mHandler.postDelayed(offerWhenReady, 2000);

      // Check if we are waiting for the video publication of the other peer
      } else if (callState == CallState.WAITING_REMOTE_USER){
      //String user_name = Integer.toString(publishVideoRequestId);
      callState = CallState.RECEIVING_REMOTE_USER;
      String connectionId = videoRequestUserMapping.get(publishVideoRequestId);
      nbmWebRTCPeer.processAnswer(sd, connectionId);
      }
      }*/

      }

      @Override public void onRoomError (RoomError error){
      Log.e(TAG, "OnRoomError:" + error);
      }

      @Override public void onRoomNotification (RoomNotification notification){
      Log.i(TAG, "OnRoomNotification (state=" + callState.toString() + "):" + notification);
      /* Map<String, Object> map = notification.getParams();

      if(notification.getMethod().equals(RoomListener.METHOD_ICE_CANDIDATE)) {
      String sdpMid = map.get("sdpMid").toString();
      int sdpMLineIndex = Integer.valueOf(map.get("sdpMLineIndex").toString());
      String sdp = map.get("candidate").toString();
      IceCandidate ic = new IceCandidate(sdpMid, sdpMLineIndex, sdp);

      if (callState == CallState.PUBLISHING || callState == CallState.PUBLISHED) {
      nbmWebRTCPeer.addRemoteIceCandidate(ic, "local");
      } else {
      nbmWebRTCPeer.addRemoteIceCandidate(ic, "remote");
      }
      }

      // Somebody in the room published their video
      else if(notification.getMethod().equals(RoomListener.METHOD_PARTICIPANT_PUBLISHED)) {
      mHandler.postDelayed(offerWhenReady, 2000);
      }*/
      }

      @Override public void onRoomConnected () {
      }

      @Override public void onRoomDisconnected () {
      Utils.showFinishingError(this, "Disconnected", "You have been disconnected from room.");
      }

      private HashMap<String, Boolean> getUserMap () {
      HashMap<String, Boolean> map = new HashMap<>();
      if (usrArr != null) {
      try {
      JSONArray arr = new JSONArray(usrArr);
      if (arr.length() > 0) {
      map = new HashMap();
      for (int i = 0; i < arr.length(); i++) {
      JSONObject obj = (JSONObject) arr.get(i);
      map.put(obj.getString("userId"), true);
      //GenerateOfferForRemote(obj.getString("userId"));
      }
      }
      } catch (JSONException e) {
      e.printStackTrace();
      }
      }
      return map;
      }
      }






      android kurento






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 27 '18 at 14:28







      user2980181

















      asked Nov 25 '18 at 5:35









      user2980181user2980181

      1721313




      1721313
























          0






          active

          oldest

          votes












          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53464943%2fimplementing-group-callmany-2-many-kurento-room-client-android%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53464943%2fimplementing-group-callmany-2-many-kurento-room-client-android%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          Tangent Lines Diagram Along Smooth Curve

          Yusuf al-Mu'taman ibn Hud

          Zucchini