diff --git a/res/menu/videocall_activity_menu.xml b/res/menu/videocall_activity_menu.xml
new file mode 100644
index 000000000..eaae6cf7a
--- /dev/null
+++ b/res/menu/videocall_activity_menu.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8f2d27a54..127e89c5c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1,5 +1,13 @@
+ Display dialer
+ High resolution
+ Low resolution
+ Change resolution
+ Mute/Unmute camera
+ Disable camera
+ Enable camera
+ Terminate call
Video settings
Share my camera
Initiate video calls
diff --git a/src/org/linphone/BandwidthManager.java b/src/org/linphone/BandwidthManager.java
new file mode 100644
index 000000000..cb1f4d101
--- /dev/null
+++ b/src/org/linphone/BandwidthManager.java
@@ -0,0 +1,81 @@
+/*
+BandwithManager.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;
+
+import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCallParams;
+import org.linphone.core.LinphoneCore;
+import org.linphone.core.VideoSize;
+
+public class BandwidthManager {
+
+ public static final int HIGH_RESOLUTION = 0;
+ public static final int LOW_RESOLUTION = 1;
+ public static final int LOW_BANDWIDTH = 2;
+
+ private static final int[][] bandwidthes = {{512,512}, {128,128}, {80,80}};
+ private static BandwidthManager instance;
+
+ private int currentProfile = LOW_RESOLUTION; // FIXME first profile never defined in C part
+ public int getCurrentProfile() {return currentProfile;}
+
+ public static final synchronized BandwidthManager getInstance() {
+ if (instance == null) instance = new BandwidthManager();
+ return instance;
+ }
+
+ private BandwidthManager() {}
+
+ public void changeTo(int profile) {
+ LinphoneCore lc = LinphoneService.instance().getLinphoneCore();
+ LinphoneCall lCall = lc.getCurrentCall();
+ LinphoneCallParams params = lCall.getCurrentParamsReadOnly().copy();
+
+ if (profile == LOW_BANDWIDTH) { // OR video disabled by settings?
+// lc.enableVideo(false, false);
+ params.setVideoEnabled(false);
+ } else {
+ params.setVideoEnabled(true);
+ VideoSize targetVideoSize;
+ switch (profile) {
+ case LOW_RESOLUTION:
+ targetVideoSize = VideoSize.createStandard(VideoSize.HVGA);
+ break;
+ case HIGH_RESOLUTION:
+ targetVideoSize = VideoSize.createStandard(VideoSize.CIF);
+ break;
+ default:
+ throw new RuntimeException("profile not managed : " + profile);
+ }
+
+ lc.setPreferredVideoSize(targetVideoSize);
+ VideoSize actualVideoSize = lc.getPreferredVideoSize();
+ if (!targetVideoSize.equals(actualVideoSize)) {
+ lc.setPreferredVideoSize(VideoSize.createStandard(VideoSize.QCIF));
+ }
+ }
+
+
+ lc.setUploadBandwidth(bandwidthes[profile][0]);
+ lc.setDownloadBandwidth(bandwidthes[profile][1]);
+
+ lc.updateCall(lCall, params);
+ currentProfile = profile;
+ }
+}
diff --git a/src/org/linphone/DialerActivity.java b/src/org/linphone/DialerActivity.java
index 321cef397..3f2aabadb 100644
--- a/src/org/linphone/DialerActivity.java
+++ b/src/org/linphone/DialerActivity.java
@@ -152,18 +152,22 @@ public class DialerActivity extends Activity implements LinphoneCoreListener {
return true;
}
});
-
+
mAddVideo = (ImageButton) findViewById(R.id.AddVideo);
mAddVideo.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
LinphoneCore lLinphoneCore = LinphoneService.instance().getLinphoneCore();
- LinphoneCallParams params = lLinphoneCore.getCurrentCall().getCurrentParamsReadOnly();
+ LinphoneCall lCall = lLinphoneCore.getCurrentCall();
+ LinphoneCallParams params = lCall.getCurrentParamsReadOnly();
String msg;
if (params.getVideoEnabled()) {
msg = "In video call; going back to video call activity";
- startVideoView();
+ startVideoView(VIDEO_VIEW_ACTIVITY);
} else {
msg = "Not in video call; should go try to reinvite with video";
+ params.setVideoEnabled(true);
+ AndroidCameraRecord.setMuteCamera(false);
+ lLinphoneCore.updateCall(lCall, params);
}
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
@@ -228,7 +232,7 @@ public class DialerActivity extends Activity implements LinphoneCoreListener {
} else {
mCall.setEnabled(false);
mHangup.setEnabled(!mCall.isEnabled());
- boolean prefVideoEnabled = getPref(getApplicationContext().getString(R.string.pref_video_enable_key));
+ boolean prefVideoEnabled = mPref.getBoolean(getString(R.string.pref_video_enable_key), false);
if (!prefVideoEnabled && !mCall.isEnabled()) {
mAddVideo.setEnabled(true);
}
@@ -416,12 +420,10 @@ public class DialerActivity extends Activity implements LinphoneCoreListener {
}
}
}
- private void startVideoView() {
- //start video view
+ private void startVideoView(int requestCode) {
Intent lIntent = new Intent();
- lIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
lIntent.setClass(this, VideoCallActivity.class);
- startActivityForResult(lIntent,VIDEO_VIEW_ACTIVITY);
+ startActivityForResult(lIntent,requestCode);
}
public void registrationState(final LinphoneCore lc, final LinphoneProxyConfig cfg,final LinphoneCore.RegistrationState state,final String smessage) {/*nop*/};
@@ -445,7 +447,12 @@ public class DialerActivity extends Activity implements LinphoneCoreListener {
exitCallMode();
} else if (state == LinphoneCall.State.StreamsRunning) {
if (LinphoneService.instance().getLinphoneCore().getCurrentCall().getCurrentParamsReadOnly().getVideoEnabled()) {
- startVideoView();
+ startVideoView(VIDEO_VIEW_ACTIVITY);
+ }
+ } else if (state == LinphoneCall.State.CallUpdated) {
+ if (LinphoneService.instance().getLinphoneCore().getCurrentCall().getCurrentParamsReadOnly().getVideoEnabled()) {
+ AndroidCameraRecord.invalidateParameters();
+ finishActivity(VIDEO_VIEW_ACTIVITY);
}
}
}
@@ -520,17 +527,14 @@ public class DialerActivity extends Activity implements LinphoneCoreListener {
routeAudioToSpeaker();
// Privacy setting to not share the user camera by default
- boolean prefVideoEnable = getPref(getApplicationContext().getString(R.string.pref_video_enable_key));
- boolean prefAutomaticallyShareMyCamera = getPref(getApplicationContext().getString(R.string.pref_video_automatically_share_my_video_key));
+ boolean prefVideoEnable = mPref.getBoolean(getString(R.string.pref_video_enable_key), false);
+ boolean prefAutomaticallyShareMyCamera = mPref.getBoolean(getString(R.string.pref_video_automatically_share_my_video_key), false);
AndroidCameraRecord.setMuteCamera(!(prefVideoEnable && prefAutomaticallyShareMyCamera));
}
public void newOutgoingCall(String aTo) {
newOutgoingCall(aTo,null);
}
- private boolean getPref(String key) {
- return PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getBoolean(key, false);
- }
public synchronized void newOutgoingCall(String aTo, String displayName) {
String lto = aTo;
@@ -559,20 +563,21 @@ public class DialerActivity extends Activity implements LinphoneCoreListener {
try {
LinphoneCallParams lParams = lLinphoneCore.createDefaultCallParameters().copy();
- boolean prefVideoEnable = getPref(getApplicationContext().getString(R.string.pref_video_enable_key));
- boolean prefInitiateWithVideo = getPref(getApplicationContext().getString(R.string.pref_video_initiate_call_with_video_key));
+ boolean prefVideoEnable = mPref.getBoolean(getString(R.string.pref_video_enable_key), false);
+ boolean prefInitiateWithVideo = mPref.getBoolean(getString(R.string.pref_video_initiate_call_with_video_key), false);
if (prefVideoEnable && prefInitiateWithVideo && lParams.getVideoEnabled()) {
- lParams.setVideoEnalbled(true);
+ AndroidCameraRecord.setMuteCamera(false);
+ lParams.setVideoEnabled(true);
lLinphoneCore.inviteAddressWithParams(lAddress, lParams);
} else {
- lParams.setVideoEnalbled(false);
+ lParams.setVideoEnabled(false);
lLinphoneCore.inviteAddressWithParams(lAddress, lParams);
}
} catch (LinphoneCoreException e) {
Toast toast = Toast.makeText(DialerActivity.this
,String.format(getString(R.string.error_cannot_get_call_parameters),mAddress.getText().toString())
- , Toast.LENGTH_LONG);
+ ,Toast.LENGTH_LONG);
toast.show();
return;
}
diff --git a/src/org/linphone/VideoCallActivity.java b/src/org/linphone/VideoCallActivity.java
index 9c5466b17..6190366bc 100644
--- a/src/org/linphone/VideoCallActivity.java
+++ b/src/org/linphone/VideoCallActivity.java
@@ -21,18 +21,20 @@ package org.linphone;
import org.linphone.core.AndroidCameraRecord;
+import org.linphone.core.LinphoneCore;
import android.app.Activity;
+import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.SurfaceView;
-import android.view.View;
-import android.widget.FrameLayout;
public class VideoCallActivity extends Activity {
SurfaceView mVideoView;
SurfaceView mVideoCaptureView;
- private static boolean firstLaunch = true;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -46,25 +48,97 @@ public class VideoCallActivity extends Activity {
final int rotation = getWindowManager().getDefaultDisplay().getRotation();
AndroidCameraRecord.setOrientationCode(rotation);
- if (!firstLaunch) workaroundCapturePreviewHiddenOnSubsequentRotations();
-
AndroidCameraRecord.setSurfaceView(mVideoCaptureView);
- firstLaunch = false;
+ mVideoCaptureView.setZOrderOnTop(true);
}
+ private void rewriteToggleCameraItem(MenuItem item) {
+ if (AndroidCameraRecord.getCameraMuted()) {
+ item.setTitle(getString(R.string.menu_videocall_toggle_camera_enable));
+ } else {
+ item.setTitle(getString(R.string.menu_videocall_toggle_camera_disable));
+ }
+ }
+
+ private void rewriteChangeResolutionItem(MenuItem item) {
+ switch (BandwidthManager.getInstance().getCurrentProfile()) {
+ case BandwidthManager.HIGH_RESOLUTION:
+ item.setTitle(getString(R.string.menu_videocall_change_resolution_when_high_resolution));
+ break;
+ case BandwidthManager.LOW_RESOLUTION:
+ item.setTitle(getString(R.string.menu_videocall_change_resolution_when_low_resolution));
+ break;
+ default:
+ throw new RuntimeException("Current profile is unknown " + BandwidthManager.getInstance().getCurrentProfile());
+ }
+ }
+
- private void workaroundCapturePreviewHiddenOnSubsequentRotations() {
- View view = findViewById(R.id.video_frame);
- if (view == null) {
- Log.e("Linphone", "Android BUG: video frame not found; mix with landscape???");
- return;
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the currently selected menu XML resource.
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.videocall_activity_menu, menu);
+
+ rewriteToggleCameraItem(menu.findItem(R.id.videocall_menu_toggle_camera));
+ rewriteChangeResolutionItem(menu.findItem(R.id.videocall_menu_change_resolution));
+
+ return true;
+ }
+
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.videocall_menu_back_to_dialer:
+ finish();
+ break;
+ case R.id.videocall_menu_change_resolution:
+ BandwidthManager manager = BandwidthManager.getInstance();
+ switch (manager.getCurrentProfile()) {
+ case BandwidthManager.HIGH_RESOLUTION:
+ manager.changeTo(BandwidthManager.LOW_RESOLUTION);
+ break;
+ case BandwidthManager.LOW_RESOLUTION:
+ manager.changeTo(BandwidthManager.HIGH_RESOLUTION);
+ break;
+ default:
+ throw new RuntimeException("Current profile is unknown " + manager.getCurrentProfile());
+ }
+
+ rewriteChangeResolutionItem(item);
+ break;
+ case R.id.videocall_menu_terminate_call:
+ LinphoneCore lLinphoneCore = LinphoneService.instance().getLinphoneCore();
+ if (lLinphoneCore.isIncall()) {
+ lLinphoneCore.terminateCall(lLinphoneCore.getCurrentCall());
+ }
+ finish();
+ break;
+ case R.id.videocall_menu_toggle_camera:
+ AndroidCameraRecord.toggleMute();
+ rewriteToggleCameraItem(item);
+ break;
+ default:
+ Log.e(LinphoneService.TAG, "Unknown menu item ["+item+"]");
+ break;
}
- FrameLayout frame = (FrameLayout) view;
- frame.removeAllViews();
- frame.addView(mVideoCaptureView);
- frame.addView(mVideoView);
+ return false;
+ }
+ protected void startprefActivity() {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(this, LinphonePreferencesActivity.class);
+ startActivity(intent);
}
+
+ @Override
+ protected void onDestroy() {
+ // TODO Auto-generated method stub
+ super.onDestroy();
+ }
+
+
}
diff --git a/src/org/linphone/core/AndroidCameraRecord.java b/src/org/linphone/core/AndroidCameraRecord.java
index c16ef065d..138912f57 100644
--- a/src/org/linphone/core/AndroidCameraRecord.java
+++ b/src/org/linphone/core/AndroidCameraRecord.java
@@ -18,10 +18,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
+import java.util.ArrayList;
+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.os.Build;
import android.util.Log;
import android.view.SurfaceHolder;
@@ -44,8 +48,9 @@ public abstract class AndroidCameraRecord {
private static boolean previewStarted;
private static boolean parametersSet;
protected static int orientationCode;
- private static boolean mute;
+ private static boolean muted;
private static final String tag="Linphone";
+ private static List supportedVideoSizes;
public AndroidCameraRecord() {
// TODO check if another instance is loaded and kill it.
@@ -66,7 +71,7 @@ public abstract class AndroidCameraRecord {
* It will start automatically
*/
private void startPreview() {
- if (mute) {
+ if (muted) {
Log.d(tag, "Not starting preview as camera has been muted");
return;
}
@@ -100,6 +105,9 @@ public abstract class AndroidCameraRecord {
Camera.Parameters parameters=camera.getParameters();
+ if (supportedVideoSizes == null) {
+ supportedVideoSizes = camera.getParameters().getSupportedPreviewSizes();
+ }
parameters.setPreviewSize(width, height);
parameters.setPreviewFrameRate(fps);
@@ -174,6 +182,13 @@ public abstract class AndroidCameraRecord {
}
+ private static void stopPreview() {
+ camera.setPreviewCallback(null); // TODO check if used whatever the SDK version
+ camera.stopPreview();
+ camera.release();
+ camera=null;
+ previewStarted = false;
+ }
public static final void setSurfaceView(final SurfaceView sv) {
SurfaceHolder holder = sv.getHolder();
@@ -187,11 +202,7 @@ public abstract class AndroidCameraRecord {
Log.e(tag, "Video capture: illegal state: surface destroyed but camera is already null");
return;
}
- camera.setPreviewCallback(null); // TODO check if used whatever the SDK version
- camera.stopPreview();
- camera.release();
- camera=null;
- previewStarted = false;
+ stopPreview();
Log.w(tag, "Video capture Surface destroyed");
}
@@ -235,19 +246,45 @@ public abstract class AndroidCameraRecord {
}
public static void setMuteCamera(boolean m) {
- if (m == mute) return;
+ if (m == muted) return;
- mute = m;
- if (mute && previewStarted) {
- camera.stopPreview();
+ muted = m;
+ if (muted && previewStarted) {
+ stopPreview();
return;
}
- if (!mute) {
+ if (!muted) {
instance.startPreview();
}
}
+
+ public static void toggleMute() {
+ setMuteCamera(!muted);
+ }
+
+ public static List supportedVideoSizes() {
+ if (supportedVideoSizes != null) {
+ return new ArrayList(supportedVideoSizes);
+ }
+
+ if (camera == null) {
+ camera = Camera.open();
+ supportedVideoSizes = camera.getParameters().getSupportedPreviewSizes();
+ camera.release();
+ return supportedVideoSizes;
+ }
+
+ throw new RuntimeException("Should not be there");
+ }
+
+ public static boolean getCameraMuted() {
+ return muted;
+ }
+
+ public static void invalidateParameters() {
+ parametersSet = false;
+ stopPreview();
+ }
}
-
-
diff --git a/src/org/linphone/core/LinphoneCallImpl.java b/src/org/linphone/core/LinphoneCallImpl.java
index 4c9a770c9..b6194c26f 100644
--- a/src/org/linphone/core/LinphoneCallImpl.java
+++ b/src/org/linphone/core/LinphoneCallImpl.java
@@ -66,6 +66,4 @@ class LinphoneCallImpl implements LinphoneCall {
public LinphoneCallParams getCurrentParamsReadWrite() {
return getCurrentParamsReadOnly().copy();
}
-
-
}
diff --git a/src/org/linphone/core/LinphoneCallParamsImpl.java b/src/org/linphone/core/LinphoneCallParamsImpl.java
index add724f21..1242ee996 100644
--- a/src/org/linphone/core/LinphoneCallParamsImpl.java
+++ b/src/org/linphone/core/LinphoneCallParamsImpl.java
@@ -34,7 +34,7 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams {
return getVideoEnabled(nativePtr);
}
- public void setVideoEnalbled(boolean b) {
+ public void setVideoEnabled(boolean b) {
enableVideo(nativePtr, b);
}
diff --git a/src/org/linphone/core/LinphoneCoreImpl.java b/src/org/linphone/core/LinphoneCoreImpl.java
index 91913e322..532a7ae2c 100644
--- a/src/org/linphone/core/LinphoneCoreImpl.java
+++ b/src/org/linphone/core/LinphoneCoreImpl.java
@@ -81,7 +81,10 @@ class LinphoneCoreImpl implements LinphoneCore {
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 static String TAG = "LinphoneCore";
@@ -379,4 +382,27 @@ class LinphoneCoreImpl implements LinphoneCore {
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;
+ }
}