Merge branch 'video' of git.linphone.org:linphone-android-private

Conflicts:
	libs/armeabi-v7a/liblinphone.so
	libs/armeabi/liblinphone.so
	src/org/linphone/core/LinphoneCallImpl.java
	src/org/linphone/core/LinphoneProxyConfigImpl.java
	src/org/linphone/core/tutorials/TutorialRegistrationActivity.java
	submodules/linphone
This commit is contained in:
Guillaume Beraudo 2010-12-14 09:32:47 +01:00
commit 013e835343
14 changed files with 1247 additions and 66 deletions

217
AndroidCameraRecord.java Normal file
View file

@ -0,0 +1,217 @@
/*
AndroidCameraRecordImpl.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.core;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.hardware.Camera;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public abstract class AndroidCameraRecord {
protected Camera camera;
private RecorderParams params;
private PreviewCallback storedPreviewCallback;
private boolean previewStarted;
protected int displayOrientation;
protected static final String tag="Linphone";
private List <Size> supportedVideoSizes;
private Size currentPreviewSize;
public AndroidCameraRecord(RecorderParams parameters) {
this.params = parameters;
setDisplayOrientation(parameters.rotation);
}
protected List<Size> getSupportedPreviewSizes(Camera.Parameters parameters) {
return Collections.emptyList();
}
public void startPreview() { // FIXME throws exception?
if (previewStarted) {
Log.w(tag, "Already started");
throw new RuntimeException("Video recorder already started");
// return
}
if (params.surfaceView.getVisibility() != SurfaceView.VISIBLE) {
// Illegal state
Log.e(tag, "Illegal state: video capture surface view is not visible");
return;
}
camera=Camera.open();
camera.setErrorCallback(new ErrorCallback() {
public void onError(int error, Camera camera) {
Log.e(tag, "Camera error : " + error);
}
});
Camera.Parameters parameters=camera.getParameters();
parameters.set("camera-id",params.cameraId);
camera.setParameters(parameters);
parameters = camera.getParameters();
if (supportedVideoSizes == null) {
supportedVideoSizes = new ArrayList<Size>(getSupportedPreviewSizes(parameters));
}
if (!params.videoDimensionsInverted) {
parameters.setPreviewSize(params.width, params.height);
} else {
parameters.setPreviewSize(params.height, params.width);
}
parameters.setPreviewFrameRate(Math.round(params.fps));
onSettingCameraParameters(parameters);
camera.setParameters(parameters);
currentPreviewSize = camera.getParameters().getPreviewSize();
SurfaceHolder holder = params.surfaceView.getHolder();
try {
camera.setPreviewDisplay(holder);
}
catch (Throwable t) {
Log.e(tag, "Exception in Video capture setPreviewDisplay()", t);
}
try {
camera.startPreview();
previewStarted = true;
} catch (Throwable e) {
Log.e(tag, "Can't start camera preview");
}
previewStarted = true;
// Register callback to get capture buffer
lowLevelSetPreviewCallback(camera, storedPreviewCallback);
onPreviewStarted(camera);
}
protected void onSettingCameraParameters(Parameters parameters) {}
/**
* Hook.
* @param camera
*/
public void onPreviewStarted(Camera camera) {}
public void storePreviewCallBack(PreviewCallback cb) {
this.storedPreviewCallback = cb;
if (camera == null) {
Log.w(tag, "Capture camera not ready, storing callback");
return;
}
lowLevelSetPreviewCallback(camera, cb);
}
public void stopPreview() {
if (!previewStarted) return;
lowLevelSetPreviewCallback(camera, null);
camera.stopPreview();
camera.release();
camera=null;
if (currentPreviewSize != null) currentPreviewSize = null;
previewStarted = false;
}
public void stopCaptureCallback() {
if (camera != null) {
lowLevelSetPreviewCallback(camera, null);
}
}
protected abstract void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb);
public void setDisplayOrientation(int rotation) {
displayOrientation = rotation;
}
protected int rotateCapturedFrame() {
if (params.videoDimensionsInverted) {
return 1; // always rotate 90°
} else if (params.cameraId == 2) {
return 0;
} else {
return (4 + 1 - displayOrientation) % 4;
}
}
public static class RecorderParams {
public float fps;
public int height;
public int width;
final long filterDataNativePtr;
public int cameraId;
public int rotation;
public SurfaceView surfaceView;
public boolean videoDimensionsInverted;
public RecorderParams(long ptr) {
filterDataNativePtr = ptr;
}
}
public boolean isStarted() {
return previewStarted;
}
public List<Size> getSupportedVideoSizes() {
return new ArrayList<Size>(supportedVideoSizes);
}
protected int getExpectedBufferLength() {
if (currentPreviewSize == null) return -1;
return currentPreviewSize.width * currentPreviewSize.height * 3 /2;
}
}

