diff --git a/default.properties b/default.properties index 51e933a98..247186a6a 100644 --- a/default.properties +++ b/default.properties @@ -10,4 +10,4 @@ # Indicates whether an apk should be generated for each density. split.density=false # Project target. -target=android-8 +target=android-9 diff --git a/res/menu/videocall_activity_menu.xml b/res/menu/videocall_activity_menu.xml index 4a3b5e099..88dca9776 100644 --- a/res/menu/videocall_activity_menu.xml +++ b/res/menu/videocall_activity_menu.xml @@ -8,5 +8,5 @@ - + diff --git a/src/org/linphone/BandwidthManager.java b/src/org/linphone/BandwidthManager.java index 6af77423c..2ebf5d112 100644 --- a/src/org/linphone/BandwidthManager.java +++ b/src/org/linphone/BandwidthManager.java @@ -28,7 +28,6 @@ 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 boolean portraitMode = true; // FIXME: preference? private static final int[][] bandwidthes = {{256,256}, {128,128}, {80,80}}; private static BandwidthManager instance; @@ -71,7 +70,7 @@ public class BandwidthManager { lc.setDownloadBandwidth(bandwidthes[newProfile][1]); if (lc.isIncall()) { - InviteManager.getInstance().reinvite(); + CallManager.getInstance().reinvite(); } else { updateWithProfileSettings(lc, null); } @@ -80,11 +79,9 @@ public class BandwidthManager { public void updateWithProfileSettings(LinphoneCore lc, LinphoneCallParams callParams) { // Setting Linphone Core Preferred Video Size - AndroidCameraRecordManager cameraManager = AndroidCameraRecordManager.getInstance(); - boolean bandwidthOKForVideo = isVideoPossible(); if (bandwidthOKForVideo) { - VideoSize targetVideoSize = cameraManager.doYouSupportThisVideoSize(getMaximumVideoSize()); + VideoSize targetVideoSize = getMaximumVideoSize(); lc.setPreferredVideoSize(targetVideoSize); VideoSize actualVideoSize = lc.getPreferredVideoSize(); @@ -106,12 +103,12 @@ public class BandwidthManager { } - private VideoSize maximumVideoSize(int profile) { + private VideoSize maximumVideoSize(int profile, boolean cameraIsPortrait) { switch (profile) { case LOW_RESOLUTION: - return VideoSize.createStandard(VideoSize.QCIF, portraitMode); + return VideoSize.createStandard(VideoSize.QCIF, cameraIsPortrait); case HIGH_RESOLUTION: - return VideoSize.createStandard(VideoSize.QVGA, portraitMode); + return VideoSize.createStandard(VideoSize.QVGA, cameraIsPortrait); default: throw new RuntimeException("profile not managed : " + profile); } @@ -123,6 +120,6 @@ public class BandwidthManager { } public VideoSize getMaximumVideoSize() { - return maximumVideoSize(currentProfile); + return maximumVideoSize(currentProfile, AndroidCameraRecordManager.getInstance().outputIsPortrait()); } } diff --git a/src/org/linphone/InviteManager.java b/src/org/linphone/CallManager.java similarity index 83% rename from src/org/linphone/InviteManager.java rename to src/org/linphone/CallManager.java index 9ba2770f2..4d0eff734 100644 --- a/src/org/linphone/InviteManager.java +++ b/src/org/linphone/CallManager.java @@ -1,5 +1,5 @@ /* -InviteManager.java +CallManager.java Copyright (C) 2010 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or @@ -25,13 +25,19 @@ import org.linphone.core.LinphoneCallParams; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCoreException; -public class InviteManager { +/** + * Handle call updating, reinvites. + * + * @author Guillaume Beraudo + * + */ +public class CallManager { - private static InviteManager instance; + private static CallManager instance; - private InviteManager() {} - public static final synchronized InviteManager getInstance() { - if (instance == null) instance = new InviteManager(); + private CallManager() {} + public static final synchronized CallManager getInstance() { + if (instance == null) instance = new CallManager(); return instance; } @@ -107,4 +113,14 @@ public class InviteManager { lc.updateCall(lCall, params); } + /** + * Update current call, without reinvite. + */ + public void updateCall() { + LinphoneCore lc = lc(); + LinphoneCall lCall = lc.getCurrentCall(); + LinphoneCallParams params = lCall.getCurrentParamsCopy(); + bm().updateWithProfileSettings(lc, params); + } + } diff --git a/src/org/linphone/DialerActivity.java b/src/org/linphone/DialerActivity.java index cb2ae8022..5fe8626c9 100644 --- a/src/org/linphone/DialerActivity.java +++ b/src/org/linphone/DialerActivity.java @@ -168,7 +168,7 @@ public class DialerActivity extends Activity implements LinphoneCoreListener { mAddVideo.setOnClickListener(new OnClickListener() { public void onClick(View v) { // If no in video call; try to reinvite with video - boolean alreadyInVideoCall = !InviteManager.getInstance().reinviteWithVideo(); + boolean alreadyInVideoCall = !CallManager.getInstance().reinviteWithVideo(); if (alreadyInVideoCall) { // In video call; going back to video call activity startVideoView(VIDEO_VIEW_ACTIVITY); @@ -364,6 +364,7 @@ public class DialerActivity extends Activity implements LinphoneCoreListener { if (mWakeLock.isHeld()) mWakeLock.release(); theDialer=null; } + @Override protected void onResume() { super.onResume(); @@ -522,6 +523,8 @@ public class DialerActivity extends Activity implements LinphoneCoreListener { private void resetCameraFromPreferences() { boolean useFrontCam = mPref.getBoolean(getString(R.string.pref_video_use_front_camera_key), false); AndroidCameraRecordManager.getInstance().setUseFrontCamera(useFrontCam); + final int phoneOrientation = 90 * getWindowManager().getDefaultDisplay().getOrientation(); + AndroidCameraRecordManager.getInstance().setPhoneOrientation(phoneOrientation); } private void exitCallMode() { @@ -605,7 +608,7 @@ public class DialerActivity extends Activity implements LinphoneCoreListener { 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); resetCameraFromPreferences(); - InviteManager.getInstance().inviteAddress(lAddress, prefVideoEnable && prefInitiateWithVideo); + CallManager.getInstance().inviteAddress(lAddress, prefVideoEnable && prefInitiateWithVideo); } catch (LinphoneCoreException e) { Toast toast = Toast.makeText(DialerActivity.this diff --git a/src/org/linphone/LinphoneService.java b/src/org/linphone/LinphoneService.java index 73075df4e..dc938c184 100644 --- a/src/org/linphone/LinphoneService.java +++ b/src/org/linphone/LinphoneService.java @@ -54,7 +54,6 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Handler; import android.os.IBinder; -import android.os.PowerManager; import android.os.Vibrator; import android.preference.PreferenceManager; import android.util.Log; diff --git a/src/org/linphone/VideoCallActivity.java b/src/org/linphone/VideoCallActivity.java index 4c913ee81..cc720699e 100644 --- a/src/org/linphone/VideoCallActivity.java +++ b/src/org/linphone/VideoCallActivity.java @@ -22,12 +22,12 @@ package org.linphone; import org.linphone.core.AndroidCameraRecordManager; import org.linphone.core.LinphoneCore; +import org.linphone.core.Version; import org.linphone.core.VideoSize; import android.app.Activity; import android.content.Context; import android.content.pm.ActivityInfo; -import android.os.Build; import android.os.Bundle; import android.os.PowerManager; import android.os.PowerManager.WakeLock; @@ -47,7 +47,8 @@ public class VideoCallActivity extends Activity { private WakeLock mWakeLock; private static final int capturePreviewLargestDimension = 150; // private static final float similarRatio = 0.1f; - private static final int version = Integer.parseInt(Build.VERSION.SDK); + private int previousPhoneOrientation; + private int phoneOrientation; public void onCreate(Bundle savedInstanceState) { launched = true; @@ -61,9 +62,10 @@ public class VideoCallActivity extends Activity { mVideoCaptureView = (SurfaceView) findViewById(R.id.video_capture_surface); - final int rotation = getWindowManager().getDefaultDisplay().getOrientation(); + previousPhoneOrientation = AndroidCameraRecordManager.getInstance().getPhoneOrientation(); + phoneOrientation = 90 * getWindowManager().getDefaultDisplay().getOrientation(); recordManager = AndroidCameraRecordManager.getInstance(); - recordManager.setSurfaceView(mVideoCaptureView, rotation); + recordManager.setSurfaceView(mVideoCaptureView, phoneOrientation); mVideoCaptureView.setZOrderOnTop(true); if (!recordManager.isMuted()) sendStaticImage(false); @@ -71,15 +73,32 @@ public class VideoCallActivity extends Activity { mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE,"Linphone"); mWakeLock.acquire(); - if (version < 8) { + if (Version.sdkBelow(8)) { // Force to display in portrait orientation for old devices // as they do not support surfaceView rotation - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + setRequestedOrientation(recordManager.isCameraOrientationPortrait() ? + ActivityInfo.SCREEN_ORIENTATION_PORTRAIT : + ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } - // Handle the fact that the preferred size may have a ratio /an orientation different from the one - // in the videocall.xml as the front camera on Samsung captures in landscape. - resizeCapturePreviewForOldPhones(mVideoCaptureView, lc.getPreferredVideoSize()); + // Base capture frame on streamed dimensions and orientation. + resizeCapturePreview(mVideoCaptureView, lc.getPreferredVideoSize()); + } + + private void updateCallIfOrientationChanged() { + if (Version.sdkAbove(8) && previousPhoneOrientation != phoneOrientation) { + CallManager.getInstance().updateCall(); + // camera will be restarted when mediastreamer chain is recreated and setParameters is called + + // Base capture frame on streamed dimensions and orientation. + resizeCapturePreview(mVideoCaptureView, LinphoneService.getLc().getPreferredVideoSize()); + } + } + + @Override + protected void onResume() { + updateCallIfOrientationChanged(); + super.onResume(); } @@ -109,6 +128,9 @@ public class VideoCallActivity extends Activity { rewriteToggleCameraItem(menu.findItem(R.id.videocall_menu_toggle_camera)); rewriteChangeResolutionItem(menu.findItem(R.id.videocall_menu_change_resolution)); + if (!recordManager.hasSeveralCameras()) { + menu.findItem(R.id.videocall_menu_switch_camera).setVisible(false); + } return true; } @@ -123,9 +145,7 @@ public class VideoCallActivity extends Activity { * @param sv capture surface view to resize the layout * @param vs video size from which to calculate the dimensions */ - private void resizeCapturePreviewForOldPhones(SurfaceView sv, VideoSize vs) { - if (version >= 8) return; - + private void resizeCapturePreview(SurfaceView sv, VideoSize vs) { LayoutParams lp = sv.getLayoutParams(); float newRatio = ratioWidthHeight(vs); @@ -158,7 +178,7 @@ public class VideoCallActivity extends Activity { // Resize preview frame VideoSize newVideoSize = LinphoneService.getLc().getPreferredVideoSize(); - resizeCapturePreviewForOldPhones(mVideoCaptureView, newVideoSize); + resizeCapturePreview(mVideoCaptureView, newVideoSize); break; case R.id.videocall_menu_terminate_call: LinphoneCore lc = LinphoneService.getLc(); @@ -171,13 +191,17 @@ public class VideoCallActivity extends Activity { sendStaticImage(recordManager.toggleMute()); rewriteToggleCameraItem(item); break; -/* case R.id.videocall_menu_switch_camera: + case R.id.videocall_menu_switch_camera: recordManager.stopVideoRecording(); + sendStaticImage(true); recordManager.toggleUseFrontCamera(); - InviteManager.getInstance().reinvite(); + CallManager.getInstance().updateCall(); // camera will be restarted when mediastreamer chain is recreated and setParameters is called + + // Base capture frame on streamed dimensions and orientation. + resizeCapturePreview(mVideoCaptureView, LinphoneService.getLc().getPreferredVideoSize()); break; -*/ default: + default: Log.e(LinphoneService.TAG, "Unknown menu item ["+item+"]"); break; } diff --git a/src/org/linphone/core/AndroidCameraRecord.java b/src/org/linphone/core/AndroidCameraRecord.java index 1696efbc7..6feafc322 100644 --- a/src/org/linphone/core/AndroidCameraRecord.java +++ b/src/org/linphone/core/AndroidCameraRecord.java @@ -39,14 +39,12 @@ public abstract class AndroidCameraRecord { private PreviewCallback storedPreviewCallback; private boolean previewStarted; - protected int displayOrientation; protected static final String tag="Linphone"; private List supportedVideoSizes; private Size currentPreviewSize; public AndroidCameraRecord(RecorderParams parameters) { this.params = parameters; - setDisplayOrientation(parameters.rotation); } protected List getSupportedPreviewSizes(Camera.Parameters parameters) { @@ -67,7 +65,7 @@ public abstract class AndroidCameraRecord { } - camera=Camera.open(); + camera = openCamera(params.cameraId); camera.setErrorCallback(new ErrorCallback() { public void onError(int error, Camera camera) { Log.e(tag, "Camera error : " + error); @@ -84,9 +82,10 @@ public abstract class AndroidCameraRecord { } - if (!params.videoDimensionsInverted) { + if (params.width >= params.height) { parameters.setPreviewSize(params.width, params.height); } else { + // invert height and width parameters.setPreviewSize(params.height, params.width); } parameters.setPreviewFrameRate(Math.round(params.fps)); @@ -126,6 +125,10 @@ public abstract class AndroidCameraRecord { + protected Camera openCamera(int cameraId) { + return Camera.open(); + } + protected void onSettingCameraParameters(Parameters parameters) {} /** @@ -164,24 +167,8 @@ public abstract class AndroidCameraRecord { protected abstract void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb); - public void setDisplayOrientation(int rotation) { - displayOrientation = rotation; - } - protected int getDisplayOrientation() {return displayOrientation;} - - 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; @@ -191,7 +178,6 @@ public abstract class AndroidCameraRecord { public int cameraId; public int rotation; public SurfaceView surfaceView; - public boolean videoDimensionsInverted; public RecorderParams(long ptr) { filterDataNativePtr = ptr; @@ -200,7 +186,6 @@ public abstract class AndroidCameraRecord { - public boolean isStarted() { return previewStarted; } @@ -215,4 +200,5 @@ public abstract class AndroidCameraRecord { return currentPreviewSize.width * currentPreviewSize.height * 3 /2; } + } diff --git a/src/org/linphone/core/AndroidCameraRecordImplAPI5.java b/src/org/linphone/core/AndroidCameraRecord5Impl.java similarity index 93% rename from src/org/linphone/core/AndroidCameraRecordImplAPI5.java rename to src/org/linphone/core/AndroidCameraRecord5Impl.java index 7ff307d03..18e487d12 100644 --- a/src/org/linphone/core/AndroidCameraRecordImplAPI5.java +++ b/src/org/linphone/core/AndroidCameraRecord5Impl.java @@ -26,9 +26,9 @@ import android.hardware.Camera.Size; import android.util.Log; -public class AndroidCameraRecordImplAPI5 extends AndroidCameraRecordImpl { +public class AndroidCameraRecord5Impl extends AndroidCameraRecordImpl { - public AndroidCameraRecordImplAPI5(RecorderParams parameters) { + public AndroidCameraRecord5Impl(RecorderParams parameters) { super(parameters); } diff --git a/src/org/linphone/core/AndroidCameraRecordAPI8Impl.java b/src/org/linphone/core/AndroidCameraRecord8Impl.java similarity index 86% rename from src/org/linphone/core/AndroidCameraRecordAPI8Impl.java rename to src/org/linphone/core/AndroidCameraRecord8Impl.java index 9655428db..490d9ad97 100644 --- a/src/org/linphone/core/AndroidCameraRecordAPI8Impl.java +++ b/src/org/linphone/core/AndroidCameraRecord8Impl.java @@ -30,10 +30,10 @@ import android.util.Log; * @author Guillaume Beraudo * */ -public class AndroidCameraRecordAPI8Impl extends AndroidCameraRecordImplAPI5 { +public class AndroidCameraRecord8Impl extends AndroidCameraRecord5Impl { - public AndroidCameraRecordAPI8Impl(RecorderParams parameters) { + public AndroidCameraRecord8Impl(RecorderParams parameters) { super(parameters); } @@ -66,10 +66,6 @@ public class AndroidCameraRecordAPI8Impl extends AndroidCameraRecordImplAPI5 { protected void onSettingCameraParameters(Parameters parameters) { super.onSettingCameraParameters(parameters); // Only on v8 hardware - camera.setDisplayOrientation(90 * getPreviewCaptureRotation()); - } - - private int getPreviewCaptureRotation() { - return (4 + 1 - displayOrientation) % 4; + camera.setDisplayOrientation(rotation); } } diff --git a/src/org/linphone/core/AndroidCameraRecord9Impl.java b/src/org/linphone/core/AndroidCameraRecord9Impl.java new file mode 100644 index 000000000..0ddb283d2 --- /dev/null +++ b/src/org/linphone/core/AndroidCameraRecord9Impl.java @@ -0,0 +1,40 @@ +/* +AndroidCameraRecord9Impl.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; + +/** + * + * Android >= 9 (2.3) version. + * @author Guillaume Beraudo + * + */ +public class AndroidCameraRecord9Impl extends AndroidCameraRecord8Impl { + + + public AndroidCameraRecord9Impl(RecorderParams parameters) { + super(parameters); + } + + @Override + protected Camera openCamera(int cameraId) { + return Camera.open(cameraId); + } +} diff --git a/src/org/linphone/core/AndroidCameraRecordImpl.java b/src/org/linphone/core/AndroidCameraRecordImpl.java index daf26ea4e..f1a4f4844 100644 --- a/src/org/linphone/core/AndroidCameraRecordImpl.java +++ b/src/org/linphone/core/AndroidCameraRecordImpl.java @@ -34,19 +34,19 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev private double timeElapsedBetweenFrames = 0; private long lastFrameTime = 0; private final double expectedTimeBetweenFrames; - private boolean sizesInverted; + protected final int rotation; public AndroidCameraRecordImpl(RecorderParams parameters) { super(parameters); expectedTimeBetweenFrames = 1d / Math.round(parameters.fps); filterCtxPtr = parameters.filterDataNativePtr; - sizesInverted = parameters.videoDimensionsInverted; + rotation = parameters.rotation; storePreviewCallBack(this); } - private native void putImage(long filterCtxPtr, byte[] buffer, int rotate, boolean sizesInverted); + private native void putImage(long filterCtxPtr, byte[] buffer, int rotate); public void onPreviewFrame(byte[] data, Camera camera) { @@ -69,7 +69,7 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev long curTime = System.currentTimeMillis(); if (lastFrameTime == 0) { lastFrameTime = curTime; - putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted); + putImage(filterCtxPtr, data, rotation); return; } @@ -82,7 +82,7 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev timeElapsedBetweenFrames = currentTimeElapsed; // Log.d("onPreviewFrame: ", Integer.toString(data.length)); - putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted); + putImage(filterCtxPtr, data, rotation); } @@ -92,6 +92,4 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev camera.setPreviewCallback(cb); } - - } diff --git a/src/org/linphone/core/AndroidCameraRecordManager.java b/src/org/linphone/core/AndroidCameraRecordManager.java index a6c38d76d..5c9f4d7c8 100644 --- a/src/org/linphone/core/AndroidCameraRecordManager.java +++ b/src/org/linphone/core/AndroidCameraRecordManager.java @@ -22,6 +22,7 @@ import java.util.List; import org.linphone.core.AndroidCameraRecord.RecorderParams; +import android.hardware.Camera; import android.hardware.Camera.Size; import android.os.Build; import android.util.Log; @@ -38,14 +39,9 @@ import android.view.SurfaceHolder.Callback; * */ 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 */ @@ -59,31 +55,76 @@ public class AndroidCameraRecordManager { private AndroidCameraRecord.RecorderParams parameters; private SurfaceView surfaceView; private boolean muted; - + private int cameraId; private AndroidCameraRecord recorder; - - private List supportedVideoSizes; - private int rotation; + private int phoneOrientation; + public int getPhoneOrientation() {return phoneOrientation;} + public void setPhoneOrientation(int degrees) {this.phoneOrientation = degrees;} - private boolean useFrontCamera; + private int frontCameraId; + private int rearCameraId; + + // singleton + private AndroidCameraRecordManager() { + findFrontAndRearCameraIds(); + } + + + private void findFrontAndRearCameraIds() { + if (Version.sdkAbove(9)) { + findFrontAndRearCameraIds9(); + return; + } + + if (Build.DEVICE.startsWith("GT-I9000")) { + // Galaxy S has 2 cameras + frontCameraId = 2; + rearCameraId = 1; + cameraId = rearCameraId; + return; + } + + // default to 0/0 + } + + private void findFrontAndRearCameraIds9() { + for (int id=0; id < getNumberOfCameras9(); id++) { + if (isFrontCamera9(id)) { + frontCameraId = id; + } else { + rearCameraId = id; + } + } + } + + public boolean hasSeveralCameras() { + return frontCameraId != rearCameraId; + } + + public void setUseFrontCamera(boolean value) { - if (useFrontCamera == value) return; - this.useFrontCamera = value; - + if (isFrontCamera() == value) return; // already OK + + toggleUseFrontCamera(); + } + + public boolean isUseFrontCamera() {return isFrontCamera();} + public boolean toggleUseFrontCamera() { + boolean previousUseFront = isFrontCamera(); + + cameraId = previousUseFront ? rearCameraId : frontCameraId; + if (parameters != null) { - parameters.cameraId = cameraId(); + parameters.cameraId = cameraId; if (isRecording()) { stopVideoRecording(); tryToStartVideoRecording(); } } - } - public boolean isUseFrontCamera() {return useFrontCamera;} - public boolean toggleUseFrontCamera() { - setUseFrontCamera(!useFrontCamera); - return useFrontCamera; + + return !previousUseFront; } @@ -94,16 +135,14 @@ public class AndroidCameraRecordManager { 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 + p.cameraId = cameraId; parameters = p; tryToStartVideoRecording(); } - public final void setSurfaceView(final SurfaceView sv, final int rotation) { - this.rotation = useFrontCamera ? 1 : rotation; + public final void setSurfaceView(final SurfaceView sv, final int phoneOrientation) { + this.phoneOrientation = phoneOrientation; SurfaceHolder holder = sv.getHolder(); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); @@ -152,12 +191,15 @@ public class AndroidCameraRecordManager { private void tryToStartVideoRecording() { if (muted || surfaceView == null || parameters == null) return; - parameters.rotation = rotation; + parameters.rotation = bufferRotationForCorrectImageOrientation(); + parameters.surfaceView = surfaceView; - if (version >= 8) { - recorder = new AndroidCameraRecordAPI8Impl(parameters); - } else if (version >= 5) { - recorder = new AndroidCameraRecordImplAPI5(parameters); + if (Version.sdkAbove(9)) { + recorder = new AndroidCameraRecord9Impl(parameters); + } else if (Version.sdkAbove(8)) { + recorder = new AndroidCameraRecord8Impl(parameters); + } else if (Version.sdkAbove(5)) { + recorder = new AndroidCameraRecord5Impl(parameters); } else { recorder = new AndroidCameraRecordImpl(parameters); } @@ -188,8 +230,8 @@ public class AndroidCameraRecordManager { if (supportedVideoSizes != null) return supportedVideoSizes; } - if (version >= 5) { - supportedVideoSizes = AndroidCameraRecordImplAPI5.oneShotSupportedVideoSizes(); + if (Version.sdkAbove(5)) { + supportedVideoSizes = AndroidCameraRecord5Impl.oneShotSupportedVideoSizes(); } // eventually null @@ -212,34 +254,86 @@ public class AndroidCameraRecordManager { 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; - } + public boolean outputIsPortrait() { + final int rotation = bufferRotationForCorrectImageOrientation(); + final boolean isPortrait = (rotation % 180) == 90; + + Log.d(tag, "Camera sensor in portrait orientation ?" + isPortrait); + return isPortrait; } - 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.height && s.width == testSize.width) { - return vSize; - } - } - - return VideoSize.createStandard(defaultSizeCode, defaultIsPortrait); + + + public static int getNumberOfCameras() { + if (Version.sdkAbove(9)) return getNumberOfCameras9(); + + // Use hacks to guess the number of cameras + if (Build.DEVICE.startsWith("GT-I9000")) { + // Galaxy S has 2 cameras + return 2; + } else + return 1; } - private static final int rearCamId() {return 1;} - private static final int frontCamId() {return 2;} - private final int cameraId() {return useFrontCamera? frontCamId() : rearCamId(); } + private static int getNumberOfCameras9() { + return Camera.getNumberOfCameras(); + } + + public boolean isCameraOrientationPortrait() { + return (getCameraOrientation() % 180) == 90; + } + + public int getCameraOrientation() { + if (Version.sdkAbove(9)) return getCameraOrientation9(); + + // Use hacks to guess orientation of the camera + if (cameraId == 2 && Build.DEVICE.startsWith("GT-I9000")) { + // Galaxy S rear camera + // mounted in landscape for a portrait phone orientation + return 90; + } + return 0; + } + + + private int getCameraOrientation9() { + android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); + Camera.getCameraInfo(cameraId, info); + return info.orientation; + } + + public boolean isFrontCamera() { + if (Version.sdkAbove(9)) return isFrontCamera9(); + + // Use hacks to guess facing of the camera + + if (cameraId == 2 && Build.DEVICE.startsWith("GT-I9000")) { + return true; + } + + return false; + } + + private boolean isFrontCamera9() { + return isFrontCamera9(cameraId); + } + + + private boolean isFrontCamera9(int cameraId) { + android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); + Camera.getCameraInfo(cameraId, info); + return info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT ? true : false; + } + + private int bufferRotationForCorrectImageOrientation() { + final int cameraOrientation = getCameraOrientation(); + final int rotation = Version.sdkAbove(8) ? + (360 - cameraOrientation + 90 - phoneOrientation) % 360 + : 0; + Log.d(tag, "Capture video buffer will need a rotation of " + rotation + + " degrees : camera " + cameraOrientation + + ", phone " + phoneOrientation); + return rotation; + } } diff --git a/src/org/linphone/core/Version.java b/src/org/linphone/core/Version.java new file mode 100644 index 000000000..0ec07fc25 --- /dev/null +++ b/src/org/linphone/core/Version.java @@ -0,0 +1,41 @@ +/* +Version.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.os.Build; + +/** + * Centralize version access and allow simulation of lower versions. + * @author Guillaume Beraudo + */ +public class Version { + + private static final int buildVersion = +// Integer.parseInt(Build.VERSION.SDK); + 7; // 2.1 + + public static final boolean sdkAbove(int value) { + return buildVersion >= value; + } + + public static final boolean sdkBelow(int value) { + return buildVersion < value; + } + +}