<commit_before>package com.dooble.phonertc;

import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.graphics.Point;
import android.webkit.WebView;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.AudioSource;
import org.webrtc.DataChannel;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.MediaStreamTrack;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.PeerConnection.IceConnectionState;
import org.webrtc.PeerConnection.IceGatheringState;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoRenderer;
import org.webrtc.VideoRenderer.I420Frame;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import android.media.AudioManager;
import android.util.Log;

public class PhoneRTCPlugin extends CordovaPlugin {
	public static final String ACTION_CALL = "call";
	public static final String ACTION_RECEIVE_MESSAGE = "receiveMessage";
	public static final String ACTION_DISCONNECT = "disconnect";
	public static final String ACTION_UPDATE_VIDEO_POSITION = "updateVideoPosition";
	public static final String ACTION_SET_ENABLED_MEDIUM = "setEnabledMedium";

	CallbackContext _callbackContext;

	private final SDPObserver sdpObserver = new SDPObserver();
	private final PCObserver pcObserver = new PCObserver();

	private boolean isInitiator;

	private PeerConnectionFactory factory;
	private PeerConnection pc;
	private MediaConstraints sdpMediaConstraints;

	private LinkedList<IceCandidate> queuedRemoteCandidates;
	private Object queuedRemoteCandidatesLocker = new Object();
	
	private MediaStream localStream;
	private MediaStream remoteStream;

	// Synchronize on quit[0] to avoid teardown-related crashes.
	private final Boolean[] quit = new Boolean[] { false };
	
	private AudioSource audioSource;

	private VideoCapturer videoCapturer;
	private VideoSource videoSource;
	private VideoStreamsView localVideoView;
	private VideoStreamsView remoteVideoView;

	@Override
	public boolean execute(String action, JSONArray args,
			CallbackContext callbackContext) throws JSONException {

		if (action.equals(ACTION_CALL)) {
			isInitiator = args.getBoolean(0);

			final String turnServerHost = args.getString(1);
			final String turnUsername = args.getString(2);
			final String turnPassword = <PASSWORD>(3);
			final JSONObject video = (!args.isNull(4)) ? args.getJSONObject(4) : null;

			_callbackContext = callbackContext;
			queuedRemoteCandidates = new LinkedList<IceCandidate>();
			quit[0] = false;

			cordova.getThreadPool().execute(new Runnable() {
				public void run() {
					PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
					result.setKeepCallback(true);
					_callbackContext.sendPluginResult(result);

					AudioManager audioManager = ((AudioManager) cordova.getActivity().getSystemService(cordova.getActivity().AUDIO_SERVICE));
					@SuppressWarnings("deprecation")
					boolean isWiredHeadsetOn = audioManager.isWiredHeadsetOn();
					//audioManager.setMode(isWiredHeadsetOn ? AudioManager.MODE_IN_CALL
					//		: AudioManager.MODE_IN_COMMUNICATION);
					audioManager.setSpeakerphoneOn(!isWiredHeadsetOn);
					audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);

					abortUnless(PeerConnectionFactory.initializeAndroidGlobals(cordova.getActivity(), true, true),
							"Failed to initializeAndroidGlobals");

					final LinkedList<PeerConnection.IceServer> iceServers = new LinkedList<PeerConnection.IceServer>();
					iceServers.add(new PeerConnection.IceServer(
							"stun:stun.l.google.com:19302"));
					iceServers.add(new PeerConnection.IceServer(
							turnServerHost, turnUsername, turnPassword));

					sdpMediaConstraints = new MediaConstraints();
					sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
							"OfferToReceiveAudio", "true"));
					sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
							"OfferToReceiveVideo", (video != null) ? "true" : "false"));