View file

@ -0,0 +1,73 @@
/*
AndroidCameraRecord8Impl.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.core;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.util.Log;
/**
*
* Android >= 8 (2.2) version.
* @author Guillaume Beraudo
*
*/
public class AndroidCameraRecordBufferedImpl extends AndroidCameraRecordImplAPI5 {
public AndroidCameraRecordBufferedImpl(RecorderParams parameters) {
super(parameters);
}
@Override
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
if (cb != null) {
Log.d("Linphone", "Setting optimized callback with buffer (Android >= 8). Remember to manage the pool of buffers!!!");
}
camera.setPreviewCallbackWithBuffer(cb);
}
@Override
public void onPreviewStarted(Camera camera) {
super.onPreviewStarted(camera);
Size s = camera.getParameters().getPreviewSize();
int wishedBufferSize = s.height * s.width * 3 / 2;
camera.addCallbackBuffer(new byte[wishedBufferSize]);
camera.addCallbackBuffer(new byte[wishedBufferSize]);
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
super.onPreviewFrame(data, camera);
camera.addCallbackBuffer(data);
}
@Override
protected void onSettingCameraParameters(Parameters parameters) {
super.onSettingCameraParameters(parameters);
// Only on v8 hardware
camera.setDisplayOrientation(90 * rotateCapturedFrame());
}
}

View file

@ -0,0 +1,97 @@
/*
AndroidCameraRecordImpl.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.core;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;
/**
* Record from Android camera.
*
* @author Guillaume Beraudo
*
*/
public class AndroidCameraRecordImpl extends AndroidCameraRecord implements PreviewCallback {
private long filterCtxPtr;
private double timeElapsedBetweenFrames = 0;
private long lastFrameTime = 0;
private final double expectedTimeBetweenFrames;
private boolean sizesInverted;
public AndroidCameraRecordImpl(RecorderParams parameters) {
super(parameters);
expectedTimeBetweenFrames = 1d / Math.round(parameters.fps);
filterCtxPtr = parameters.filterDataNativePtr;
sizesInverted = parameters.videoDimensionsInverted;
storePreviewCallBack(this);
}
private native void putImage(long filterCtxPtr, byte[] buffer, int rotate, boolean sizesInverted);
public void onPreviewFrame(byte[] data, Camera camera) {
if (data == null) {
Log.e("Linphone", "onPreviewFrame Called with null buffer");
return;
}
if (filterCtxPtr == 0l) {
Log.e("Linphone", "onPreviewFrame Called with no filterCtxPtr set");
return;
}
int expectedBuffLength = getExpectedBufferLength();
if (expectedBuffLength != data.length) {
Log.e("Linphone", "onPreviewFrame called with bad buffer length " + data.length
+ " whereas expected is " + expectedBuffLength + " don't calling putImage");
return;
}
long curTime = System.currentTimeMillis();
if (lastFrameTime == 0) {
lastFrameTime = curTime;
putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted);
return;
}
double currentTimeElapsed = 0.8 * (curTime - lastFrameTime) / 1000 + 0.2 * timeElapsedBetweenFrames;
if (currentTimeElapsed < expectedTimeBetweenFrames) {
// Log.d("Linphone", "Clipping frame " + Math.round(1 / currentTimeElapsed) + " > " + fps);
return;
}
lastFrameTime = curTime;
timeElapsedBetweenFrames = currentTimeElapsed;
// Log.d("onPreviewFrame: ", Integer.toString(data.length));
putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted);
}
@Override
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
camera.setPreviewCallback(cb);
}
}

View file

