Skip to content

Instantly share code, notes, and snippets.

@GleasonK
Last active August 29, 2015 14:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GleasonK/2dbe293ee358b6755d8d to your computer and use it in GitHub Desktop.
Save GleasonK/2dbe293ee358b6755d8d to your computer and use it in GitHub Desktop.
Code for the PnWebRTC Tutorial
<!-- res/layout/activity_video_chat.xml -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="me.pntutorial.pnrtcblog.VideoChatActivity">
<android.opengl.GLSurfaceView
android:id="@+id/gl_surface"
android:layout_height="match_parent"
android:layout_width="match_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="END"
android:onClick="hangup"
/>
</RelativeLayout>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- PubNub Dependencies -->
<!--<uses-permission android:name="android.permission.INTERNET" />-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="your.package.name.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="your.package.name.permission.C2D_MESSAGE" />
// app/build.gradle
dependencies {
// ...
compile 'io.pristine:libjingle:9694@aar'
compile 'com.pubnub:pubnub-android:3.7.4'
compile 'me.kevingleason:pnwebrtc:1.0.6@aar'
}
// util.Constants.java
public class Constants {
public static final String STDBY_SUFFIX = "-stdby";
public static final String PUB_KEY = "demo"; // Use Your Pub Key
public static final String SUB_KEY = "demo"; // Use Your Sub Key
...
}
public void makeCall(View view){
String callNum = mCallNumET.getText().toString();
if (callNum.isEmpty() || callNum.equals(this.username)) {
Toast.makeText(this, "Enter a valid number.", Toast.LENGTH_SHORT).show();
}
dispatchCall(callNum);
}
public void dispatchCall(final String callNum) {
final String callNumStdBy = callNum + Constants.STDBY_SUFFIX;
JSONObject jsonCall = new JSONObject();
try {
jsonCall.put(Constants.JSON_CALL_USER, this.username);
mPubNub.publish(callNumStdBy, jsonCall, new Callback() {
@Override
public void successCallback(String channel, Object message) {
Log.d("MA-dCall", "SUCCESS: " + message.toString());
Intent intent = new Intent(MainActivity.this, VideoChatActivity.class);
intent.putExtra(Constants.USER_NAME, username);
intent.putExtra(Constants.CALL_USER, callNum); // Only accept from this number?
startActivity(intent);
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
public class MainActivity extends Activity {
private Pubnub mPubNub;
...
public void initPubNub() {
String stdbyChannel = this.username + Constants.STDBY_SUFFIX;
this.mPubNub = new Pubnub(Constants.PUB_KEY, Constants.SUB_KEY);
this.mPubNub.setUUID(this.username);
try {
this.mPubNub.subscribe(stdbyChannel, new Callback() {
@Override
public void successCallback(String channel, Object message) {
Log.d("MA-success", "MESSAGE: " + message.toString());
if (!(message instanceof JSONObject)) return; // Ignore if not JSONObject
JSONObject jsonMsg = (JSONObject) message;
try {
if (!jsonMsg.has(Constants.JSON_CALL_USER)) return;
String user = jsonMsg.getString(Constants.JSON_CALL_USER);
// Consider Accept/Reject call here
Intent intent = new Intent(MainActivity.this, VideoChatActivity.class);
intent.putExtra(Constants.USER_NAME, username);
intent.putExtra(Constants.JSON_CALL_USER, user);
startActivity(intent);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
} catch (PubnubException e) {
e.printStackTrace();
}
}
...
}
@Override
public void onLocalStream(final MediaStream localStream) {
VideoChatActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
if(localStream.videoTracks.size()==0) return;
localStream.videoTracks.get(0).addRenderer(new VideoRenderer(localRender));
}
});
}
@Override
public void onAddRemoteStream(final MediaStream remoteStream, final PnPeer peer) {
VideoChatActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(VideoChatActivity.this,"Connected to " + peer.getId(), Toast.LENGTH_SHORT).show();
try {
if(remoteStream.audioTracks.size()==0 || remoteStream.videoTracks.size()==0) return;
remoteStream.videoTracks.get(0).addRenderer(new VideoRenderer(remoteRender));
VideoRendererGui.update(remoteRender, 0, 0, 100, 100, VideoRendererGui.ScalingType.SCALE_ASPECT_FILL, false);
VideoRendererGui.update(localRender, 72, 72, 25, 25, VideoRendererGui.ScalingType.SCALE_ASPECT_FIT, true);
}
catch (Exception e){ e.printStackTrace(); }
}
});
}
@Override
public void onPeerConnectionClosed(PnPeer peer) {
Intent intent = new Intent(VideoChatActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
public class VideoChatActivity extends Activity {
public static final String VIDEO_TRACK_ID = "videoPN";
public static final String AUDIO_TRACK_ID = "audioPN";
public static final String LOCAL_MEDIA_STREAM_ID = "localStreamPN";
private PnRTCClient pnRTCClient;
private VideoSource localVideoSource;
private VideoRenderer.Callbacks localRender;
private VideoRenderer.Callbacks remoteRender;
private GLSurfaceView mVideoView;
private String username;
...
}
// VideoChatActivity#onCreate()
Bundle extras = getIntent().getExtras();
if (extras == null || !extras.containsKey(Constants.USER_NAME)) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
Toast.makeText(this, "Need to pass username to VideoChatActivity in intent extras (Constants.USER_NAME).",
Toast.LENGTH_SHORT).show();
finish();
return;
}
this.username = extras.getString(Constants.USER_NAME, "");
// VideoChatActivity#onCreate()
PeerConnectionFactory.initializeAndroidGlobals(
this, // Context
true, // Audio Enabled
true, // Video Enabled
true, // Hardware Acceleration Enabled
null); // Render EGL Context
PeerConnectionFactory pcFactory = new PeerConnectionFactory();
this.pnRTCClient = new PnRTCClient(Constants.PUB_KEY, Constants.SUB_KEY, this.username);
// VideoChatActivity#onCreate()
// Returns the number of cams & front/back face device name
int camNumber = VideoCapturerAndroid.getDeviceCount();
String frontFacingCam = VideoCapturerAndroid.getNameOfFrontFacingDevice();
String backFacingCam = VideoCapturerAndroid.getNameOfBackFacingDevice();
// Creates a VideoCapturer instance for the device name
VideoCapturer capturer = VideoCapturerAndroid.create(frontFacingCam);
// First create a Video Source, then we can make a Video Track
localVideoSource = pcFactory.createVideoSource(capturer, this.pnRTCClient.videoConstraints());
VideoTrack localVideoTrack = pcFactory.createVideoTrack(VIDEO_TRACK_ID, localVideoSource);
// First we create an AudioSource then we can create our AudioTrack
AudioSource audioSource = pcFactory.createAudioSource(this.pnRTCClient.audioConstraints());
AudioTrack localAudioTrack = pcFactory.createAudioTrack(AUDIO_TRACK_ID, audioSource);
// VideoChatActivity#onCreate()
MediaStream mediaStream = pcFactory.createLocalMediaStream(LOCAL_MEDIA_STREAM_ID);
// Now we can add our tracks.
mediaStream.addTrack(localVideoTrack);
mediaStream.addTrack(localAudioTrack);
// VideoChatActivity#onCreate()
// Then we set that view, and pass a Runnable to run once the surface is ready
VideoRendererGui.setView(mVideoView, null);
// Now that VideoRendererGui is ready, we can get our VideoRenderer.
// IN THIS ORDER. Effects which is on top or bottom
remoteRender = VideoRendererGui.create(0, 0, 100, 100, VideoRendererGui.ScalingType.SCALE_ASPECT_FILL, false);
localRender = VideoRendererGui.create(0, 0, 100, 100, VideoRendererGui.ScalingType.SCALE_ASPECT_FILL, true);
public class VideoChatActivity extends Activity {
// VCA Code
private class MyRTCListener extends PnRTCListener {
// Override methods you plan on using
}
}
// VideoChatActivity#onCreate()
// First attach the RTC Listener so that callback events will be triggered
this.pnRTCClient.attachRTCListener(new MyRTCListener());
this.pnRTCClient.attachLocalMediaStream(mediaStream);
// Listen on a channel. This is your "phone number," also set the max chat users.
this.pnRTCClient.listenOn(this.username);
this.pnRTCClient.setMaxConnections(1);
// If Constants.CALL_USER is in the intent extras, auto call them.
if (extras.containsKey(Constants.CALL_USER)) {
String callUser = extras.getString(Constants.CALL_USER, "");
connectToUser(callUser);
}
// VideoChatActivity#hangup()
public void hangup(View view) {
this.pnRTCClient.closeAllConnections();
startActivity(new Intent(VideoChatActivity.this, MainActivity.class));
}
@Override
protected void onPause() {
super.onPause();
this.mVideoView.onPause();
this.localVideoSource.stop();
}
@Override
protected void onResume() {
super.onResume();
this.mVideoView.onResume();
this.localVideoSource.restart();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (this.localVideoSource != null) {
this.localVideoSource.stop();
}
if (this.pnRTCClient != null) {
this.pnRTCClient.onDestroy();
}
}
private void sendMsg(String msgText){
JSONObject msgJson = new JSONObject();
try {
msgJson.put("msg_user", username);
msgJson.put("msg_text", msgText);
this.pnRTCClient.transmitAll(msgJson);
} catch (JSONException e){
e.printStackTrace();
}
}
@Override
public void onMessage(PnPeer peer, Object message) {
if (!(message instanceof JSONObject)) return; //Ignore if not JSONObject
JSONObject jsonMsg = (JSONObject) message;
try {
String user = jsonMsg.getString("msg_user");
String text = jsonMsg.getString("msg_text");
final ChatMessage chatMsg = new ChatMessage(user, text);
VideoChatActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(VideoChatActivity.this,chatMsg.toString(),Toast.LENGTH_SHORT).show();
}
});
} catch (JSONException e){
e.printStackTrace();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment