Related
I have designed a code which leads to application not responding.
I have used okhttp3.WebSocket for continuous input stream of data on which i am deciding to start an IntentService which will be fetching data from server.
I have an IntentService; in onHandleIntent i am giving an service call for fetching data from the server(roughly 3 calls).
For Service call i am using AsyncTask of android inside which my WebConnectionManger class runs on different thread.
Inside websocket i am getting details of a particular record for which i am going to fetch the details from the service call.
For 5-6 such records my application runs fine, but if records get 80-100 my application do not respond at all and i get ANR.
I am using simple plain TCP request for this.
can any on tells me what is the actual issue and how i can get rid of it?
any help is appreciated.
i am pasting the code of WebSocket, AsyncTask(rest two have same implementation), WebConnectionManger class and IntentService class.
WebSocket.class
public class WebSocket {
public static boolean isConnected;
public static String TO_UPDATE = "toOrderUpdate";
#SuppressLint("StaticFieldLeak")
private static WebSocket _instance;
private static OkHttpClient client;
private static WebSocket webSocket = null;
private Context mContext;
private AppPreferences preferences;
private WebSocket() {
client = new OkHttpClient();
}
public WebSocket(Context context) {
client = new OkHttpClient();
mContext = context;
preferences = new AppPreferences(mContext);
init(mContext);
}
public static WebSocket getInstance(Context mContext) {
if (_instance == null) {
_instance = new WebSocket(mContext);
}
return _instance;
}
public static void closeWebSocket() {
if (isConnected) {
webSocket.close(1001, LOGOUT);
_instance = null;
webSocket = null;
isConnected = false;
}
}
public void init(Context context) {
if (webSocket == null) {
preferences = new AppPreferences(context);
Request request = new Request.Builder()
.url(preferences.getWSUrl() + ":" + preferences.getWSPort() + "/" + preferences.getUserID())
.build();
WebSocketMessageListener messageListener = new WebSocketMessageListener();
webSocket = client.newWebSocket(request, messageListener);
isConnected = true;
}
}
private class WebSocketMessageListener extends WebSocketListener {
// private static final int NORMAL_CLOSURE_STATUS = 1000;
#Override
public void onOpen(WebSocket webSocket, Response response) {
super.onOpen(webSocket, response);
Log.i("******", "Socket Open");
}
#Override
public void onMessage(WebSocket webSocket, String response) {
try {
super.onMessage(webSocket, response);
Log.i("******", "Message Received " + response);
// Logger.log("OnMessage : " + response);
ModelAdvertisements modelAdvertisements = DecoderJSONWebSocket.decode(response);
Intent intentForService = new Intent(mContext, WebSocketService.class);
int transCode = Integer.parseInt(modelAdvertisements.getTC());
Intent mwBroadcastIntent = new Intent();
switch (transCode) {
case 1005:
mwBroadcastIntent.setAction(Constants.IntentKeys.KEY_LOGICAL_SESSION_START_END);
mContext.sendBroadcast(mwBroadcastIntent);
break;
case 1004:
case 1006:
case 1007:
intentForService.putExtra(TO_UPDATE, true);
mContext.startService(intentForService);
break;
case 1008:
try {
mwBroadcastIntent.putExtra(KEY_AUCTION_FLOOR_SNAPSHOT, modelAdvertisements);
mwBroadcastIntent.setAction(Constants.IntentKeys.KEY_MARKET_DATASNAPSHOT);
mContext.sendBroadcast(mwBroadcastIntent);
} catch (Exception e) {
e.printStackTrace();
}
break;
}
} catch (Exception e) {
// e.printStackTrace();
}
}
#Override
public void onClosing(WebSocket webSockett, int code, String reason) {
super.onClosing(webSockett, code, reason);
Log.i("******", "Socket Closing Reason: " + reason);
}
#Override
public void onClosed(WebSocket webSockett, int code, String reason) {
super.onClosed(webSockett, code, reason);
Log.i("******", "Socket closed reason: " + reason);
webSocket = null;
isConnected = false;
}
#Override
public void onFailure(WebSocket webSockett, Throwable t, Response response) {
super.onFailure(webSockett, t, response);
isConnected = false;
webSocket = null;
Logger.log(e);
}
}
}
WebSocketService.class
public class WebSocketService extends IntentService {
String securityId;
private Context mContext;
private String tokenId;
private String contractCode;
private int transCode;
private boolean toUpdate;
private String mktCode;
public WebSocketService() {
super("WebSocketService");
}
public WebSocketService(String name) {
super(name);
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
if (intent != null) {
tokenId = intent.getStringExtra(KEY_TOKEN_ID);
transCode = intent.getIntExtra(KEY_TRANSCODE, 0);
toUpdate = intent.getBooleanExtra(NeMLWebSocket.TO_UPDATE, false);
contractCode = intent.getStringExtra(KEY_SYMBOL);
mktCode = intent.getStringExtra(KEY_ADV_REF_ID);
}
securityId = DatabaseUtils.getSecurityIdFromFOOrders(mContext, tokenId);
performTokenMasterTask();
}
#Override
public void onCreate() {
super.onCreate();
mContext = this;
}
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
protected void performTokenMasterTask() {
synchronized (this) {
TokenMasterTask tokenMasterTask = new TokenMasterTask(mContext, new RequestCallback() {
#Override
public void onStart() {
}
#Override
public void onComplete(Object object) {
if (transCode == TC_1004_WEB_SOCKET) {
Intent mwBroadcastIntent = new Intent();
mwBroadcastIntent.setAction(Constants.IntentKeys.KEY_TOKEN_SESSION_START_END);
mContext.sendBroadcast(mwBroadcastIntent);
// stopSelf();
} else if (transCode == TC_TIME_WEB_SOCKET || transCode == TC_AUCTION_WEB_SOCKET) {
performTimeSessionTask();
}
}
#Override
public void onProgress(int current, int total) {
}
#Override
public void onError(int transCode, String msg) {
try {
Logger.log(transCode + "--->" + msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}, mktCode);
tokenMasterTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, tokenId);
if (transCode == TC_TIME_WEB_SOCKET || transCode == TC_AUCTION_WEB_SOCKET) {
performTimeSessionTask();
}
}
}
public void performTimeSessionTask() {
synchronized (this) {
TimeSessionMapTask timeSessionMapTask = new TimeSessionMapTask(mContext, new RequestCallback() {
ProgressDialog progressDialog;
private boolean m_ConnectionErr = false;
#Override
public void onStart() {
}
#Override
public void onComplete(Object object) {
if (!m_ConnectionErr) {
if (transCode == TC_AUCTION_WEB_SOCKET) {
performFoOrderTask();
}
}
}
#Override
public void onProgress(int current, int total) {
}
#Override
public void onError(int transCode, String msg) {
try {
Logger.log("Received ErrorMessage :" + msg + " \n ErrorCode :" + transCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}, modelMarket);
timeSessionMapTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, TIME_SESSION);
if (transCode == TC_AUCTION_WEB_SOCKET) {
performFoOrderTask();
}
}
}
private synchronized void performFoOrderTask() {
synchronized (mContext) {
FOOrdersTask foOrdersTask = new FOOrdersTask(mContext, new RequestCallback() {
#Override
public void onStart() {
}
#Override
public void onComplete(Object object) {
}
#Override
public void onProgress(int current, int total) {
}
#Override
public void onError(int transCode, String msg) {
}
});
foOrdersTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, tokenId);
}
}
}
TokenMasterTask.class
public class TokenMasterTask extends AsyncTask<Object, Void, ModelToken> {
private final String mktCode;
private RequestCallback _callback;
#SuppressLint("StaticFieldLeak")
private Context context;
private boolean isConnectionError;
private ModelToken modelToken;
private boolean isServerDown;
public TokenMasterTask(Context context, RequestCallback requestCallback, String mktCode) {
this.context = context;
this.mktCode = mktCode;
if (requestCallback == null) {
requestCallback = new RequestCallback() {
#Override
public void onStart() {
}
#Override
public void onComplete(Object object) {
}
#Override
public void onProgress(int current, int total) {
}
#Override
public void onError(int transCode, String msg) {
}
};
}
this._callback = requestCallback;
}
#Override
protected ModelToken doInBackground(Object... voids) {
if (voids != null && voids.length > 0) {
String tokenId = String.valueOf(voids[0]);
isConnectionError = false;
transactionCall(tokenId);
}
return modelToken;
}
private void transactionCall(String tokenId) {
try {
WebConnectionManager connectionManager = new WebConnectionManager(context, new ConnectionListener() {
#Override
public void notifyReadCompleted(String f_Response) {
modelToken = DecoderTokenRequest.decode(f_Response);
synchronized (TokenMasterTask.this) {
TokenMasterTask.this.notify();
}
}
#Override
public void notifySocketError(boolean isServerDown) {
if (!isServerDown) {
isConnectionError = true;
}
TokenMasterTask.this.isServerDown = isServerDown;
synchronized (TokenMasterTask.this) {
TokenMasterTask.this.notify();
}
}
#Override
public void onReceivePacket(int total, int current) {
_callback.onProgress(current, total);
}
});
connectionManager.modifiedHandleRequest(EncoderTokenRequest.encode(context, tokenId,mktCode).getBytes());
} catch (Exception e) {
e.printStackTrace();
Logger.log(e);
}
synchronized( TokenMasterTask.this) {
try {
TokenMasterTask.this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
protected void onPostExecute(ModelToken modelToken) {
if (isServerDown) {
_callback.onError(Constants.ErrorCode.TC_ERROR_SERVER_DOWN, "");
} else if (isConnectionError) {
_callback.onError(0, "Connection Error.");
} else if (modelToken!=null && modelToken.getErrorCode() != null && !TextUtils.isEmpty(modelToken.getErrorCode()) && !modelToken.getErrorCode().equalsIgnoreCase("200")) {
_callback.onError(Integer.parseInt(modelToken.getErrorCode()), modelToken.getError());
} else {
_callback.onComplete(modelToken);
}
super.onPostExecute(modelToken);
}
}
WebConnectionManager.class
public class WebConnectionManager {
private String m_Response = "";
byte[] m_RequestData;
boolean m_Read_Response_Completed = false;
Thread l_WorkerThread;
ConnectionListener m_ConnectionListener;
boolean m_IsFetchCompleted;
Context context;
AppPreferences preferences;
Socket mWebSocket;
public WebConnectionManager(Context mcontext, ConnectionListener f_LoginListener) {
m_ConnectionListener = f_LoginListener;
m_IsFetchCompleted = false;
context = mcontext;
preferences = new AppPreferences(context);
}
public String modifiedHandleRequest(byte[] f_RequestData) {
m_RequestData = f_RequestData;
Logger.log("" + Constants.TIME_OUT);
l_WorkerThread = new Thread(new Runnable() {
#Override
public void run() {
String encodedIP = null;
try {
if (mWebSocket == null || !mWebSocket.isBound()
|| mWebSocket.isClosed() ) {
mWebSocket = new Socket(ip, port);
mWebSocket.setKeepAlive(true);
mWebSocket.setSoTimeout(Constants.TIME_OUT);
}
if (m_RequestData == null) {
m_Read_Response_Completed = true;
if (!mWebSocket.isClosed()) {
m_ConnectionListener.notifyReadCompleted("Connected");
return;
} else {
m_ConnectionListener.notifyReadCompleted("Disconnected");
return;
}
} else {
String request = new String(m_RequestData);
Logger.log(Utils.encodePackets(request));
}
InputStream inputStream = mWebSocket.getInputStream();
try {
mWebSocket.getOutputStream().write(m_RequestData);
} catch (Exception e) {
Logger.log(e);
}
ByteArrayOutputStream byteArrayOutputStream =
new ByteArrayOutputStream(1048576);
byte[] buffer = new byte[1048576];
int bytesRead = 0;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
m_Response = byteArrayOutputStream.toString();
}
inputStream.close();
byteArrayOutputStream.close();
mWebSocket.close();
if (TextUtils.isEmpty(m_Response.toString().trim())) {
throw new IOException("Empty Response");
} else {
m_ConnectionListener.notifyReadCompleted(m_Response.toString());
}
} catch (UnknownHostException e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(true);
mWebSocket = null;
} catch (SocketTimeoutException e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(false);
mWebSocket = null;
e.printStackTrace();
} catch (SocketException e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(true);
mWebSocket = null;
e.printStackTrace();
} catch (IOException e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(true);
mWebSocket = null;
e.printStackTrace();
} catch (Exception e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(true);
mWebSocket = null;
e.printStackTrace();
}
}
});
l_WorkerThread.start();
return m_Response;
}
}
And the interfaces.
public interface ConnectionListener {
void notifyReadCompleted(String f_Response);
void notifySocketError(boolean isServerDown);
void onReceivePacket(int total, int current);
}
public interface RequestCallback {
void onStart();
void onComplete(Object object);
void onProgress(int current, int total);
void onError(int transCode, String msg);
}
You may want to check what is blocking the main thread for more than 6 seconds.
Usually ANR happens when main thread is blocked for some time. 6-10 seconds.
I am developing the chatbot app. I am using the RecycleView to render the chat of user and bot. I have to show the user listview or text response depend upon his query. All is working until my RecyclerView get's scroll. Whenever my RecyclerView gets scroll it changes the item position. I search a lot and applied every solution but not able to solve my issue.
here is my activity.java
public class HomeActivity extends AppCompatActivity implements AIListener,
View.OnClickListener {
private RecyclerView recyclerView;
private ChatAdapter mAdapter;
LinearLayoutManager layoutManager;
private ArrayList<Message> messageArrayList;
private EditText inputMessage;
private RelativeLayout btnSend;
Boolean flagFab = true;
PaytmPGService service = null;
Map<String, String> paytmparam = new HashMap<>();
PrefManager prefManager;
private AIService aiService;
AIDataService aiDataService;
AIRequest aiRequest;
Gson gson;
String food_dish = " ";
double price = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1);
inputMessage = findViewById(R.id.editText_ibm);
btnSend = findViewById(R.id.addBtnibm);
recyclerView = findViewById(R.id.recycler_view_ibm);
messageArrayList = new ArrayList<>();
mAdapter = new ChatAdapter(this,messageArrayList);
prefManager = new PrefManager(this);
GsonBuilder gsonBuilder = new GsonBuilder();
gson = gsonBuilder.create();
layoutManager = new LinearLayoutManager(this);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
int msgCount = mAdapter.getItemCount();
int lastVisiblePosition = layoutManager.findLastCompletelyVisibleItemPosition();
if (lastVisiblePosition == -1 ||
(positionStart >= (msgCount - 1) &&
lastVisiblePosition == (positionStart - 1))) {
recyclerView.scrollToPosition(positionStart);
}
}
});
recyclerView.setAdapter(mAdapter);
this.inputMessage.setText("");
final AIConfiguration configuration = new AIConfiguration("cabc4b7b9c20409aa7ffb1b3d5fe1243",
AIConfiguration.SupportedLanguages.English,
AIConfiguration.RecognitionEngine.System);
aiService = AIService.getService(this, configuration);
aiService.setListener(this);
aiDataService = new AIDataService(configuration);
aiRequest = new AIRequest();
btnSend.setOnClickListener(this);
inputMessage.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
ImageView fab_img = findViewById(R.id.fab_img_ibm);
Bitmap img = BitmapFactory.decodeResource(getResources(), R.drawable.ic_send_white_24dp);
Bitmap img1 = BitmapFactory.decodeResource(getResources(), R.drawable.ic_mic_white_24dp);
if (s.toString().trim().length() != 0 && flagFab) {
ImageViewAnimatedChange(HomeActivity.this, fab_img, img);
flagFab = false;
} else if (s.toString().trim().length() == 0) {
ImageViewAnimatedChange(HomeActivity.this, fab_img, img1);
flagFab = true;
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
public void ImageViewAnimatedChange(Context c, final ImageView v, final Bitmap new_image) {
final Animation anim_out = AnimationUtils.loadAnimation(c, R.anim.zoom_out);
final Animation anim_in = AnimationUtils.loadAnimation(c, R.anim.zoom_in);
anim_out.setAnimationListener(new Animation.AnimationListener()
{
#Override public void onAnimationStart(Animation animation) {}
#Override public void onAnimationRepeat(Animation animation) {}
#Override public void onAnimationEnd(Animation animation)
{
v.setImageBitmap(new_image);
anim_in.setAnimationListener(new Animation.AnimationListener() {
#Override public void onAnimationStart(Animation animation) {}
#Override public void onAnimationRepeat(Animation animation) {}
#Override public void onAnimationEnd(Animation animation) {}
});
v.startAnimation(anim_in);
}
});
v.startAnimation(anim_out);
}
#Override
public void onClick(View v) {
final String inputmessage = this.inputMessage.getText().toString().trim();
if(!inputmessage.equals("")){
new AsyncTask<String, Void, AIResponse>(){
private AIError aiError;
#Override
protected AIResponse doInBackground(final String... params) {
final AIRequest request = new AIRequest();
String query = params[0];
if (!TextUtils.isEmpty(query))
request.setQuery(query);
try {
return aiDataService.request(request);
} catch (final AIServiceException e) {
aiError = new AIError(e);
return null;
}
}
#Override
protected void onPostExecute(final AIResponse response) {
if (response != null) {
onResult(response);
} else {
onError(aiError);
}
}
}.execute(inputmessage);
}else {
aiService.startListening();
}
inputMessage.setText("");
}
#Override
public void onResult(AIResponse response) {
int itemNumber = 0;
Log.d("dialogeflow response",response.toString());
try {
JSONObject AIResponse = new JSONObject(gson.toJson(response));
Log.d("json response",AIResponse.toString());
final JSONObject result = AIResponse.getJSONObject("result");
JSONArray contexts = result.getJSONArray("contexts");
final JSONObject fulfillment = result.getJSONObject("fulfillment");
if(contexts.length()>0) {
for(int i = 0;i<contexts.length();i++) {
JSONObject context_items = contexts.getJSONObject(i);
JSONObject paramters = context_items.getJSONObject("parameters");
if (paramters.has("Cuisine")) {
prefManager.setCuisinetype(paramters.getString("Cuisine"));
} else if (paramters.has("Restaurants_name")) {
prefManager.setRestaurant_name(paramters.getString("Restaurants_name"));
}
if (paramters.has("number") && !paramters.getString("number").equals("") && paramters.has("Food_Dishes") && !paramters.getString("Food_Dishes").equals("")) {
itemNumber = Integer.parseInt(paramters.getString("number"));
if (itemNumber <= 2 && price !=0) {
price = 300 + (int) (Math.random() * ((1400 - 300) + 1));
} else {
price = 600 + (int) (Math.random() * ((2200 - 600) + 1));
}
food_dish = paramters.getString("Food_Dishes");
}
}
}
final double finalPrice = price;
final int finalItemNumber = itemNumber;
if(!result.getString("resolvedQuery").matches("payment is done successfully")) {
Message usermsg = new Message();
usermsg.setMessage(result.getString("resolvedQuery"));
usermsg.setId("1");
messageArrayList.add(usermsg);
mAdapter.notifyDataSetChanged();
if (fulfillment.has("speech")) {
Log.d("response of speech", fulfillment.getString("speech"));
if (!fulfillment.getString("speech").equals("") && fulfillment.getString("speech") != null) {
final String speech = fulfillment.getString("speech");
if (fulfillment.getString("speech").matches("Redirecting you to the Pay-Tm site")) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
Message outMessage = new Message();
outMessage.setMessage(speech);
outMessage.setId("2");
messageArrayList.add(outMessage);
mAdapter.notifyDataSetChanged();
getpaytm_params((int) price);
}
}, 2000);
} else {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
Message outMessage = new Message();
if (speech.contains("Your total bill is ₹")) {
Log.d("price", String.valueOf(price));
outMessage.setMessage("Please Confirm your order:- \n" +finalItemNumber +" "+food_dish+" from "+prefManager.getRestaurant_name()+" at Flat No: 20,Galaxy Apartment,Airport Authority Colony,Andheri,Mumbai,Maharashtra 400 047 \n Your total bill is ₹"+price+". \n Do you want to pay by Wallet or by PayTm");
}else{
outMessage.setMessage(speech);
}
outMessage.setId("2");
messageArrayList.add(outMessage);
Log.d("messgae",outMessage.getMessage());
mAdapter.notifyDataSetChanged();
}
}, 2000);
}
} else {
final JSONArray msg = fulfillment.getJSONArray("messages");
for (int i = 0; i < msg.length(); i++) {
if (i == 0) {
Message outMessage = new Message();
JSONObject speechobj = msg.getJSONObject(i);
JSONArray speech = speechobj.getJSONArray("speech");
Log.d("response of speech", speech.getString(0));
outMessage.setMessage(speech.getString(0));
outMessage.setId("2");
messageArrayList.add(outMessage);
} else {
final int itemposition = i;
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
Message outMessage = new Message();
try {
JSONObject speechobj = msg.getJSONObject(itemposition);
JSONArray speech = speechobj.getJSONArray("speech");
Log.d("response of speech", speech.getString(0));
outMessage.setMessage(speech.getString(0));
outMessage.setId("2");
messageArrayList.add(outMessage);
mAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, 5000);
}
}
}
}
}else{
if (!fulfillment.getString("speech").equals("") && fulfillment.getString("speech") != null) {
final String speech = fulfillment.getString("speech");
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
Message outMessage = new Message();
outMessage.setMessage(speech);
outMessage.setId("2");
messageArrayList.add(outMessage);
mAdapter.notifyDataSetChanged();
}
},2000);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onError(AIError error) {
}
#Override
public void onAudioLevel(float level) {
}
#Override
public void onListeningStarted() {
btnSend.setBackground(getDrawable(R.drawable.recording_bg));
}
#Override
public void onListeningCanceled() {
btnSend.setBackground(getDrawable(R.drawable.stedy_recording));
}
#Override
public void onListeningFinished() {
btnSend.setBackground(getDrawable(R.drawable.stedy_recording));
}
}`
my ChatAdapter.java class
public class ChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private int BOT = 100;
private int BOT_Restaurant_ListView = 101;
private int USER = 102;
private Activity activity;
private PrefManager prefManager;
private int itemposition = -1;
private int menu_itemposition = -1;
private List<Restaurant_List_Model> restaurant_list;
private ArrayList<Message> messageArrayList;
private RestaurantListViewAdapter restaurantListViewAdapter;
private TextToSpeech tts ;
public ChatAdapter(Activity activity, ArrayList<Message> messageArrayList) {
this.activity = activity;
this.messageArrayList = messageArrayList;
tts = new TextToSpeech(activity, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR){
tts.setLanguage(Locale.ENGLISH);
}
}
});
prefManager = new PrefManager(activity.getApplicationContext());
setHasStableIds(true);
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemview;
if(viewType == BOT){
itemview = LayoutInflater.from(parent.getContext()).inflate(R.layout.bot_msg_view,parent,false);
}else if(viewType == BOT_Restaurant_ListView){
itemview = LayoutInflater.from(parent.getContext()).inflate(R.layout.bot_msg_restaurant_listview,parent,false);
}else {
itemview = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_msg_view,parent,false);
}
return new ViewHolder(itemview);
}
#Override
public int getItemViewType(int position) {
Message message = messageArrayList.get(position);
if(message.getId()!=null && message.getId().equals("2")){
if(message.getMessage().contains("restaurants") || message.getMessage().contains("restaurant")) {
return BOT_Restaurant_ListView;
}else {
return BOT;
}
}else{
return USER;
}
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
int pic_int = 1;
String filename = null;
final Message message = messageArrayList.get(position);
message.setMessage(message.getMessage());
if (holder.getItemViewType() == BOT_Restaurant_ListView) {
Log.d("inside bot listview msg", String.valueOf(BOT_Restaurant_ListView ));
Log.d("adapter position", String.valueOf(holder.getAdapterPosition()));
if(itemposition<holder.getAdapterPosition()){
itemposition = holder.getAdapterPosition();
Log.d("itemposition",String.valueOf(itemposition));
String jsonFileContent;
Log.d("cuisine value", prefManager.getCuisinetype());
if (message.getMessage().contains("restaurants")) {
if(!prefManager.getCuisinetype().equals("") && prefManager.getCuisinetype() != null){
Log.d("restauratn has drawn", "greate");
try {
restaurant_list = new ArrayList<>();
restaurantListViewAdapter = new RestaurantListViewAdapter(activity, restaurant_list);
((ViewHolder) holder).retaurant_listView.setVisibility(View.VISIBLE);
((ViewHolder) holder).retaurant_listView.setAdapter(restaurantListViewAdapter);
Log.d("cuisine value", prefManager.getCuisinetype());
if(message.getMessage().contains("Here are restaurants near you")){
String [] restaurant_Array ={
"indian","french","mexican","italian"
};
int randomNumber = (int) Math.floor(Math.random()*restaurant_Array.length);
filename = restaurant_Array[randomNumber];
Log.d("filename",filename);
jsonFileContent = readFile(activity.getResources().getIdentifier(filename, "raw", activity.getPackageName()));
}else {
filename = prefManager.getCuisinetype().toLowerCase() + "_restaurants";
Log.d("filename", filename);
jsonFileContent = readFile(activity.getResources().getIdentifier(filename, "raw", activity.getPackageName()));
}
JSONObject restaurantfile = new JSONObject(jsonFileContent);
JSONArray jsonArray = restaurantfile.getJSONArray("restaurants");
for (int i = 0; i < jsonArray.length(); i++) {
ImageRoundCorner imageRoundCorner = new ImageRoundCorner();
JSONObject restaurantList = jsonArray.getJSONObject(i);
Restaurant_List_Model restaurant_list_obj = new Restaurant_List_Model();
restaurant_list_obj.setName(restaurantList.getString("name"));
restaurant_list_obj.setLocation(restaurantList.getString("location"));
restaurant_list_obj.setImage_of_item(imageRoundCorner.getRoundedCornerBitmap(BitmapFactory.decodeResource(activity.getResources(), activity.getResources().getIdentifier("restaurant_" + pic_int, "drawable", activity.getPackageName()))));
pic_int++;
restaurant_list_obj.setRating(restaurantList.getLong("rating"));
restaurant_list.add(restaurant_list_obj);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null, null);
} else {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null);
}
prefManager.setCuisinetype("");
pic_int = 1;
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
restaurantListViewAdapter.notifyDataSetChanged();
}
}else if(message.getMessage().contains("Here are some famous food items from "+prefManager.getRestaurant_name()+" restaurant")){
try {
Log.d("menu has draw","greate");
restaurant_list = new ArrayList<>();
restaurantListViewAdapter = new RestaurantListViewAdapter(activity, restaurant_list);
((ViewHolder) holder).retaurant_listView.setAdapter(restaurantListViewAdapter);
((ViewHolder) holder).retaurant_listView.setVisibility(View.VISIBLE);
Log.d("restaurant name value", prefManager.getRestaurant_name());
jsonFileContent = readFile(R.raw.restaurant_menu);
JSONObject menu_cuisine = new JSONObject(jsonFileContent);
ImageRoundCorner imageRoundCorner = new ImageRoundCorner();
if (menu_cuisine.has(prefManager.getRestaurant_name())) {
JSONObject restaurant_menu = menu_cuisine.getJSONObject("Dominos");
Log.d("Chili's American menu", restaurant_menu.toString());
JSONArray menu = restaurant_menu.getJSONArray("menu");
for (int j = 0; j < menu.length(); j++) {
JSONObject menu_obj = menu.getJSONObject(j);
Restaurant_List_Model restaurant_list_obj = new Restaurant_List_Model();
restaurant_list_obj.setName(menu_obj.getString("name"));
restaurant_list_obj.setLocation(menu_obj.getString("cuisine_type"));
restaurant_list_obj.setImage_of_item(imageRoundCorner.getRoundedCornerBitmap(BitmapFactory.decodeResource(activity.getResources(), activity.getResources().getIdentifier("menu_" + pic_int, "drawable", activity.getPackageName()))));
//restaurant_list_obj.setImage_of_item(imageRoundCorner.getRoundedCornerBitmap(BitmapFactory.decodeResource(activity.getResources(), activity.getResources().getIdentifier("menu_" + pic_int, "drawable", activity.getPackageName()))));
pic_int++;
restaurant_list_obj.setRating(menu_obj.getLong("rating"));
restaurant_list.add(restaurant_list_obj);
}
restaurantListViewAdapter.notifyDataSetChanged();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null, null);
} else {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null);
}
pic_int = 1;
prefManager.setRestaurant_name("");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Log.d("user_message",message.getMessage());
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null, null);
}else {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null);
}
pic_int = 1;
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
((ViewHolder) holder).retaurant_listView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
v.getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
v.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
v.onTouchEvent(event);
return true;
}
});
}
} if(holder.getItemViewType()==BOT) {
Log.d("adapter position", String.valueOf(holder.getAdapterPosition()));
Log.d("inside bot msg", String.valueOf(BOT));
((ViewHolder) holder).bot_msg.setText(message.getMessage());
if(itemposition<holder.getAdapterPosition()) {
itemposition = holder.getAdapterPosition();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null, null);
} else {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null);
}
}
}if(holder.getItemViewType() == USER) {
((ViewHolder) holder).user_message.setText(message.getMessage());
}
}
#Override
public void onViewRecycled(#NonNull RecyclerView.ViewHolder holder) {
super.onViewRecycled(holder);
if(holder.isRecyclable()){
Log.d("inside onViewRecycled","great");
// itemposition = holder.getAdapterPosition();
}
}
#Override
public long getItemId(int position) {
return super.getItemId(position);
}
#Override
public int getItemCount() {
return messageArrayList.size();
}
private String readFile(int id) throws IOException
{
BufferedReader reader = null;
reader = new BufferedReader(new InputStreamReader(activity.getResources().openRawResource(id)));
String content = "";
String line;
while ((line = reader.readLine()) != null)
{
content = content + line;
}
return content;
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView user_message,bot_msg;
private ListView retaurant_listView;
ViewHolder(View itemView) {
super(itemView);
bot_msg = itemView.findViewById(R.id.bot_message);
user_message = itemView.findViewById(R.id.message);
retaurant_listView = itemView.findViewById(R.id.restaurant_items_list_ibm);
}
}
}
Please help me out with this issue.
In gif, you can see the lower list is swap with the upper list and then return back
Here I have a query related to connection between android socket and server. I'm following https://socket.io/blog/native-socket-io-and-android/ and found that it is working fine, so I replaced my local server URL with the URL in the tutorial. But here I'm always getting a connection failed or disconnection error. Here is my application class for further clarification.
public class ChatApplication extends Application {
private Socket mSocket;
{
try {
IO.Options options = new IO.Options();
options.forceNew = true;
options.reconnection = true;
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("uid", 1);
jsonObject.put("usid", 6847);
options.query = jsonObject.toString();
} catch (JSONException e) {
e.printStackTrace();
}
Log.e("JSON", jsonObject.toString());
Log.e("OPTIONS", options.toString());
mSocket = IO.socket(Constants.CHAT_SERVER_URL, options);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
public Socket getSocket() {
return mSocket;
}
}
And the code of the fragment is below. It keeps calling onDisconnect() whenever I use my local server for it.
public class MainFragment extends Fragment {
private static final String TAG = "MainFragment";
private static final int REQUEST_LOGIN = 0;
private static final int TYPING_TIMER_LENGTH = 600;
private RecyclerView mMessagesView;
private EditText mInputMessageView;
private List<Message> mMessages = new ArrayList<Message>();
private RecyclerView.Adapter mAdapter;
private boolean mTyping = false;
private Handler mTypingHandler = new Handler();
private String mUsername;
private Socket mSocket;
private Boolean isConnected = true;
private Emitter.Listener onConnect = new Emitter.Listener() {
#Override
public void call(Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (!isConnected) {
if (null != mUsername)
mSocket.emit("add user", mUsername);
Toast.makeText(getActivity().getApplicationContext(),
R.string.connect, Toast.LENGTH_LONG).show();
isConnected = true;
}
}
});
}
};
private Emitter.Listener onDisconnect = new Emitter.Listener() {
#Override
public void call(Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i(TAG, "diconnected");
isConnected = false;
Toast.makeText(getActivity().getApplicationContext(),
R.string.disconnect, Toast.LENGTH_LONG).show();
}
});
}
};
private Emitter.Listener onConnectError = new Emitter.Listener() {
#Override
public void call(Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e(TAG, "Error connecting");
Toast.makeText(getActivity().getApplicationContext(),
R.string.error_connect, Toast.LENGTH_LONG).show();
}
});
}
};
private Emitter.Listener onNewMessage = new Emitter.Listener() {
#Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
String message;
try {
username = data.getString("username");
message = data.getString("message");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
removeTyping(username);
addMessage(username, message);
}
});
}
};
private Emitter.Listener onUserJoined = new Emitter.Listener() {
#Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
int numUsers;
try {
username = data.getString("username");
numUsers = data.getInt("numUsers");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
addLog(getResources().getString(R.string.message_user_joined, username));
addParticipantsLog(numUsers);
}
});
}
};
private Emitter.Listener onUserLeft = new Emitter.Listener() {
#Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
int numUsers;
try {
username = data.getString("username");
numUsers = data.getInt("numUsers");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
addLog(getResources().getString(R.string.message_user_left, username));
addParticipantsLog(numUsers);
removeTyping(username);
}
});
}
};
private Emitter.Listener onTyping = new Emitter.Listener() {
#Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
try {
username = data.getString("username");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
addTyping(username);
}
});
}
};
private Emitter.Listener onStopTyping = new Emitter.Listener() {
#Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
try {
username = data.getString("username");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
removeTyping(username);
}
});
}
};
private Runnable onTypingTimeout = new Runnable() {
#Override
public void run() {
if (!mTyping) return;
mTyping = false;
mSocket.emit("stop typing");
}
};
public MainFragment() {
super();
}
// This event fires 1st, before creation of fragment or any views
// The onAttach method is called when the Fragment instance is associated with an Activity.
// This does not mean the Activity is fully initialized.
#Override
public void onAttach(Context context) {
super.onAttach(context);
mAdapter = new MessageAdapter(context, mMessages);
if (context instanceof Activity) {
//this.listener = (MainActivity) context;
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
ChatApplication app = (ChatApplication) getActivity().getApplication();
mSocket = app.getSocket();
mSocket.on(Socket.EVENT_CONNECT, onConnect);
mSocket.on(Socket.EVENT_DISCONNECT, onDisconnect);
mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
mSocket.on("new message", onNewMessage);
mSocket.on("user joined", onUserJoined);
mSocket.on("user left", onUserLeft);
mSocket.on("typing", onTyping);
mSocket.on("stop typing", onStopTyping);
mSocket.connect();
startSignIn();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onDestroy() {
super.onDestroy();
mSocket.disconnect();
mSocket.off(Socket.EVENT_CONNECT, onConnect);
mSocket.off(Socket.EVENT_DISCONNECT, onDisconnect);
mSocket.off(Socket.EVENT_CONNECT_ERROR, onConnectError);
mSocket.off(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
mSocket.off("new message", onNewMessage);
mSocket.off("user joined", onUserJoined);
mSocket.off("user left", onUserLeft);
mSocket.off("typing", onTyping);
mSocket.off("stop typing", onStopTyping);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMessagesView = (RecyclerView) view.findViewById(R.id.messages);
mMessagesView.setLayoutManager(new LinearLayoutManager(getActivity()));
mMessagesView.setAdapter(mAdapter);
mInputMessageView = (EditText) view.findViewById(R.id.message_input);
mInputMessageView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int id, KeyEvent event) {
if (id == R.id.send || id == EditorInfo.IME_NULL) {
attemptSend();
return true;
}
return false;
}
});
mInputMessageView.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (null == mUsername) return;
if (!mSocket.connected()) return;
if (!mTyping) {
mTyping = true;
mSocket.emit("typing");
}
mTypingHandler.removeCallbacks(onTypingTimeout);
mTypingHandler.postDelayed(onTypingTimeout, TYPING_TIMER_LENGTH);
}
#Override
public void afterTextChanged(Editable s) {
}
});
ImageButton sendButton = (ImageButton) view.findViewById(R.id.send_button);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
attemptSend();
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (Activity.RESULT_OK != resultCode) {
getActivity().finish();
return;
}
mUsername = data.getStringExtra("username");
int numUsers = data.getIntExtra("numUsers", 1);
addLog(getResources().getString(R.string.message_welcome));
addParticipantsLog(numUsers);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Inflate the menu; this adds items to the action bar if it is present.
inflater.inflate(R.menu.menu_main, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_leave) {
leave();
return true;
}
return super.onOptionsItemSelected(item);
}
private void addLog(String message) {
mMessages.add(new Message.Builder(Message.TYPE_LOG)
.message(message).build());
mAdapter.notifyItemInserted(mMessages.size() - 1);
scrollToBottom();
}
private void addParticipantsLog(int numUsers) {
addLog(getResources().getQuantityString(R.plurals.message_participants, numUsers, numUsers));
}
private void addMessage(String username, String message) {
mMessages.add(new Message.Builder(Message.TYPE_MESSAGE)
.username(username).message(message).build());
mAdapter.notifyItemInserted(mMessages.size() - 1);
scrollToBottom();
}
private void addTyping(String username) {
mMessages.add(new Message.Builder(Message.TYPE_ACTION)
.username(username).build());
mAdapter.notifyItemInserted(mMessages.size() - 1);
scrollToBottom();
}
private void removeTyping(String username) {
for (int i = mMessages.size() - 1; i >= 0; i--) {
Message message = mMessages.get(i);
if (message.getType() == Message.TYPE_ACTION && message.getUsername().equals(username)) {
mMessages.remove(i);
mAdapter.notifyItemRemoved(i);
}
}
}
private void attemptSend() {
if (null == mUsername) return;
if (!mSocket.connected()) return;
mTyping = false;
String message = mInputMessageView.getText().toString().trim();
if (TextUtils.isEmpty(message)) {
mInputMessageView.requestFocus();
return;
}
mInputMessageView.setText("");
addMessage(mUsername, message);
// perform the sending message attempt.
mSocket.emit("new message", message);
}
private void startSignIn() {
// mUsername = null;
Intent intent = new Intent(getActivity(), LoginActivity.class);
startActivityForResult(intent, REQUEST_LOGIN);
}
private void leave() {
mUsername = null;
mSocket.disconnect();
mSocket.connect();
startSignIn();
}
private void scrollToBottom() {
mMessagesView.scrollToPosition(mAdapter.getItemCount() - 1);
}
}
I'm using CHAT_SERVER_URL = "http://192.168.1.14:3000/" to make connection with server but it's not working for me. It works fine when we try to make a web connection through emulator or computer system. Can anyone please give me an idea if I'm doing anything wrong.
Thanks.
After debugging at the server end too, I got to know how to hit my server to make a connection and I got that we don't require IO.Options and Options.query in every case and now it is working fine completely. So for more clarification I'm posting an answer here:
//connect to server
public void startRunning() {
try {
if (baseUrl != null) {
socket = IO.socket("http://" + baseUrl + ":3000?uid=" + userId + "&usid=" + userSessionId);
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
if (socket == null) return;
socket
.on(Socket.EVENT_CONNECT, CONNECTED)
.on(Socket.EVENT_DISCONNECT, DISCONNECTED)
.on("chat-message", CHAT_MESSAGE)
.on("chats-active", CHATS_ACTIVE)
.on("chat-logout", LOGOUT)
.on("messages-read", MESSAGE_READ)
.on("chat-login", CHAT_LOGIN);
socket.connect();
}
So I'm badly stuck in creating a datachannel between android app client and Web App client running on Chrome.
Following is my complete code for which Audio and Video is streaming fine. But When I try to send the message using DataChannel it returns False and State as CONNECTING. I'm trying to resolve since 1 week but couldn't make it run.
EDIT: Issue resolved. Here is the final Working Code. Android Do not support RTPDataChannel anymore
Home.java
public class Home extends Activity {
public List<PeerConnection.IceServer> iceServers;
private GLSurfaceView videoView;
public static SocketIO socket;
ArrayList<String> userIDs = new ArrayList<>();
private static final String FIELD_TRIAL_VP9 = "WebRTC-SupportVP9/Enabled/";
String RoomId = "";
String sreverURL = "http://xx.xx.xx.xx:xxxx/";
private EditText roomid;
private VideoRenderer.Callbacks remote_view;
private VideoRenderer.Callbacks local_view;
protected PeerConnectionFactory factory;
PeerConnectionFactory.Options options = null;
Events pc_events;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
videoView = (GLSurfaceView) findViewById(R.id.glview_call_remote);
VideoRendererGui.setView(videoView, new Runnable() {
#Override
public void run() {
createPeerConnectionFactory();
}
});
remote_view = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FIT, false);
local_view = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FILL, true);
iceServers = new ArrayList<>();
IceServer icc = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(icc);
roomid = (EditText) findViewById(R.id.roomId);
Random rand = new Random();
roomid.setText("" + rand.nextInt(9999));
pc_events = new peerEventHandler();
}
private void createPeerConnectionFactory() {
runOnUiThread(new Runnable() {
#Override
public void run() {
PeerConnectionFactory.initializeFieldTrials(FIELD_TRIAL_VP9);
PeerConnectionFactory.initializeAndroidGlobals(Home.this, true, true, true, VideoRendererGui.getEGLContext());
try {
factory = new PeerConnectionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void ondail(View view) {
try {
try {
SocketIO.setDefaultSSLSocketFactory(SSLContext.getDefault());
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
socket = new SocketIO();
//startCall();
socket.connect(sreverURL, new IOCallback() {
#Override
public void onMessage(JSONObject json, IOAcknowledge ack) {
}
#Override
public void onMessage(String data, IOAcknowledge ack) {
}
#Override
public void onError(SocketIOException socketIOException) {
socketIOException.printStackTrace();
}
#Override
public void onDisconnect() {
}
#Override
public void onConnect() {
showToast("Connected to " + sreverURL);
}
#Override
public void on(final String event, IOAcknowledge ack, final Object... args) {
String argument = "";
try {
if (args instanceof Object[]) {
argument = args[0].toString();
} else {
argument = args.toString();
}
} catch (Exception e) {
argument = args.toString();
}
Log.e("Socked.on", event + ", " + argument);
switch (getEvent(event)) {
case LOG:
break;
case MESSAGE:
if (args instanceof Object[]) {
pc_events.setMessage(args[0].toString());
} else {
pc_events.setMessage(args.toString());
}
break;
case CREATED:
runOnUiThread(new Runnable() {
public void run() {
showToast("Room Created " + args[0]);
}
});
break;
case BROADCAST:
break;
case JOIN:
break;
case EMIT:
Log.e("Socked.onEMIT", argument);
startCall();
pc_events.createOffer();
break;
case ERROR:
Log.e("Socked.onERROR", argument);
break;
default:
break;
}
}
});
try {
RoomId = roomid.getText().toString();
} catch (Exception e) {
}
socket.emit("create or join", RoomId);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public void oncancel(View view) {
}
public SocketEvent getEvent(String eventString) {
SocketEvent eventType;
try {
if (eventString.contains("log")) {
eventType = SocketEvent.LOG;
} else if (eventString.contains("created")) {
eventType = SocketEvent.CREATED;
} else if (eventString.contains("emit():")) {
eventType = SocketEvent.EMIT;
} else if (eventString.contains("broadcast():")) {
eventType = SocketEvent.BROADCAST;
} else if (eventString.contains("message")) {
eventType = SocketEvent.MESSAGE;
} else if (eventString.toLowerCase().substring(0, 20).contains("join")) {
eventType = SocketEvent.JOIN;
} else {
eventType = SocketEvent.ERROR;
}
} catch (Exception e) {
eventType = SocketEvent.ERROR;
}
return eventType;
}
public static interface Events {
public void peerConnectionEvent(VideoRenderer.Callbacks localRender, VideoRenderer.Callbacks remoteRender);
public void setFactory(PeerConnectionFactory factory);
public void setMessage(String message);
public void createOffer();
public void sendMessage(String msg);
}
private void startCall() {
pc_events.setFactory(factory);
pc_events.peerConnectionEvent(remote_view, local_view);
}
public void showToast(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(Home.this, message, Toast.LENGTH_SHORT).show();
}
});
}
public void sendMessage(View v) {
pc_events.sendMessage("Hello");
}
}
peerEventHandler.java
public class peerEventHandler implements Events {
private PeerConnection peerConnection;
private PeerConnectionFactory factory;
PCObserver pcObserver = new PCObserver();
public LooperExecutor executor;
private MediaStream mediaStream;
private VideoSource videoSource;
private DcObserver dc_observer;
public static final String VIDEO_TRACK_ID = "ARDAMSv0";
public static final String AUDIO_TRACK_ID = "ARDAMSa0";
private VideoCapturerAndroid videoCapturer;
private VideoTrack localVideoTrack;
private VideoTrack remoteVideoTrack;
public boolean preferIsac = false;
public boolean videoCallEnabled = true;
public boolean preferH264 = false;
private SessionDescription localSdp;
private final SDPObserver sdpObserver = new SDPObserver();
public boolean isInitiator = false;
private MediaConstraints sdpMediaConstraints;
private VideoRenderer.Callbacks remote_view;
private VideoRenderer.Callbacks local_view;
private DataChannel dataChannel;
#Override
public void peerConnectionEvent(Callbacks remoteRender, Callbacks localRender) {
this.remote_view = remoteRender;
this.local_view = localRender;
creatPeerConnection();
}
public void creatPeerConnection() {
executor = new LooperExecutor();
executor.requestStart();
MediaConstraints pcConstraints = new MediaConstraints();
MediaConstraints videoConstraints = new MediaConstraints();
MediaConstraints audioConstraints = new MediaConstraints();
sdpMediaConstraints = new MediaConstraints();
creatvideoConstraints(videoConstraints);
creataudioConstraints(audioConstraints);
creatsdpMediaConstraints(sdpMediaConstraints);
List<PeerConnection.IceServer> iceServers = new ArrayList<PeerConnection.IceServer>();
IceServer iceServer = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(iceServer);
PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED;
rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.BALANCED;
rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.NEGOTIATE;
pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "false"));
pcConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
peerConnection = factory.createPeerConnection(rtcConfig, pcConstraints, pcObserver);
Logging.enableTracing("logcat:", EnumSet.of(Logging.TraceLevel.TRACE_DEFAULT), Logging.Severity.LS_WARNING);
mediaStream = factory.createLocalMediaStream("ARDAMS");
Log.e("DC Add", "Adding Data Channel");
dataChannel = peerConnection.createDataChannel("sendDataChannel", new DataChannel.Init());
dc_observer = new DcObserver();
dataChannel.registerObserver(dc_observer);
Log.e("DC Add", "Data Channel added");
String cameraDeviceName = CameraEnumerationAndroid.getDeviceName(0);
String frontCameraDeviceName = CameraEnumerationAndroid.getNameOfFrontFacingDevice();
cameraDeviceName = frontCameraDeviceName;
videoCapturer = VideoCapturerAndroid.create(cameraDeviceName, null);
videoSource = factory.createVideoSource(videoCapturer, videoConstraints);
localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
localVideoTrack.setEnabled(true);
localVideoTrack.addRenderer(new VideoRenderer(local_view));
mediaStream.addTrack(factory.createAudioTrack(AUDIO_TRACK_ID, factory.createAudioSource(audioConstraints)));
mediaStream.addTrack(localVideoTrack);
peerConnection.addStream(mediaStream);
}
#Override
public void createOffer() {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection != null) {
isInitiator = true;
peerConnection.createOffer(sdpObserver, sdpMediaConstraints);
}
}
});
}
public void createAnswer() {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection != null) {
isInitiator = false;
peerConnection.createAnswer(sdpObserver, sdpMediaConstraints);
}
}
});
}
private class PCObserver implements PeerConnection.Observer {
#Override
public void onAddStream(final MediaStream stream) {
Log.e("onAddStream", "onAddStream");
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
if (stream.audioTracks.size() > 1 || stream.videoTracks.size() > 1) {
// /reportError("Weird-looking stream: " + stream);
return;
}
if (stream.videoTracks.size() == 1) {
remoteVideoTrack = stream.videoTracks.get(0);
remoteVideoTrack.setEnabled(true);
remoteVideoTrack.addRenderer(new VideoRenderer(remote_view));
VideoRendererGui.update(local_view, 75, 70, 60, 60, ScalingType.SCALE_ASPECT_FIT, true);
VideoRendererGui.update(remote_view, 0, 0, 200, 200, ScalingType.SCALE_ASPECT_FILL, false);
}
}
});
}
#Override
public void onDataChannel(final DataChannel dc) {
executor.execute(new Runnable() {
#Override
public void run() {
dataChannel = dc;
String channelName = dataChannel.label();
dc_observer = new DcObserver();
dataChannel.registerObserver(dc_observer);
}
});
}
#Override
public void onIceCandidate(IceCandidate candidate) {
SocketIO socket = Home.socket;
JSONObject json;
try {
/*
json.putOpt("label", candidate.sdpMLineIndex);
json.putOpt("id", candidate.sdpMid);
json.putOpt("candidate", candidate.sdp);*/
Gson gson = new Gson();
String json_str = gson.toJson(candidate);
json = new JSONObject(json_str);
json.putOpt("type", "candidate");
socket.emit("message", json);
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onIceConnectionChange(IceConnectionState state) {
}
#Override
public void onIceConnectionReceivingChange(boolean arg0) {
}
#Override
public void onIceGatheringChange(IceGatheringState arg0) {
}
#Override
public void onRemoveStream(MediaStream arg0) {
}
#Override
public void onRenegotiationNeeded() {
}
#Override
public void onSignalingChange(SignalingState arg0) {
}
}
public void creatPcConstrains(MediaConstraints pcConstraints) {
}
public void creatvideoConstraints(MediaConstraints videoConstraints) {
String MAX_VIDEO_WIDTH_CONSTRAINT = "maxWidth";
String MIN_VIDEO_WIDTH_CONSTRAINT = "minWidth";
String MAX_VIDEO_HEIGHT_CONSTRAINT = "maxHeight";
String MIN_VIDEO_HEIGHT_CONSTRAINT = "minHeight";
String MAX_VIDEO_FPS_CONSTRAINT = "maxFrameRate";
String MIN_VIDEO_FPS_CONSTRAINT = "minFrameRate";
int videoWidth = 0;
int videoHeight = 0;
if ((videoWidth == 0 || videoHeight == 0) && true && MediaCodecVideoEncoder.isVp8HwSupported()) {
videoWidth = 1280;
videoHeight = 1280;
}
if (videoWidth > 0 && videoHeight > 0) {
videoWidth = Math.min(videoWidth, 1280);
videoHeight = Math.min(videoHeight, 1280);
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
}
int videoFps = 30;
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
}
public void creataudioConstraints(MediaConstraints audioConstraints) {
audioConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(new KeyValuePair("internalSctpDataChannels", "true"));
}
public void creatsdpMediaConstraints(MediaConstraints sdpMediaConstraints) {
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveAudio", "true"));
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveVideo", "true"));
}
private class SDPObserver implements SdpObserver {
#Override
public void onCreateFailure(String arg0) {
System.out.print(arg0);
}
#Override
public void onCreateSuccess(SessionDescription origSdp) {
if (localSdp != null) {
return;
}
localSdp = origSdp;
setLocalDescription(origSdp);
}
#Override
public void onSetFailure(String arg0) {
}
#Override
public void onSetSuccess() {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
if (isInitiator) {
if (peerConnection != null) {
JSONObject json = new JSONObject();
try {
json.putOpt("type", localSdp.type.toString().toLowerCase());
json.putOpt("sdp", localSdp.description);
} catch (JSONException e) {
e.printStackTrace();
}
Home.socket.emit("message", json);
}
} else {
// createAnswer();
}
}
});
}
}
public void addRemoteIceCandidate(final IceCandidate candidate) {
executor.execute(new Runnable() {
#Override
public void run() {
peerConnection.addIceCandidate(candidate);
}
});
}
public void setLocalDescription(final SessionDescription sdp) {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
peerConnection.setLocalDescription(sdpObserver, sdp);
}
});
}
public void setRemoteDescription(final SessionDescription sdp) {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
peerConnection.setRemoteDescription(sdpObserver, sdp);
}
});
}
#Override
public void setFactory(PeerConnectionFactory factory) {
this.factory = factory;
}
public void onWebSocketMessage(final String msg) {
try {
Log.e("onWebSocketMessage", msg);
JSONObject json = new JSONObject(msg);
json = new JSONObject(msg);
String type = json.optString("type");
if (type.equals("candidate")) {
IceCandidate candidate = new IceCandidate(json.getString("id"), json.getInt("label"), json.getString("candidate"));
addRemoteIceCandidate(candidate);
} else if (type.equals("answer")) {
isInitiator = false;
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else if (type.equals("offer")) {
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else if (type.equals("bye")) {
} else {
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void setMessage(String message) {
if (message.toString().contains("got user media") || message.toString().contains("bye")) {
} else
onWebSocketMessage(message);
}
private class DcObserver implements DataChannel.Observer {
#Override
public void onMessage(DataChannel.Buffer buffer) {
ByteBuffer data = buffer.data;
byte[] bytes = new byte[data.remaining()];
data.get(bytes);
String command = new String(bytes);
Log.e("onMessage ", command);
}
#Override
public void onStateChange() {
Log.e("onStateChange ", "onStateChange");
}
#Override
public void onBufferedAmountChange(long arg0) {
Log.e("onMessage ", "" + arg0);
}
}
#Override
public void sendMessage(String msg) {
Log.e("DataChannel State", "" + dataChannel.state());
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
boolean sent = dataChannel.send(new DataChannel.Buffer(buffer, false));
Log.e("Message sent", "" + sent);
}
}
Edit: There is no issue at web client as similar app in ios is working fine in similar scenario.
So I'm trying to connect Android to Browser via webRTC via socket.io and libjingle and server is running on Node.js .
Issue I'm facing is weired.
When 1 client is at Android(native app) and other is at Ipad(native app), Everything works fine.
When 1 client is at iPad(Native app) and other is WebApp, Everyting works fine.
But When 1 Client is at Android(native app) and other is WebPage, everyting works fine except the audio and video is not streaming to that end.
Following are the two major classes i've used for the purpose:
PS. The method makeOffer(View v) called by the button.
MainActivity.java
public List<PeerConnection.IceServer> iceServers;
private GLSurfaceView videoView;
public static SocketIO socket;
ArrayList<String> userIDs = new ArrayList<>();
private static final String FIELD_TRIAL_VP9 = "WebRTC-SupportVP9/Enabled/";
String RoomId = "";
String sreverURL = "http://xx.xx.xx.xx:xxxx/";
private EditText roomid;
private VideoRenderer.Callbacks localRender;
private VideoRenderer.Callbacks remoteRender;
protected PeerConnectionFactory factory;
PeerConnectionFactory.Options options = null;
Events pc_events;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
videoView = (GLSurfaceView) findViewById(R.id.glview_call);
VideoRendererGui.setView(videoView, new Runnable() {
#Override
public void run() {
createPeerConnectionFactory();
}
});
remoteRender = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FILL, false);
localRender = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FILL, true);
iceServers = new ArrayList<>();
IceServer icc = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(icc);
roomid = (EditText) findViewById(R.id.roomId);
Random rand = new Random();
roomid.setText("" + rand.nextInt(9999));
pc_events = new peerEventHandler();
}
private void createPeerConnectionFactory() {
runOnUiThread(new Runnable() {
#Override
public void run() {
PeerConnectionFactory.initializeFieldTrials(FIELD_TRIAL_VP9);
PeerConnectionFactory.initializeAndroidGlobals(Home.this, true, true, true, VideoRendererGui.getEGLContext());
try {
factory = new PeerConnectionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void ondail(View view) {
try {
try {
SocketIO.setDefaultSSLSocketFactory(SSLContext.getDefault());
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
socket = new SocketIO();
socket.connect(sreverURL, new IOCallback() {
#Override
public void onMessage(JSONObject json, IOAcknowledge ack) {
Log.e("json Object", json.toString());
}
#Override
public void onMessage(String data, IOAcknowledge ack) {
Log.e("json Object", data.toString());
}
#Override
public void onError(SocketIOException socketIOException) {
socketIOException.printStackTrace();
System.out.println(socketIOException.toString());
}
#Override
public void onDisconnect() {
}
#Override
public void onConnect() {
showToast("Connected to " + sreverURL);
startCall("");
}
#Override
public void on(final String event, IOAcknowledge ack, final Object... args) {
Log.e("Socked.on", event + ", " + args);
switch (getEvent(event)) {
case LOG :
break;
case MESSAGE :
if (args instanceof Object[]) {
if (args[0].toString().contains("offer")) {
// startCall("");
}
pc_events.setMessage(args[0].toString());
} else {
pc_events.setMessage(args.toString());
}
break;
case CREATED :
runOnUiThread(new Runnable() {
public void run() {
showToast("Room Created " + args[0]);
}
});
break;
case BROADCAST :
Log.e("Socked.onBROADCAST", args.toString());
break;
case JOIN :
Log.e("Socked.onJOIN", args.toString());
break;
case EMIT :
Log.e("Socked.onEMIT", args.toString());
Log.e("Socked.onBROADCOST", args.toString());
break;
case ERROR :
Log.e("Socked.onERROR", args.toString());
break;
default :
break;
}
}
});
try {
RoomId = roomid.getText().toString();
} catch (Exception e) {
}
socket.emit("create or join", RoomId);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public void oncancel(View view) {
}
public SocketEvent getEvent(String eventString) {
SocketEvent eventType;
try {
if (eventString.contains("log")) {
eventType = SocketEvent.LOG;
} else if (eventString.contains("created")) {
eventType = SocketEvent.CREATED;
} else if (eventString.contains("emit():")) {
eventType = SocketEvent.EMIT;
}
else if (eventString.contains("broadcast():")) {
eventType = SocketEvent.BROADCAST;
} else if (eventString.contains("message")) {
eventType = SocketEvent.MESSAGE;
} else if (eventString.toLowerCase().substring(0, 20).contains("join")) {
eventType = SocketEvent.JOIN;
} else {
eventType = SocketEvent.ERROR;
}
} catch (Exception e) {
eventType = SocketEvent.ERROR;
}
return eventType;
}
public static interface Events {
public void peerConnectionEvent(String clintID, VideoRenderer.Callbacks localRender, VideoRenderer.Callbacks remoteRender);
public void setFactory(PeerConnectionFactory factory);
public void setMessage(String message);
public void createOffer();
}
private void startCall(String clientID) {
pc_events.setFactory(factory);
pc_events.peerConnectionEvent(clientID, localRender, remoteRender);
}
public void showToast(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(Home.this, message, Toast.LENGTH_SHORT).show();
}
});
}
public void makeOffer(View v) {
pc_events.createOffer();
}
}
PeerEventHandler.java
public class peerEventHandler implements Events {
private PeerConnection peerConnection;
private PeerConnectionFactory factory;
PCObserver pcObserver = new PCObserver();
public LooperExecutor executor;
private MediaStream mediaStream;
private VideoSource videoSource;
public static final String VIDEO_TRACK_ID = "ARDAMSv0";
public static final String AUDIO_TRACK_ID = "ARDAMSa0";
private VideoCapturerAndroid videoCapturer;
private VideoTrack localVideoTrack;
private VideoTrack remoteVideoTrack;
public boolean preferIsac = false;
public boolean videoCallEnabled = true;
public boolean preferH264 = true;
private static final String VIDEO_CODEC_H264 = "VP8";
private static final String AUDIO_CODEC_ISAC = "ISAC";
private SessionDescription localSdp;
private final SDPObserver sdpObserver = new SDPObserver();
private LinkedList<IceCandidate> queuedRemoteCandidates;
public boolean isInitiator = false;
private MediaConstraints sdpMediaConstraints;
private VideoRenderer.Callbacks localRender;
private VideoRenderer.Callbacks remoteRender;
#Override
public void peerConnectionEvent(String clintID, Callbacks localRender, Callbacks remoteRender) {
this.localRender = localRender;
this.remoteRender = remoteRender;
creatPeerConnection();
}
public void creatPeerConnection() {
queuedRemoteCandidates = new LinkedList<IceCandidate>();
executor = new LooperExecutor();
executor.requestStart();
MediaConstraints pcConstraints = new MediaConstraints();
MediaConstraints videoConstraints = new MediaConstraints();
MediaConstraints audioConstraints = new MediaConstraints();
sdpMediaConstraints = new MediaConstraints();
creatPcConstrains(pcConstraints);
creatvideoConstraints(videoConstraints);
creatsdpMediaConstraints(sdpMediaConstraints);
List<PeerConnection.IceServer> iceServers = new ArrayList<PeerConnection.IceServer>();
IceServer iceServer = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(iceServer);
PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
// TCP candidates are only useful when connecting to a server that
// supports
// ICE-TCP.
rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED;
rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.BALANCED;
rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.NEGOTIATE;
peerConnection = factory.createPeerConnection(rtcConfig, pcConstraints, pcObserver);
Logging.enableTracing("logcat:", EnumSet.of(Logging.TraceLevel.TRACE_DEFAULT), Logging.Severity.LS_WARNING);
mediaStream = factory.createLocalMediaStream("ARDAMS");
String cameraDeviceName = CameraEnumerationAndroid.getDeviceName(0);
String frontCameraDeviceName = CameraEnumerationAndroid.getNameOfFrontFacingDevice();
cameraDeviceName = frontCameraDeviceName;
videoCapturer = VideoCapturerAndroid.create(cameraDeviceName, null);
videoSource = factory.createVideoSource(videoCapturer, videoConstraints);
localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
localVideoTrack.setEnabled(true);
localVideoTrack.addRenderer(new VideoRenderer(localRender));
mediaStream.addTrack(factory.createAudioTrack(AUDIO_TRACK_ID, factory.createAudioSource(audioConstraints)));
mediaStream.addTrack(localVideoTrack);
peerConnection.addStream(mediaStream);
}
#Override
public void createOffer() {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection != null) {
isInitiator = true;
peerConnection.createOffer(sdpObserver, sdpMediaConstraints);
}
}
});
}
public void createAnswer() {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection != null) {
isInitiator = false;
peerConnection.createAnswer(sdpObserver, sdpMediaConstraints);
}
}
});
}
private class PCObserver implements PeerConnection.Observer {
#Override
public void onAddStream(final MediaStream stream) {
Log.e("onAddStream", "onAddStream");
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
if (stream.audioTracks.size() > 1 || stream.videoTracks.size() > 1) {
// /reportError("Weird-looking stream: " + stream);
return;
}
if (stream.videoTracks.size() == 1) {
remoteVideoTrack = stream.videoTracks.get(0);
remoteVideoTrack.setEnabled(true);
remoteVideoTrack.addRenderer(new VideoRenderer(remoteRender));
}
}
});
}
#Override
public void onDataChannel(DataChannel arg0) {
Log.e("On data channel", "Data Channel");
}
#Override
public void onIceCandidate(IceCandidate candidate) {
SocketIO socket = Home.socket;
JSONObject json = new JSONObject();
try {
json.putOpt("type", "candidate");
json.putOpt("label", candidate.sdpMLineIndex);
json.putOpt("id", candidate.sdpMid);
json.putOpt("candidate", candidate.sdp);
} catch (JSONException e) {
}
socket.emit("message", json);
}
#Override
public void onIceConnectionChange(IceConnectionState arg0) {
Log.e("onIceConnectionChange", "onIceConnectionChange");
}
#Override
public void onIceConnectionReceivingChange(boolean arg0) {
Log.e("onIceConnectionReceivingChange", "onIceConnectionReceivingChange");
}
#Override
public void onIceGatheringChange(IceGatheringState arg0) {
Log.e("onIceGatheringChange", "onIceGatheringChange");
}
#Override
public void onRemoveStream(MediaStream arg0) {
Log.e("onRemoveStream", "onRemoveStream");
}
#Override
public void onRenegotiationNeeded() {
Log.e("onRenegotiationNeeded", "onRenegotiationNeeded");
}
#Override
public void onSignalingChange(SignalingState arg0) {
Log.e("onSignalingChange", "onSignalingChange");
}
}
public void creatPcConstrains(MediaConstraints pcConstraints) {
pcConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(new KeyValuePair("RtpDataChannels", "true"));
}
public void creatvideoConstraints(MediaConstraints videoConstraints) {
String MAX_VIDEO_WIDTH_CONSTRAINT = "maxWidth";
String MIN_VIDEO_WIDTH_CONSTRAINT = "minWidth";
String MAX_VIDEO_HEIGHT_CONSTRAINT = "maxHeight";
String MIN_VIDEO_HEIGHT_CONSTRAINT = "minHeight";
String MAX_VIDEO_FPS_CONSTRAINT = "maxFrameRate";
String MIN_VIDEO_FPS_CONSTRAINT = "minFrameRate";
int videoWidth = 0;
int videoHeight = 0;
// If VP8 HW video encoder is supported and video resolution is not
// specified force it to HD.
if ((videoWidth == 0 || videoHeight == 0) && true && MediaCodecVideoEncoder.isVp8HwSupported()) {
videoWidth = 1280;
videoHeight = 1280;
}
// Add video resolution constraints.
if (videoWidth > 0 && videoHeight > 0) {
videoWidth = Math.min(videoWidth, 1280);
videoHeight = Math.min(videoHeight, 1280);
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
}
// Add fps constraints.
int videoFps = 30;
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
}
public void creataudioConstraints(MediaConstraints pcConstraints) {
pcConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(new KeyValuePair("RtpDataChannels", "true"));
}
public void creatsdpMediaConstraints(MediaConstraints sdpMediaConstraints) {
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveAudio", "true"));
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveVideo", "true"));
}
private class SDPObserver implements SdpObserver {
#Override
public void onCreateFailure(String arg0) {
System.out.print(arg0);
}
#Override
public void onCreateSuccess(SessionDescription origSdp) {
if (localSdp != null) {
return;
}
String sdpDescription = origSdp.description;
if (preferIsac) {
sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true);
}
if (videoCallEnabled && preferH264) {
sdpDescription = preferCodec(sdpDescription, VIDEO_CODEC_H264, false);
}
final SessionDescription sdp = new SessionDescription(origSdp.type, sdpDescription);
localSdp = sdp;
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection != null) {
JSONObject json = new JSONObject();
try {
// peerConnection.setLocalDescription(null, localSdp);
json.putOpt("type", "offer");
json.putOpt("sdp", localSdp.description);
} catch (JSONException e) {
e.printStackTrace();
}
Home.socket.emit("message", json);
}
}
});
}
#Override
public void onSetFailure(String arg0) {
Log.e("onSetFailure", arg0);
}
#Override
public void onSetSuccess() {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
if (isInitiator) {
createOffer();
} else {
createAnswer();
}
}
});
}
}
private static String preferCodec(String sdpDescription, String codec, boolean isAudio) {
String[] lines = sdpDescription.split("\r\n");
int mLineIndex = -1;
String codecRtpMap = null;
// a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding
// parameters>]
String regex = "^a=rtpmap:(\\d+) " + codec + "(/\\d+)+[\r]?$";
Pattern codecPattern = Pattern.compile(regex);
String mediaDescription = "m=video ";
if (isAudio) {
mediaDescription = "m=audio ";
}
for (int i = 0; (i < lines.length) && (mLineIndex == -1 || codecRtpMap == null); i++) {
if (lines[i].startsWith(mediaDescription)) {
mLineIndex = i;
continue;
}
Matcher codecMatcher = codecPattern.matcher(lines[i]);
if (codecMatcher.matches()) {
codecRtpMap = codecMatcher.group(1);
continue;
}
}
if (mLineIndex == -1) {
// Log.w(TAG, "No " + mediaDescription + " line, so can't prefer " +
// codec);
return sdpDescription;
}
if (codecRtpMap == null) {
// Log.w(TAG, "No rtpmap for " + codec);
return sdpDescription;
}
// Log.d(TAG, "Found " + codec + " rtpmap " + codecRtpMap +
// ", prefer at "
// + lines[mLineIndex]);
String[] origMLineParts = lines[mLineIndex].split(" ");
if (origMLineParts.length > 3) {
StringBuilder newMLine = new StringBuilder();
int origPartIndex = 0;
// Format is: m=<media> <port> <proto> <fmt> ...
newMLine.append(origMLineParts[origPartIndex++]).append(" ");
newMLine.append(origMLineParts[origPartIndex++]).append(" ");
newMLine.append(origMLineParts[origPartIndex++]).append(" ");
newMLine.append(codecRtpMap);
for (; origPartIndex < origMLineParts.length; origPartIndex++) {
if (!origMLineParts[origPartIndex].equals(codecRtpMap)) {
newMLine.append(" ").append(origMLineParts[origPartIndex]);
}
}
lines[mLineIndex] = newMLine.toString();
// Log.d(TAG, "Change media description: " + lines[mLineIndex]);
} else {
// Log.e(TAG, "Wrong SDP media description format: " +
// lines[mLineIndex]);
}
StringBuilder newSdpDescription = new StringBuilder();
for (String line : lines) {
newSdpDescription.append(line).append("\r\n");
}
return newSdpDescription.toString();
}
private void drainCandidates() {
if (queuedRemoteCandidates != null) {
// Log.d(TAG, "Add " + queuedRemoteCandidates.size() +
// " remote candidates");
for (IceCandidate candidate : queuedRemoteCandidates) {
// if(!candidate.sdpMid.contains("video"))
peerConnection.addIceCandidate(candidate);
}
queuedRemoteCandidates = null;
}
}
public void addRemoteIceCandidate(final IceCandidate candidate) {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection != null) {
if (queuedRemoteCandidates != null) {
queuedRemoteCandidates.add(candidate);
} else {
peerConnection.addIceCandidate(candidate);
}
}
}
});
}
public void setRemoteDescription(final SessionDescription sdp) {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
String sdpDescription = sdp.description;
if (preferIsac) {
sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true);
}
if (videoCallEnabled && preferH264) {
sdpDescription = preferCodec(sdpDescription, VIDEO_CODEC_H264, false);
}
SessionDescription sdpRemote = new SessionDescription(sdp.type, sdpDescription);
peerConnection.setRemoteDescription(sdpObserver, sdpRemote);
}
});
}
#Override
public void setFactory(PeerConnectionFactory factory) {
this.factory = factory;
}
public void onWebSocketMessage(final String msg) {
try {
Log.e("onWebSocketMessage", msg);
JSONObject json = new JSONObject(msg);
json = new JSONObject(msg);
String type = json.optString("type");
if (type.equals("candidate")) {
IceCandidate candidate = new IceCandidate(json.getString("id"), json.getInt("label"), json.getString("candidate"));
addRemoteIceCandidate(candidate);
} else if (type.equals("answer")) {
if (isInitiator) {
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else {
}
} else if (type.equals("offer")) {
if (!isInitiator) {
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else {
}
} else if (type.equals("bye")) {
} else {
}
} catch (JSONException e) {
}
}
#Override
public void setMessage(String message) {
if (message.toString().contains("got user media") || message.toString().contains("bye")) {
} else
onWebSocketMessage(message);
}
}
I don't know why but I changed target=android-19 to target=android-21 and everything worked fine as desired (Except Datachannel).
Final Working Code
PS: You can use this code without any royalty and Guarantees :p
Home.java
public class Home extends Activity {
public List<PeerConnection.IceServer> iceServers;
private GLSurfaceView videoView;
public static SocketIO socket;
ArrayList<String> userIDs = new ArrayList<>();
private static final String FIELD_TRIAL_VP9 = "WebRTC-SupportVP9/Enabled/";
String RoomId = "";
String sreverURL = "http://xx.xx.xx.xx:xxxx/";
private EditText roomid;
private VideoRenderer.Callbacks remote_view;
private VideoRenderer.Callbacks local_view;
protected PeerConnectionFactory factory;
PeerConnectionFactory.Options options = null;
Events pc_events;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
videoView = (GLSurfaceView) findViewById(R.id.glview_call_remote);
VideoRendererGui.setView(videoView, new Runnable() {
#Override
public void run() {
createPeerConnectionFactory();
}
});
remote_view = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FIT, false);
local_view = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FILL, true);
iceServers = new ArrayList<>();
IceServer icc = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(icc);
roomid = (EditText) findViewById(R.id.roomId);
Random rand = new Random();
roomid.setText("" + rand.nextInt(9999));
pc_events = new peerEventHandler();
}
private void createPeerConnectionFactory() {
runOnUiThread(new Runnable() {
#Override
public void run() {
PeerConnectionFactory.initializeFieldTrials(FIELD_TRIAL_VP9);
PeerConnectionFactory.initializeAndroidGlobals(Home.this, true, true, true, VideoRendererGui.getEGLContext());
try {
factory = new PeerConnectionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void ondail(View view) {
try {
try {
SocketIO.setDefaultSSLSocketFactory(SSLContext.getDefault());
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
socket = new SocketIO();
socket.connect(sreverURL, new IOCallback() {
#Override
public void onMessage(JSONObject json, IOAcknowledge ack) {
}
#Override
public void onMessage(String data, IOAcknowledge ack) {
}
#Override
public void onError(SocketIOException socketIOException) {
socketIOException.printStackTrace();
}
#Override
public void onDisconnect() {
}
#Override
public void onConnect() {
showToast("Connected to " + sreverURL);
}
#Override
public void on(final String event, IOAcknowledge ack, final Object... args) {
Log.e("Socked.on", event + ", " + args);
switch (getEvent(event)) {
case LOG :
break;
case MESSAGE :
if (args instanceof Object[]) {
pc_events.setMessage(args[0].toString());
} else {
pc_events.setMessage(args.toString());
}
break;
case CREATED :
runOnUiThread(new Runnable() {
public void run() {
showToast("Room Created " + args[0]);
}
});
break;
case BROADCAST :
break;
case JOIN :
break;
case EMIT :
Log.e("Socked.onEMIT", args.toString());
startCall();
pc_events.createOffer();
break;
case ERROR :
Log.e("Socked.onERROR", args.toString());
break;
default :
break;
}
}
});
try {
RoomId = roomid.getText().toString();
} catch (Exception e) {
}
socket.emit("create or join", RoomId);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public void oncancel(View view) {
}
public SocketEvent getEvent(String eventString) {
SocketEvent eventType;
try {
if (eventString.contains("log")) {
eventType = SocketEvent.LOG;
} else if (eventString.contains("created")) {
eventType = SocketEvent.CREATED;
} else if (eventString.contains("emit():")) {
eventType = SocketEvent.EMIT;
}
else if (eventString.contains("broadcast():")) {
eventType = SocketEvent.BROADCAST;
} else if (eventString.contains("message")) {
eventType = SocketEvent.MESSAGE;
} else if (eventString.toLowerCase().substring(0, 20).contains("join")) {
eventType = SocketEvent.JOIN;
} else {
eventType = SocketEvent.ERROR;
}
} catch (Exception e) {
eventType = SocketEvent.ERROR;
}
return eventType;
}
public static interface Events {
public void peerConnectionEvent(VideoRenderer.Callbacks localRender, VideoRenderer.Callbacks remoteRender);
public void setFactory(PeerConnectionFactory factory);
public void setMessage(String message);
public void createOffer();
public void sendMessage(String msg);
}
private void startCall() {
pc_events.setFactory(factory);
pc_events.peerConnectionEvent(remote_view, local_view);
}
public void showToast(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(Home.this, message, Toast.LENGTH_SHORT).show();
}
});
}
public void makeOffer(View v) {
pc_events.sendMessage("Hello");
}
}
peerEventHandler.java
public class peerEventHandler implements Events {
private PeerConnection peerConnection;
private PeerConnectionFactory factory;
PCObserver pcObserver = new PCObserver();
public LooperExecutor executor;
private MediaStream mediaStream;
private VideoSource videoSource;
private DcObserver dc_observer;
public static final String VIDEO_TRACK_ID = "ARDAMSv0";
public static final String AUDIO_TRACK_ID = "ARDAMSa0";
private VideoCapturerAndroid videoCapturer;
private VideoTrack localVideoTrack;
private VideoTrack remoteVideoTrack;
public boolean preferIsac = false;
public boolean videoCallEnabled = true;
public boolean preferH264 = false;
private SessionDescription localSdp;
private final SDPObserver sdpObserver = new SDPObserver();
public boolean isInitiator = false;
private MediaConstraints sdpMediaConstraints;
private VideoRenderer.Callbacks remote_view;
private VideoRenderer.Callbacks local_view;
private DataChannel dataChannel;
#Override
public void peerConnectionEvent(Callbacks remoteRender, Callbacks localRender) {
this.remote_view = remoteRender;
this.local_view = localRender;
creatPeerConnection();
}
public void creatPeerConnection() {
executor = new LooperExecutor();
executor.requestStart();
MediaConstraints pcConstraints = new MediaConstraints();
MediaConstraints videoConstraints = new MediaConstraints();
MediaConstraints audioConstraints = new MediaConstraints();
sdpMediaConstraints = new MediaConstraints();
creatPcConstrains(pcConstraints);
creatvideoConstraints(videoConstraints);
creatsdpMediaConstraints(sdpMediaConstraints);
List<PeerConnection.IceServer> iceServers = new ArrayList<PeerConnection.IceServer>();
IceServer iceServer = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(iceServer);
PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED;
rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.BALANCED;
rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.NEGOTIATE;
peerConnection = factory.createPeerConnection(rtcConfig, pcConstraints, pcObserver);
Logging.enableTracing("logcat:", EnumSet.of(Logging.TraceLevel.TRACE_DEFAULT), Logging.Severity.LS_WARNING);
mediaStream = factory.createLocalMediaStream("ARDAMS");
String cameraDeviceName = CameraEnumerationAndroid.getDeviceName(0);
String frontCameraDeviceName = CameraEnumerationAndroid.getNameOfFrontFacingDevice();
cameraDeviceName = frontCameraDeviceName;
videoCapturer = VideoCapturerAndroid.create(cameraDeviceName, null);
videoSource = factory.createVideoSource(videoCapturer, videoConstraints);
localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
localVideoTrack.setEnabled(true);
localVideoTrack.addRenderer(new VideoRenderer(local_view));
mediaStream.addTrack(factory.createAudioTrack(AUDIO_TRACK_ID, factory.createAudioSource(audioConstraints)));
mediaStream.addTrack(localVideoTrack);
peerConnection.addStream(mediaStream);
dataChannel = peerConnection.createDataChannel("sendDataChannel", new DataChannel.Init());
dc_observer = new DcObserver();
dataChannel.registerObserver(dc_observer);
}
#Override
public void createOffer() {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection != null) {
isInitiator = true;
peerConnection.createOffer(sdpObserver, sdpMediaConstraints);
}
}
});
}
public void createAnswer() {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection != null) {
isInitiator = false;
peerConnection.createAnswer(sdpObserver, sdpMediaConstraints);
}
}
});
}
private class PCObserver implements PeerConnection.Observer {
#Override
public void onAddStream(final MediaStream stream) {
Log.e("onAddStream", "onAddStream");
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
if (stream.audioTracks.size() > 1 || stream.videoTracks.size() > 1) {
// /reportError("Weird-looking stream: " + stream);
return;
}
if (stream.videoTracks.size() == 1) {
remoteVideoTrack = stream.videoTracks.get(0);
remoteVideoTrack.setEnabled(true);
remoteVideoTrack.addRenderer(new VideoRenderer(remote_view));
VideoRendererGui.update(local_view, 75, 70, 60, 60, ScalingType.SCALE_ASPECT_FIT, true);
VideoRendererGui.update(remote_view, 0, 0, 200, 200, ScalingType.SCALE_ASPECT_FILL, false);
}
}
});
}
#Override
public void onDataChannel(final DataChannel dc) {
executor.execute(new Runnable() {
#Override
public void run() {
dataChannel = dc;
String channelName = dataChannel.label();
dataChannel.registerObserver(new DcObserver());
}
});
}
#Override
public void onIceCandidate(IceCandidate candidate) {
SocketIO socket = Home.socket;
JSONObject json = new JSONObject();
try {
json.putOpt("type", "candidate");
json.putOpt("label", candidate.sdpMLineIndex);
json.putOpt("id", candidate.sdpMid);
json.putOpt("candidate", candidate.sdp);
} catch (JSONException e) {
e.printStackTrace();
}
socket.emit("message", json);
}
#Override
public void onIceConnectionChange(IceConnectionState arg0) {
}
#Override
public void onIceConnectionReceivingChange(boolean arg0) {
}
#Override
public void onIceGatheringChange(IceGatheringState arg0) {
}
#Override
public void onRemoveStream(MediaStream arg0) {
}
#Override
public void onRenegotiationNeeded() {
}
#Override
public void onSignalingChange(SignalingState arg0) {
}
}
public void creatPcConstrains(MediaConstraints pcConstraints) {
pcConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(new KeyValuePair("RtpDataChannels", "true"));
pcConstraints.optional.add(new KeyValuePair("internalSctpDataChannels", "true"));
}
public void creatvideoConstraints(MediaConstraints videoConstraints) {
String MAX_VIDEO_WIDTH_CONSTRAINT = "maxWidth";
String MIN_VIDEO_WIDTH_CONSTRAINT = "minWidth";
String MAX_VIDEO_HEIGHT_CONSTRAINT = "maxHeight";
String MIN_VIDEO_HEIGHT_CONSTRAINT = "minHeight";
String MAX_VIDEO_FPS_CONSTRAINT = "maxFrameRate";
String MIN_VIDEO_FPS_CONSTRAINT = "minFrameRate";
int videoWidth = 0;
int videoHeight = 0;
if ((videoWidth == 0 || videoHeight == 0) && true && MediaCodecVideoEncoder.isVp8HwSupported()) {
videoWidth = 1280;
videoHeight = 1280;
}
if (videoWidth > 0 && videoHeight > 0) {
videoWidth = Math.min(videoWidth, 1280);
videoHeight = Math.min(videoHeight, 1280);
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
}
int videoFps = 30;
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
}
public void creataudioConstraints(MediaConstraints pcConstraints) {
pcConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(new KeyValuePair("RtpDataChannels", "true"));
pcConstraints.optional.add(new KeyValuePair("internalSctpDataChannels", "true"));
}
public void creatsdpMediaConstraints(MediaConstraints sdpMediaConstraints) {
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveAudio", "true"));
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveVideo", "true"));
}
private class SDPObserver implements SdpObserver {
#Override
public void onCreateFailure(String arg0) {
System.out.print(arg0);
}
#Override
public void onCreateSuccess(SessionDescription origSdp) {
if (localSdp != null) {
return;
}
localSdp = origSdp;
setLocalDescription(origSdp);
}
#Override
public void onSetFailure(String arg0) {
}
#Override
public void onSetSuccess() {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
if (isInitiator) {
if (peerConnection != null) {
JSONObject json = new JSONObject();
try {
json.putOpt("type", localSdp.type.toString().toLowerCase());
json.putOpt("sdp", localSdp.description);
} catch (JSONException e) {
e.printStackTrace();
}
Home.socket.emit("message", json);
}
} else {
// createAnswer();
}
}
});
}
}
public void addRemoteIceCandidate(final IceCandidate candidate) {
executor.execute(new Runnable() {
#Override
public void run() {
peerConnection.addIceCandidate(candidate);
}
});
}
public void setLocalDescription(final SessionDescription sdp) {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
peerConnection.setLocalDescription(sdpObserver, sdp);
}
});
}
public void setRemoteDescription(final SessionDescription sdp) {
executor.execute(new Runnable() {
#Override
public void run() {
if (peerConnection == null) {
return;
}
peerConnection.setRemoteDescription(sdpObserver, sdp);
}
});
}
#Override
public void setFactory(PeerConnectionFactory factory) {
this.factory = factory;
}
public void onWebSocketMessage(final String msg) {
try {
Log.e("onWebSocketMessage", msg);
JSONObject json = new JSONObject(msg);
json = new JSONObject(msg);
String type = json.optString("type");
if (type.equals("candidate")) {
IceCandidate candidate = new IceCandidate(json.getString("id"), json.getInt("label"), json.getString("candidate"));
addRemoteIceCandidate(candidate);
} else if (type.equals("answer")) {
isInitiator = false;
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else if (type.equals("offer")) {
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else if (type.equals("bye")) {
} else {
}
} catch (JSONException e) {
}
}
#Override
public void setMessage(String message) {
if (message.toString().contains("got user media") || message.toString().contains("bye")) {
} else
onWebSocketMessage(message);
}
private class DcObserver implements DataChannel.Observer {
#Override
public void onMessage(DataChannel.Buffer buffer) {
ByteBuffer data = buffer.data;
byte[] bytes = new byte[data.remaining()];
data.get(bytes);
String command = new String(bytes);
Log.e("onMessage ", command);
}
#Override
public void onStateChange() {
Log.e("onStateChange ", "onStateChange");
}
#Override
public void onBufferedAmountChange(long arg0) {
Log.e("onMessage ", "" + arg0);
}
}
#Override
public void sendMessage(String msg) {
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
boolean sent = dataChannel.send(new DataChannel.Buffer(buffer, false));
if (sent) {
Log.e("Message sent", "" + sent);
}
}
}