I am trying to make a custom app using liblinphone sdk. The first steps I am taking are to get a simple video call going. I am however, running into some issues with displaying the video on the GL2JNIView. The main activity does a sip register which is successful. The linphone core object is made available and persisted through a service. The user can then click a button which initiates a call and then switches to VideoActivity. After onResume method of VideoActivity is reached it encounters the following exception.
public class VideoActivity extends Activity implements VideoServiceNotifier {
private SurfaceView sView;
private SurfaceView captureView;
private AndroidVideoWindowImpl aVideoWindowImpl;
//private boolean zoomed = false;
private LinphoneCore core;
private VideoServiceNotifier notifier;
@SuppressWarnings("unused")
private boolean bound = false;
private VideoService service;
private ServiceConnection con = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service2) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
VideoBinder binder = (VideoBinder) service2;
service = binder.getService();
bound = true;
service.setNotifier(notifier);
setupCallOnMainThread();
}
@Override
public void onServiceDisconnected(ComponentName name) {
bound = false;
}
};
private void setupCallOnMainThread() {
runOnUiThread(new Runnable() {
@Override
public void run() {
setupCall();
}
});
}
@SuppressLint("NewApi") @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.video);
VideoUncaughtExceptionHandler handler = VideoUncaughtExceptionHandler.getInstance(this);
Thread.setDefaultUncaughtExceptionHandler(handler);
/*
* Note that if a stopped service still has ServiceConnection objects
* bound to it with the BIND_AUTO_CREATE set, it will not be destroyed
* until all of these bindings are removed. See the Service documentation
* for more details on a service's lifecycle.
*/
notifier = this;
Intent intent = new Intent(this, VideoService.class);
this.bindService(intent, con, Context.BIND_AUTO_CREATE);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK) {
end();
return true;
}
return false;
}
public void end() {
core.terminateAllCalls();
service.unregister();
this.unbindService(con);
Intent main = new Intent(this, MainActivity.class);
startActivity(main);
finish();
}
private void setupCall() {
this.core = service.getCore();
sView = (SurfaceView) findViewById(R.id.videoSurface);
captureView = (SurfaceView) findViewById(R.id.videoCaptureSurface);
setRotation();
aVideoWindowImpl = new AndroidVideoWindowImpl(sView, captureView);
fixZOrder(sView, captureView);
aVideoWindowImpl.setListener(new AndroidVideoWindowImpl.VideoWindowListener() {
@Override
public void onVideoRenderingSurfaceReady(AndroidVideoWindowImpl vw, SurfaceView surface) {
core.setVideoWindow(vw);
//surface.setRotation(180);
Log.v("Singletons", "Current Stream Rotation is: " + Double.toString(surface.getRotation()));
sView = surface;
setRotation();
}
@Override
public void onVideoRenderingSurfaceDestroyed(AndroidVideoWindowImpl vw) {
if(core != null) {
core.setVideoWindow(null);
}
}
@Override
public void onVideoPreviewSurfaceReady(AndroidVideoWindowImpl vw, SurfaceView surface) {
core.setDeviceRotation(0);
captureView = surface;
vw.update();
//Log.v("Singletons", "Orientation: " + Integer.toString(info.orientation));
Log.v("Singletons", "Current Rotation is: " + Double.toString(captureView.getRotation()));
core.setPreviewWindow(captureView);
setRotation();
}
@Override
public void onVideoPreviewSurfaceDestroyed(AndroidVideoWindowImpl sv) {
core.setPreviewWindow(null);
}
});
aVideoWindowImpl.init();
}
@Override
public void onResume() {
super.onResume();
if (sView != null) {
((GLSurfaceView) sView).onResume();
}
if (aVideoWindowImpl != null) {
synchronized (aVideoWindowImpl) {
core.setVideoWindow(aVideoWindowImpl);
}
}
setContentView(R.layout.video);
sView = (SurfaceView) findViewById(R.id.videoSurface);
captureView = (SurfaceView) findViewById(R.id.videoCaptureSurface);
}
@Override
public void onPause() {
if (this.aVideoWindowImpl != null) {
synchronized (this.aVideoWindowImpl) {
/*
* this call will destroy native opengl renderer which is used by
* androidVideoWindowImpl
*/
core.setVideoWindow(null);
}
}
if (this.sView != null) {
((GLSurfaceView) sView).onPause();
}
super.onPause();
}
private void setRotation() {
int rotation = getWindowManager().getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
rotation = 0;
break;
case Surface.ROTATION_90:
rotation = 90;
break;
case Surface.ROTATION_180:
rotation = 180;
break;
case Surface.ROTATION_270:
rotation = 270;
break;
}
core.setDeviceRotation(rotation);
}
@Override
public void onDestroy() {
sView = null;
captureView = null;
if(aVideoWindowImpl != null) {
aVideoWindowImpl.release();
aVideoWindowImpl = null;
}
super.onDestroy();
}
private void fixZOrder(SurfaceView video, SurfaceView preview) {
video.setZOrderOnTop(false);
preview.setZOrderOnTop(true);
preview.setZOrderMediaOverlay(true);
}
@Override
public void onRegister() {
// TODO Auto-generated method stub
}
@Override
public void onUnregister() {
// TODO Auto-generated method stub
}
@Override
public void onCall(LinphoneCore core) {
// TODO Auto-generated method stub
}
@Override
public void onTryingToRegister() {
// TODO Auto-generated method stub
}
}
This has been a real head scratcher, since I do not have access to the part of the code where this is breaking. Any help is greatly appreciated.