					cordova.getActivity().runOnUiThread(new Runnable() {
						public void run() {
							factory = new PeerConnectionFactory();
							MediaConstraints pcMediaConstraints = new MediaConstraints();
							pcMediaConstraints.optional.add(new MediaConstraints.KeyValuePair(
								"DtlsSrtpKeyAgreement", "true"));
							pc = factory.createPeerConnection(iceServers, pcMediaConstraints,
									pcObserver);

							localStream = factory.createLocalMediaStream("ARDAMS");

							if (video != null) {
								try {
									localVideoView = createVideoView(video.getJSONObject("localVideo"), true);
									remoteVideoView = createVideoView(video.getJSONObject("remoteVideo"), false);

									VideoCapturer capturer = getVideoCapturer();
									videoSource = factory.createVideoSource(capturer, new MediaConstraints());
									VideoTrack videoTrack =
										factory.createVideoTrack("ARDAMSv0", videoSource);
									videoTrack.addRenderer(new VideoRenderer(new VideoCallbacks(
										localVideoView, VideoStreamsView.Endpoint.REMOTE)));
									localStream.addTrack(videoTrack);
								} catch (JSONException e) {
									Log.e("com.dooble.phonertc", "A JSON exception has occured while trying to add video.", e);
								}
							}

							audioSource = factory.createAudioSource(new MediaConstraints());
							localStream.addTrack(factory.createAudioTrack("ARDAMSa0", audioSource));
							pc.addStream(localStream, new MediaConstraints());

							if (isInitiator) {
								pc.createOffer(sdpObserver, sdpMediaConstraints);
							}

						}
					});
					}
			});

			return true;
		} else if (action.equals(ACTION_RECEIVE_MESSAGE)) {
			final String message = args.getString(0);

			cordova.getThreadPool().execute(new Runnable() {
				public void run() {
					try {
						JSONObject json = new JSONObject(message);
						String type = (String) json.get("type");
						if (type.equals("candidate")) {
							final IceCandidate candidate = new IceCandidate(
									(String) json.get("id"), json.getInt("label"),
									(String) json.get("candidate"));
							
							synchronized (queuedRemoteCandidatesLocker) {
								if (queuedRemoteCandidates != null) {
									queuedRemoteCandidates.add(candidate);
								} else {
									cordova.getActivity().runOnUiThread(new Runnable() {
										public void run() {
											pc.addIceCandidate(candidate);
										}
									});	
								}
							}

						} else if (type.equals("answer") || type.equals("offer")) {
							final SessionDescription sdp = new SessionDescription(
									SessionDescription.Type.fromCanonicalForm(type),
									preferISAC((String) json.get("sdp")));
							cordova.getActivity().runOnUiThread(new Runnable() {
								public void run() {
									pc.setRemoteDescription(sdpObserver, sdp);
								}<commit_msg>fix(android): make sure pc is not null<commit_after>package com.dooble.phonertc;

import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.graphics.Point;
import android.webkit.WebView;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.AudioSource;
import org.webrtc.DataChannel;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.MediaStreamTrack;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.PeerConnection.IceConnectionState;
import org.webrtc.PeerConnection.IceGatheringState;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoRenderer;
import org.webrtc.VideoRenderer.I420Frame;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import android.media.AudioManager;
import android.util.Log;

public class PhoneRTCPlugin extends CordovaPlugin {
	public static final String ACTION_CALL = "call";
	public static final String ACTION_RECEIVE_MESSAGE = "receiveMessage";
	public static final String ACTION_DISCONNECT = "disconnect";
	public static final String ACTION_UPDATE_VIDEO_POSITION = "updateVideoPosition";
	public static final String ACTION_SET_ENABLED_MEDIUM = "setEnabledMedium";

	CallbackContext _callbackContext;

	private final SDPObserver sdpObserver = new SDPObserver();
	private final PCObserver pcObserver = new PCObserver();

	private boolean isInitiator;

	private PeerConnectionFactory factory;
	private PeerConnection pc;
	private MediaConstraints sdpMediaConstraints;

	private LinkedList<IceCandidate> queuedRemoteCandidates;
	private Object queuedRemoteCandidatesLocker = new Object();
	
	private MediaStream localStream;
	private MediaStream remoteStream;

	// Synchronize on quit[0] to avoid teardown-related crashes.
	private final Boolean[] quit = new Boolean[] { false };
	
	private AudioSource audioSource;

	private VideoCapturer videoCapturer;
	private VideoSource videoSource;
	private VideoStreamsView localVideoView;
	private VideoStreamsView remoteVideoView;

	@Override
	public boolean execute(String action, JSONArray args,
			CallbackContext callbackContext) throws JSONException {

		if (action.equals(ACTION_CALL)) {
			isInitiator = args.getBoolean(0);

			final String turnServerHost = args.getString(1);
			final String turnUsername = args.getString(2);
			final String turnPassword = args.getString(3);
			final JSONObject video = (!args.isNull(4)) ? args.getJSONObject(4) : null;

			_callbackContext = callbackContext;
			queuedRemoteCandidates = new LinkedList<IceCandidate>();
			quit[0] = false;

			cordova.getThreadPool().execute(new Runnable() {
				public void run() {
					PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
					result.setKeepCallback(true);
					_callbackContext.sendPluginResult(result);

					AudioManager audioManager = ((AudioManager) cordova.getActivity().getSystemService(cordova.getActivity().AUDIO_SERVICE));
					@SuppressWarnings("deprecation")
					boolean isWiredHeadsetOn = audioManager.isWiredHeadsetOn();
					//audioManager.setMode(isWiredHeadsetOn ? AudioManager.MODE_IN_CALL
					//		: AudioManager.MODE_IN_COMMUNICATION);
					audioManager.setSpeakerphoneOn(!isWiredHeadsetOn);
					audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);

					abortUnless(PeerConnectionFactory.initializeAndroidGlobals(cordova.getActivity(), true, true),
							"Failed to initializeAndroidGlobals");

					final LinkedList<PeerConnection.IceServer> iceServers = new LinkedList<PeerConnection.IceServer>();
					iceServers.add(new PeerConnection.IceServer(
							"stun:stun.l.google.com:19302"));
					iceServers.add(new PeerConnection.IceServer(
							turnServerHost, turnUsername, turnPassword));

					sdpMediaConstraints = new MediaConstraints();
					sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
							"OfferToReceiveAudio", "true"));
					sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
							"OfferToReceiveVideo", (video != null) ? "true" : "false"));

					cordova.getActivity().runOnUiThread(new Runnable() {
						public void run() {
							factory = new PeerConnectionFactory();
							MediaConstraints pcMediaConstraints = new MediaConstraints();
							pcMediaConstraints.optional.add(new MediaConstraints.KeyValuePair(
								"DtlsSrtpKeyAgreement", "true"));
							pc = factory.createPeerConnection(iceServers, pcMediaConstraints,
									pcObserver);

							localStream = factory.createLocalMediaStream("ARDAMS");

							if (video != null) {
								try {
									localVideoView = createVideoView(video.getJSONObject("localVideo"), true);
									remoteVideoView = createVideoView(video.getJSONObject("remoteVideo"), false);

									VideoCapturer capturer = getVideoCapturer();
									videoSource = factory.createVideoSource(capturer, new MediaConstraints());
									VideoTrack videoTrack =
										factory.createVideoTrack("ARDAMSv0", videoSource);
									videoTrack.addRenderer(new VideoRenderer(new VideoCallbacks(
										localVideoView, VideoStreamsView.Endpoint.REMOTE)));
									localStream.addTrack(videoTrack);
								} catch (JSONException e) {
									Log.e("com.dooble.phonertc", "A JSON exception has occured while trying to add video.", e);
								}
							}

							audioSource = factory.createAudioSource(new MediaConstraints());
							localStream.addTrack(factory.createAudioTrack("ARDAMSa0", audioSource));
							pc.addStream(localStream, new MediaConstraints());

							if (isInitiator) {
								pc.createOffer(sdpObserver, sdpMediaConstraints);
							}

						}
					});
					}
			});

			return true;
		} else if (action.equals(ACTION_RECEIVE_MESSAGE)) {
			final String message = args.getString(0);

			cordova.getThreadPool().execute(new Runnable() {
				public void run() {
					try {
						JSONObject json = new JSONObject(message);
						String type = (String) json.get("type");
						if (type.equals("candidate")) {
							final IceCandidate candidate = new IceCandidate(
									(String) json.get("id"), json.getInt("label"),
									(String) json.get("candidate"));
							
							synchronized (queuedRemoteCandidatesLocker) {
								if (queuedRemoteCandidates != null) {
									queuedRemoteCandidates.add(candidate);
								} else {
									cordova.getActivity().runOnUiThread(new Runnable() {
										public void run() {
											if (pc != null) {
												pc.addIceCandidate(candidate);
											}
										}
									});	
								}
							}

						} else if (type.equals("answer") || type.equals("offer")) {
							final SessionDescription sdp = new SessionDescription(
									SessionDescription.Type.fromCanonicalForm(type),
									preferISAC((String) json.get("sdp")));
							cordova.getActivity().runOnUiThread(new Runnable() {
								public void run() {
									pc.setRemoteDescription(sdpObserver, sdp);
								}
{'fraction_non_alphanumeric': 0.09918609463374259, 'fraction_numerical': 0.0027590012415505587, 'mean_word_length': 4.22110190853439, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5445679', 'n_tokens_mistral': 5291, 'n_tokens_neox': 4058, 'n_words': 829}