@ -0,0 +1,64 @@
/*
AndroidCameraRecordImplAPI5.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.core;
import java.util.List;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
public class AndroidCameraRecordImplAPI5 extends AndroidCameraRecordImpl {
public AndroidCameraRecordImplAPI5(RecorderParams parameters) {
super(parameters);
}
@Override
protected void onSettingCameraParameters(Parameters parameters) {
super.onSettingCameraParameters(parameters);
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
Log.w(tag, "Auto Focus supported by camera device");
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
} else {
Log.w(tag, "Auto Focus not supported by camera device");
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
Log.w(tag, "Infinity Focus supported by camera device");
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
} else {
Log.w(tag, "Infinity Focus not supported by camera device");
}
}
}
public static List<Size> oneShotSupportedVideoSizes() {
Camera camera = Camera.open();
List<Size> supportedVideoSizes =camera.getParameters().getSupportedPreviewSizes();
camera.release();
return supportedVideoSizes;
}
@Override
protected List<Size> getSupportedPreviewSizes(Parameters parameters) {
return parameters.getSupportedPreviewSizes();
}
}

View file

@ -0,0 +1,245 @@
/*
AndroidCameraRecordManager.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.core;
import java.util.List;
import org.linphone.core.AndroidCameraRecord.RecorderParams;
import android.hardware.Camera.Size;
import android.os.Build;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
/**
* Manage the video capture, only on for all cameras.
*
* @author Guillaume Beraudo
*
*/
public class AndroidCameraRecordManager {
private static final int version = Integer.parseInt(Build.VERSION.SDK);
private static final String tag = "Linphone";
private static AndroidCameraRecordManager instance;
// singleton
private AndroidCameraRecordManager() {}
/**
* @return instance
*/
public static final synchronized AndroidCameraRecordManager getInstance() {
if (instance == null) {
instance = new AndroidCameraRecordManager();
}
return instance;
}
private AndroidCameraRecord.RecorderParams parameters;
private SurfaceView surfaceView;
private boolean muted;
private AndroidCameraRecord recorder;
private List<Size> supportedVideoSizes;
private int rotation;
private boolean useFrontCamera;
public void setUseFrontCamera(boolean value) {
if (useFrontCamera == value) return;
this.useFrontCamera = value;
if (parameters != null) {
parameters.cameraId = cameraId();
if (isRecording()) {
stopVideoRecording();
tryToStartVideoRecording();
}
}
}
public boolean isUseFrontCamera() {return useFrontCamera;}
public boolean toggleUseFrontCamera() {
setUseFrontCamera(!useFrontCamera);
return useFrontCamera;
}
public void setParametersFromFilter(long filterDataPtr, int height, int width, float fps) {
stopVideoRecording();
RecorderParams p = new RecorderParams(filterDataPtr);
p.fps = fps;
p.width = width;
p.height = height;
p.cameraId = cameraId();
p.videoDimensionsInverted = width < height;
// width and height will be inverted in Recorder on startPreview
parameters = p;
tryToStartVideoRecording();
}
public final void setSurfaceView(final SurfaceView sv, final int rotation) {
this.rotation = useFrontCamera ? 1 : rotation;
SurfaceHolder holder = sv.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
surfaceView = null;
Log.d(tag , "Video capture surface destroyed");
stopVideoRecording();
}
public void surfaceCreated(SurfaceHolder holder) {
surfaceView = sv;
Log.d(tag , "Video capture surface created");
tryToStartVideoRecording();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.d(tag , "Video capture surface changed");
}
});
}
public void setMuted(boolean muteState) {
if (muteState == muted) return;
muted = muteState;
if (muted) {
stopVideoRecording();
} else {
tryToStartVideoRecording();
}
}
public boolean toggleMute() {
setMuted(!muted);
return muted;
}
public boolean isMuted() {
return muted;
}
public void tryResumingVideoRecording() {
if (isRecording()) return;
tryToStartVideoRecording();
}
private void tryToStartVideoRecording() {
if (muted || surfaceView == null || parameters == null) return;
parameters.rotation = rotation;
parameters.surfaceView = surfaceView;
if (version >= 8) {
recorder = new AndroidCameraRecordBufferedImpl(parameters);
} else if (version >= 5) {
recorder = new AndroidCameraRecordImplAPI5(parameters);
} else {
recorder = new AndroidCameraRecordImpl(parameters);
}
recorder.startPreview();
}
public void stopVideoRecording() {
if (recorder != null) {
recorder.stopPreview();
recorder = null;
}
}
// FIXME select right camera
/**
* Eventually null if API < 5.
*
*/
public List<Size> supportedVideoSizes() {
if (supportedVideoSizes != null) {
return supportedVideoSizes;
}
if (recorder != null) {
supportedVideoSizes = recorder.getSupportedVideoSizes();
if (supportedVideoSizes != null) return supportedVideoSizes;
}
if (version >= 5) {
supportedVideoSizes = AndroidCameraRecordImplAPI5.oneShotSupportedVideoSizes();
}
// eventually null
return supportedVideoSizes;
}
public boolean isRecording() {
if (recorder != null) {
return recorder.isStarted();
}
return false;
}
public void invalidateParameters() {
stopVideoRecording();
parameters = null;
}
/**
* Naive simple version.
* @param askedSize
* @return
*/
public VideoSize doYouSupportThisVideoSize(VideoSize askedSize) {
Log.d(tag, "Asking camera if it supports size "+askedSize);
if (useFrontCamera && askedSize.isPortrait()) {
return askedSize.createInverted(); // only landscape supported
} else {
return askedSize;
}
}
private VideoSize closestVideoSize(VideoSize vSize, int defaultSizeCode, boolean defaultIsPortrait) {
VideoSize testSize = vSize.isPortrait() ? vSize.createInverted() : vSize;
for (Size s : AndroidCameraRecordManager.getInstance().supportedVideoSizes()) {
if (s.height == testSize.getHeight() && s.width == testSize.getWidth()) {
return vSize;
}
}
return VideoSize.createStandard(defaultSizeCode, defaultIsPortrait);
}
private static final int rearCamId() {return 1;}
private static final int frontCamId() {return 2;}
private final int cameraId() {return useFrontCamera? frontCamId() : rearCamId(); }
}

View file

@ -0,0 +1,89 @@
package org.linphone.core;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Bitmap.Config;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceHolder.Callback;
public class AndroidVideoWindowImpl {
private Bitmap mBitmap;
private SurfaceView mView;
private Surface mSurface;
private VideoWindowListener mListener;
static private String TAG = "Linphone";
public static interface VideoWindowListener{
void onSurfaceReady(AndroidVideoWindowImpl vw);
void onSurfaceDestroyed(AndroidVideoWindowImpl vw);
};
public AndroidVideoWindowImpl(SurfaceView view){
mView=view;
mBitmap=null;
mSurface=null;
mListener=null;
view.getHolder().addCallback(new Callback(){
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
Log.i(TAG,"Surface is being changed.");
synchronized(AndroidVideoWindowImpl.this){
mBitmap=Bitmap.createBitmap(width,height,Config.RGB_565);
mSurface=holder.getSurface();
}
if (mListener!=null) mListener.onSurfaceReady(AndroidVideoWindowImpl.this);
Log.w("Linphone", "Video display surface changed");
}
public void surfaceCreated(SurfaceHolder holder) {
Log.w("Linphone", "Video display surface created");
}
public void surfaceDestroyed(SurfaceHolder holder) {
synchronized(AndroidVideoWindowImpl.this){
mSurface=null;
mBitmap=null;
}
if (mListener!=null)
mListener.onSurfaceDestroyed(AndroidVideoWindowImpl.this);
Log.d("Linphone", "Video display surface destroyed");
}
});
}
static final int LANDSCAPE=0;
static final int PORTRAIT=1;
public void requestOrientation(int orientation){
//Surface.setOrientation(0, orientation==LANDSCAPE ? 1 : 0);
//Log.d("Linphone", "Orientation changed.");
}
public void setListener(VideoWindowListener l){
mListener=l;
}
public Surface getSurface(){
return mView.getHolder().getSurface();
}
public Bitmap getBitmap(){
return mBitmap;
}
//Called by the mediastreamer2 android display filter
public synchronized void update(){
if (mSurface!=null){
try {
Canvas canvas=mSurface.lockCanvas(null);
canvas.drawBitmap(mBitmap, 0, 0, null);
mSurface.unlockCanvasAndPost(canvas);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OutOfResourcesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

View file

@ -29,6 +29,9 @@ class LinphoneCallImpl implements LinphoneCall {
private native boolean isIncoming(long nativePtr);
native private long getRemoteAddress(long nativePtr);
native private int getState(long nativePtr);
private native long getCurrentParamsCopy(long nativePtr);
private native void enableCamera(long nativePtr, boolean enabled);
protected LinphoneCallImpl(long aNativePtr) {
nativePtr = aNativePtr;
ref(nativePtr);
@ -58,12 +61,11 @@ class LinphoneCallImpl implements LinphoneCall {
public State getState() {
return LinphoneCall.State.fromInt(getState(nativePtr));
}
public LinphoneCallParams getCurrentParamsReadOnly() {
throw new RuntimeException("Not Implemenetd yet");
public LinphoneCallParams getCurrentParamsCopy() {
return new LinphoneCallParamsImpl(getCurrentParamsCopy(nativePtr));
}
public void enableCamera(boolean enabled) {
throw new RuntimeException("Not Implemenetd yet");
enableCamera(nativePtr, enabled);
}
}

View file

@ -43,8 +43,7 @@ class LinphoneCallLogImpl implements LinphoneCallLog {
return new LinphoneAddressImpl(getTo(nativePtr));
}
public CallStatus getStatus() {
// TODO Auto-generated method stub
return null;
throw new RuntimeException("not implemented yet");
}
}

View file

@ -0,0 +1,51 @@
/*
LinphoneCallParamsImpl.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.core;
public class LinphoneCallParamsImpl implements LinphoneCallParams {
protected final long nativePtr;
public LinphoneCallParamsImpl(long nativePtr) {
this.nativePtr = nativePtr;
}
private native void enableVideo(long nativePtr, boolean b);
private native boolean getVideoEnabled(long nativePtr);
private native void audioBandwidth(long nativePtr, int bw);
private native void destroy(long nativePtr);
public boolean getVideoEnabled() {
return getVideoEnabled(nativePtr);
}
public void setVideoEnabled(boolean b) {
enableVideo(nativePtr, b);
}
@Override
protected void finalize() throws Throwable {
destroy(nativePtr);
super.finalize();
}
public void setAudioBandwidth(int value) {
audioBandwidth(nativePtr, value);
}
}

View file

@ -22,6 +22,8 @@ import java.io.File;
import java.io.IOException;
import java.util.Vector;
import android.view.SurfaceView;
class LinphoneCoreImpl implements LinphoneCore {
@ -53,6 +55,7 @@ class LinphoneCoreImpl implements LinphoneCore {
private native void muteMic(long nativePtr,boolean isMuted);
private native long interpretUrl(long nativePtr,String destination);
private native long inviteAddress(long nativePtr,long to);
private native long inviteAddressWithParams(long nativePtrLc,long to, long nativePtrParam);
private native void sendDtmf(long nativePtr,char dtmf);
private native void clearCallLogs(long nativePtr);
private native boolean isMicMuted(long nativePtr);
@ -63,12 +66,31 @@ class LinphoneCoreImpl implements LinphoneCore {
private native long getCurrentCall(long nativePtr) ;
private native void playDtmf(long nativePtr,char dtmf,int duration);
private native void stopDtmf(long nativePtr);
private native void setVideoWindowId(long nativePtr, Object wid);
private native void setPreviewWindowId(long nativePtr, Object wid);
private AndroidVideoWindowImpl mVideoWindow;
private AndroidVideoWindowImpl mPreviewWindow;
private native void addFriend(long nativePtr,long friend);
private native void setPresenceInfo(long nativePtr,int minute_away, String alternative_contact,int status);
private native long createChatRoom(long nativePtr,String to);
private native void enableVideo(long nativePtr,boolean vcap_enabled,boolean display_enabled);
private native boolean isVideoEnabled(long nativePtr);
private native void setFirewallPolicy(long nativePtr, int enum_value);
private native int getFirewallPolicy(long nativePtr);
private native void setStunServer(long nativePtr, String stun_server);
private native String getStunServer(long nativePtr);
private native long createDefaultCallParams(long nativePtr);
private native int updateCall(long ptrLc, long ptrCall, long ptrParams);
private native void setUploadBandwidth(long nativePtr, int bw);
private native void setDownloadBandwidth(long nativePtr, int bw);
private native void setPreferredVideoSize(long nativePtr, int width, int heigth);
private native int[] getPreferredVideoSize(long nativePtr);
private native void setRing(long nativePtr, String path);
private native String getRing(long nativePtr);
private native long[] listVideoPayloadTypes(long nativePtr);
private static final String TAG = "LinphoneCore";
LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException {
mListener=listener;
@ -200,14 +222,15 @@ class LinphoneCoreImpl implements LinphoneCore {
throw new LinphoneCoreException("Cannot interpret ["+destination+"]");
}
}
public LinphoneCall invite(LinphoneAddress to) {
public LinphoneCall invite(LinphoneAddress to) throws LinphoneCoreException {
long lNativePtr = inviteAddress(nativePtr,((LinphoneAddressImpl)to).nativePtr);
if (lNativePtr!=0) {
return new LinphoneCallImpl(lNativePtr);
} else {
return null;
throw new LinphoneCoreException("Unable to invite address " + to.asString());
}
}
public void sendDtmf(char number) {
sendDtmf(nativePtr,number);
}
@ -295,73 +318,114 @@ class LinphoneCoreImpl implements LinphoneCore {
return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to));
}
public void setPreviewWindow(Object w) {
throw new RuntimeException("not implemented yet");
// TODO Auto-generated method stub
if (mPreviewWindow!=null)
mPreviewWindow.setListener(null);
mPreviewWindow=new AndroidVideoWindowImpl((SurfaceView)w);
mPreviewWindow.setListener(new AndroidVideoWindowImpl.VideoWindowListener(){
public void onSurfaceDestroyed(AndroidVideoWindowImpl vw) {
setPreviewWindowId(nativePtr,null);
}
public void onSurfaceReady(AndroidVideoWindowImpl vw) {
setPreviewWindowId(nativePtr,vw);
}
});
}
public void setVideoWindow(Object w) {
throw new RuntimeException("not implemented yet");
// TODO Auto-generated method stub
if (mVideoWindow!=null)
mVideoWindow.setListener(null);
mVideoWindow=new AndroidVideoWindowImpl((SurfaceView) w);
mVideoWindow.setListener(new AndroidVideoWindowImpl.VideoWindowListener(){
public void onSurfaceDestroyed(AndroidVideoWindowImpl vw) {
setVideoWindowId(nativePtr,null);
}
public void onSurfaceReady(AndroidVideoWindowImpl vw) {
setVideoWindowId(nativePtr,vw);
}
});
}
public void enableVideo(boolean vcap_enabled, boolean display_enabled) {
// TODO Auto-generated method stub
enableVideo(nativePtr,vcap_enabled, display_enabled);
}
public boolean isVideoEnabled() {
// TODO Auto-generated method stub
return false;
}
public void setStunServer(String stun_server) {
// TODO Auto-generated method stub
}
public String getStunServer() {
// TODO Auto-generated method stub
return null;
}
public void setFirewallPolicy(FirewallPolicy pol) {
// TODO Auto-generated method stub
return isVideoEnabled(nativePtr);
}
public FirewallPolicy getFirewallPolicy() {
// TODO Auto-generated method stub
return null;
return FirewallPolicy.fromInt(getFirewallPolicy(nativePtr));
}
public String getStunServer() {
return getStunServer(nativePtr);
}
public void setFirewallPolicy(FirewallPolicy pol) {
setFirewallPolicy(nativePtr,pol.value());
}
public void setStunServer(String stunServer) {
setStunServer(nativePtr,stunServer);
}
public LinphoneCallParams createDefaultCallParameters() {
return new LinphoneCallParamsImpl(createDefaultCallParams(nativePtr));
}
public LinphoneCall inviteAddressWithParams(LinphoneAddress to, LinphoneCallParams params) throws LinphoneCoreException {
long ptrDestination = ((LinphoneAddressImpl)to).nativePtr;
long ptrParams =((LinphoneCallParamsImpl)params).nativePtr;
long lcNativePtr = inviteAddressWithParams(nativePtr, ptrDestination, ptrParams);
if (lcNativePtr!=0) {
return new LinphoneCallImpl(lcNativePtr);
} else {
throw new LinphoneCoreException("Unable to invite with params " + to.asString());
}
}
public int updateCall(LinphoneCall call, LinphoneCallParams params) {
long ptrCall = ((LinphoneCallImpl) call).nativePtr;
long ptrParams = ((LinphoneCallParamsImpl)params).nativePtr;
return updateCall(nativePtr, ptrCall, ptrParams);
}
public void setUploadBandwidth(int bw) {
setUploadBandwidth(nativePtr, bw);
}
public void setDownloadBandwidth(int bw) {
setDownloadBandwidth(nativePtr, bw);
}
public void setPreferredVideoSize(VideoSize vSize) {
setPreferredVideoSize(nativePtr, vSize.getWidth(), vSize.getHeight());
}
public VideoSize getPreferredVideoSize() {
int[] nativeSize = getPreferredVideoSize(nativePtr);
VideoSize vSize = new VideoSize();
vSize.setWidth(nativeSize[0]);
vSize.setHeight(nativeSize[1]);
return vSize;
}
public void setRing(String path) {
setRing(nativePtr,path);
setRing(nativePtr, path);
}
public String getRing() {
return getRing(nativePtr);
}
public LinphoneCall inviteAddressWithParams(LinphoneAddress destination,
LinphoneCallParams params) throws LinphoneCoreException {
throw new RuntimeException("Not Implemenetd yet");
}
public int updateCall(LinphoneCall call, LinphoneCallParams params) {
throw new RuntimeException("Not Implemenetd yet");
}
public LinphoneCallParams createDefaultCallParameters() {
throw new RuntimeException("Not Implemenetd yet");
public PayloadType[] listVideoCodecs() {
long[] typesPtr = listVideoPayloadTypes(nativePtr);
if (typesPtr == null) return null;
PayloadType[] codecs = new PayloadType[typesPtr.length];
for (int i=0; i < codecs.length; i++) {
codecs[i] = new PayloadTypeImpl(typesPtr[i]);
}
return codecs;
}
public boolean isNetworkReachable() {
throw new RuntimeException("Not Implemenetd yet");
throw new RuntimeException("Not implemented");
}
public void setUploadBandwidth(int bw) {
throw new RuntimeException("Not Implemenetd yet");
}
public void setDownloadBandwidth(int bw) {
throw new RuntimeException("Not Implemenetd yet");
}
public void setPreferredVideoSize(VideoSize vSize) {
throw new RuntimeException("Not Implemenetd yet");
}
public VideoSize getPreferredVideoSize() {
throw new RuntimeException("Not Implemenetd yet");
}
public PayloadType[] listVideoCodecs() {
throw new RuntimeException("Not Implemenetd yet");
}
}

View file

@ -24,15 +24,22 @@ class PayloadTypeImpl implements PayloadType {
protected final long nativePtr;
private native String toString(long ptr);
private native String getMime(long ptr);
private native int getRate(long ptr);
protected PayloadTypeImpl(long aNativePtr) {
nativePtr = aNativePtr;
}
public String toString() {
return toString(nativePtr);
public int getRate() {
return getRate(nativePtr);
}
public String getMime() {
throw new RuntimeException("Not Implemenetd yet");
return getMime(nativePtr);
}
public String toString() {
return toString(nativePtr);
}
}

View file

@ -0,0 +1,81 @@
/*
JavaCameraRecordImpl.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.core.tutorials;
import org.linphone.core.AndroidCameraRecord;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.util.Log;
import android.widget.TextView;
public class JavaCameraRecordImpl extends AndroidCameraRecord implements PreviewCallback {
private TextView debug;
private long count = 0;
private float averageCalledRate;
private long startTime;
private long endTime;
private int fps;
public JavaCameraRecordImpl(AndroidCameraRecord.RecorderParams parameters) {
super(parameters);
storePreviewCallBack(this);
fps = Math.round(parameters.fps);
}
public void setDebug(TextView debug) {
this.debug = debug;
}
public void onPreviewFrame(byte[] data, Camera camera) {
Size s = camera.getParameters().getPreviewSize();
int expectedBuffLength = s.width * s.height * 3 /2;
if (expectedBuffLength != data.length) {
Log.e("Linphone", "onPreviewFrame called with bad buffer length " + data.length
+ " whereas expected is " + expectedBuffLength + " don't calling putImage");
return;
}
if ((count % 2 * fps) == 0) {
endTime = System.currentTimeMillis();
averageCalledRate = (100000 * 2 * fps) / (endTime - startTime);
averageCalledRate /= 100f;
startTime = endTime;
}
count++;
String msg = "Frame " + count + ": " + data.length + "bytes (avg="+averageCalledRate+"frames/s)";
if (debug != null) debug.setText(msg);
Log.d("onPreviewFrame:", msg);
}
@Override
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
camera.setPreviewCallback(cb);
}
}

View file

@ -0,0 +1,191 @@
/*
TutorialHelloWorldActivity.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.core.tutorials;
import java.util.Stack;
import org.linphone.R;
import org.linphone.core.AndroidCameraRecord;
import org.linphone.core.VideoSize;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.TextView;
import static org.linphone.core.VideoSize.*;
/**
* Activity for displaying and starting the HelloWorld example on Android phone.
*
* @author Guillaume Beraudo
*
*/
public class TestVideoActivity extends Activity implements Callback, OnClickListener {
private SurfaceView surfaceView;
private static final int rate = 7;
private JavaCameraRecordImpl recorder;
private static String tag = "Linphone";
private TextView debugView;
private Button nextSize;
private Button changeCamera;
private Button changeOrientation;
private AndroidCameraRecord.RecorderParams params;
private Stack<VideoSize> videoSizes = createSizesToTest();
private int currentCameraId = 2;
private boolean currentOrientationIsPortrait = false;
private int width;
private int height;
private boolean started;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.videotest);
surfaceView=(SurfaceView)findViewById(R.id.videotest_surfaceView);
nextSize = (Button) findViewById(R.id.test_video_size);
nextSize.setOnClickListener(this);
changeCamera = (Button) findViewById(R.id.test_video_camera);
changeCamera.setText("Cam"+otherCameraId(currentCameraId));
changeCamera.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
changeCamera.setText("Cam"+currentCameraId);
currentCameraId = otherCameraId(currentCameraId);
updateRecording();
}
});
changeOrientation = (Button) findViewById(R.id.test_video_orientation);
changeOrientation.setText(orientationToString(!currentOrientationIsPortrait));
changeOrientation.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
currentOrientationIsPortrait = !currentOrientationIsPortrait;
changeOrientation.setText(orientationToString(!currentOrientationIsPortrait));
if (width == 0 || height == 0) return;
int newWidth = currentOrientationIsPortrait? Math.min(height, width) : Math.max(height, width);
int newHeight = currentOrientationIsPortrait? Math.max(height, width) : Math.min(height, width);
changeSurfaceViewLayout(newWidth, newHeight); // will change width and height on surfaceChanged
}
});
SurfaceHolder holder = surfaceView.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(this);
debugView = (TextView) findViewById(R.id.videotest_debug);
}
protected void updateRecording() {
if (width == 0 || height == 0) return;
if (recorder != null) recorder.stopPreview();
params = new AndroidCameraRecord.RecorderParams(0);
params.surfaceView = surfaceView;
params.width = width;
params.height = height;
params.fps = rate;
params.cameraId = currentCameraId;
recorder = new JavaCameraRecordImpl(params);
// recorder.setDebug(debugView);
debugView.setText(orientationToString(currentOrientationIsPortrait)
+ " w="+width + " h="+height+ " cam"+currentCameraId);
recorder.startPreview();
}
private String orientationToString(boolean orientationIsPortrait) {
return orientationIsPortrait? "Por" : "Lan";
}
private int otherCameraId(int currentId) {
return (currentId == 2) ? 1 : 2;
}
public void onClick(View v) {
nextSize.setText("Next");
started=true;
if (videoSizes.isEmpty()) {
videoSizes = createSizesToTest();
}
VideoSize size = videoSizes.pop();
changeSurfaceViewLayout(size.getWidth(), size.getHeight());
// on surface changed the recorder will be restarted with new values
// and the surface will be resized
}
private void changeSurfaceViewLayout(int width, int height) {
LayoutParams params = surfaceView.getLayoutParams();
params.height = height;
params.width = width;
surfaceView.setLayoutParams(params);
}
private Stack<VideoSize> createSizesToTest() {
Stack<VideoSize> stack = new Stack<VideoSize>();
stack.push(VideoSize.createStandard(QCIF, false));
stack.push(VideoSize.createStandard(CIF, false));
stack.push(VideoSize.createStandard(QVGA, false));
stack.push(VideoSize.createStandard(HVGA, false));
stack.push(new VideoSize(640,480));
stack.push(new VideoSize(800,480));
return stack;
}
public void surfaceDestroyed(SurfaceHolder holder) {
surfaceView = null;
Log.d(tag , "Video capture surface destroyed");
if (recorder != null) recorder.stopPreview();
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(tag , "Video capture surface created");
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (!started) return;
if (recorder != null) recorder.stopPreview();
this.width = width;
this.height = height;
updateRecording();
}
}

View file

@ -76,6 +76,7 @@ public class TutorialRegistrationActivity extends TutorialHelloWorldActivity {
}
});
Button buttonStop = (Button) findViewById(R.id.ButtonStop);
buttonStop.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {