Skip to content

Commit

Permalink
Added video support for iOS and Android, and related fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
datso committed Nov 27, 2017
1 parent 828e0ff commit 67f25f4
Show file tree
Hide file tree
Showing 275 changed files with 2,972 additions and 676 deletions.
31 changes: 15 additions & 16 deletions android/react-native-pjsip.iml
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fbui.textlayoutbuilder/textlayoutbuilder/1.0.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/drawee/1.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/fbcore/1.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/fresco/1.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline-base/1.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline-okhttp3/1.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline/1.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.react/react-native/0.47.2/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/drawee/1.3.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/fbcore/1.3.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/fresco/1.3.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline-base/1.3.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline-okhttp3/1.3.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline/1.3.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.react/react-native/0.49.3/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.soloader/soloader/0.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/org.webkit/android-jsc/r174650/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
Expand All @@ -100,34 +100,33 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/typedefs.txt" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="imagepipeline-base-1.0.1" level="project" />
<orderEntry type="library" exported="" name="fresco-1.3.0" level="project" />
<orderEntry type="library" exported="" name="gson-2.8.2" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-1.3.0" level="project" />
<orderEntry type="library" exported="" name="textlayoutbuilder-1.0.0" level="project" />
<orderEntry type="library" exported="" name="gson-2.8.1" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-base-1.3.0" level="project" />
<orderEntry type="library" exported="" name="okio-1.13.0" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-1.0.1" level="project" />
<orderEntry type="library" exported="" name="soloader-0.1.0" level="project" />
<orderEntry type="library" exported="" name="javax.inject-1" level="project" />
<orderEntry type="library" exported="" name="jsr305-3.0.0" level="project" />
<orderEntry type="library" exported="" name="react-native-0.49.3" level="project" />
<orderEntry type="library" exported="" name="bolts-tasks-1.4.0" level="project" />
<orderEntry type="library" exported="" name="drawee-1.0.1" level="project" />
<orderEntry type="library" exported="" name="fbcore-1.0.1" level="project" />
<orderEntry type="library" exported="" name="react-native-0.47.2" level="project" />
<orderEntry type="library" exported="" name="okhttp-3.6.0" level="project" />
<orderEntry type="library" exported="" name="drawee-1.3.0" level="project" />
<orderEntry type="library" exported="" name="fbcore-1.3.0" level="project" />
<orderEntry type="library" exported="" name="okhttp-urlconnection-3.6.0" level="project" />
<orderEntry type="library" exported="" name="android-jsc-r174650" level="project" />
<orderEntry type="library" exported="" name="staticlayout-proxy-1.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-23.0.1" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-okhttp3-1.0.1" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="fresco-1.0.1" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-okhttp3-1.3.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.0.1" level="project" />
</component>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,6 @@ private void onCallback(Intent intent) {

private void emit(String eventName, @Nullable Object data) {
Log.d(TAG, "emit " + eventName + " / " + data);
Log.d(TAG, "emit context.hasActiveCatalystInstance()" + context.hasActiveCatalystInstance());
Log.d(TAG, "emit context.getCurrentActivity() == null" + (context.getCurrentActivity() == null));
Log.d(TAG, "emit context.getLifecycleState()" + (context.getLifecycleState()));

context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, data);
}
Expand Down
70 changes: 51 additions & 19 deletions android/src/main/java/com/carusto/ReactNativePjSip/PjSipCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,25 @@
import android.content.Context;
import android.media.AudioManager;
import android.util.Log;
import android.view.View;

import com.google.gson.Gson;

import org.json.JSONArray;
import org.json.JSONObject;
import org.pjsip.pjsua2.*;

import java.util.HashMap;
import java.util.concurrent.CopyOnWriteArrayList;

public class PjSipCall extends Call {

public static VideoWindow videoWindow;

public static VideoPreview videoPreview;

public static CopyOnWriteArrayList<PjSipVideoMediaChange> mediaListeners = new CopyOnWriteArrayList<>();

private static String TAG = "PjSipCall";

private PjSipAccount account;
Expand Down Expand Up @@ -102,7 +114,7 @@ private void doMute(boolean mute) throws Exception {
try {
audioMedia.adjustRxLevel((float) (mute ? 0 : 1));
} catch (Exception exc) {
Log.e(TAG, "Error while adjusting levels", exc);
Log.e(TAG, "An error occurs while adjusting audio levels", exc);
}
}
}
Expand All @@ -128,37 +140,57 @@ public void redirect(String destination) throws Exception {

@Override
public void onCallState(OnCallStateParam prm) {
try {
getService().emmitCallStateChanged(this, prm);
} catch (Exception e) {
Log.e(TAG, "Exception for onCallState callback", e);
super.onCallState(prm);

getService().emmitCallStateChanged(this, prm);
}

@Override
public void onCallMediaEvent(OnCallMediaEventParam prm) {
super.onCallMediaEvent(prm);

// Hack to resize all video windows.
for (PjSipVideoMediaChange listener : mediaListeners) {
listener.onChange();
}
}

@Override
public void onCallMediaState(OnCallMediaStateParam prm) {
CallInfo info;
try {
CallInfo info = getInfo();
info = getInfo();
} catch (Exception exc) {
Log.e(TAG, "An error occurs while getting call info", exc);
return;
}

for (int i = 0; i < info.getMedia().size(); i++) {
Media media = getMedia(i);
CallMediaInfo mediaInfo = info.getMedia().get(i);
for (int i = 0; i < info.getMedia().size(); i++) {
Media media = getMedia(i);
CallMediaInfo mediaInfo = info.getMedia().get(i);

if (mediaInfo.getType() == pjmedia_type.PJMEDIA_TYPE_AUDIO &&
media != null &&
mediaInfo.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE) {
AudioMedia audioMedia = AudioMedia.typecastFromMedia(media);
if (mediaInfo.getType() == pjmedia_type.PJMEDIA_TYPE_AUDIO
&& media != null
&& mediaInfo.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE) {
AudioMedia audioMedia = AudioMedia.typecastFromMedia(media);

// connect the call audio media to sound device
// connect the call audio media to sound device
try {
AudDevManager mgr = account.getService().getAudDevManager();
audioMedia.adjustRxLevel((float) 1.0);
audioMedia.adjustTxLevel((float) 1.0);

try {
audioMedia.adjustRxLevel((float) 1.5);
audioMedia.adjustTxLevel((float) 1.5);
} catch (Exception exc) {
Log.e(TAG, "An error while adjusting audio levels", exc);
}

audioMedia.startTransmit(mgr.getPlaybackDevMedia());
mgr.getCaptureDevMedia().startTransmit(audioMedia);
} catch (Exception exc) {
Log.e(TAG, "An error occurs while connecting audio media to sound device", exc);
}
}
} catch (Exception e) {
Log.e(TAG, "Failed to start transmit to playback device", e);
}

// Emmit changes
Expand Down Expand Up @@ -215,7 +247,7 @@ public JSONObject toJson() {
json.put("remoteOfferer", info.getRemOfferer());
json.put("remoteAudioCount", info.getRemAudioCount());
json.put("remoteVideoCount", info.getRemVideoCount());

// -----
json.put("audioCount", info.getSetting().getAudioCount());
json.put("videoCount", info.getSetting().getVideoCount());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public List<NativeModule> createNativeModules(

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(new PjSipVideoPreviewViewManager());
return Arrays.<ViewManager>asList(
new PjSipRemoteVideoViewManager(),
new PjSipPreviewVideoViewManager()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.carusto.ReactNativePjSip;

import android.content.Context;
import android.util.Log;
import android.view.SurfaceHolder;

import org.pjsip.pjsua2.VideoPreview;
import org.pjsip.pjsua2.VideoPreviewOpParam;
import org.pjsip.pjsua2.VideoWindow;
import org.pjsip.pjsua2.VideoWindowHandle;

public class PjSipPreviewVideo extends PjSipVideo {

private int deviceId = -1;

public PjSipPreviewVideo(Context context) {
super(context);
}

public void setDeviceId(int deviceId) {
if (this.deviceId == deviceId) {
return;
}

final VideoPreview windowPreview = new VideoPreview(deviceId);

setCallback(new PjSipVideoWindowHandler() {
@Override
public VideoWindow start(SurfaceHolder surfaceHolder) throws Exception {
VideoWindowHandle handle = new VideoWindowHandle();
handle.getHandle().setWindow(surfaceHolder.getSurface());

VideoPreviewOpParam op = new VideoPreviewOpParam();
op.setWindow(handle);

windowPreview.start(op);
return windowPreview.getVideoWindow();
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.carusto.ReactNativePjSip;

import android.graphics.Color;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewProps;

import org.pjsip.pjsua2.MediaFormat;
import org.pjsip.pjsua2.MediaFormatVector;
import org.pjsip.pjsua2.VideoDevInfo;
import org.pjsip.pjsua2.VideoPreview;
import org.pjsip.pjsua2.VideoPreviewOpParam;
import org.pjsip.pjsua2.VideoWindowHandle;
import org.pjsip.pjsua2.WindowHandle;

public class PjSipPreviewVideoViewManager extends SimpleViewManager<PjSipPreviewVideo> {

private String LOCAL_VIDEO_CLASS = "PjSipPreviewVideoView";

@Override
public String getName() {
return LOCAL_VIDEO_CLASS;
}

@ReactProp(name = "deviceId")
public void setDeviceId(PjSipPreviewVideo view, int deviceId) {
view.setDeviceId(deviceId);
}

@ReactProp(name = "objectFit")
public void setObjectFit(PjSipPreviewVideo view, String objectFit) {
view.setObjectFit(objectFit);
}

@Override
protected PjSipPreviewVideo createViewInstance(ThemedReactContext reactContext) {
return new PjSipPreviewVideo(reactContext);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.carusto.ReactNativePjSip;

import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;

import org.pjsip.pjsua2.VideoWindow;
import org.pjsip.pjsua2.VideoWindowHandle;
import org.pjsip.pjsua2.WindowHandle;

public class PjSipRemoteVideo extends PjSipVideo implements PjSipVideoMediaChange {

private static String TAG = "PjSipRemoteVideo";

public PjSipRemoteVideo(Context context) {
super(context);
}

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

PjSipCall.mediaListeners.add(this);
}

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

PjSipCall.mediaListeners.remove(this);
}

public void setWindowId(int windowId) {
final VideoWindow videoWindow = new VideoWindow(windowId);

setCallback(new PjSipVideoWindowHandler() {
@Override
public VideoWindow start(SurfaceHolder surfaceHolder) throws Exception {
WindowHandle winHandle = new WindowHandle();
winHandle.setWindow(surfaceHolder.getSurface());

VideoWindowHandle handle = new VideoWindowHandle();
handle.setHandle(winHandle);

videoWindow.setWindow(handle);
return videoWindow;
}
});
}

@Override
public void onChange() {
Handler mainHandler = new Handler(getContext().getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
try {
doLayout();
} catch (Exception e) {
Log.e(TAG, "An error occurs while layout a video", e);
}
}
});
}
}
Loading

0 comments on commit 67f25f4

Please sign in to comment.