New Mediastreamer Android Camera filter integration
android: new mediastreamer integration android: new ms2 integration Video calls minor corrections
This commit is contained in:
parent
1b0cb40009
commit
77898e052d
31 changed files with 207 additions and 2034 deletions
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry excluding="org/linphone/mediastream/MediastreamerActivity.java" kind="src" path="submodules/linphone/mediastreamer2/java/src"/>
|
||||||
<classpathentry kind="src" path="submodules/linphone/java/j2se"/>
|
<classpathentry kind="src" path="submodules/linphone/java/j2se"/>
|
||||||
<classpathentry kind="src" path="submodules/linphone/java/common"/>
|
<classpathentry kind="src" path="submodules/linphone/java/common"/>
|
||||||
<classpathentry kind="src" path="gen"/>
|
<classpathentry kind="src" path="gen"/>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
android:id="@+id/video_frame" android:orientation="vertical"
|
android:id="@+id/video_frame" android:orientation="vertical"
|
||||||
android:layout_height="fill_parent" android:layout_width="fill_parent">
|
android:layout_height="fill_parent" android:layout_width="fill_parent">
|
||||||
|
|
||||||
<org.linphone.GL2JNIView android:layout_height="fill_parent" android:layout_width="fill_parent" android:id="@+id/video_surface"></org.linphone.GL2JNIView>
|
<org.linphone.mediastream.video.display.GL2JNIView android:layout_height="fill_parent" android:layout_width="fill_parent" android:id="@+id/video_surface"></org.linphone.mediastream.video.display.GL2JNIView>
|
||||||
<SurfaceView android:layout_height="72dip" android:layout_width="88dip" android:id="@+id/video_capture_surface" android:layout_gravity="right|bottom"
|
<SurfaceView android:layout_height="72dip" android:layout_width="88dip" android:id="@+id/video_capture_surface" android:layout_gravity="right|bottom"
|
||||||
android:layout_margin="15dip"></SurfaceView>
|
android:layout_margin="15dip"></SurfaceView>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
android:id="@+id/video_frame"
|
android:id="@+id/video_frame"
|
||||||
android:layout_height="fill_parent" android:layout_width="fill_parent">
|
android:layout_height="fill_parent" android:layout_width="fill_parent">
|
||||||
|
|
||||||
<org.linphone.GL2JNIView android:layout_height="fill_parent" android:layout_width="fill_parent" android:id="@+id/video_surface"></org.linphone.GL2JNIView>
|
<org.linphone.mediastream.video.display.GL2JNIView android:layout_height="fill_parent" android:layout_width="fill_parent" android:id="@+id/video_surface"></org.linphone.mediastream.video.display.GL2JNIView>
|
||||||
<SurfaceView android:layout_height="88dip" android:layout_width="72dip" android:id="@+id/video_capture_surface" android:layout_gravity="right|bottom"
|
<SurfaceView android:layout_height="88dip" android:layout_width="72dip" android:id="@+id/video_capture_surface" android:layout_gravity="right|bottom"
|
||||||
android:layout_margin="15dip"></SurfaceView>
|
android:layout_margin="15dip"></SurfaceView>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
|
@ -1,35 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent" android:layout_height="fill_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
<!--
|
|
||||||
<LinearLayout android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
-->
|
|
||||||
<!--
|
|
||||||
<Button android:text="TEST" android:id="@+id/videotest_test"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"></Button>
|
|
||||||
-->
|
|
||||||
<LinearLayout android:id="@+id/LinearLayout01"
|
|
||||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
<Button android:text="Start" android:id="@+id/test_video_size"
|
|
||||||
android:layout_width="fill_parent" android:layout_height="wrap_content" />
|
|
||||||
<Button android:text="Change camera" android:id="@+id/test_video_camera"
|
|
||||||
android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
|
|
||||||
<Button android:text="Change to portrait" android:id="@+id/test_video_orientation"
|
|
||||||
android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
|
|
||||||
<TextView android:id="@+id/videotest_debug"
|
|
||||||
android:layout_weight="1" android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"></TextView>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<SurfaceView android:id="@+id/videotest_surfaceView"
|
|
||||||
android:layout_width="wrap_content" android:layout_height="wrap_content"></SurfaceView>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -44,5 +44,5 @@ ng_floorgain=0.01
|
||||||
|
|
||||||
|
|
||||||
[video]
|
[video]
|
||||||
size=qvga-portrait
|
size=vga
|
||||||
|
|
||||||
|
|
|
@ -18,14 +18,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
package org.linphone;
|
package org.linphone;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.core.LinphoneCallParams;
|
import org.linphone.core.LinphoneCallParams;
|
||||||
import org.linphone.core.LinphoneCore;
|
import org.linphone.core.LinphoneCore;
|
||||||
import org.linphone.core.Log;
|
|
||||||
import org.linphone.core.Version;
|
|
||||||
import org.linphone.core.VideoSize;
|
|
||||||
import org.linphone.core.video.AndroidCameraRecordManager;
|
|
||||||
|
|
||||||
public class BandwidthManager {
|
public class BandwidthManager {
|
||||||
|
|
||||||
|
@ -82,24 +76,9 @@ public class BandwidthManager {
|
||||||
|
|
||||||
|
|
||||||
public void updateWithProfileSettings(LinphoneCore lc, LinphoneCallParams callParams) {
|
public void updateWithProfileSettings(LinphoneCore lc, LinphoneCallParams callParams) {
|
||||||
// Setting Linphone Core Preferred Video Size
|
|
||||||
boolean bandwidthOKForVideo = isVideoPossible();
|
|
||||||
if (bandwidthOKForVideo && Version.isVideoCapable()) {
|
|
||||||
AndroidCameraRecordManager acrm = AndroidCameraRecordManager.getInstance();
|
|
||||||
boolean isPortrait=acrm.isFrameToBeShownPortrait();
|
|
||||||
VideoSize targetVideoSize=maxSupportedVideoSize(isPortrait, getMaximumVideoSize(isPortrait),
|
|
||||||
acrm.supportedVideoSizes());
|
|
||||||
|
|
||||||
lc.setPreferredVideoSize(targetVideoSize);
|
|
||||||
VideoSize actualVideoSize = lc.getPreferredVideoSize();
|
|
||||||
if (!targetVideoSize.equals(actualVideoSize)) {
|
|
||||||
lc.setPreferredVideoSize(VideoSize.createStandard(VideoSize.QCIF, targetVideoSize.isPortrait()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callParams != null) { // in call
|
if (callParams != null) { // in call
|
||||||
// Update video parm if
|
// Update video parm if
|
||||||
if (!bandwidthOKForVideo) { // NO VIDEO
|
if (!isVideoPossible()) { // NO VIDEO
|
||||||
callParams.setVideoEnabled(false);
|
callParams.setVideoEnabled(false);
|
||||||
callParams.setAudioBandwidth(40);
|
callParams.setAudioBandwidth(40);
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,44 +88,7 @@ public class BandwidthManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private VideoSize maxSupportedVideoSize(boolean isPortrait, VideoSize maximumVideoSize,
|
|
||||||
List<VideoSize> supportedVideoSizes) {
|
|
||||||
Log.d("Searching for maximum video size for ", isPortrait ? "portrait" : "landscape","capture from (",maximumVideoSize);
|
|
||||||
VideoSize selected = VideoSize.createStandard(VideoSize.QCIF, isPortrait);
|
|
||||||
for (VideoSize s : supportedVideoSizes) {
|
|
||||||
int sW = s.width;
|
|
||||||
int sH = s.height;
|
|
||||||
if (s.isPortrait() != isPortrait) {
|
|
||||||
sW=s.height;
|
|
||||||
sH=s.width;
|
|
||||||
}
|
|
||||||
if (sW >maximumVideoSize.width || sH>maximumVideoSize.height) continue;
|
|
||||||
if (selected.width <sW && selected.height <sH) {
|
|
||||||
selected=new VideoSize(sW, sH);
|
|
||||||
Log.d("A better video size has been found: ",selected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
private VideoSize maximumVideoSize(int profile, boolean cameraIsPortrait) {
|
|
||||||
switch (profile) {
|
|
||||||
case LOW_RESOLUTION:
|
|
||||||
return VideoSize.createStandard(VideoSize.QCIF, cameraIsPortrait);
|
|
||||||
case HIGH_RESOLUTION:
|
|
||||||
return VideoSize.createStandard(VideoSize.QVGA, cameraIsPortrait);
|
|
||||||
default:
|
|
||||||
throw new RuntimeException("profile not managed : " + profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isVideoPossible() {
|
public boolean isVideoPossible() {
|
||||||
return currentProfile != LOW_BANDWIDTH;
|
return currentProfile != LOW_BANDWIDTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
private VideoSize getMaximumVideoSize(boolean isPortrait) {
|
|
||||||
return maximumVideoSize(currentProfile, isPortrait);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.linphone.core.LinphoneCallParams;
|
||||||
import org.linphone.core.LinphoneCore;
|
import org.linphone.core.LinphoneCore;
|
||||||
import org.linphone.core.LinphoneCoreException;
|
import org.linphone.core.LinphoneCoreException;
|
||||||
import org.linphone.core.Log;
|
import org.linphone.core.Log;
|
||||||
import org.linphone.core.video.AndroidCameraRecordManager;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +32,7 @@ import org.linphone.core.video.AndroidCameraRecordManager;
|
||||||
* @author Guillaume Beraudo
|
* @author Guillaume Beraudo
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class CallManager {
|
public class CallManager {
|
||||||
|
|
||||||
private static CallManager instance;
|
private static CallManager instance;
|
||||||
|
|
||||||
|
@ -43,9 +42,6 @@ class CallManager {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AndroidCameraRecordManager videoManager() {
|
|
||||||
return AndroidCameraRecordManager.getInstance();
|
|
||||||
}
|
|
||||||
private BandwidthManager bm() {
|
private BandwidthManager bm() {
|
||||||
return BandwidthManager.getInstance();
|
return BandwidthManager.getInstance();
|
||||||
}
|
}
|
||||||
|
@ -60,7 +56,6 @@ class CallManager {
|
||||||
bm().updateWithProfileSettings(lc, params);
|
bm().updateWithProfileSettings(lc, params);
|
||||||
|
|
||||||
if (videoEnabled && params.getVideoEnabled()) {
|
if (videoEnabled && params.getVideoEnabled()) {
|
||||||
videoManager().setMuted(false);
|
|
||||||
params.setVideoEnabled(true);
|
params.setVideoEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
params.setVideoEnabled(false);
|
params.setVideoEnabled(false);
|
||||||
|
@ -98,7 +93,6 @@ class CallManager {
|
||||||
|
|
||||||
// Not yet in video call: try to re-invite with video
|
// Not yet in video call: try to re-invite with video
|
||||||
params.setVideoEnabled(true);
|
params.setVideoEnabled(true);
|
||||||
videoManager().setMuted(false);
|
|
||||||
lc.updateCall(lCall, params);
|
lc.updateCall(lCall, params);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +119,7 @@ class CallManager {
|
||||||
* Update current call, without reinvite.
|
* Update current call, without reinvite.
|
||||||
* The camera will be restarted when mediastreamer chain is recreated and setParameters is called.
|
* The camera will be restarted when mediastreamer chain is recreated and setParameters is called.
|
||||||
*/
|
*/
|
||||||
void updateCall() {
|
public void updateCall() {
|
||||||
LinphoneCore lc = LinphoneManager.getLc();
|
LinphoneCore lc = LinphoneManager.getLc();
|
||||||
LinphoneCall lCall = lc.getCurrentCall();
|
LinphoneCall lCall = lc.getCurrentCall();
|
||||||
if (lCall == null) {
|
if (lCall == null) {
|
||||||
|
|
|
@ -22,11 +22,10 @@ import org.linphone.LinphoneManager.NewOutgoingCallUiListener;
|
||||||
import org.linphone.LinphoneService.LinphoneGuiListener;
|
import org.linphone.LinphoneService.LinphoneGuiListener;
|
||||||
import org.linphone.core.CallDirection;
|
import org.linphone.core.CallDirection;
|
||||||
import org.linphone.core.LinphoneCall;
|
import org.linphone.core.LinphoneCall;
|
||||||
import org.linphone.core.LinphoneCall.State;
|
|
||||||
import org.linphone.core.LinphoneCore;
|
import org.linphone.core.LinphoneCore;
|
||||||
import org.linphone.core.Log;
|
import org.linphone.core.Log;
|
||||||
import org.linphone.core.Version;
|
import org.linphone.core.Version;
|
||||||
import org.linphone.core.video.AndroidCameraRecordManager;
|
import org.linphone.core.LinphoneCall.State;
|
||||||
import org.linphone.ui.AddVideoButton;
|
import org.linphone.ui.AddVideoButton;
|
||||||
import org.linphone.ui.AddressAware;
|
import org.linphone.ui.AddressAware;
|
||||||
import org.linphone.ui.AddressText;
|
import org.linphone.ui.AddressText;
|
||||||
|
@ -321,14 +320,13 @@ public class DialerActivity extends SoftVolumeActivity implements LinphoneGuiLis
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
if (Version.isVideoCapable()) {
|
if (Version.isVideoCapable()) {
|
||||||
LinphoneManager.getInstance().resetCameraFromPreferences();
|
LinphoneManager.getInstance().resetCameraFromPreferences();
|
||||||
|
|
||||||
// Privacy setting to not share the user camera by default
|
// Privacy setting to not share the user camera by default
|
||||||
boolean prefVideoEnable = LinphoneManager.getInstance().isVideoEnabled();
|
boolean prefVideoEnable = LinphoneManager.getInstance().isVideoEnabled();
|
||||||
int key = R.string.pref_video_automatically_share_my_video_key;
|
int key = R.string.pref_video_automatically_share_my_video_key;
|
||||||
boolean prefAutoShareMyCamera = mPref.getBoolean(getString(key), false);
|
boolean prefAutoShareMyCamera = mPref.getBoolean(getString(key), false);
|
||||||
boolean videoMuted = !(prefVideoEnable && prefAutoShareMyCamera);
|
boolean videoMuted = !(prefVideoEnable && prefAutoShareMyCamera);
|
||||||
AndroidCameraRecordManager.getInstance().setMuted(videoMuted);
|
|
||||||
|
|
||||||
LinphoneManager.getLc().getCurrentCall().enableCamera(prefAutoShareMyCamera);
|
LinphoneManager.getLc().getCurrentCall().enableCamera(prefAutoShareMyCamera);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,7 +376,7 @@ public class DialerActivity extends SoftVolumeActivity implements LinphoneGuiLis
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void onCannotGetCallParameters() {
|
public void onCannotGetCallParameters() {
|
||||||
showToast(R.string.error_cannot_get_call_parameters,mAddress.getText());
|
showToast(R.string.error_cannot_get_call_parameters,mAddress.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,20 +392,35 @@ public class DialerActivity extends SoftVolumeActivity implements LinphoneGuiLis
|
||||||
/* we are certainly exiting, ignore then.*/
|
/* we are certainly exiting, ignore then.*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (state == LinphoneCall.State.OutgoingInit) {
|
|
||||||
enterIncallMode(lc);
|
switch (state) {
|
||||||
} else if (state == LinphoneCall.State.IncomingReceived) {
|
case OutgoingInit:
|
||||||
callPending(call);
|
|
||||||
} else if (state == LinphoneCall.State.Connected) {
|
|
||||||
if (call.getDirection() == CallDirection.Incoming) {
|
|
||||||
enterIncallMode(lc);
|
enterIncallMode(lc);
|
||||||
}
|
if (!LinphoneManager.getInstance().shareMyCamera())
|
||||||
} else if (state == LinphoneCall.State.Error) {
|
call.enableCamera(false);
|
||||||
if (mWakeLock.isHeld()) mWakeLock.release();
|
LinphoneActivity.instance().startOrientationSensor();
|
||||||
showToast(R.string.call_error, message);
|
break;
|
||||||
exitCallMode();
|
case IncomingReceived:
|
||||||
} else if (state == LinphoneCall.State.CallEnd) {
|
callPending(call);
|
||||||
exitCallMode();
|
if (!LinphoneManager.getInstance().shareMyCamera())
|
||||||
|
call.enableCamera(false);
|
||||||
|
LinphoneActivity.instance().startOrientationSensor();
|
||||||
|
break;
|
||||||
|
case Connected:
|
||||||
|
if (call.getDirection() == CallDirection.Incoming) {
|
||||||
|
enterIncallMode(lc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Error:
|
||||||
|
if (mWakeLock.isHeld()) mWakeLock.release();
|
||||||
|
showToast(R.string.call_error, message);
|
||||||
|
exitCallMode();
|
||||||
|
LinphoneActivity.instance().stopOrientationSensor();
|
||||||
|
break;
|
||||||
|
case CallEnd:
|
||||||
|
exitCallMode();
|
||||||
|
LinphoneActivity.instance().stopOrientationSensor();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.linphone.core.Log;
|
||||||
import org.linphone.core.Version;
|
import org.linphone.core.Version;
|
||||||
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
|
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
|
||||||
import org.linphone.core.LinphoneCore.RegistrationState;
|
import org.linphone.core.LinphoneCore.RegistrationState;
|
||||||
|
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.TabActivity;
|
import android.app.TabActivity;
|
||||||
|
@ -68,7 +69,7 @@ import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.widget.TabHost.TabSpec;
|
import android.widget.TabHost.TabSpec;
|
||||||
|
|
||||||
public class LinphoneActivity extends TabActivity {
|
public class LinphoneActivity extends TabActivity implements SensorEventListener {
|
||||||
public static final String DIALER_TAB = "dialer";
|
public static final String DIALER_TAB = "dialer";
|
||||||
public static final String PREF_FIRST_LAUNCH = "pref_first_launch";
|
public static final String PREF_FIRST_LAUNCH = "pref_first_launch";
|
||||||
private static final int video_activity = 100;
|
private static final int video_activity = 100;
|
||||||
|
@ -82,6 +83,8 @@ public class LinphoneActivity extends TabActivity {
|
||||||
|
|
||||||
private FrameLayout mMainFrame;
|
private FrameLayout mMainFrame;
|
||||||
private SensorManager mSensorManager;
|
private SensorManager mSensorManager;
|
||||||
|
private Sensor mAccelerometer;
|
||||||
|
private int previousRotation = -1;
|
||||||
private static SensorEventListener mSensorEventListener;
|
private static SensorEventListener mSensorEventListener;
|
||||||
|
|
||||||
private static final String SCREEN_IS_HIDDEN = "screen_is_hidden";
|
private static final String SCREEN_IS_HIDDEN = "screen_is_hidden";
|
||||||
|
@ -283,9 +286,30 @@ public class LinphoneActivity extends TabActivity {
|
||||||
Toast.makeText(this, getString(R.string.dialer_null_on_new_intent), Toast.LENGTH_LONG).show();
|
Toast.makeText(this, getString(R.string.dialer_null_on_new_intent), Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||||
|
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onSensorChanged(SensorEvent event) {
|
||||||
|
if (event==null || event.sensor == mAccelerometer) {
|
||||||
|
// WARNING : getRotation() is SDK > 5
|
||||||
|
int rot = AndroidVideoWindowImpl.rotationToAngle(getWindowManager().getDefaultDisplay().getRotation());
|
||||||
|
|
||||||
|
if (rot != previousRotation) {
|
||||||
|
Log.d("New device rotation: ", rot);
|
||||||
|
// Returning rotation FROM ITS NATURAL ORIENTATION
|
||||||
|
LinphoneManager.getLc().setDeviceRotation(rot);
|
||||||
|
previousRotation = rot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
||||||
if (isFinishing()) {
|
if (isFinishing()) {
|
||||||
//restore audio settings
|
//restore audio settings
|
||||||
LinphoneManager.getInstance().routeAudioToReceiver();
|
LinphoneManager.getInstance().routeAudioToReceiver();
|
||||||
|
@ -359,7 +383,7 @@ public class LinphoneActivity extends TabActivity {
|
||||||
if (event.timestamp == 0) return;
|
if (event.timestamp == 0) return;
|
||||||
instance().hideScreen(LinphoneManager.isProximitySensorNearby(event));
|
instance().hideScreen(LinphoneManager.isProximitySensorNearby(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||||
};
|
};
|
||||||
if (lSensorList.size() >0) {
|
if (lSensorList.size() >0) {
|
||||||
|
@ -367,6 +391,22 @@ public class LinphoneActivity extends TabActivity {
|
||||||
Log.i("Proximity sensor detected, registering");
|
Log.i("Proximity sensor detected, registering");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void startOrientationSensor() {
|
||||||
|
if (mSensorManager!=null) {
|
||||||
|
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||||
|
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* init LC orientation value on orientation sensor startup */
|
||||||
|
previousRotation = -1;
|
||||||
|
onSensorChanged(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void stopOrientationSensor() {
|
||||||
|
if (mSensorManager!=null)
|
||||||
|
mSensorManager.unregisterListener(this, mAccelerometer);
|
||||||
|
}
|
||||||
|
|
||||||
protected synchronized void stopProxymitySensor() {
|
protected synchronized void stopProxymitySensor() {
|
||||||
if (mSensorManager!=null) {
|
if (mSensorManager!=null) {
|
||||||
|
|
|
@ -30,7 +30,6 @@ import static org.linphone.R.string.pref_codec_amr_key;
|
||||||
import static org.linphone.R.string.pref_codec_ilbc_key;
|
import static org.linphone.R.string.pref_codec_ilbc_key;
|
||||||
import static org.linphone.R.string.pref_codec_speex16_key;
|
import static org.linphone.R.string.pref_codec_speex16_key;
|
||||||
import static org.linphone.R.string.pref_codec_speex32_key;
|
import static org.linphone.R.string.pref_codec_speex32_key;
|
||||||
import static org.linphone.R.string.pref_echo_cancellation_key;
|
|
||||||
import static org.linphone.R.string.pref_video_enable_key;
|
import static org.linphone.R.string.pref_video_enable_key;
|
||||||
import static org.linphone.core.LinphoneCall.State.CallEnd;
|
import static org.linphone.core.LinphoneCall.State.CallEnd;
|
||||||
import static org.linphone.core.LinphoneCall.State.Error;
|
import static org.linphone.core.LinphoneCall.State.Error;
|
||||||
|
@ -43,7 +42,6 @@ import java.io.InputStream;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
import org.linphone.core.Hacks;
|
|
||||||
import org.linphone.core.LinphoneAddress;
|
import org.linphone.core.LinphoneAddress;
|
||||||
import org.linphone.core.LinphoneAuthInfo;
|
import org.linphone.core.LinphoneAuthInfo;
|
||||||
import org.linphone.core.LinphoneCall;
|
import org.linphone.core.LinphoneCall;
|
||||||
|
@ -63,7 +61,10 @@ import org.linphone.core.LinphoneCore.FirewallPolicy;
|
||||||
import org.linphone.core.LinphoneCore.GlobalState;
|
import org.linphone.core.LinphoneCore.GlobalState;
|
||||||
import org.linphone.core.LinphoneCore.RegistrationState;
|
import org.linphone.core.LinphoneCore.RegistrationState;
|
||||||
import org.linphone.core.LinphoneCore.Transports;
|
import org.linphone.core.LinphoneCore.Transports;
|
||||||
import org.linphone.core.video.AndroidCameraRecordManager;
|
import org.linphone.mediastream.video.capture.AndroidVideoApi5JniWrapper;
|
||||||
|
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
|
||||||
|
import org.linphone.mediastream.video.capture.hwconf.Hacks;
|
||||||
|
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.AndroidCamera;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
|
@ -211,9 +212,8 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
||||||
instance = new LinphoneManager(c);
|
instance = new LinphoneManager(c);
|
||||||
instance.serviceListener = listener;
|
instance.serviceListener = listener;
|
||||||
instance.startLibLinphone(c);
|
instance.startLibLinphone(c);
|
||||||
if (Version.isVideoCapable()) {
|
|
||||||
AndroidCameraRecordManager.getInstance().startOrientationSensor(c.getApplicationContext());
|
AndroidVideoApi5JniWrapper.setAndroidSdkVersion(Build.VERSION.SDK_INT);
|
||||||
}
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +261,6 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
||||||
boolean prefVideoEnable = isVideoEnabled();
|
boolean prefVideoEnable = isVideoEnabled();
|
||||||
int key = R.string.pref_video_initiate_call_with_video_key;
|
int key = R.string.pref_video_initiate_call_with_video_key;
|
||||||
boolean prefInitiateWithVideo = mPref.getBoolean(mR.getString(key), false);
|
boolean prefInitiateWithVideo = mPref.getBoolean(mR.getString(key), false);
|
||||||
resetCameraFromPreferences();
|
|
||||||
CallManager.getInstance().inviteAddress(lAddress, prefVideoEnable && prefInitiateWithVideo);
|
CallManager.getInstance().inviteAddress(lAddress, prefVideoEnable && prefInitiateWithVideo);
|
||||||
} else {
|
} else {
|
||||||
CallManager.getInstance().inviteAddress(lAddress, false);
|
CallManager.getInstance().inviteAddress(lAddress, false);
|
||||||
|
@ -273,13 +272,20 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void resetCameraFromPreferences() {
|
public void resetCameraFromPreferences() {
|
||||||
boolean useFrontCam = mPref.getBoolean(mR.getString(R.string.pref_video_use_front_camera_key), false);
|
boolean useFrontCam = mPref.getBoolean(mR.getString(R.string.pref_video_use_front_camera_key), false);
|
||||||
AndroidCameraRecordManager.getInstance().setUseFrontCamera(useFrontCam);
|
|
||||||
|
int camId = 0;
|
||||||
|
AndroidCamera[] cameras = AndroidCameraConfiguration.retrieveCameras();
|
||||||
|
for (AndroidCamera androidCamera : cameras) {
|
||||||
|
if (androidCamera.frontFacing == useFrontCam)
|
||||||
|
camId = androidCamera.id;
|
||||||
|
}
|
||||||
|
LinphoneManager.getLc().setVideoDevice(camId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static interface AddressType {
|
public static interface AddressType {
|
||||||
void setText(CharSequence s);
|
void setText(CharSequence s);
|
||||||
CharSequence getText();
|
CharSequence getText();
|
||||||
|
@ -294,7 +300,12 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
||||||
public void onAlreadyInCall();
|
public void onAlreadyInCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void toggleEnableCamera() {
|
||||||
|
if (mLc.isIncall()) {
|
||||||
|
mLc.getCurrentCall().enableCamera(!mLc.getCurrentCall().cameraEnabled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void sendStaticImage(boolean send) {
|
public void sendStaticImage(boolean send) {
|
||||||
if (mLc.isIncall()) {
|
if (mLc.isIncall()) {
|
||||||
mLc.getCurrentCall().enableCamera(!send);
|
mLc.getCurrentCall().enableCamera(!send);
|
||||||
|
@ -324,20 +335,6 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Camera will be restarted when mediastreamer chain is recreated and setParameters is called.
|
|
||||||
*/
|
|
||||||
public void switchCamera() {
|
|
||||||
AndroidCameraRecordManager.getInstance().stopVideoRecording();
|
|
||||||
AndroidCameraRecordManager.getInstance().toggleUseFrontCamera();
|
|
||||||
CallManager.getInstance().updateCall();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleCameraMuting() {
|
|
||||||
AndroidCameraRecordManager rm = AndroidCameraRecordManager.getInstance();
|
|
||||||
sendStaticImage(rm.toggleMute());
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void startLibLinphone(final Context context) {
|
private synchronized void startLibLinphone(final Context context) {
|
||||||
try {
|
try {
|
||||||
copyAssetsFromPackage(context);
|
copyAssetsFromPackage(context);
|
||||||
|
@ -417,7 +414,7 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
||||||
|
|
||||||
public void initFromConf(Context context) throws LinphoneConfigException {
|
public void initFromConf(Context context) throws LinphoneConfigException {
|
||||||
//traces
|
//traces
|
||||||
boolean lIsDebug = mPref.getBoolean(getString(R.string.pref_debug_key), false);
|
boolean lIsDebug = true;//mPref.getBoolean(getString(R.string.pref_debug_key), false);
|
||||||
LinphoneCoreFactory.instance().setDebugMode(lIsDebug);
|
LinphoneCoreFactory.instance().setDebugMode(lIsDebug);
|
||||||
|
|
||||||
if (initialTransports == null)
|
if (initialTransports == null)
|
||||||
|
@ -843,6 +840,10 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
||||||
public boolean isVideoEnabled() {
|
public boolean isVideoEnabled() {
|
||||||
return mPref.getBoolean(getString(R.string.pref_video_enable_key), false);
|
return mPref.getBoolean(getString(R.string.pref_video_enable_key), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean shareMyCamera() {
|
||||||
|
return mPref.getBoolean(getString(R.string.pref_video_automatically_share_my_video), false);
|
||||||
|
}
|
||||||
|
|
||||||
public void setAudioModeIncallForGalaxyS() {
|
public void setAudioModeIncallForGalaxyS() {
|
||||||
stopRinging();
|
stopRinging();
|
||||||
|
|
|
@ -32,12 +32,12 @@ import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.linphone.LinphoneManager.EcCalibrationListener;
|
import org.linphone.LinphoneManager.EcCalibrationListener;
|
||||||
import org.linphone.core.Hacks;
|
|
||||||
import org.linphone.core.LinphoneCoreException;
|
import org.linphone.core.LinphoneCoreException;
|
||||||
import org.linphone.core.Log;
|
import org.linphone.core.Log;
|
||||||
import org.linphone.core.Version;
|
import org.linphone.core.Version;
|
||||||
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
|
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
|
||||||
import org.linphone.core.video.AndroidCameraRecordManager;
|
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
|
||||||
|
import org.linphone.mediastream.video.capture.hwconf.Hacks;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -98,7 +98,7 @@ public class LinphonePreferencesActivity extends PreferenceActivity implements E
|
||||||
// No video
|
// No video
|
||||||
if (!Version.isVideoCapable()) {
|
if (!Version.isVideoCapable()) {
|
||||||
uncheckAndDisableCheckbox(pref_video_enable_key);
|
uncheckAndDisableCheckbox(pref_video_enable_key);
|
||||||
} else if (!AndroidCameraRecordManager.getInstance().hasFrontCamera()) {
|
} else if (!AndroidCameraConfiguration.hasFrontCamera()) {
|
||||||
uncheckDisableAndHideCheckbox(R.string.pref_video_use_front_camera_key);
|
uncheckDisableAndHideCheckbox(R.string.pref_video_use_front_camera_key);
|
||||||
}
|
}
|
||||||
if (prefs().getBoolean(LinphoneActivity.PREF_FIRST_LAUNCH,true)) {
|
if (prefs().getBoolean(LinphoneActivity.PREF_FIRST_LAUNCH,true)) {
|
||||||
|
|
|
@ -22,13 +22,13 @@ import java.io.IOException;
|
||||||
|
|
||||||
import org.linphone.LinphoneManager.LinphoneServiceListener;
|
import org.linphone.LinphoneManager.LinphoneServiceListener;
|
||||||
import org.linphone.LinphoneManager.NewOutgoingCallUiListener;
|
import org.linphone.LinphoneManager.NewOutgoingCallUiListener;
|
||||||
import org.linphone.core.Hacks;
|
|
||||||
import org.linphone.core.LinphoneCall;
|
import org.linphone.core.LinphoneCall;
|
||||||
import org.linphone.core.Log;
|
import org.linphone.core.Log;
|
||||||
import org.linphone.core.Version;
|
import org.linphone.core.Version;
|
||||||
import org.linphone.core.LinphoneCall.State;
|
import org.linphone.core.LinphoneCall.State;
|
||||||
import org.linphone.core.LinphoneCore.GlobalState;
|
import org.linphone.core.LinphoneCore.GlobalState;
|
||||||
import org.linphone.core.LinphoneCore.RegistrationState;
|
import org.linphone.core.LinphoneCore.RegistrationState;
|
||||||
|
import org.linphone.mediastream.video.capture.hwconf.Hacks;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
|
|
@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
package org.linphone;
|
package org.linphone;
|
||||||
|
|
||||||
import org.linphone.core.Hacks;
|
import org.linphone.mediastream.video.capture.hwconf.Hacks;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
|
|
@ -20,89 +20,97 @@ package org.linphone;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import org.linphone.core.LinphoneCore;
|
|
||||||
import org.linphone.core.Log;
|
import org.linphone.core.Log;
|
||||||
import org.linphone.core.Version;
|
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
|
||||||
import org.linphone.core.VideoSize;
|
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
|
||||||
import org.linphone.core.video.AndroidCameraRecordManager;
|
|
||||||
import org.linphone.core.video.AndroidCameraRecordManager.OnCapturingStateChangedListener;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ActivityInfo;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
import android.view.ViewGroup.LayoutParams;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For Android SDK >= 5
|
* For Android SDK >= 5
|
||||||
* @author Guillaume Beraudo
|
* @author Guillaume Beraudo
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class VideoCallActivity extends SoftVolumeActivity implements OnCapturingStateChangedListener {
|
public class VideoCallActivity extends SoftVolumeActivity {
|
||||||
private SurfaceView mVideoView;
|
private SurfaceView mVideoView;
|
||||||
private SurfaceView mVideoCaptureView;
|
private SurfaceView mVideoCaptureView;
|
||||||
private AndroidCameraRecordManager recordManager;
|
|
||||||
public static boolean launched = false;
|
public static boolean launched = false;
|
||||||
private WakeLock mWakeLock;
|
private WakeLock mWakeLock;
|
||||||
private static final int capturePreviewLargestDimension = 150;
|
|
||||||
private Handler handler = new Handler();
|
AndroidVideoWindowImpl androidVideoWindowImpl;
|
||||||
|
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
launched = true;
|
launched = true;
|
||||||
Log.d("onCreate VideoCallActivity");
|
Log.d("onCreate VideoCallActivity");
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.videocall);
|
setContentView(R.layout.videocall);
|
||||||
|
|
||||||
mVideoView = (SurfaceView) findViewById(R.id.video_surface);
|
mVideoView = (SurfaceView) findViewById(R.id.video_surface);
|
||||||
LinphoneCore lc = LinphoneManager.getLc();
|
|
||||||
lc.setVideoWindow(mVideoView);
|
|
||||||
|
|
||||||
mVideoCaptureView = (SurfaceView) findViewById(R.id.video_capture_surface);
|
mVideoCaptureView = (SurfaceView) findViewById(R.id.video_capture_surface);
|
||||||
|
mVideoCaptureView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||||
|
|
||||||
recordManager = AndroidCameraRecordManager.getInstance();
|
/* force surfaces Z ordering */
|
||||||
recordManager.setOnCapturingStateChanged(this);
|
mVideoView.setZOrderOnTop(false);
|
||||||
recordManager.setSurfaceView(mVideoCaptureView);
|
|
||||||
mVideoCaptureView.setZOrderOnTop(true);
|
mVideoCaptureView.setZOrderOnTop(true);
|
||||||
|
|
||||||
|
androidVideoWindowImpl = new AndroidVideoWindowImpl(mVideoView, mVideoCaptureView);
|
||||||
|
androidVideoWindowImpl.setListener(new AndroidVideoWindowImpl.VideoWindowListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVideoRenderingSurfaceReady(AndroidVideoWindowImpl vw) {
|
||||||
|
LinphoneManager.getLc().setVideoWindow(vw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVideoRenderingSurfaceDestroyed(AndroidVideoWindowImpl vw) {
|
||||||
|
LinphoneManager.getLc().setVideoWindow(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVideoPreviewSurfaceReady(AndroidVideoWindowImpl vw) {
|
||||||
|
LinphoneManager.getLc().setPreviewWindow(mVideoCaptureView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVideoPreviewSurfaceDestroyed(AndroidVideoWindowImpl vw) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
androidVideoWindowImpl.init();
|
||||||
|
|
||||||
|
// When changing phone orientation _DURING_ a call, VideoCallActivity is destroyed then recreated
|
||||||
|
// In this case, the following sequence happen:
|
||||||
|
// * onDestroy -> sendStaticImage(true) => destroy video graph
|
||||||
|
// * onCreate -> sendStaticImage(false) => recreate the video graph.
|
||||||
|
// Before creating the graph, the orientation must be known to LC => this is done here
|
||||||
|
LinphoneManager.getLc().setDeviceRotation(AndroidVideoWindowImpl.rotationToAngle(getWindowManager().getDefaultDisplay().getRotation()));
|
||||||
|
|
||||||
if (!recordManager.isMuted()) LinphoneManager.getInstance().sendStaticImage(false);
|
if (LinphoneManager.getInstance().shareMyCamera())
|
||||||
|
LinphoneManager.getInstance().sendStaticImage(false);
|
||||||
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
|
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
|
||||||
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE,Log.TAG);
|
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE,Log.TAG);
|
||||||
mWakeLock.acquire();
|
mWakeLock.acquire();
|
||||||
|
|
||||||
fixScreenOrientationForOldDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fixScreenOrientationForOldDevices() {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API08_FROYO_22)) return;
|
|
||||||
|
|
||||||
// Force to display in portrait orientation for old devices
|
|
||||||
// as they do not support surfaceView rotation
|
|
||||||
setRequestedOrientation(recordManager.isCameraMountedPortrait() ?
|
|
||||||
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT :
|
|
||||||
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
|
||||||
resizeCapturePreview(mVideoCaptureView);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
if (Version.sdkAboveOrEqual(8) && recordManager.isOutputOrientationMismatch(LinphoneManager.getLc())) {
|
|
||||||
Log.i("Phone orientation has changed: updating call.");
|
|
||||||
CallManager.getInstance().updateCall();
|
|
||||||
// resizeCapturePreview by callback when recording started
|
|
||||||
}
|
|
||||||
super.onResume();
|
super.onResume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void rewriteToggleCameraItem(MenuItem item) {
|
private void rewriteToggleCameraItem(MenuItem item) {
|
||||||
if (recordManager.isRecording()) {
|
if (LinphoneManager.getLc().getCurrentCall().cameraEnabled()) {
|
||||||
item.setTitle(getString(R.string.menu_videocall_toggle_camera_disable));
|
item.setTitle(getString(R.string.menu_videocall_toggle_camera_disable));
|
||||||
} else {
|
} else {
|
||||||
item.setTitle(getString(R.string.menu_videocall_toggle_camera_enable));
|
item.setTitle(getString(R.string.menu_videocall_toggle_camera_enable));
|
||||||
|
@ -128,38 +136,12 @@ public class VideoCallActivity extends SoftVolumeActivity implements OnCapturing
|
||||||
rewriteToggleCameraItem(menu.findItem(R.id.videocall_menu_toggle_camera));
|
rewriteToggleCameraItem(menu.findItem(R.id.videocall_menu_toggle_camera));
|
||||||
rewriteChangeResolutionItem(menu.findItem(R.id.videocall_menu_change_resolution));
|
rewriteChangeResolutionItem(menu.findItem(R.id.videocall_menu_change_resolution));
|
||||||
|
|
||||||
if (!recordManager.hasSeveralCameras()) {
|
if (!AndroidCameraConfiguration.hasSeveralCameras()) {
|
||||||
menu.findItem(R.id.videocall_menu_switch_camera).setVisible(false);
|
menu.findItem(R.id.videocall_menu_switch_camera).setVisible(false);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base capture frame on streamed dimensions and orientation.
|
|
||||||
* @param sv capture surface view to resize the layout
|
|
||||||
* @param vs video size from which to calculate the dimensions
|
|
||||||
*/
|
|
||||||
private void resizeCapturePreview(SurfaceView sv) {
|
|
||||||
LayoutParams lp = sv.getLayoutParams();
|
|
||||||
VideoSize vs = LinphoneManager.getLc().getPreferredVideoSize();
|
|
||||||
|
|
||||||
float newRatio = (float) vs.width / vs.height;
|
|
||||||
|
|
||||||
if (vs.isPortrait()) {
|
|
||||||
lp.height = capturePreviewLargestDimension;
|
|
||||||
lp.width = Math.round(lp.height * newRatio);
|
|
||||||
} else {
|
|
||||||
lp.width = capturePreviewLargestDimension;
|
|
||||||
lp.height = Math.round(lp.width / newRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
sv.setLayoutParams(lp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
|
@ -168,30 +150,37 @@ public class VideoCallActivity extends SoftVolumeActivity implements OnCapturing
|
||||||
break;
|
break;
|
||||||
case R.id.videocall_menu_change_resolution:
|
case R.id.videocall_menu_change_resolution:
|
||||||
LinphoneManager.getInstance().changeResolution();
|
LinphoneManager.getInstance().changeResolution();
|
||||||
|
// previous call will cause graph reconstruction -> regive preview window
|
||||||
rewriteChangeResolutionItem(item);
|
rewriteChangeResolutionItem(item);
|
||||||
break;
|
break;
|
||||||
case R.id.videocall_menu_terminate_call:
|
case R.id.videocall_menu_terminate_call:
|
||||||
LinphoneManager.getInstance().terminateCall();
|
LinphoneManager.getInstance().terminateCall();
|
||||||
break;
|
break;
|
||||||
case R.id.videocall_menu_toggle_camera:
|
case R.id.videocall_menu_toggle_camera:
|
||||||
LinphoneManager.getInstance().toggleCameraMuting();
|
LinphoneManager.getInstance().toggleEnableCamera();
|
||||||
rewriteToggleCameraItem(item);
|
rewriteToggleCameraItem(item);
|
||||||
|
// previous call will cause graph reconstruction -> regive preview window
|
||||||
|
LinphoneManager.getLc().setPreviewWindow(mVideoCaptureView);
|
||||||
break;
|
break;
|
||||||
case R.id.videocall_menu_switch_camera:
|
case R.id.videocall_menu_switch_camera:
|
||||||
LinphoneManager.getInstance().switchCamera();
|
int id = LinphoneManager.getLc().getVideoDevice();
|
||||||
fixScreenOrientationForOldDevices();
|
id = (id + 1) % AndroidCameraConfiguration.retrieveCameras().length;
|
||||||
|
LinphoneManager.getLc().setVideoDevice(id);
|
||||||
|
CallManager.getInstance().updateCall();
|
||||||
|
// previous call will cause graph reconstruction -> regive preview window
|
||||||
|
LinphoneManager.getLc().setPreviewWindow(mVideoCaptureView);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Log.e("Unknown menu item [",item,"]");
|
Log.e("Unknown menu item [",item,"]");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
|
androidVideoWindowImpl.release();
|
||||||
launched = false;
|
launched = false;
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
@ -203,16 +192,4 @@ public class VideoCallActivity extends SoftVolumeActivity implements OnCapturing
|
||||||
if (mWakeLock.isHeld()) mWakeLock.release();
|
if (mWakeLock.isHeld()) mWakeLock.release();
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void captureStarted() {
|
|
||||||
handler.post(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
resizeCapturePreview(mVideoCaptureView);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void captureStopped() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,162 +0,0 @@
|
||||||
package org.linphone.core;
|
|
||||||
|
|
||||||
import javax.microedition.khronos.egl.EGLConfig;
|
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
|
||||||
|
|
||||||
import org.linphone.OpenGLESDisplay;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Bitmap.Config;
|
|
||||||
import android.opengl.GLSurfaceView;
|
|
||||||
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 boolean useGLrendering;
|
|
||||||
private Bitmap mBitmap;
|
|
||||||
private SurfaceView mView;
|
|
||||||
private Surface mSurface;
|
|
||||||
private VideoWindowListener mListener;
|
|
||||||
private Renderer renderer;
|
|
||||||
public static interface VideoWindowListener{
|
|
||||||
void onSurfaceReady(AndroidVideoWindowImpl vw);
|
|
||||||
void onSurfaceDestroyed(AndroidVideoWindowImpl vw);
|
|
||||||
};
|
|
||||||
public AndroidVideoWindowImpl(SurfaceView view){
|
|
||||||
useGLrendering = (view instanceof GLSurfaceView);
|
|
||||||
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("Surface is being changed.");
|
|
||||||
if (!useGLrendering) {
|
|
||||||
synchronized(AndroidVideoWindowImpl.this){
|
|
||||||
mBitmap=Bitmap.createBitmap(width,height,Config.RGB_565);
|
|
||||||
mSurface=holder.getSurface();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mListener!=null) mListener.onSurfaceReady(AndroidVideoWindowImpl.this);
|
|
||||||
Log.w("Video display surface changed");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
|
||||||
Log.w("Video display surface created");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
|
||||||
if (!useGLrendering) {
|
|
||||||
synchronized(AndroidVideoWindowImpl.this){
|
|
||||||
mSurface=null;
|
|
||||||
mBitmap=null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mListener!=null)
|
|
||||||
mListener.onSurfaceDestroyed(AndroidVideoWindowImpl.this);
|
|
||||||
Log.d("Video display surface destroyed");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (useGLrendering) {
|
|
||||||
renderer = new Renderer();
|
|
||||||
((GLSurfaceView)mView).setRenderer(renderer);
|
|
||||||
((GLSurfaceView)mView).setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static final int LANDSCAPE=0;
|
|
||||||
static final int PORTRAIT=1;
|
|
||||||
public void requestOrientation(int orientation){
|
|
||||||
//Surface.setOrientation(0, orientation==LANDSCAPE ? 1 : 0);
|
|
||||||
//Log.d("Orientation changed.");
|
|
||||||
}
|
|
||||||
public void setListener(VideoWindowListener l){
|
|
||||||
mListener=l;
|
|
||||||
}
|
|
||||||
public Surface getSurface(){
|
|
||||||
if (useGLrendering)
|
|
||||||
Log.e("View class does not match Video display filter used (you must use a non-GL View)");
|
|
||||||
return mView.getHolder().getSurface();
|
|
||||||
}
|
|
||||||
public Bitmap getBitmap(){
|
|
||||||
if (useGLrendering)
|
|
||||||
Log.e("View class does not match Video display filter used (you must use a non-GL View)");
|
|
||||||
return mBitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOpenGLESDisplay(int ptr) {
|
|
||||||
if (!useGLrendering)
|
|
||||||
Log.e("View class does not match Video display filter used (you must use a GL View)");
|
|
||||||
renderer.setOpenGLESDisplay(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestRender() {
|
|
||||||
((GLSurfaceView)mView).requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
//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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Renderer implements GLSurfaceView.Renderer {
|
|
||||||
int ptr;
|
|
||||||
boolean initPending;
|
|
||||||
int width=-1, height=-1;
|
|
||||||
|
|
||||||
public Renderer() {
|
|
||||||
ptr = 0;
|
|
||||||
initPending = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOpenGLESDisplay(int ptr) {
|
|
||||||
this.ptr = ptr;
|
|
||||||
// if dimension are set, we are recreating MS2 graph without
|
|
||||||
// recreating the surface => need to force init
|
|
||||||
if (width > 0 && height > 0) {
|
|
||||||
initPending = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDrawFrame(GL10 gl) {
|
|
||||||
if (ptr == 0)
|
|
||||||
return;
|
|
||||||
if (initPending) {
|
|
||||||
OpenGLESDisplay.init(ptr, width, height);
|
|
||||||
initPending = false;
|
|
||||||
}
|
|
||||||
OpenGLESDisplay.render(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
|
||||||
/* delay init until ptr is set */
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
initPending = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,146 +0,0 @@
|
||||||
/*
|
|
||||||
Hacks.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.media.AudioManager;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
public final class Hacks {
|
|
||||||
|
|
||||||
private Hacks() {}
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean isGalaxySOrTabWithFrontCamera() {
|
|
||||||
return isGalaxySOrTab() && !isGalaxySOrTabWithoutFrontCamera();
|
|
||||||
}
|
|
||||||
private static boolean isGalaxySOrTabWithoutFrontCamera() {
|
|
||||||
return isSC02B() || isSGHI896();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean isGalaxySOrTab() {
|
|
||||||
return isGalaxyS() || isGalaxyTab();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isGalaxyTab() {
|
|
||||||
return isGTP1000();
|
|
||||||
}
|
|
||||||
private static boolean isGalaxyS() {
|
|
||||||
return isGT9000() || isSC02B() || isSGHI896() || isSPHD700();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final boolean hasTwoCamerasRear0Front1() {
|
|
||||||
return isSPHD700() || isADR6400();
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTC
|
|
||||||
private static final boolean isADR6400() {
|
|
||||||
return Build.MODEL.startsWith("ADR6400") || Build.DEVICE.startsWith("ADR6400");
|
|
||||||
} // HTC Thunderbolt
|
|
||||||
|
|
||||||
// Galaxy S variants
|
|
||||||
private static final boolean isSPHD700() {return Build.DEVICE.startsWith("SPH-D700");} // Epic
|
|
||||||
private static boolean isSGHI896() {return Build.DEVICE.startsWith("SGH-I896");} // Captivate
|
|
||||||
private static boolean isGT9000() {return Build.DEVICE.startsWith("GT-I9000");} // Galaxy S
|
|
||||||
private static boolean isSC02B() {return Build.DEVICE.startsWith("SC-02B");} // Docomo
|
|
||||||
private static boolean isGTP1000() {return Build.DEVICE.startsWith("GT-P1000");} // Tab
|
|
||||||
|
|
||||||
|
|
||||||
/* private static final boolean log(final String msg) {
|
|
||||||
Log.d(msg);
|
|
||||||
return true;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/* Not working as now
|
|
||||||
* Calling from Galaxy S to PC is "usable" even with no hack; other side is not even with this one*/
|
|
||||||
public static void galaxySSwitchToCallStreamUnMuteLowerVolume(AudioManager am) {
|
|
||||||
// Switch to call audio channel (Galaxy S)
|
|
||||||
am.setSpeakerphoneOn(false);
|
|
||||||
sleep(200);
|
|
||||||
|
|
||||||
// Lower volume
|
|
||||||
am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, 1, 0);
|
|
||||||
|
|
||||||
// Another way to select call channel
|
|
||||||
am.setMode(AudioManager.MODE_NORMAL);
|
|
||||||
sleep(200);
|
|
||||||
|
|
||||||
// Mic is muted if not doing this
|
|
||||||
am.setMicrophoneMute(true);
|
|
||||||
sleep(200);
|
|
||||||
am.setMicrophoneMute(false);
|
|
||||||
sleep(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final void sleep(int time) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(time);
|
|
||||||
} catch(InterruptedException ie){}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void dumpDeviceInformation() {
|
|
||||||
StringBuilder sb = new StringBuilder(" ==== Phone information dump ====\n");
|
|
||||||
sb.append("DEVICE=").append(Build.DEVICE).append("\n");
|
|
||||||
sb.append("MODEL=").append(Build.MODEL).append("\n");
|
|
||||||
//MANUFACTURER doesn't exist in android 1.5.
|
|
||||||
//sb.append("MANUFACTURER=").append(Build.MANUFACTURER).append("\n");
|
|
||||||
sb.append("SDK=").append(Build.VERSION.SDK);
|
|
||||||
|
|
||||||
Log.i(sb.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean needSoftvolume() {
|
|
||||||
return isGalaxySOrTab();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean needRoutingAPI() {
|
|
||||||
return Version.sdkStrictlyBelow(5) /*<donut*/;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean needGalaxySAudioHack() {
|
|
||||||
return isGalaxySOrTab() && !isSC02B();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean needPausingCallForSpeakers() {
|
|
||||||
// return false;
|
|
||||||
return isGalaxySOrTab() && !isSC02B();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasTwoCameras() {
|
|
||||||
return isSPHD700() || isGalaxySOrTabWithFrontCamera();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasCamera() {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
int nb = 0;
|
|
||||||
try {
|
|
||||||
nb = (Integer) Camera.class.getMethod("getNumberOfCameras", (Class[])null).invoke(null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("Error getting number of cameras");
|
|
||||||
}
|
|
||||||
return nb > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i("Hack: considering there IS a camera.\n"
|
|
||||||
+ "If it is not the case, report DEVICE and MODEL to linphone-users@nongnu.org");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -20,7 +20,7 @@ package org.linphone.core;
|
||||||
|
|
||||||
|
|
||||||
class LinphoneCallImpl implements LinphoneCall {
|
class LinphoneCallImpl implements LinphoneCall {
|
||||||
|
|
||||||
protected final long nativePtr;
|
protected final long nativePtr;
|
||||||
boolean ownPtr = false;
|
boolean ownPtr = false;
|
||||||
native private void ref(long ownPtr);
|
native private void ref(long ownPtr);
|
||||||
|
@ -31,6 +31,7 @@ class LinphoneCallImpl implements LinphoneCall {
|
||||||
native private int getState(long nativePtr);
|
native private int getState(long nativePtr);
|
||||||
private native long getCurrentParamsCopy(long nativePtr);
|
private native long getCurrentParamsCopy(long nativePtr);
|
||||||
private native void enableCamera(long nativePtr, boolean enabled);
|
private native void enableCamera(long nativePtr, boolean enabled);
|
||||||
|
private native boolean cameraEnabled(long nativePtr);
|
||||||
private native void enableEchoCancellation(long nativePtr,boolean enable);
|
private native void enableEchoCancellation(long nativePtr,boolean enable);
|
||||||
private native boolean isEchoCancellationEnabled(long nativePtr) ;
|
private native boolean isEchoCancellationEnabled(long nativePtr) ;
|
||||||
private native void enableEchoLimiter(long nativePtr,boolean enable);
|
private native void enableEchoLimiter(long nativePtr,boolean enable);
|
||||||
|
@ -48,7 +49,7 @@ class LinphoneCallImpl implements LinphoneCall {
|
||||||
ref(nativePtr);
|
ref(nativePtr);
|
||||||
}
|
}
|
||||||
protected void finalize() throws Throwable {
|
protected void finalize() throws Throwable {
|
||||||
unref(nativePtr);
|
unref(nativePtr);
|
||||||
}
|
}
|
||||||
public LinphoneCallLog getCallLog() {
|
public LinphoneCallLog getCallLog() {
|
||||||
long lNativePtr = getCallLog(nativePtr);
|
long lNativePtr = getCallLog(nativePtr);
|
||||||
|
@ -79,6 +80,10 @@ class LinphoneCallImpl implements LinphoneCall {
|
||||||
public void enableCamera(boolean enabled) {
|
public void enableCamera(boolean enabled) {
|
||||||
enableCamera(nativePtr, enabled);
|
enableCamera(nativePtr, enabled);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public boolean cameraEnabled() {
|
||||||
|
return cameraEnabled(nativePtr);
|
||||||
|
}
|
||||||
public boolean equals(Object call) {
|
public boolean equals(Object call) {
|
||||||
return nativePtr == ((LinphoneCallImpl)call).nativePtr;
|
return nativePtr == ((LinphoneCallImpl)call).nativePtr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,8 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
import android.view.SurfaceView;
|
import org.linphone.LinphoneManager;
|
||||||
|
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
|
||||||
|
|
||||||
|
|
||||||
class LinphoneCoreImpl implements LinphoneCore {
|
class LinphoneCoreImpl implements LinphoneCore {
|
||||||
|
@ -68,8 +69,7 @@ class LinphoneCoreImpl implements LinphoneCore {
|
||||||
private native void stopDtmf(long nativePtr);
|
private native void stopDtmf(long nativePtr);
|
||||||
private native void setVideoWindowId(long nativePtr, Object wid);
|
private native void setVideoWindowId(long nativePtr, Object wid);
|
||||||
private native void setPreviewWindowId(long nativePtr, Object wid);
|
private native void setPreviewWindowId(long nativePtr, Object wid);
|
||||||
private AndroidVideoWindowImpl mVideoWindow;
|
private native void setDeviceRotation(long nativePtr, int rotation);
|
||||||
private AndroidVideoWindowImpl mPreviewWindow;
|
|
||||||
private native void addFriend(long nativePtr,long friend);
|
private native void addFriend(long nativePtr,long friend);
|
||||||
private native void setPresenceInfo(long nativePtr,int minute_away, String alternative_contact,int status);
|
private native void setPresenceInfo(long nativePtr,int minute_away, String alternative_contact,int status);
|
||||||
private native long createChatRoom(long nativePtr,String to);
|
private native long createChatRoom(long nativePtr,String to);
|
||||||
|
@ -104,6 +104,8 @@ class LinphoneCoreImpl implements LinphoneCore {
|
||||||
private native void setDownloadPtime(long nativePtr, int ptime);
|
private native void setDownloadPtime(long nativePtr, int ptime);
|
||||||
private native void setZrtpSecretsCache(long nativePtr, String file);
|
private native void setZrtpSecretsCache(long nativePtr, String file);
|
||||||
private native void enableEchoLimiter(long nativePtr2, boolean val);
|
private native void enableEchoLimiter(long nativePtr2, boolean val);
|
||||||
|
private native int setVideoDevice(long nativePtr2, int id);
|
||||||
|
private native int getVideoDevice(long nativePtr2);
|
||||||
|
|
||||||
LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException {
|
LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException {
|
||||||
mListener=listener;
|
mListener=listener;
|
||||||
|
@ -327,33 +329,15 @@ class LinphoneCoreImpl implements LinphoneCore {
|
||||||
return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to));
|
return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to));
|
||||||
}
|
}
|
||||||
public synchronized void setPreviewWindow(Object w) {
|
public synchronized void setPreviewWindow(Object w) {
|
||||||
if (mPreviewWindow!=null)
|
setPreviewWindowId(nativePtr,w);
|
||||||
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 synchronized void setVideoWindow(Object w) {
|
public synchronized void setVideoWindow(Object w) {
|
||||||
if (mVideoWindow!=null)
|
setVideoWindowId(nativePtr, w);
|
||||||
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 synchronized void setDeviceRotation(int rotation) {
|
||||||
|
setDeviceRotation(nativePtr, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void enableVideo(boolean vcap_enabled, boolean display_enabled) {
|
public synchronized void enableVideo(boolean vcap_enabled, boolean display_enabled) {
|
||||||
enableVideo(nativePtr,vcap_enabled, display_enabled);
|
enableVideo(nativePtr,vcap_enabled, display_enabled);
|
||||||
}
|
}
|
||||||
|
@ -507,5 +491,16 @@ class LinphoneCoreImpl implements LinphoneCore {
|
||||||
public void enableEchoLimiter(boolean val) {
|
public void enableEchoLimiter(boolean val) {
|
||||||
enableEchoLimiter(nativePtr,val);
|
enableEchoLimiter(nativePtr,val);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void setVideoDevice(int id) {
|
||||||
|
Log.i("Setting camera id :", id);
|
||||||
|
if (setVideoDevice(nativePtr, id) != 0) {
|
||||||
|
Log.e("Failed to set video device to id:", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getVideoDevice() {
|
||||||
|
return getVideoDevice(nativePtr);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
package org.linphone.core;
|
package org.linphone.core;
|
||||||
|
|
||||||
|
import org.linphone.mediastream.video.capture.hwconf.Hacks;
|
||||||
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
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.Log;
|
|
||||||
import org.linphone.core.video.AndroidCameraRecord;
|
|
||||||
|
|
||||||
import android.hardware.Camera;
|
|
||||||
import android.hardware.Camera.PreviewCallback;
|
|
||||||
import android.hardware.Camera.Size;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an helper class, not a test activity.
|
|
||||||
*
|
|
||||||
* @author Guillaume Beraudo
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
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("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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,194 +0,0 @@
|
||||||
/*
|
|
||||||
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 static org.linphone.core.VideoSize.CIF;
|
|
||||||
import static org.linphone.core.VideoSize.HVGA;
|
|
||||||
import static org.linphone.core.VideoSize.QCIF;
|
|
||||||
import static org.linphone.core.VideoSize.QVGA;
|
|
||||||
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
import org.linphone.R;
|
|
||||||
import org.linphone.core.Log;
|
|
||||||
import org.linphone.core.VideoSize;
|
|
||||||
import org.linphone.core.video.AndroidCameraRecord;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 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.width, size.height);
|
|
||||||
|
|
||||||
// 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("Video capture surface destroyed");
|
|
||||||
if (recorder != null) recorder.stopPreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
|
||||||
Log.d("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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
AndroidCameraConf.java
|
|
||||||
Copyright (C) 2011 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.video;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.core.VideoSize;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Guillaume Beraudo
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
interface AndroidCameraConf {
|
|
||||||
|
|
||||||
AndroidCameras getFoundCameras();
|
|
||||||
|
|
||||||
int getNumberOfCameras();
|
|
||||||
|
|
||||||
int getCameraOrientation(int cameraId);
|
|
||||||
|
|
||||||
boolean isFrontCamera(int cameraId);
|
|
||||||
|
|
||||||
List<VideoSize> getSupportedPreviewSizes(int cameraId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default: no front; rear=0; default=rear
|
|
||||||
* @author Guillaume Beraudo
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class AndroidCameras {
|
|
||||||
Integer front;
|
|
||||||
Integer rear = 0;
|
|
||||||
Integer defaultC = rear;
|
|
||||||
|
|
||||||
boolean hasFrontCamera() { return front != null; }
|
|
||||||
boolean hasRearCamera() { return rear != null; }
|
|
||||||
boolean hasSeveralCameras() { return front != rear && front != null; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("Cameras :");
|
|
||||||
if (rear != null) sb.append(" rear=").append(rear);
|
|
||||||
if (front != null) sb.append(" front=").append(front);
|
|
||||||
if (defaultC != null) sb.append(" default=").append(defaultC);
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
/*
|
|
||||||
AndroidCameraConf.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.video;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.core.Hacks;
|
|
||||||
import org.linphone.core.Log;
|
|
||||||
import org.linphone.core.VideoSize;
|
|
||||||
|
|
||||||
import android.hardware.Camera;
|
|
||||||
|
|
||||||
|
|
||||||
class AndroidCameraConf5 implements AndroidCameraConf {
|
|
||||||
private AndroidCameras foundCameras;
|
|
||||||
public AndroidCameras getFoundCameras() {return foundCameras;}
|
|
||||||
|
|
||||||
public AndroidCameraConf5() {
|
|
||||||
// Defaults
|
|
||||||
foundCameras = new AndroidCameras();
|
|
||||||
|
|
||||||
if (Hacks.isGalaxySOrTab()) {
|
|
||||||
Log.d("Hack Galaxy S : has one or more cameras");
|
|
||||||
if (Hacks.isGalaxySOrTabWithFrontCamera()) {
|
|
||||||
Log.d("Hack Galaxy S : HAS a front camera with id=2");
|
|
||||||
foundCameras.front = 2;
|
|
||||||
} else {
|
|
||||||
Log.d("Hack Galaxy S : NO front camera");
|
|
||||||
}
|
|
||||||
Log.d("Hack Galaxy S : HAS a rear camera with id=1");
|
|
||||||
foundCameras.rear = 1;
|
|
||||||
foundCameras.defaultC = foundCameras.rear;
|
|
||||||
} else if (Hacks.hasTwoCamerasRear0Front1()) {
|
|
||||||
Log.d("Hack SPHD700 has 2 cameras a rear with id=0 and a front with id=1");
|
|
||||||
foundCameras.front = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumberOfCameras() {
|
|
||||||
Log.i("Detecting the number of cameras");
|
|
||||||
if (Hacks.hasTwoCamerasRear0Front1() || Hacks.isGalaxySOrTabWithFrontCamera()) {
|
|
||||||
Log.d("Hack: we know this model has 2 cameras");
|
|
||||||
return 2;
|
|
||||||
} else
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public int getCameraOrientation(int cameraId) {
|
|
||||||
// Use hacks to guess orientation of the camera
|
|
||||||
if (Hacks.isGalaxySOrTab() && isFrontCamera(cameraId)) {
|
|
||||||
Log.d("Hack Galaxy S : front camera mounted landscape");
|
|
||||||
// mounted in landscape for a portrait phone orientation
|
|
||||||
// |^^^^^^^^|
|
|
||||||
// | ____ |
|
|
||||||
// | |____| |
|
|
||||||
// | |
|
|
||||||
// | |
|
|
||||||
// | Phone |
|
|
||||||
// |________|
|
|
||||||
return 180;
|
|
||||||
}
|
|
||||||
return 90;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isFrontCamera(int cameraId) {
|
|
||||||
// Use hacks to guess facing of the camera
|
|
||||||
if (cameraId == 2 && Hacks.isGalaxySOrTab()) {
|
|
||||||
Log.d("Hack Galaxy S : front camera has id=2");
|
|
||||||
return true;
|
|
||||||
} else if (cameraId == 1 && Hacks.hasTwoCamerasRear0Front1()) {
|
|
||||||
Log.d("Hack SPHD700 : front camera has id=1");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<VideoSize> getSupportedPreviewSizes(int cameraId) {
|
|
||||||
if (getNumberOfCameras() >1) {
|
|
||||||
Log.w("Hack: on older devices, using video formats supported by default camera");
|
|
||||||
}
|
|
||||||
Log.i("Opening camera to retrieve supported video sizes");
|
|
||||||
Camera c = Camera.open();
|
|
||||||
List<VideoSize> sizes=VideoUtil.createList(c.getParameters().getSupportedPreviewSizes());
|
|
||||||
c.release();
|
|
||||||
Log.i("Camera opened to retrieve supported video sizes released");
|
|
||||||
return sizes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
AndroidCameraConf9.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.video;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.linphone.core.Log;
|
|
||||||
import org.linphone.core.VideoSize;
|
|
||||||
|
|
||||||
import android.hardware.Camera;
|
|
||||||
|
|
||||||
class AndroidCameraConf9 implements AndroidCameraConf {
|
|
||||||
private AndroidCameras foundCameras;
|
|
||||||
private Map<Integer,List<VideoSize>> supportedSizes = new HashMap<Integer, List<VideoSize>>();
|
|
||||||
public AndroidCameras getFoundCameras() {return foundCameras;}
|
|
||||||
|
|
||||||
public AndroidCameraConf9() {
|
|
||||||
foundCameras = new AndroidCameras();
|
|
||||||
|
|
||||||
for (int id=0; id < getNumberOfCameras(); id++) {
|
|
||||||
if (foundCameras.defaultC == null)
|
|
||||||
foundCameras.defaultC = id;
|
|
||||||
|
|
||||||
if (isFrontCamera(id)) {
|
|
||||||
foundCameras.front = id;
|
|
||||||
} else {
|
|
||||||
foundCameras.rear = id;
|
|
||||||
}
|
|
||||||
supportedSizes.put(id, findSupportedVideoSizes(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<VideoSize> findSupportedVideoSizes(int id) {
|
|
||||||
Log.i("Opening camera ",id," to retrieve supported video sizes");
|
|
||||||
Camera c = Camera.open(id);
|
|
||||||
List<VideoSize> sizes=VideoUtil.createList(c.getParameters().getSupportedPreviewSizes());
|
|
||||||
c.release();
|
|
||||||
Log.i("Camera ",id," opened to retrieve supported video sizes released");
|
|
||||||
return sizes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumberOfCameras() {
|
|
||||||
return Camera.getNumberOfCameras();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCameraOrientation(int cameraId) {
|
|
||||||
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
|
|
||||||
Camera.getCameraInfo(cameraId, info);
|
|
||||||
Log.d("Camera info for ",cameraId,": orientation=",info.orientation);
|
|
||||||
return info.orientation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFrontCamera(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<VideoSize> getSupportedPreviewSizes(int cameraId) {
|
|
||||||
return supportedSizes.get(cameraId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,279 +0,0 @@
|
||||||
/*
|
|
||||||
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.video;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.core.Log;
|
|
||||||
import org.linphone.core.Version;
|
|
||||||
import org.linphone.core.VideoSize;
|
|
||||||
|
|
||||||
import android.hardware.Camera;
|
|
||||||
import android.hardware.Camera.AutoFocusCallback;
|
|
||||||
import android.hardware.Camera.ErrorCallback;
|
|
||||||
import android.hardware.Camera.Parameters;
|
|
||||||
import android.hardware.Camera.PreviewCallback;
|
|
||||||
import android.hardware.Camera.Size;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
import android.view.SurfaceView;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class AndroidCameraRecord implements AutoFocusCallback {
|
|
||||||
|
|
||||||
protected Camera camera;
|
|
||||||
private RecorderParams params;
|
|
||||||
|
|
||||||
private PreviewCallback storedPreviewCallback;
|
|
||||||
private boolean previewStarted;
|
|
||||||
private List <VideoSize> supportedVideoSizes;
|
|
||||||
private Size currentPreviewSize;
|
|
||||||
|
|
||||||
public AndroidCameraRecord(RecorderParams parameters) {
|
|
||||||
this.params = parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<Size> getSupportedPreviewSizes(Camera.Parameters parameters) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] findClosestEnclosingFpsRange(int expectedFps, List<int[]> fpsRanges) {
|
|
||||||
Log.d("Searching for closest fps range from ",expectedFps);
|
|
||||||
int measure = Integer.MAX_VALUE;
|
|
||||||
int[] closestRange = fpsRanges.get(0);
|
|
||||||
for (int[] curRange : fpsRanges) {
|
|
||||||
if (curRange[0] > expectedFps || curRange[1] < expectedFps) continue;
|
|
||||||
int curMeasure = Math.abs(curRange[0] - expectedFps)
|
|
||||||
+ Math.abs(curRange[1] - expectedFps);
|
|
||||||
if (curMeasure < measure) {
|
|
||||||
closestRange=curRange;
|
|
||||||
Log.d("a better range has been found: w=",closestRange[0],",h=",closestRange[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.d("The closest fps range is w=",closestRange[0],",h=",closestRange[1]);
|
|
||||||
return closestRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void startPreview() { // FIXME throws exception?
|
|
||||||
if (previewStarted) {
|
|
||||||
Log.w("Already started");
|
|
||||||
throw new RuntimeException("Video recorder already started");
|
|
||||||
// return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.surfaceView.getVisibility() != SurfaceView.VISIBLE) {
|
|
||||||
// Illegal state
|
|
||||||
Log.e("Illegal state: video capture surface view is not visible");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Log.d("Trying to open camera with id ", params.cameraId);
|
|
||||||
if (camera != null) {
|
|
||||||
Log.e("Camera is not null, ?already open? : aborting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
camera = openCamera(params.cameraId);
|
|
||||||
camera.setErrorCallback(new ErrorCallback() {
|
|
||||||
public void onError(int error, Camera camera) {
|
|
||||||
Log.e("Camera error : ", error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Camera.Parameters parameters=camera.getParameters();
|
|
||||||
if (Version.sdkStrictlyBelow(Version.API09_GINGERBREAD_23)) {
|
|
||||||
parameters.set("camera-id",params.cameraId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportedVideoSizes == null) {
|
|
||||||
supportedVideoSizes = VideoUtil.createList(getSupportedPreviewSizes(parameters));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (params.width >= params.height) {
|
|
||||||
parameters.setPreviewSize(params.width, params.height);
|
|
||||||
} else {
|
|
||||||
// invert height and width
|
|
||||||
parameters.setPreviewSize(params.height, params.width);
|
|
||||||
}
|
|
||||||
// should setParameters and get again to have the real one??
|
|
||||||
currentPreviewSize = parameters.getPreviewSize();
|
|
||||||
|
|
||||||
// Frame rate
|
|
||||||
if (Version.sdkStrictlyBelow(Version.API09_GINGERBREAD_23)) {
|
|
||||||
// Select the supported fps just faster than the target rate
|
|
||||||
List<Integer> supportedFrameRates=parameters.getSupportedPreviewFrameRates();
|
|
||||||
if (supportedFrameRates != null && supportedFrameRates.size() > 0) {
|
|
||||||
Collections.sort(supportedFrameRates);
|
|
||||||
int selectedRate = -1;
|
|
||||||
for (Integer rate : supportedFrameRates) {
|
|
||||||
selectedRate=rate;
|
|
||||||
if (rate >= params.fps) break;
|
|
||||||
}
|
|
||||||
parameters.setPreviewFrameRate(selectedRate);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
List<int[]> supportedRanges = parameters.getSupportedPreviewFpsRange();
|
|
||||||
int[] range=findClosestEnclosingFpsRange((int)(1000*params.fps), supportedRanges);
|
|
||||||
parameters.setPreviewFpsRange(range[0], range[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onSettingCameraParameters(parameters);
|
|
||||||
camera.setParameters(parameters);
|
|
||||||
|
|
||||||
SurfaceHolder holder = params.surfaceView.getHolder();
|
|
||||||
try {
|
|
||||||
camera.setPreviewDisplay(holder);
|
|
||||||
}
|
|
||||||
catch (Throwable t) {
|
|
||||||
Log.e(t,"Exception in Video capture setPreviewDisplay()");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
camera.startPreview();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Log.e("Error, can't start camera preview. Releasing camera!");
|
|
||||||
camera.release();
|
|
||||||
camera = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
previewStarted = true;
|
|
||||||
|
|
||||||
// Activate autofocus
|
|
||||||
if (Camera.Parameters.FOCUS_MODE_AUTO.equals(parameters.getFocusMode())) {
|
|
||||||
OnClickListener svClickListener = new OnClickListener() {
|
|
||||||
public void onClick(View v) {
|
|
||||||
Log.i("Auto focus requested");
|
|
||||||
camera.autoFocus(AndroidCameraRecord.this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
params.surfaceView.setOnClickListener(svClickListener);
|
|
||||||
// svClickListener.onClick(null);
|
|
||||||
} else {
|
|
||||||
params.surfaceView.setOnClickListener(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register callback to get capture buffer
|
|
||||||
lowLevelSetPreviewCallback(camera, storedPreviewCallback);
|
|
||||||
|
|
||||||
|
|
||||||
onPreviewStarted(camera);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected Camera openCamera(int cameraId) {
|
|
||||||
return Camera.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
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("Capture camera not ready, storing preview callback");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lowLevelSetPreviewCallback(camera, cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void stopPreview() {
|
|
||||||
if (!previewStarted) return;
|
|
||||||
lowLevelSetPreviewCallback(camera, null);
|
|
||||||
camera.stopPreview();
|
|
||||||
camera.release();
|
|
||||||
camera=null;
|
|
||||||
Log.d("Camera released");
|
|
||||||
currentPreviewSize = null;
|
|
||||||
previewStarted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void stopCaptureCallback() {
|
|
||||||
if (camera != null) {
|
|
||||||
lowLevelSetPreviewCallback(camera, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static class RecorderParams {
|
|
||||||
public static enum MirrorType {NO, HORIZONTAL, CENTRAL, VERTICAL};
|
|
||||||
|
|
||||||
public float fps;
|
|
||||||
public int height;
|
|
||||||
public int width;
|
|
||||||
|
|
||||||
final long filterDataNativePtr;
|
|
||||||
public int cameraId;
|
|
||||||
public boolean isFrontCamera;
|
|
||||||
public int rotation;
|
|
||||||
public SurfaceView surfaceView;
|
|
||||||
|
|
||||||
public MirrorType mirror = MirrorType.NO;
|
|
||||||
public int phoneOrientation;
|
|
||||||
|
|
||||||
public RecorderParams(long ptr) {
|
|
||||||
filterDataNativePtr = ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isStarted() {
|
|
||||||
return previewStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<VideoSize> getSupportedVideoSizes() {
|
|
||||||
return supportedVideoSizes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected int getExpectedBufferLength() {
|
|
||||||
if (currentPreviewSize == null) return -1;
|
|
||||||
|
|
||||||
return currentPreviewSize.width * currentPreviewSize.height * 3 /2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onAutoFocus(boolean success, Camera camera) {
|
|
||||||
if (success) Log.i("Autofocus success");
|
|
||||||
else Log.i("Autofocus failure");
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStoredPhoneOrientation() {
|
|
||||||
return params.phoneOrientation;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
/*
|
|
||||||
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.video;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.core.Log;
|
|
||||||
import org.linphone.core.video.AndroidCameraRecord.RecorderParams.MirrorType;
|
|
||||||
|
|
||||||
import android.hardware.Camera;
|
|
||||||
import android.hardware.Camera.Parameters;
|
|
||||||
import android.hardware.Camera.PreviewCallback;
|
|
||||||
import android.hardware.Camera.Size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Record from Android camera.
|
|
||||||
* Android >= 5 (2.0) version.
|
|
||||||
*
|
|
||||||
* @author Guillaume Beraudo
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class AndroidCameraRecord5 extends AndroidCameraRecord implements PreviewCallback {
|
|
||||||
|
|
||||||
private long filterCtxPtr;
|
|
||||||
private double timeElapsedBetweenFrames = 0;
|
|
||||||
private long lastFrameTime = 0;
|
|
||||||
private final double expectedTimeBetweenFrames;
|
|
||||||
protected final int rotation;
|
|
||||||
private MirrorType mirror;
|
|
||||||
// private boolean isUsingFrontCamera;
|
|
||||||
|
|
||||||
public AndroidCameraRecord5(RecorderParams parameters) {
|
|
||||||
super(parameters);
|
|
||||||
expectedTimeBetweenFrames = 1d / Math.round(parameters.fps);
|
|
||||||
filterCtxPtr = parameters.filterDataNativePtr;
|
|
||||||
rotation = parameters.rotation;
|
|
||||||
mirror = parameters.mirror;
|
|
||||||
// isUsingFrontCamera = parameters.isFrontCamera;
|
|
||||||
|
|
||||||
storePreviewCallBack(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private native void putImage(long filterCtxPtr, byte[] buffer, int rotate, int mirror);
|
|
||||||
|
|
||||||
|
|
||||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
|
||||||
if (data == null) {
|
|
||||||
Log.e("onPreviewFrame Called with null buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (filterCtxPtr == 0l) {
|
|
||||||
Log.e("onPreviewFrame Called with no filterCtxPtr set");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int expectedBuffLength = getExpectedBufferLength();
|
|
||||||
if (expectedBuffLength != data.length) {
|
|
||||||
Log.e("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, rotation, mirror.ordinal());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double currentTimeElapsed = 0.8 * (curTime - lastFrameTime) / 1000 + 0.2 * timeElapsedBetweenFrames;
|
|
||||||
if (currentTimeElapsed < expectedTimeBetweenFrames) {
|
|
||||||
// Log.d("Clipping frame ", Math.round(1 / currentTimeElapsed), " > ", fps);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastFrameTime = curTime;
|
|
||||||
timeElapsedBetweenFrames = currentTimeElapsed;
|
|
||||||
|
|
||||||
// Log.d("onPreviewFrame: ", Integer.toString(data.length));
|
|
||||||
putImage(filterCtxPtr, data, rotation, mirror.ordinal());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String selectFocusMode(final List<String> supportedFocusModes) {/*
|
|
||||||
if (isUsingFrontCamera && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
|
|
||||||
return Camera.Parameters.FOCUS_MODE_FIXED;
|
|
||||||
}
|
|
||||||
if (!isUsingFrontCamera && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
|
|
||||||
return Camera.Parameters.FOCUS_MODE_INFINITY;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
|
|
||||||
return Camera.Parameters.FOCUS_MODE_AUTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null; // Should not occur?
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSettingCameraParameters(Parameters parameters) {
|
|
||||||
super.onSettingCameraParameters(parameters);
|
|
||||||
List<String> supportedFocusModes = parameters.getSupportedFocusModes();
|
|
||||||
String focusMode = selectFocusMode(supportedFocusModes);
|
|
||||||
if (focusMode != null) {
|
|
||||||
Log.w("Selected focus mode: ", focusMode);
|
|
||||||
parameters.setFocusMode(focusMode);
|
|
||||||
} else {
|
|
||||||
Log.i("No suitable focus mode found in : ", Arrays.toString(supportedFocusModes.toArray()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<Size> getSupportedPreviewSizes(Parameters parameters) {
|
|
||||||
return parameters.getSupportedPreviewSizes();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
|
|
||||||
camera.setPreviewCallback(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
/*
|
|
||||||
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.video;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.core.Log;
|
|
||||||
|
|
||||||
import android.hardware.Camera;
|
|
||||||
import android.hardware.Camera.Parameters;
|
|
||||||
import android.hardware.Camera.PreviewCallback;
|
|
||||||
import android.hardware.Camera.Size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Android >= 8 (2.2) version.
|
|
||||||
* @author Guillaume Beraudo
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class AndroidCameraRecord8 extends AndroidCameraRecord5 {
|
|
||||||
|
|
||||||
|
|
||||||
public AndroidCameraRecord8(RecorderParams parameters) {
|
|
||||||
super(parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
|
|
||||||
if (cb != null) {
|
|
||||||
Log.d("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(rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String selectFocusMode(final List<String> supportedFocusModes) {
|
|
||||||
if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_EDOF)) {
|
|
||||||
return Camera.Parameters.FOCUS_MODE_EDOF;
|
|
||||||
} else
|
|
||||||
return super.selectFocusMode(supportedFocusModes);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
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.video;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import android.hardware.Camera;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Android >= 9 (2.3) version.
|
|
||||||
* @author Guillaume Beraudo
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class AndroidCameraRecord9 extends AndroidCameraRecord8 {
|
|
||||||
|
|
||||||
|
|
||||||
public AndroidCameraRecord9(RecorderParams parameters) {
|
|
||||||
super(parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Camera openCamera(int cameraId) {
|
|
||||||
return Camera.open(cameraId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String selectFocusMode(final List<String> supportedFocusModes) {
|
|
||||||
if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
|
|
||||||
return Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
|
|
||||||
} else
|
|
||||||
return super.selectFocusMode(supportedFocusModes);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,362 +0,0 @@
|
||||||
/*
|
|
||||||
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.video;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.core.LinphoneCore;
|
|
||||||
import org.linphone.core.Log;
|
|
||||||
import org.linphone.core.Version;
|
|
||||||
import org.linphone.core.VideoSize;
|
|
||||||
import org.linphone.core.video.AndroidCameraRecord.RecorderParams;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.OrientationEventListener;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
import android.view.SurfaceView;
|
|
||||||
import android.view.SurfaceHolder.Callback;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manage the video capture, only one for all cameras.
|
|
||||||
*
|
|
||||||
* @author Guillaume Beraudo
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class AndroidCameraRecordManager {
|
|
||||||
private static AndroidCameraRecordManager instance;
|
|
||||||
private OrientationEventListener orientationEventListener;
|
|
||||||
private OnCapturingStateChangedListener capturingStateChangedListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return instance
|
|
||||||
*/
|
|
||||||
public static final synchronized AndroidCameraRecordManager getInstance() {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new AndroidCameraRecordManager();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private AndroidCameraRecord.RecorderParams parameters;
|
|
||||||
private final AndroidCameraConf cc;
|
|
||||||
private SurfaceView surfaceView;
|
|
||||||
private boolean muted;
|
|
||||||
private int cameraId;
|
|
||||||
|
|
||||||
private AndroidCameraRecord recorder;
|
|
||||||
private int mAlwaysChangingPhoneOrientation=0;
|
|
||||||
|
|
||||||
|
|
||||||
// singleton
|
|
||||||
private AndroidCameraRecordManager() {
|
|
||||||
if (!Version.isVideoCapable()) { // imply sdk>=5
|
|
||||||
throw new RuntimeException("AndroidCameraRecordManager: hardware is not video capable");
|
|
||||||
}
|
|
||||||
cc = Version.sdkAboveOrEqual(9) ? new AndroidCameraConf9() : new AndroidCameraConf5();
|
|
||||||
Log.i("=== Detected " + cc.getFoundCameras()+ " ===");
|
|
||||||
cameraId = cc.getFoundCameras().defaultC;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public boolean hasSeveralCameras() {
|
|
||||||
return cc.getFoundCameras().hasSeveralCameras();
|
|
||||||
}
|
|
||||||
public boolean hasFrontCamera() {
|
|
||||||
return cc.getFoundCameras().front != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setUseFrontCamera(boolean value) {
|
|
||||||
if (!hasFrontCamera()) {
|
|
||||||
Log.e("setUseFrontCamera(true) while no front camera detected on device: using rear");
|
|
||||||
value = false;
|
|
||||||
}
|
|
||||||
if (cc.isFrontCamera(cameraId) == value) return; // already OK
|
|
||||||
toggleUseFrontCamera();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUseFrontCamera() {return cc.isFrontCamera(cameraId);}
|
|
||||||
public boolean toggleUseFrontCamera() {
|
|
||||||
boolean previousUseFront = cc.isFrontCamera(cameraId);
|
|
||||||
|
|
||||||
cameraId = previousUseFront ? cc.getFoundCameras().rear : cc.getFoundCameras().front;
|
|
||||||
|
|
||||||
if (parameters != null) {
|
|
||||||
parameters.cameraId = cameraId;
|
|
||||||
parameters.isFrontCamera = !previousUseFront;
|
|
||||||
if (isRecording()) {
|
|
||||||
stopVideoRecording();
|
|
||||||
tryToStartVideoRecording();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !previousUseFront;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setParametersFromFilter(long filterDataPtr, int height, int width, float fps) {
|
|
||||||
if (recorder != null) {
|
|
||||||
Log.w("Recorder should not be running");
|
|
||||||
stopVideoRecording();
|
|
||||||
}
|
|
||||||
RecorderParams p = new RecorderParams(filterDataPtr);
|
|
||||||
p.fps = fps;
|
|
||||||
p.width = width;
|
|
||||||
p.height = height;
|
|
||||||
p.cameraId = cameraId;
|
|
||||||
p.isFrontCamera = isUseFrontCamera();
|
|
||||||
parameters = p;
|
|
||||||
|
|
||||||
// Mirror the sent frames in order to make them readable
|
|
||||||
// (otherwise it is mirrored and thus unreadable)
|
|
||||||
if (p.isFrontCamera) {
|
|
||||||
if (!isCameraMountedPortrait()) {
|
|
||||||
// Code for Nexus S
|
|
||||||
if (isFrameToBeShownPortrait())
|
|
||||||
p.mirror = RecorderParams.MirrorType.CENTRAL;
|
|
||||||
} else {
|
|
||||||
// Code for Galaxy S like: camera mounted landscape when phone hold portrait
|
|
||||||
p.mirror = RecorderParams.MirrorType.HORIZONTAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tryToStartVideoRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public final void setSurfaceView(final SurfaceView sv) {
|
|
||||||
SurfaceHolder holder = sv.getHolder();
|
|
||||||
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
|
||||||
|
|
||||||
holder.addCallback(new Callback() {
|
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
|
||||||
surfaceView = null;
|
|
||||||
Log.d("Video capture surface destroyed");
|
|
||||||
stopVideoRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
|
||||||
surfaceView = sv;
|
|
||||||
Log.d("Video capture surface created");
|
|
||||||
tryToStartVideoRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width,
|
|
||||||
int height) {
|
|
||||||
Log.d("Video capture surface changed");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param muteState
|
|
||||||
* @return true if mute state changed
|
|
||||||
*/
|
|
||||||
public boolean setMuted(boolean muteState) {
|
|
||||||
if (muteState == muted) return false;
|
|
||||||
muted = muteState;
|
|
||||||
if (muted) {
|
|
||||||
stopVideoRecording();
|
|
||||||
} else {
|
|
||||||
tryToStartVideoRecording();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public boolean toggleMute() {
|
|
||||||
setMuted(!muted);
|
|
||||||
return muted;
|
|
||||||
}
|
|
||||||
public boolean isMuted() {
|
|
||||||
return muted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void tryResumingVideoRecording() {
|
|
||||||
if (isRecording()) return;
|
|
||||||
tryToStartVideoRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void tryToStartVideoRecording() {
|
|
||||||
if (orientationEventListener == null) {
|
|
||||||
throw new RuntimeException("startOrientationSensor was not called");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (muted || surfaceView == null || parameters == null) return;
|
|
||||||
|
|
||||||
if (recorder != null) {
|
|
||||||
Log.e("Recorder already present");
|
|
||||||
stopVideoRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
parameters.rotation = bufferRotationToCompensateCameraAndPhoneOrientations();
|
|
||||||
|
|
||||||
parameters.surfaceView = surfaceView;
|
|
||||||
if (Version.sdkAboveOrEqual(9)) {
|
|
||||||
recorder = new AndroidCameraRecord9(parameters);
|
|
||||||
} else if (Version.sdkAboveOrEqual(8)) {
|
|
||||||
recorder = new AndroidCameraRecord8(parameters);
|
|
||||||
} else if (Version.sdkAboveOrEqual(5)) {
|
|
||||||
recorder = new AndroidCameraRecord5(parameters);
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("SDK version unsupported " + Version.sdk());
|
|
||||||
}
|
|
||||||
|
|
||||||
recorder.startPreview();
|
|
||||||
|
|
||||||
if (capturingStateChangedListener != null) {
|
|
||||||
capturingStateChangedListener.captureStarted();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void stopVideoRecording() {
|
|
||||||
if (recorder != null) {
|
|
||||||
recorder.stopPreview();
|
|
||||||
recorder = null;
|
|
||||||
if (capturingStateChangedListener != null) {
|
|
||||||
capturingStateChangedListener.captureStopped();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public List<VideoSize> supportedVideoSizes() {
|
|
||||||
Log.d("Using supportedVideoSizes of camera ",cameraId);
|
|
||||||
return cc.getSupportedPreviewSizes(cameraId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isRecording() {
|
|
||||||
if (recorder != null) {
|
|
||||||
return recorder.isStarted();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void invalidateParameters() {
|
|
||||||
stopVideoRecording();
|
|
||||||
parameters = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Depends on currently selected camera, camera mounted portrait/landscape, current phone orientation */
|
|
||||||
public boolean isFrameToBeShownPortrait() {
|
|
||||||
final int rotation = bufferRotationToCompensateCameraAndPhoneOrientations();
|
|
||||||
|
|
||||||
boolean isPortrait;
|
|
||||||
if (isCameraMountedPortrait()) {
|
|
||||||
// Nexus S
|
|
||||||
isPortrait = (rotation % 180) == 0;
|
|
||||||
} else {
|
|
||||||
isPortrait = (rotation % 180) == 90;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d("The frame to be shown and sent to remote is ", isPortrait? "portrait":"landscape"," orientation.");
|
|
||||||
return isPortrait;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isCameraMountedPortrait() {
|
|
||||||
return (cc.getCameraOrientation(cameraId) % 180) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private int bufferRotationToCompensateCameraAndPhoneOrientations() {
|
|
||||||
if (Version.sdkStrictlyBelow(Version.API08_FROYO_22)) {
|
|
||||||
// Don't perform any rotation
|
|
||||||
// Phone screen should use fitting orientation
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int phoneOrientation = mAlwaysChangingPhoneOrientation;
|
|
||||||
final int cameraOrientation = cc.getCameraOrientation(cameraId);
|
|
||||||
int frontCameraCorrection = 0;
|
|
||||||
if (cc.isFrontCamera(cameraId)) {
|
|
||||||
frontCameraCorrection=180; // hack that "just works" on Galaxy S and Nexus S.
|
|
||||||
// See also magic with mirrors in setParametersFromFilter
|
|
||||||
}
|
|
||||||
final int rotation = (cameraOrientation + phoneOrientation + frontCameraCorrection) % 360;
|
|
||||||
Log.d("Capture video buffer of cameraId=",cameraId,
|
|
||||||
" will need a rotation of ",rotation,
|
|
||||||
" degrees: camera_orientation=",cameraOrientation,
|
|
||||||
" phone_orientation=", phoneOrientation);
|
|
||||||
return rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a sensor to track phoneOrientation changes
|
|
||||||
*/
|
|
||||||
public void startOrientationSensor(Context c) {
|
|
||||||
if (orientationEventListener == null) {
|
|
||||||
orientationEventListener = new LocalOrientationEventListener(c);
|
|
||||||
orientationEventListener.enable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LocalOrientationEventListener extends OrientationEventListener {
|
|
||||||
public LocalOrientationEventListener(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void onOrientationChanged(final int o) {
|
|
||||||
if (o == OrientationEventListener.ORIENTATION_UNKNOWN) return;
|
|
||||||
|
|
||||||
int degrees=270;
|
|
||||||
if (o < 45 || o >315) degrees=0;
|
|
||||||
else if (o<135) degrees=90;
|
|
||||||
else if (o<225) degrees=180;
|
|
||||||
|
|
||||||
if (mAlwaysChangingPhoneOrientation == degrees) return;
|
|
||||||
|
|
||||||
Log.i("Phone orientation changed to ", degrees);
|
|
||||||
mAlwaysChangingPhoneOrientation = degrees;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if linphone core configured to send a A buffer while phone orientation induces !A buffer (A=landscape or portrait)
|
|
||||||
*/
|
|
||||||
public boolean isOutputOrientationMismatch(LinphoneCore lc) {
|
|
||||||
final boolean currentlyPortrait = lc.getPreferredVideoSize().isPortrait();
|
|
||||||
final boolean shouldBePortrait = isFrameToBeShownPortrait();
|
|
||||||
return currentlyPortrait ^ shouldBePortrait;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnCapturingStateChanged(OnCapturingStateChangedListener listener) {
|
|
||||||
this.capturingStateChangedListener=listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static interface OnCapturingStateChangedListener {
|
|
||||||
void captureStarted();
|
|
||||||
void captureStopped();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
9
submodules/externals/build/ffmpeg/Android.mk
vendored
9
submodules/externals/build/ffmpeg/Android.mk
vendored
|
@ -1,5 +1,4 @@
|
||||||
include $(root-dir)/submodules/externals/build/ffmpeg/Android_libavutil.mk
|
include $(linphone-root-dir)/submodules/externals/build/ffmpeg/Android_libavutil.mk
|
||||||
include $(root-dir)/submodules/externals/build/ffmpeg/Android_libavcodec.mk
|
include $(linphone-root-dir)/submodules/externals/build/ffmpeg/Android_libavcodec.mk
|
||||||
include $(root-dir)/submodules/externals/build/ffmpeg/Android_libswscale.mk
|
include $(linphone-root-dir)/submodules/externals/build/ffmpeg/Android_libswscale.mk
|
||||||
include $(root-dir)/submodules/externals/build/ffmpeg/Android_libavcore.mk
|
include $(linphone-root-dir)/submodules/externals/build/ffmpeg/Android_libavcore.mk
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 09bf68a5f14d756872bb28a9a860c853bf9ad06a
|
Subproject commit 9db25e99e4ba2997c20ed7aab7301f772facda81
|
Loading…
Reference in a new issue