package org.deviceconnect.android.deviceplugin.webrtc.util; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Point; import android.os.Handler; import android.util.DisplayMetrics; import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import android.widget.RelativeLayout; import org.deviceconnect.android.deviceplugin.webrtc.R; import org.deviceconnect.android.deviceplugin.webrtc.WebRTCApplication; import org.deviceconnect.android.deviceplugin.webrtc.activity.VideoChatActivity; import org.deviceconnect.android.deviceplugin.webrtc.core.AudioTrackExternal; import org.deviceconnect.android.deviceplugin.webrtc.core.MySurfaceViewRenderer; import org.deviceconnect.android.deviceplugin.webrtc.core.Peer; import org.deviceconnect.android.deviceplugin.webrtc.core.PeerConfig; import org.deviceconnect.android.deviceplugin.webrtc.core.WebRTCController; import org.deviceconnect.android.deviceplugin.webrtc.fragment.PercentFrameLayout; import org.deviceconnect.android.profile.VideoChatProfile; import org.webrtc.EglBase; import org.webrtc.RendererCommon; import org.webrtc.voiceengine.WebRtcAudioTrack; import org.webrtc.voiceengine.WebRtcAudioTrackModule; import org.webrtc.voiceengine.WebRtcAudioTrackModuleFactory; import java.util.HashMap; import java.util.Map; public class WebRTCManager { private static final int VIDEO_PORT = 12345; private static final int AUDIO_PORT = 11111; private WebRTCApplication mApplication; private Handler mHandler = new Handler(); private Map<Peer, WebRTCController> mMap = new HashMap<>(); private WindowManager mWinMgr; private AudioTrackExternal mAudioTrackExternal; private MixedReplaceMediaServer mServer = null; public WebRTCManager(WebRTCApplication application) { mApplication = application; mWinMgr = (WindowManager) mApplication.getSystemService(Context.WINDOW_SERVICE); } public void connectOnUiThread(final Intent intent) { mHandler.post(new Runnable() { @Override public void run() { connect(intent); } }); } public boolean isConnect() { return mServer != null; } public void connect(Intent intent) { if (mServer != null) { return; // Error : Already the server is running. } mServer = new MixedReplaceMediaServer(); mServer.setPort(VIDEO_PORT); mServer.start(); LayoutInflater inflater = (LayoutInflater) mApplication.getSystemService(Context.LAYOUT_INFLATER_SERVICE); RelativeLayout root = (RelativeLayout) inflater.inflate(R.layout.activity_main, null); PercentFrameLayout localLayout = (PercentFrameLayout) root.findViewById(R.id.local_view_layout); PercentFrameLayout remoteLayout = (PercentFrameLayout) root.findViewById(R.id.remote_video_layout); MySurfaceViewRenderer localRender = (MySurfaceViewRenderer) root.findViewById(R.id.local_video_view); localRender.setType(MySurfaceViewRenderer.TYPE_LOCAL); localRender.setWebServer(mServer); MySurfaceViewRenderer remoteRender = (MySurfaceViewRenderer) root.findViewById(R.id.remote_video_view); remoteRender.setType(MySurfaceViewRenderer.TYPE_REMOTE); remoteRender.setWebServer(mServer); EglBase eglBase = EglBase.create(); remoteRender.init(eglBase.getEglBaseContext(), null); remoteRender.createYuvConverter(eglBase.getEglBaseContext()); localRender.init(eglBase.getEglBaseContext(), null); localRender.createYuvConverter(eglBase.getEglBaseContext()); localRender.setZOrderMediaOverlay(true); PeerConfig config = intent.getParcelableExtra(VideoChatActivity.EXTRA_CONFIG); String videoUri = intent.getStringExtra(VideoChatActivity.EXTRA_VIDEO_URI); String audioUri = intent.getStringExtra(VideoChatActivity.EXTRA_AUDIO_URI); String addressId = intent.getStringExtra(VideoChatActivity.EXTRA_ADDRESS_ID); boolean offer = intent.getBooleanExtra(VideoChatActivity.EXTRA_OFFER, false); String audioSampleRate = intent.getStringExtra(VideoChatActivity.EXTRA_AUDIOSAMPLERATE); int audioSampleRateValue; if (audioSampleRate == null) { audioSampleRateValue = VideoChatProfile.PARAM_RATE_48000; } else { audioSampleRateValue = Integer.valueOf(audioSampleRate); } String audioBitDepth = intent.getStringExtra(VideoChatActivity.EXTRA_AUDIOBITDEPTH); String audioChannel = intent.getStringExtra(VideoChatActivity.EXTRA_AUDIOCHANNEL); WebRtcAudioTrack.setAudioTrackModuleFactory(new WebRtcAudioTrackModuleFactory() { @Override public WebRtcAudioTrackModule create(Context context) { return mAudioTrackExternal; } }); WebRTCController.Builder builder = new WebRTCController.Builder(); builder.setApplication(mApplication); builder.setWebRTCEventListener(mListener); builder.setContext(mApplication); builder.setEglBase(eglBase); builder.setConfig(config); builder.setRemoteRender(remoteRender); builder.setLocalRender(localRender); mAudioTrackExternal = new AudioTrackExternal(mApplication.getApplicationContext(), AUDIO_PORT); builder.setAudioTrackExternal(mAudioTrackExternal); builder.setVideoUri(videoUri); builder.setAudioUri(audioUri); builder.setAddressId(addressId); builder.setOffer(offer); builder.setAudioSampleRate(audioSampleRateValue); builder.setAudioBitDepth(audioBitDepth); builder.setAudioChannel(audioChannel); builder.setLandscape(isLandscape()); builder.create(); Point size = getDisplaySize(); int pt = (int) (5 * getScaledDensity()); WindowManager.LayoutParams l = new WindowManager.LayoutParams(pt, pt, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT); l.x = -size.x / 2; l.y = -size.y / 2; mWinMgr.addView(root, l); remoteLayout.setPosition(0, 0, 100, 90); remoteRender.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); remoteRender.setMirror(false); localLayout.setPosition(72, 72, 25, 25); localRender.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); localRender.setMirror("true".equals(videoUri)); localRender.requestLayout(); remoteRender.requestLayout(); } private boolean isLandscape() { return (mApplication.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); } /** * Disconnect a peer connection. * @param peer peer for disconnect */ public void disconnect(Peer peer) { WebRTCController ctl = mMap.remove(peer); if (ctl != null) { ctl.onPause(); if (mServer != null) { mServer.stop(); mServer = null; } ctl.hangup(); mWinMgr.removeView((View) ctl.getLocalRender().getParent().getParent()); } } public void destroy() { for (Map.Entry<Peer, WebRTCController> e : mMap.entrySet()) { e.getValue().hangup(); } mMap.clear(); if (mServer != null) { mServer.stop(); mServer = null; } } /** * Displayの密度を取得する. * * @return 密度 */ private float getScaledDensity() { DisplayMetrics metrics = new DisplayMetrics(); mWinMgr.getDefaultDisplay().getMetrics(metrics); return metrics.scaledDensity; } /** * Displayのサイズを取得する. * * @return サイズ */ private Point getDisplaySize() { Display disp = mWinMgr.getDefaultDisplay(); Point size = new Point(); disp.getSize(size); return size; } /** * Open a error dialog of WebRTC. */ private void openWebRTCErrorDialog(WebRTCController controller) { openErrorDialog(controller, R.string.error_failed_to_connect_p2p_msg); } /** * Open a error dialog. * * @param resId resource id */ private void openErrorDialog(final WebRTCController controller, final int resId) { mHandler.post(new Runnable() { @Override public void run() { AlertDialog.Builder builder = new AlertDialog.Builder(mApplication); builder.setTitle(R.string.error_failed_to_connect_p2p_title); builder.setMessage(resId); builder.setPositiveButton(R.string.error_failed_to_connect_p2p_btn, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); AlertDialog dialog = builder.create(); dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { disconnect(controller.getPeer()); } }); dialog.show(); } }); } private WebRTCController.WebRTCEventListener mListener = new WebRTCController.WebRTCEventListener() { @Override public void onFoundPeer(WebRTCController controller) { mMap.put(controller.getPeer(), controller); } @Override public void onNotFoundPeer(WebRTCController controller) { } @Override public void onCallFailed(WebRTCController controller) { } @Override public void onAnswerFailed(WebRTCController controller) { } @Override public void onConnected(WebRTCController controller) { controller.onResume(); } @Override public void onDisconnected(WebRTCController controller) { disconnect(controller.getPeer()); } @Override public void onError(WebRTCController controller) { openWebRTCErrorDialog(controller); } }; }