I am using Vidyo.io
service to integrate video conferencing within my android app. I have been able to successfully implement the video conferencing using the VidyoConnector
sample app that comes with the android-vidyo-sdk
.
However, I would like to get more information about the conference room and the participants who join the room.
The work flow that I have imagined is as follows:
So far, I have referenced VidyoConnector
sample app to create an activity called VideoChatActivity
by making some modifications to the original VidyoConnector
sample app’s MainActivity
. The VideoChatActivity
will be invoked via Intent
from another activity within my app with all the necessary information to initiate the vidyo connection like- token, resourceId, username etc. To track the status of each participant I have implemented the VidyoConnector.IRegisterParticipantEventListener
. Please refer my code below:
public class VideoChatActivity extends Activity
implements VidyoConnector.IConnect,
VidyoConnector.IRegisterParticipantEventListener {
private enum VIDYO_CONNECTOR_STATE {
VC_CONNECTED,
VC_DISCONNECTED,
VC_DISCONNECTED_UNEXPECTED,
VC_CONNECTION_FAILURE
}
private static final String TAG = "VideoChatActivity";
private VIDYO_CONNECTOR_STATE mVidyoConnectorState = VIDYO_CONNECTOR_STATE.VC_DISCONNECTED;
private boolean mVidyoConnectorConstructed = false;
private boolean mVidyoClientInitialized = false;
private VidyoConnector mVidyoConnector = null;
private ToggleButton mToggleConnectButton;
private ProgressBar mConnectionSpinner;
private LinearLayout mToolbarLayout;
private String mHost;
private String mDisplayName;
private String mToken;
private String mResourceId;
private TextView mToolbarStatus;
private FrameLayout mVideoFrame;
private boolean mAutoJoin = false;
private boolean mAllowReconnect = true;
private String mReturnURL = null;
/*
* Operating System Events
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_chat);
// Initialize the member variables
mToggleConnectButton = (ToggleButton) findViewById(R.id.video_chat_toggleConnectButton);
mToolbarLayout = (LinearLayout) findViewById(R.id.video_chat_toolbarLayout);
mVideoFrame = (FrameLayout) findViewById(R.id.video_chat_videoFrame);
mToolbarStatus = (TextView) findViewById(R.id.video_chat_toolbarStatusText);
mConnectionSpinner = (ProgressBar) findViewById(R.id.video_chat_connectionSpinner);
// Initialize the VidyoClient
Connector.SetApplicationUIContext(this);
mVidyoClientInitialized = Connector.Initialize();
}
@Override
protected void onNewIntent(Intent intent) {
Log.d(TAG, "onNewIntent");
super.onNewIntent(intent);
// New intent was received so set it to use in onStart()
setIntent(intent);
}
@Override
protected void onStart() {
Log.d(TAG, "onStart");
super.onStart();
// If the app was launched by a different app, then get any parameters; otherwise use default settings
Intent intent = getIntent();
mHost = intent.hasExtra("host") ? intent.getStringExtra("host") : "prod.vidyo.io";
mToken = intent.hasExtra("token") ? intent.getStringExtra("token") : "";
mDisplayName = intent.hasExtra("displayName") ? intent.getStringExtra("displayName") : "";
mResourceId = intent.hasExtra("resourceId") ? intent.getStringExtra("resourceId") : "";
mReturnURL = intent.hasExtra("returnURL") ? intent.getStringExtra("returnURL") : null;
mAutoJoin = intent.getBooleanExtra("autoJoin", false);
mAllowReconnect = intent.getBooleanExtra("allowReconnect", true);
Log.d(TAG, "onStart: autoJoin = " + mAutoJoin + ", allowReconnect = " + mAllowReconnect);
if (mDisplayName.equals("")) {
Profile myProfile = getMyProfile();
if (myProfile != null && myProfile.getDisplayName() != null) {
mDisplayName = myProfile.getDisplayName();
}
}
// Enable toggle connect button
mToggleConnectButton.setEnabled(true);
}
@Override
protected void onResume() {
Log.d(TAG, "onResume");
super.onResume();
ViewTreeObserver viewTreeObserver = mVideoFrame.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mVideoFrame.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// If the vidyo connector was not previously successfully constructed then construct it
if (!mVidyoConnectorConstructed) {
if (mVidyoClientInitialized) {
mVidyoConnector = new VidyoConnector(mVideoFrame,
VidyoConnector.VidyoConnectorViewStyle.VIDYO_CONNECTORVIEWSTYLE_Default,
16,
"info@VidyoClient info@VidyoConnector warning",
"",
0);
if (mVidyoConnector != null) {
mVidyoConnectorConstructed = true;
// Set initial position
RefreshUI();
} else {
Log.d(TAG, "VidyoConnector Construction failed - cannot " +
"connect...");
}
} else {
Log.d(TAG, "ERROR: VidyoClientInitialize failed - not constructing " +
"VidyoConnector ...");
}
Log.d(TAG, "onResume: mVidyoConnectorConstructed => " +
(mVidyoConnectorConstructed ? "success" : "failed"));
}
// If configured to auto-join, then simulate a click of the toggle connect button
if (mVidyoConnectorConstructed && mAutoJoin) {
mToggleConnectButton.performClick();
}
}
});
}
}
@Override
protected void onPause() {
Log.d(TAG, "onPause");
super.onPause();
}
@Override
protected void onRestart() {
Log.d(TAG, "onRestart");
super.onRestart();
if (mVidyoConnector != null) {
mVidyoConnector.SetMode(VidyoConnector.VidyoConnectorMode.VIDYO_CONNECTORMODE_Foreground);
}
}
@Override
protected void onStop() {
Log.d(TAG, "onStop");
if (mVidyoConnector != null) {
mVidyoConnector.SetMode(VidyoConnector.VidyoConnectorMode.VIDYO_CONNECTORMODE_Background);
}
super.onStop();
}
@Override
protected void onDestroy() {
Log.d(TAG, "onDestroy");
Connector.Uninitialize();
super.onDestroy();
}
/*
* Connector Events
*/
// Handle successful connection.
@Override
public void OnSuccess() {
Log.d(TAG, "OnSuccess: connection successful");
ConnectorStateUpdated(VIDYO_CONNECTOR_STATE.VC_CONNECTED, "Connected");
}
// Handle attempted connection failure.
@Override
public void OnFailure(VidyoConnector.VidyoConnectorFailReason reason) {
Log.d(TAG, "onFailure: connection failure reason : " + reason.toString());
// Update UI to reflect connection failed
ConnectorStateUpdated(VIDYO_CONNECTOR_STATE.VC_CONNECTION_FAILURE, "Connection failed");
}
// Handle an existing session being disconnected.
@Override
public void OnDisconnected(VidyoConnector.VidyoConnectorDisconnectReason reason) {
Log.d(TAG, "OnDisconnected: disconnect reason : " + reason.toString());
if (reason == VidyoConnector.VidyoConnectorDisconnectReason.VIDYO_CONNECTORDISCONNECTREASON_Disconnected) {
ConnectorStateUpdated(VIDYO_CONNECTOR_STATE.VC_DISCONNECTED, "Disconnected");
} else {
ConnectorStateUpdated(VIDYO_CONNECTOR_STATE.VC_DISCONNECTED_UNEXPECTED, "Unexpected disconnection");
}
}
@Override
public void OnParticipantJoined(final VidyoParticipant vidyoParticipant) {
Log.d(TAG, "joined participant id : " + vidyoParticipant.GetId());
Log.d(TAG, "joined participant name : " + vidyoParticipant.GetName());
Log.d(TAG, "joined participant userId : " + vidyoParticipant.GetUserId());
Log.d(TAG, "joined participant object ptr : " + vidyoParticipant.GetObjectPtr());
Log.d(TAG, "joined participant isHidden : " + vidyoParticipant.IsHidden());
Log.d(TAG, "joined participant isLocal : " + vidyoParticipant.IsLocal());
Log.d(TAG, "joined participant isRecording : " + vidyoParticipant.IsRecording());
Log.d(TAG, "joined participant isSelectable : " + vidyoParticipant.IsSelectable());
}
@Override
public void OnParticipantLeft(VidyoParticipant vidyoParticipant) {
Log.d(TAG, "left participant id : " + vidyoParticipant.GetId());
Log.d(TAG, "left participant name : " + vidyoParticipant.GetName());
Log.d(TAG, "left participant userId : " + vidyoParticipant.GetUserId());
Log.d(TAG, "left participant object ptr : " + vidyoParticipant.GetObjectPtr());
Log.d(TAG, "left participant isHidden : " + vidyoParticipant.IsHidden());
Log.d(TAG, "left participant isLocal : " + vidyoParticipant.IsLocal());
Log.d(TAG, "left participant isRecording : " + vidyoParticipant.IsRecording());
Log.d(TAG, "left participant isSelectable : " + vidyoParticipant.IsSelectable());
}
@Override
public void OnDynamicParticipantChanged(ArrayList<VidyoParticipant> arrayList, ArrayList<VidyoRemoteCamera> arrayList1) {
for (VidyoParticipant participant : arrayList) {
Log.d(TAG, "Participant : " + participant.GetName());
}
for (VidyoRemoteCamera remoteCamera : arrayList1) {
Log.d(TAG, "remote camera : " + remoteCamera.GetName());
}
}
@Override
public void OnLoudestParticipantChanged(VidyoParticipant vidyoParticipant, boolean b) {
Log.d(TAG, "loudest participant id : " + vidyoParticipant.GetId());
Log.d(TAG, "loudest participant name : " + vidyoParticipant.GetName());
Log.d(TAG, "loudest participant userId : " + vidyoParticipant.GetUserId());
Log.d(TAG, "loudest participant object ptr : " + vidyoParticipant.GetObjectPtr());
Log.d(TAG, "loudest participant isHidden : " + vidyoParticipant.IsHidden());
Log.d(TAG, "loudest participant isLocal : " + vidyoParticipant.IsLocal());
Log.d(TAG, "loudest participant isRecording : " + vidyoParticipant.IsRecording());
Log.d(TAG, "loudest participant isSelectable : " + vidyoParticipant.IsSelectable());
Log.d(TAG, "boolean : " + b);
}
/*
* Private Utility Functions
*/
// Refresh the UI
private void RefreshUI() {
// Refresh the rendering of the video
mVidyoConnector.ShowViewAt(mVideoFrame, 0, 0, mVideoFrame.getWidth(), mVideoFrame.getHeight());
Log.d(TAG, "VidyoConnectorShowViewAt: x = 0, y = 0, w = " + mVideoFrame.getWidth() + ", h = " + mVideoFrame.getHeight());
}
// The state of the VidyoConnector connection changed, reconfigure the UI.
// If connected, dismiss the controls layout
private void ConnectorStateUpdated(VIDYO_CONNECTOR_STATE state, final String statusText) {
Log.d(TAG, "ConnectorStateUpdated, state = " + state.toString());
mVidyoConnectorState = state;
// Execute this code on the main thread since it is updating the UI layout
runOnUiThread(new Runnable() {
@Override
public void run() {
// Update the toggle connect button to either start call or end call image
mToggleConnectButton.setChecked(mVidyoConnectorState == VIDYO_CONNECTOR_STATE.VC_CONNECTED);
// Set the status text in the toolbar
mToolbarStatus.setText(statusText);
if (mVidyoConnectorState == VIDYO_CONNECTOR_STATE.VC_CONNECTED) {
// Enable the toggle toolbar control
} else {
// VidyoConnector is disconnected
// Disable the toggle toolbar control
// If a return URL was provided as an input parameter, then return to that application
if (mReturnURL != null) {
// Provide a callstate of either 0 or 1, depending on whether the call was successful
Intent returnApp = getPackageManager().getLaunchIntentForPackage(mReturnURL);
returnApp.putExtra("callstate", (mVidyoConnectorState == VIDYO_CONNECTOR_STATE.VC_DISCONNECTED) ? 1 : 0);
startActivity(returnApp);
}
// If the allow-reconnect flag is set to false and a normal (non-failure) disconnect occurred,
// then disable the toggle connect button, in order to prevent reconnection.
if (!mAllowReconnect && (mVidyoConnectorState == VIDYO_CONNECTOR_STATE.VC_DISCONNECTED)) {
mToggleConnectButton.setEnabled(false);
mToolbarStatus.setText("Call ended");
}
}
// Hide the spinner animation
mConnectionSpinner.setVisibility(View.INVISIBLE);
}
});
}
/*
* Button Event Callbacks
*/
// The Connect button was pressed.
// If not in a call, attempt to connect to the backend service.
// If in a call, disconnect.
public void ToggleConnectButtonPressed(View v) {
if (mToggleConnectButton.isChecked()) {
mToolbarStatus.setText("Connecting...");
// Display the spinner animation
mConnectionSpinner.setVisibility(View.VISIBLE);
final boolean status = mVidyoConnector.Connect(
mHost,
mToken,
mDisplayName,
mResourceId,
this);
if (!status) {
// Hide the spinner animation
mConnectionSpinner.setVisibility(View.INVISIBLE);
ConnectorStateUpdated(VIDYO_CONNECTOR_STATE.VC_CONNECTION_FAILURE, "Connection failed");
}
Log.d(TAG, "VidyoConnectorConnect status = " + status);
mVidyoConnector.RegisterParticipantEventListener(this);
} else {
// The button just switched to the callStart image: The user is either connected to a resource
// or is in the process of connecting to a resource; call VidyoConnectorDisconnect to either disconnect
// or abort the connection attempt.
// Change the button back to the callEnd image because do not want to assume that the Disconnect
// call will actually end the call. Need to wait for the callback to be received
// before swapping to the callStart image.
mToggleConnectButton.setChecked(true);
mToolbarStatus.setText("Disconnecting...");
mVidyoConnector.UnregisterParticipantEventListener();
mVidyoConnector.Disconnect();
}
}
// Toggle the microphone privacy
public void MicrophonePrivacyButtonPressed(View v) {
mVidyoConnector.SetMicrophonePrivacy(((ToggleButton) v).isChecked());
}
// Toggle the camera privacy
public void CameraPrivacyButtonPressed(View v) {
mVidyoConnector.SetCameraPrivacy(((ToggleButton) v).isChecked());
}
// Handle the camera swap button being pressed. Cycle the camera.
public void CameraSwapButtonPressed(View v) {
mVidyoConnector.CycleCamera();
}
}
What I want to do is time each of the vidyo conference session. For this, I need to differentiate between the user who created the room (User1 in this case) and other Participants who joined the room later. By knowing this, I can time the session based on User1’s status. When the android client of User1 receives a call to OnSuccess
method of VidyoConnector.IConnect
interface (upon initiating a connection to the vidyo conference room via VidyoConnector.Connect
), I start a timer and when the android client of User1 receives a call to OnDisconnected
I stop the timer to get the total time of the session.
The issue right now is that I cannot find a way to differentiate between the User who created the room and the Participants who joined the room later. Everyone is depicted as a Participant right now. One more thing that I have noticed is that as long as there is someone present in the conference room, the room stays alive even if the user who created the room leaves it. So my questions would be:
Is there a way to differentiate between the User
who created the room and other Participants
that join the room later?
Is there a way to destroy the room and kick out all the Participants from the room when the User that created the room exits?
I understand that it might be possible to track all these info on my backend server but I want to know if it would be possible to do so on the android client.
Thanks.
The token should be generated for each user. So your work flow should be as follows -
To differentiate the user and the participant, you will have to add code in your android app. When user1 gets the "OnParticipantJoined" it can call "GetUserId" to check if it matches its own userId or if it is a different participant. Regarding booting out participants, in the current version of Vidyo.io there is no way to kick out participants from your room. One way of implementing this in your app code is by wrapping the chat methods. So if User1 is leaving its own room it can send a "Leave" message using the "SendChatMessage" to all other participants. Add some secret prefix in the string like "xyz_Leave", so that your app code on the participant side knows not to display this message but to act on it.