Commit b501ae52 authored by jehan's avatar jehan

add jni to check if ms2 was compiled with video

parent 81dd82dc
/*
MediastreamerActivity.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.mediastream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
import org.linphone.mediastream.video.capture.AndroidVideoApi5JniWrapper;
import android.app.Activity;
import android.content.Intent;
import android.hardware.Camera;
import android.opengl.GLSurfaceView;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* Mediastreamer test activity.
*
*/
public class MediastreamerActivity extends Activity {
/** native methods from {MEDIASTREAMER2}/test/mediastreamer.c */
native int initDefaultArgs();
native boolean parseArgs(int argc, String[] argv, int msObj);
native void setupMediaStreams(int msObj);
native void runLoop(int msObj);
native void clear(int msObj);
native void stopMediaStream();
native void setVideoWindowId(Object wid, int msObj);
native void setVideoPreviewWindowId(Object wid, int msObj);
native void setDeviceRotation(int rotation, int msObj);
native void changeCamera(int newCameraId, int msObj);
Thread msThread;
int cameraId = 0;
String videoCodec = VP8_MIME_TYPE;
String remoteIp = "127.0.0.1";
short remotePort = 4000, localPort = 4000;
int bitrate = 256;
boolean pleaseRestart;
int nativeObj;
AndroidVideoWindowImpl mVideoWindow;
static String BUNDLE_CAMERA_ID_KEY = "CameraIdKey";
static String BUNDLE_VIDEO_CODEC_KEY = "VideoCodecKey";
static String BUNDLE_REMOTE_IP_KEY = "RemoteIpKey";
static String BUNDLE_REMOTE_PORT_KEY = "RemotePortKey";
static String BUNDLE_LOCAL_PORT_KEY = "LocalPortKey";
static String BUNDLE_BITRATE_KEY = "BitrateKey";
static String VP8_MIME_TYPE = "VP8";
static String MPEG4_MIME_TYPE = "MP4V-ES";
Object destroyMutex= new Object();
static {
// FFMPEG (audio/video)
loadOptionalLibrary("avutil");
loadOptionalLibrary("swscale");
loadOptionalLibrary("avcore");
loadOptionalLibrary("avcodec");
loadOptionalLibrary("srtp");
// Main library
System.loadLibrary("mediastreamer2");
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* declare layout */
setContentView(R.layout.main);
AndroidVideoApi5JniWrapper.setAndroidSdkVersion(Build.VERSION.SDK_INT);
Log.i("ms", "Mediastreamer starting !");
/* retrieve preview surface */
final SurfaceView previewSurface = (SurfaceView) findViewById(R.id.video_capture_surface);
final SurfaceHolder holder = previewSurface.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
/* retrieve rendering surface */
GLSurfaceView view = (GLSurfaceView) findViewById(R.id.video_surface);
/* force surfaces Z ordering */
view.setZOrderOnTop(false);
previewSurface.setZOrderOnTop(true);
// init args from bundle/default values
Bundle bundleToUse = savedInstanceState;
if (bundleToUse == null) {
bundleToUse = getIntent().getExtras();
}
if (bundleToUse != null) {
Set<String> keys = bundleToUse.keySet();
for(String s: keys)
Log.e("sm", "Key: " + s + ", value: " + bundleToUse.get(s));
cameraId = bundleToUse.getInt(BUNDLE_CAMERA_ID_KEY, 0);
if (bundleToUse.containsKey(BUNDLE_VIDEO_CODEC_KEY))
videoCodec = bundleToUse.getString(BUNDLE_VIDEO_CODEC_KEY);
if (bundleToUse.containsKey(BUNDLE_REMOTE_IP_KEY))
remoteIp = bundleToUse.getString(BUNDLE_REMOTE_IP_KEY);
remotePort = bundleToUse.getShort(BUNDLE_REMOTE_PORT_KEY, (short)4000);
localPort = bundleToUse.getShort(BUNDLE_LOCAL_PORT_KEY, (short)4000);
bitrate = bundleToUse.getInt(BUNDLE_BITRATE_KEY, 256);
} else {
Log.w("mediastreamer", "No bundle to restore params from");
}
pleaseRestart = false;
// pass arguments to native code
final List<String> args = new ArrayList<String>();
args.add("prog_name");
args.add("--local");
args.add(Short.toString(localPort));
args.add("--remote");
args.add(remoteIp + ":" + remotePort);
args.add("--payload");
args.add("video/" + videoCodec + "/90000");
args.add("--camera");
args.add("Android" + cameraId);
// we pass device rotation as an argument (so mediastream.c can tell the videostream about it BEFORE it's configured)
args.add("--device-rotation");
int rot = rotationToAngle(getWindowManager().getDefaultDisplay()
.getRotation());
args.add(Integer.toString(rot));
args.add("--bitrate");
args.add(Integer.toString(bitrate*1000));
// override default value from mediastream.c (but the actual resolution is limited by the encoder + bitrate)
args.add("--width");
args.add("1920");
args.add("--height");
args.add("1080");
nativeObj = initDefaultArgs();
String[] _args = new String[args.size()];
parseArgs(args.size(), args.toArray(_args), nativeObj);
setupMediaStreams(nativeObj);
/* Mediastreamer is ready, we can finish Java initialization, and start
* Mediastream in a separate thread
*/
msThread = new Thread() {
public void run() {
synchronized (destroyMutex) {
Log.e("ms", "Starting mediastream !");
runLoop(nativeObj);
Log.e("ms", "Mediastreamer ended");
clear(nativeObj);
Log.e("ms", "Mediastreamer cleared");
}
};
};
/* start mediastream */
msThread.start();
/* instanciate object responsible of video rendering */
mVideoWindow = new AndroidVideoWindowImpl(view, previewSurface);
mVideoWindow
.setListener(new AndroidVideoWindowImpl.VideoWindowListener() {
public void onVideoPreviewSurfaceReady(AndroidVideoWindowImpl vw, SurfaceView sv) {
setVideoPreviewWindowId(previewSurface, nativeObj);
};
@Override
public void onVideoPreviewSurfaceDestroyed(
AndroidVideoWindowImpl vw) {
}
public void onVideoRenderingSurfaceDestroyed(AndroidVideoWindowImpl vw) {};
public void onVideoRenderingSurfaceReady(AndroidVideoWindowImpl vw, SurfaceView sv) {
setVideoWindowId(vw, nativeObj);
// set device rotation too
setDeviceRotation(rotationToAngle(getWindowManager().getDefaultDisplay()
.getRotation()), nativeObj);
}
});
mVideoWindow.init();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveStateToBundle(outState);
}
void saveStateToBundle(Bundle b) {
b.putInt(BUNDLE_CAMERA_ID_KEY, cameraId);
b.putString(BUNDLE_VIDEO_CODEC_KEY, videoCodec);
b.putString(BUNDLE_REMOTE_IP_KEY, remoteIp);
b.putShort(BUNDLE_REMOTE_PORT_KEY, remotePort);
b.putShort(BUNDLE_LOCAL_PORT_KEY, localPort);
b.putInt(BUNDLE_BITRATE_KEY, bitrate);
}
@Override
protected void onDestroy() {
mVideoWindow.release();
stopMediaStream();
Log.d("ms", "Waiting for complete mediastremer destruction");
synchronized (destroyMutex) {
Log.d("ms", "MediastreamerActivity destroyed");
}
super.onDestroy();
if (pleaseRestart) {
Intent intent = getIntent();
intent.putExtra(BUNDLE_CAMERA_ID_KEY, cameraId);
intent.putExtra(BUNDLE_VIDEO_CODEC_KEY, videoCodec);
intent.putExtra(BUNDLE_REMOTE_IP_KEY, remoteIp);
intent.putExtra(BUNDLE_REMOTE_PORT_KEY, remotePort);
intent.putExtra(BUNDLE_LOCAL_PORT_KEY, localPort);
intent.putExtra(BUNDLE_BITRATE_KEY, bitrate);
startActivity(intent);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the currently selected menu XML resource.
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.videocall_activity_menu, menu);
if (Build.VERSION.SDK_INT < 9)
menu.findItem(R.id.videocall_menu_change_camera).setVisible(false);
else {
if (Camera.getNumberOfCameras() == 1)
menu.findItem(R.id.videocall_menu_change_camera).setVisible(false);
}
// init UI
if (videoCodec.equals(VP8_MIME_TYPE))
menu.findItem(R.id.videocall_menu_codec_vp8).setChecked(true);
else if (videoCodec.equals(MPEG4_MIME_TYPE))
menu.findItem(R.id.videocall_menu_codec_mpeg4).setChecked(true);
switch (bitrate) {
case 64:
menu.findItem(R.id.videocall_menu_bitrate_64_kbps).setChecked(true); break;
case 128:
menu.findItem(R.id.videocall_menu_bitrate_128_kbps).setChecked(true); break;
case 256:
menu.findItem(R.id.videocall_menu_bitrate_256_kbps).setChecked(true); break;
case 512:
menu.findItem(R.id.videocall_menu_bitrate_512_kbps).setChecked(true); break;
case 1024:
menu.findItem(R.id.videocall_menu_bitrate_1024_kbps).setChecked(true); break;
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.videocall_menu_exit:
this.finish();
break;
case R.id.videocall_menu_change_camera:
cameraId = (cameraId + 1) % Camera.getNumberOfCameras();
changeCamera(cameraId, nativeObj);
setVideoPreviewWindowId(findViewById(R.id.video_capture_surface), nativeObj);
break;
case R.id.videocall_menu_codec_vp8:
updateVideoCodec(VP8_MIME_TYPE);
break;
case R.id.videocall_menu_codec_mpeg4:
updateVideoCodec(MPEG4_MIME_TYPE);
break;
case R.id.videocall_menu_bitrate_64_kbps:
updateBitrate(64);
break;
case R.id.videocall_menu_bitrate_128_kbps:
updateBitrate(128);
break;
case R.id.videocall_menu_bitrate_256_kbps:
updateBitrate(256);
break;
case R.id.videocall_menu_bitrate_512_kbps:
updateBitrate(512);
break;
case R.id.videocall_menu_bitrate_1024_kbps:
updateBitrate(1024);
break;
}
return true;
}
private void updateVideoCodec(String newCodec) {
if (newCodec != videoCodec) {
videoCodec = newCodec;
// restart ourself
pleaseRestart = true;
finish();
}
}
private void updateBitrate(int newBr) {
if (newBr != bitrate) {
bitrate = newBr;
pleaseRestart = true;
finish();
}
}
private static void loadOptionalLibrary(String s) {
try {
System.loadLibrary(s);
} catch (Throwable e) {
Log.w("Unable to load optional library lib", s);
}
}
static int rotationToAngle(int r) {
switch (r) {
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
}
return 0;
}
}
......@@ -50,6 +50,15 @@ JNIEXPORT jboolean JNICALL Java_org_linphone_mediastream_Version_nativeHasNeon(J
JNIEXPORT jboolean JNICALL Java_org_linphone_mediastream_Version_nativeHasZrtp(JNIEnv *env, jclass c) {
return ortp_zrtp_available();
}
JNIEXPORT jboolean JNICALL Java_org_linphone_mediastream_Version_nativeHasVideo(JNIEnv *env, jclass c) {
#ifdef VIDEO_ENABLED
return JNI_TRUE;
#else
return JNI_FALSE;
#endif
}
#ifdef __cplusplus
}
#endif
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment