How to play ad before video through chromecast using IMA sdk? - android

i am developing a streaming app in which i have implemented chromecast functionality.Everything is working fine but the only issue is when a content video have pre roll ad then either ad is skipped and content video is played if we connected with chromecast or ad is locally played and after that content video is played through chromecast.My question is can we play both ad and content video through chromecast using IMA sdk because manually it is possible and i have done this but with IMA sdk there no luck.My code is as :
public class ClassChromeCast {
Context context;
public ClassChromeCast(Context ctx){
context = ctx;
}
/**
* Chromecast
* */
private static final String TAG = "MainActivity";
public MediaRouter mMediaRouter;
public static MediaRouteSelector mMediaRouteSelector;
public MediaRouter.Callback mMediaRouterCallback;
private CastDevice mSelectedDevice;
private GoogleApiClient mApiClient;
private RemoteMediaPlayer mRemoteMediaPlayer;
private Cast.Listener mCastClientListener;
public static boolean mIsPlaying,mIsFinished,mApplicationStarted = false,mVideoIsLoaded,isConnected = false;
private boolean mWaitingForReconnect = false,temp = false,temp2 = false;
/**
* Local variable
*/
private static String videoUrl = "",videoTitle = "" ,videoAdUrl = "";
private RSSFeed_Addsplay rssFeed_AddsplayObj;
/*======================Chromecast=======================*/
public void initMediaRouter() {
// Configure Cast device discovery
mMediaRouter = MediaRouter.getInstance(context);
mMediaRouteSelector = new MediaRouteSelector.Builder()
.addControlCategory( CastMediaControlIntent.categoryForCast( context.getString( R.string.app_id ) ) )
.build();
mMediaRouterCallback = new MediaRouterCallback();
}
/**inner class MediaRouterCallback **/
private class MediaRouterCallback extends MediaRouter.Callback {
#Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
Log.d(TAG, "onRouteSelected");
initCastClientListener();
initRemoteMediaPlayer();
mSelectedDevice = CastDevice.getFromBundle( info.getExtras() );
launchReceiver();
}
#Override
public void onRouteUnselected( MediaRouter router, MediaRouter.RouteInfo info ) {
Log.d(TAG, "onRouteUnselected");
//teardown();
mSelectedDevice = null;
//isConnected = false;
//mVideoIsLoaded = false;
}
}
/**---------------to initialize CastClientListener---------------*/
private void initCastClientListener() {
mCastClientListener = new Cast.Listener() {
#Override
public void onApplicationStatusChanged() {
Log.d(TAG, "onApplicationStatusChanged");
}
#Override
public void onVolumeChanged() {
Log.d(TAG, "onVolumeChanged");
}
#Override
public void onApplicationDisconnected( int statusCode ) {
Log.d(TAG, "onApplicationDisconnected");
teardown();
}
};
}
/**---------------to initialize RemoteMediaPlayer---------------*/
private void initRemoteMediaPlayer() {
mRemoteMediaPlayer = new RemoteMediaPlayer();
mRemoteMediaPlayer.setOnStatusUpdatedListener( new RemoteMediaPlayer.OnStatusUpdatedListener() {
#Override
public void onStatusUpdated() {
try{
MediaStatus mediaStatus = mRemoteMediaPlayer.getMediaStatus();
mIsPlaying = mediaStatus.getPlayerState() == MediaStatus.PLAYER_STATE_PLAYING;
mIsFinished = mediaStatus.getPlayerState() == MediaStatus.PLAYER_STATE_IDLE;
Log.d(TAG,"IsPlaying==="+mIsPlaying+"IsFinished===="+mIsFinished);
if(mIsFinished && temp && !temp2){
//temp = false;
Log.e("startVideo2","===");
startVideo(videoUrl,videoTitle);
temp2 = true;
}
if(mIsPlaying){
temp = true;
}
}catch (Exception e){
e.printStackTrace();
}
}
});
mRemoteMediaPlayer.setOnMetadataUpdatedListener( new RemoteMediaPlayer.OnMetadataUpdatedListener() {
#Override
public void onMetadataUpdated() {
Log.d(TAG,"====mIsFinished");
}
});
}
private void launchReceiver() {
Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions
.builder( mSelectedDevice, mCastClientListener );
GoogleApiClient.ConnectionCallbacks mConnectionCallbacks = new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.d(TAG,"Connected");
isConnected = true;
if( mWaitingForReconnect ) {
mWaitingForReconnect = false;
reconnectChannels( bundle );
} else {
try {
Cast.CastApi.launchApplication(mApiClient,context.getString(R.string.app_id), false)
.setResultCallback(new ResultCallback<Cast.ApplicationConnectionResult>() {
#Override
public void onResult(Cast.ApplicationConnectionResult applicationConnectionResult) {
Status status = applicationConnectionResult.getStatus();
if (status.isSuccess()) {
mApplicationStarted = true;
reconnectChannels(null);
}
}
}
);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG,"onConnectionSuspended");
isConnected = false;
mWaitingForReconnect = true;
}
};
GoogleApiClient.OnConnectionFailedListener mConnectionFailedListener = new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed");
isConnected = false;
teardown();
}
};
mApiClient = new GoogleApiClient.Builder(context)
.addApi( Cast.API, apiOptionsBuilder.build() )
.addConnectionCallbacks( mConnectionCallbacks )
.addOnConnectionFailedListener( mConnectionFailedListener )
.build();
mApiClient.connect();
}
private void reconnectChannels( Bundle hint ) {
if( ( hint != null ) && hint.getBoolean( Cast.EXTRA_APP_NO_LONGER_RUNNING ) ) {
Log.e( TAG, "App is no longer running" );
Log.d(TAG, "reconnectChannels");
teardown();
} else {
try {
Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer );
} catch( IOException e ) {
Log.e( TAG, "Exception while creating media channel ", e );
} catch( NullPointerException e ) {
Log.e( TAG, "Something wasn't reinitialized for reconnectChannels" );
}catch (IllegalStateException e){
e.printStackTrace();
}
}
}
public void teardown() {
if( mApiClient != null ) {
if( mApplicationStarted ){
try {
Cast.CastApi.stopApplication( mApiClient );
if( mRemoteMediaPlayer != null ) {
Cast.CastApi.removeMessageReceivedCallbacks( mApiClient, mRemoteMediaPlayer.getNamespace() );
mRemoteMediaPlayer = null;
}
} catch( Exception e ) {
Log.e( TAG, "Exception while removing application " + e );
}
mApplicationStarted = false;
}
if( mApiClient.isConnected() )
mApiClient.disconnect();
mApiClient = null;
}
mSelectedDevice = null;
mVideoIsLoaded = false;
}
/**----to play video remotely-----*/
public void playOnRemoteMediaPlayer(String title,String url, String adUrl){
Log.e("OnRemoteMediaPlayer","adUrl=="+adUrl);
try{
rssFeed_AddsplayObj = new RSSFeed_Addsplay(adUrl + System.currentTimeMillis());
videoAdUrl = rssFeed_AddsplayObj.getAdUrl();
}catch (Exception e){
videoAdUrl = "";
}
if(!mVideoIsLoaded && !videoUrl.equals(url)){
videoUrl = url;
videoTitle = title;
temp2 = false;
temp = false;
if (videoAdUrl != null && videoAdUrl.length() > 0){
Log.e("IF","===");
startVideo(videoAdUrl,"Your program begin after this ad break");
} else {
Log.e("ELSE","===");
startVideo(videoUrl,videoTitle);
}
//playPauseBtn.setImageResource(R.drawable.ic_av_pause_over_video_large);
} else {
controlVideo(videoUrl,videoTitle);
if(mIsPlaying){
//playPauseBtn.setImageResource(R.drawable.ic_av_play_over_video_large);
}else {
//playPauseBtn.setImageResource(R.drawable.ic_av_pause_over_video_large);
}
}
}
private void startVideo(String url, String s) {
Log.e(TAG,"===startVideo"+url);
TVE_HomeActivity.tvVideoLoadingText.setText(context.getString(R.string.playtext));
MediaMetadata mediaMetadata = new MediaMetadata( MediaMetadata.MEDIA_TYPE_MOVIE );
mediaMetadata.putString( MediaMetadata.KEY_TITLE,s);
MediaInfo mediaInfo = new MediaInfo.Builder(url)
.setContentType("video/mp4")
.setStreamType( MediaInfo.STREAM_TYPE_BUFFERED )
.setMetadata( mediaMetadata )
.build();
try {
mRemoteMediaPlayer.load( mApiClient, mediaInfo, true )
.setResultCallback( new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
#Override
public void onResult( RemoteMediaPlayer.MediaChannelResult mediaChannelResult ) {
if( mediaChannelResult.getStatus().isSuccess() ) {
mVideoIsLoaded = true;
}
}
});
} catch( Exception e ) {
isConnected = false;
e.printStackTrace();
}
}
private void controlVideo(String url, String title) {
TVE_HomeActivity.tvVideoLoadingText.setText(context.getString(R.string.pausetext));
try{
if( mRemoteMediaPlayer == null || !mVideoIsLoaded )
return;
if( mIsPlaying ) {
mRemoteMediaPlayer.pause( mApiClient );
} else if(mIsFinished){
Log.d(TAG,"Finished===true");
startVideo(url,title);
} else {
mRemoteMediaPlayer.play( mApiClient );
}
Log.d(TAG,"running==="+mIsFinished);
}catch (Exception e){
e.printStackTrace();
}
}
}

Related

Android Design: Intentservice causing application not responding

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.

waitingInMainSignalCatcherLoop,Thread*=0x72c22ee000,peer=0x12d00280,"Signal Catcher"]: reacting to signal 3

Good day everyone, I would like to ask, hat is the cause of that ANR?. In my project I have service which is binded in a activity. Now when I exit in that activity the app is hang for a moment. My thought is that the service is still running though I unbind it in onStop() of the activity.
Here is my service class
public class SpeechService extends Service {
public interface Listener {
/**
* Called when a new piece of text was recognized by the Speech API.
*
* #param text The text.
* #param isFinal {#code true} when the API finished processing audio.
*/
void onSpeechRecognized(String text, boolean isFinal);
}
private static final String TAG = "SpeechService";
private static final String PREFS = "SpeechService";
private static final String PREF_ACCESS_TOKEN_VALUE = "access_token_value";
private static final String PREF_ACCESS_TOKEN_EXPIRATION_TIME = "access_token_expiration_time";
/** We reuse an access token if its expiration time is longer than this. */
private static final int ACCESS_TOKEN_EXPIRATION_TOLERANCE = 30 * 60 * 1000; // thirty minutes
/** We refresh the current access token before it expires. */
private static final int ACCESS_TOKEN_FETCH_MARGIN = 60 * 1000; // one minute
public static final List<String> SCOPE =
Collections.singletonList("https://www.googleapis.com/auth/cloud-platform");
private static final String HOSTNAME = "speech.googleapis.com";
private static final int PORT = 443;
private final SpeechBinder mBinder = new SpeechBinder();
private final ArrayList<Listener> mListeners = new ArrayList<>();
private volatile AccessTokenTask mAccessTokenTask;
private SpeechGrpc.SpeechStub mApi;
private static Handler mHandler;
private final StreamObserver<StreamingRecognizeResponse> mResponseObserver
= new StreamObserver<StreamingRecognizeResponse>() {
#Override
public void onNext(StreamingRecognizeResponse response) {
String text = null;
boolean isFinal = false;
if (response.getResultsCount() > 0) {
final StreamingRecognitionResult result = response.getResults(0);
isFinal = result.getIsFinal();
if (result.getAlternativesCount() > 0) {
final SpeechRecognitionAlternative alternative = result.getAlternatives(0);
text = alternative.getTranscript();
}
}
if (text != null) {
for (Listener listener : mListeners) {
listener.onSpeechRecognized(text, isFinal);
}
}
}
#Override
public void onError(Throwable t) {
Log.e(TAG, "Error calling the API.", t);
}
#Override
public void onCompleted() {
Log.i(TAG, "API completed.");
}
};
private final StreamObserver<RecognizeResponse> mFileResponseObserver
= new StreamObserver<RecognizeResponse>() {
#Override
public void onNext(RecognizeResponse response) {
String text = null;
if (response.getResultsCount() > 0) {
final SpeechRecognitionResult result = response.getResults(0);
if (result.getAlternativesCount() > 0) {
final SpeechRecognitionAlternative alternative = result.getAlternatives(0);
text = alternative.getTranscript();
}
}
if (text != null) {
for (Listener listener : mListeners) {
listener.onSpeechRecognized(text, true);
}
}
}
#Override
public void onError(Throwable t) {
Log.e(TAG, "Error calling the API.", t);
}
#Override
public void onCompleted() {
Log.i(TAG, "API completed.");
}
};
private StreamObserver<StreamingRecognizeRequest> mRequestObserver;
public static SpeechService from(IBinder binder) {
return ((SpeechBinder) binder).getService();
}
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
fetchAccessToken();
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mFetchAccessTokenRunnable);
mHandler = null;
// Release the gRPC channel.
if (mApi != null) {
final ManagedChannel channel = (ManagedChannel) mApi.getChannel();
if (channel != null && !channel.isShutdown()) {
try {
channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Log.e(TAG, "Error shutting down the gRPC channel.", e);
}
}
mApi = null;
}
}
private void fetchAccessToken() {
if (mAccessTokenTask != null) {
return;
}
mAccessTokenTask = new AccessTokenTask();
mAccessTokenTask.execute();
}
private String getDefaultLanguageCode() {
final Locale locale = Locale.getDefault();
final StringBuilder language = new StringBuilder(locale.getLanguage());
final String country = locale.getCountry();
if (!TextUtils.isEmpty(country)) {
language.append("-");
language.append(country);
}
return language.toString();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void addListener(#NonNull Listener listener) {
mListeners.add(listener);
}
public void removeListener(#NonNull Listener listener) {
mListeners.remove(listener);
}
/**
* Starts recognizing speech audio.
*
* #param sampleRate The sample rate of the audio.
*/
public void startRecognizing(int sampleRate) {
if (mApi == null) {
Log.w(TAG, "API not ready. Ignoring the request.");
return;
}
// Configure the API
mRequestObserver = mApi.streamingRecognize(mResponseObserver);
mRequestObserver.onNext(StreamingRecognizeRequest.newBuilder()
.setStreamingConfig(StreamingRecognitionConfig.newBuilder()
.setConfig(RecognitionConfig.newBuilder()
.setLanguageCode(getDefaultLanguageCode())
.setEncoding(RecognitionConfig.AudioEncoding.LINEAR16)
.setSampleRateHertz(sampleRate)
.build())
.setInterimResults(true)
.setSingleUtterance(true)
.build())
.build());
}
/**
* Recognizes the speech audio. This method should be called every time a chunk of byte buffer
* is ready.
*
* #param data The audio data.
* #param size The number of elements that are actually relevant in the {#code data}.
*/
public void recognize(byte[] data, int size) {
if (mRequestObserver == null) {
return;
}
// Call the streaming recognition API
mRequestObserver.onNext(StreamingRecognizeRequest.newBuilder()
.setAudioContent(ByteString.copyFrom(data, 0, size))
.build());
}
/**
* Finishes recognizing speech audio.
*/
public void finishRecognizing() {
if (mRequestObserver == null) {
return;
}
mRequestObserver.onCompleted();
mRequestObserver = null;
}
/**
* Recognize all data from the specified {#link InputStream}.
*
* #param stream The audio data.
*/
public void recognizeInputStream(InputStream stream) {
try {
mApi.recognize(
RecognizeRequest.newBuilder()
.setConfig(RecognitionConfig.newBuilder()
.setEncoding(RecognitionConfig.AudioEncoding.LINEAR16)
.setLanguageCode("en-US")
.setSampleRateHertz(16000)
.build())
.setAudio(RecognitionAudio.newBuilder()
.setContent(ByteString.readFrom(stream))
.build())
.build(),
mFileResponseObserver);
} catch (IOException e) {
Log.e(TAG, "Error loading the input", e);
}
}
private class SpeechBinder extends Binder {
SpeechService getService() {
return SpeechService.this;
}
}
private final Runnable mFetchAccessTokenRunnable = new Runnable() {
#Override
public void run() {
fetchAccessToken();
}
};
private class AccessTokenTask extends AsyncTask<Void, Void, AccessToken> {
#Override
protected AccessToken doInBackground(Void... voids) {
final SharedPreferences prefs =
getSharedPreferences(PREFS, Context.MODE_PRIVATE);
String tokenValue = prefs.getString(PREF_ACCESS_TOKEN_VALUE, null);
long expirationTime = prefs.getLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, -1);
// Check if the current token is still valid for a while
if (tokenValue != null && expirationTime > 0) {
if (expirationTime
> System.currentTimeMillis() + ACCESS_TOKEN_EXPIRATION_TOLERANCE) {
return new AccessToken(tokenValue, new Date(expirationTime));
}
}
// ***** WARNING *****
// In this sample, we load the credential from a JSON file stored in a raw resource
// folder of this client app. You should never do this in your app. Instead, store
// the file in your server and obtain an access token from there.
// *******************
final InputStream stream = getResources().openRawResource(R.raw.credential);
try {
final GoogleCredentials credentials = GoogleCredentials.fromStream(stream)
.createScoped(SCOPE);
final AccessToken token = credentials.refreshAccessToken();
prefs.edit()
.putString(PREF_ACCESS_TOKEN_VALUE, token.getTokenValue())
.putLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME,
token.getExpirationTime().getTime())
.apply();
return token;
} catch (IOException e) {
Log.e(TAG, "Failed to obtain access token.", e);
}
return null;
}
#Override
protected void onPostExecute(AccessToken accessToken) {
mAccessTokenTask = null;
final ManagedChannel channel = new OkHttpChannelProvider()
.builderForAddress(HOSTNAME, PORT)
.nameResolverFactory(new DnsNameResolverProvider())
.intercept(new GoogleCredentialsInterceptor(new GoogleCredentials(accessToken)
.createScoped(SCOPE)))
.build();
mApi = SpeechGrpc.newStub(channel);
// Schedule access token refresh before it expires
if (mHandler != null) {
mHandler.postDelayed(mFetchAccessTokenRunnable,
Math.max(accessToken.getExpirationTime().getTime()
- System.currentTimeMillis()
- ACCESS_TOKEN_FETCH_MARGIN, ACCESS_TOKEN_EXPIRATION_TOLERANCE));
}
}
}
/**
* Authenticates the gRPC channel using the specified {#link GoogleCredentials}.
*/
private static class GoogleCredentialsInterceptor implements ClientInterceptor {
private final Credentials mCredentials;
private Metadata mCached;
private Map<String, List<String>> mLastMetadata;
GoogleCredentialsInterceptor(Credentials credentials) {
mCredentials = credentials;
}
#Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
final MethodDescriptor<ReqT, RespT> method, CallOptions callOptions,
final Channel next) {
return new ClientInterceptors.CheckedForwardingClientCall<ReqT, RespT>(
next.newCall(method, callOptions)) {
#Override
protected void checkedStart(Listener<RespT> responseListener, Metadata headers)
throws StatusException {
Metadata cachedSaved;
URI uri = serviceUri(next, method);
synchronized (this) {
Map<String, List<String>> latestMetadata = getRequestMetadata(uri);
if (mLastMetadata == null || mLastMetadata != latestMetadata) {
mLastMetadata = latestMetadata;
mCached = toHeaders(mLastMetadata);
}
cachedSaved = mCached;
}
headers.merge(cachedSaved);
delegate().start(responseListener, headers);
}
};
}
/**
* Generate a JWT-specific service URI. The URI is simply an identifier with enough
* information for a service to know that the JWT was intended for it. The URI will
* commonly be verified with a simple string equality check.
*/
private URI serviceUri(Channel channel, MethodDescriptor<?, ?> method)
throws StatusException {
String authority = channel.authority();
if (authority == null) {
throw Status.UNAUTHENTICATED
.withDescription("Channel has no authority")
.asException();
}
// Always use HTTPS, by definition.
final String scheme = "https";
final int defaultPort = 443;
String path = "/" + MethodDescriptor.extractFullServiceName(method.getFullMethodName());
URI uri;
try {
uri = new URI(scheme, authority, path, null, null);
} catch (URISyntaxException e) {
throw Status.UNAUTHENTICATED
.withDescription("Unable to construct service URI for auth")
.withCause(e).asException();
}
// The default port must not be present. Alternative ports should be present.
if (uri.getPort() == defaultPort) {
uri = removePort(uri);
}
return uri;
}
private URI removePort(URI uri) throws StatusException {
try {
return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), -1 /* port */,
uri.getPath(), uri.getQuery(), uri.getFragment());
} catch (URISyntaxException e) {
throw Status.UNAUTHENTICATED
.withDescription("Unable to construct service URI after removing port")
.withCause(e).asException();
}
}
private Map<String, List<String>> getRequestMetadata(URI uri) throws StatusException {
try {
return mCredentials.getRequestMetadata(uri);
} catch (IOException e) {
throw Status.UNAUTHENTICATED.withCause(e).asException();
}
}
private static Metadata toHeaders(Map<String, List<String>> metadata) {
Metadata headers = new Metadata();
if (metadata != null) {
for (String key : metadata.keySet()) {
Metadata.Key<String> headerKey = Metadata.Key.of(
key, Metadata.ASCII_STRING_MARSHALLER);
for (String value : metadata.get(key)) {
headers.put(headerKey, value);
}
}
}
return headers;
}
}
}
and here is my activity class
public class MainActivity extends AppCompatActivity implements MessageDialogFragment.Listener {
private static final String FRAGMENT_MESSAGE_DIALOG = "message_dialog";
private static final String STATE_RESULTS = "results";
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
private SpeechService mSpeechService;
private VoiceRecorder mVoiceRecorder;
private final VoiceRecorder.Callback mVoiceCallback = new VoiceRecorder.Callback() {
#Override
public void onVoiceStart() {
showStatus(true);
if (mSpeechService != null) {
mSpeechService.startRecognizing(mVoiceRecorder.getSampleRate());
}
}
#Override
public void onVoice(byte[] data, int size) {
if (mSpeechService != null) {
mSpeechService.recognize(data, size);
}
}
#Override
public void onVoiceEnd() {
showStatus(false);
if (mSpeechService != null) {
mSpeechService.finishRecognizing();
}
}
};
// Resource caches
private int mColorHearing;
private int mColorNotHearing;
// View references
private TextView mStatus;
private TextView mText, mResult;
private Button editButton, clearButton;
private SharedPreferences settings;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
mSpeechService = SpeechService.from(binder);
mSpeechService.addListener(mSpeechServiceListener);
mStatus.setVisibility(View.VISIBLE);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mSpeechService = null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
final Resources resources = getResources();
final Resources.Theme theme = getTheme();
mColorHearing = ResourcesCompat.getColor(resources, R.color.status_hearing, theme);
mColorNotHearing = ResourcesCompat.getColor(resources, R.color.status_not_hearing, theme);
mStatus = (TextView) findViewById(R.id.status);
mText = (TextView) findViewById(R.id.text);
mResult = (TextView) findViewById(R.id.resultText);
editButton = (Button)findViewById(R.id.button1);
clearButton = (Button)findViewById(R.id.button2);
settings = getSharedPreferences("MyPreference", Context.MODE_PRIVATE);
clearButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Sounds sounds = new Sounds(getApplicationContext());
if(settings.getBoolean("muteAble", false ) == true){
sounds.playSound();
}
mResult.setText("");
}
});
editButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Sounds sounds = new Sounds(getApplicationContext());
if(settings.getBoolean("muteAble", false ) == true){
sounds.playSound();
}
Intent editIntent = new Intent(MainActivity.this, EditorActivity.class);
String forEditText = mResult.getText().toString();
editIntent.putExtra("forEdit", forEditText);
startActivity(editIntent);
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home){
this.finish();
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onStart() {
super.onStart();
// Prepare Cloud Speech API
bindService(new Intent(this, SpeechService.class), mServiceConnection, BIND_AUTO_CREATE);
// Start listening to voices
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_GRANTED) {
startVoiceRecorder();
} else if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.RECORD_AUDIO)) {
showPermissionMessageDialog();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_RECORD_AUDIO_PERMISSION);
}
}
#Override
protected void onStop() {
// Stop listening to voice
stopVoiceRecorder();
// Stop Cloud Speech API
mSpeechService.removeListener(mSpeechServiceListener);
unbindService(mServiceConnection);
mSpeechService = null;
super.onStop();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode == REQUEST_RECORD_AUDIO_PERMISSION) {
if (permissions.length == 1 && grantResults.length == 1
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startVoiceRecorder();
} else {
showPermissionMessageDialog();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void startVoiceRecorder() {
if (mVoiceRecorder != null) {
mVoiceRecorder.stop();
}
mVoiceRecorder = new VoiceRecorder(mVoiceCallback);
mVoiceRecorder.start();
}
private void stopVoiceRecorder() {
if (mVoiceRecorder != null) {
mVoiceRecorder.stop();
mVoiceRecorder = null;
}
}
private void showPermissionMessageDialog() {
MessageDialogFragment
.newInstance(getString(R.string.permission_message))
.show(getSupportFragmentManager(), FRAGMENT_MESSAGE_DIALOG);
}
private void showStatus(final boolean hearingVoice) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mStatus.setTextColor(hearingVoice ? mColorHearing : mColorNotHearing);
}
});
}
#Override
public void onMessageDialogDismissed() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_RECORD_AUDIO_PERMISSION);
}
private final SpeechService.Listener mSpeechServiceListener =
new SpeechService.Listener() {
#Override
public void onSpeechRecognized(final String text, final boolean isFinal) {
if (isFinal) {
mVoiceRecorder.dismiss();
}
if (mText != null && !TextUtils.isEmpty(text)) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (isFinal) {
mText.setText(null);
mResult.append(" "+text.toString());
} else {
mText.setText(text);
}
}
});
}
}
};
}
Thank in advance for your help

Register a new user on ejabberd server in android

I am facing the problem to create a new user on ejabberd server but sign in is working fine. i used the github repository (https://github.com/dilicode/LetsChat) for register the new user and chat between two and more users. I search on intenet, i found some way to register those are:
1.add
%% In-band registration
{access, register, [{allow, all}]}.
in access rules in ejabberd server and
2. also add
{mod_register, [
{access_from, register},
...
] ...
it in access rules of ejabberd server.
my sign up activity as follows:
public class SignupActivity extends AppCompatActivity implements OnClickListener, Listener<Boolean> {
private static final int REQUEST_CODE_SELECT_PICTURE = 1;
private static final int REQUEST_CODE_CROP_IMAGE = 2;
private static final String RAW_PHOTO_FILE_NAME = "camera.png";
private static final String AVATAR_FILE_NAME = "avatar.png";
private EditText nameText;
private EditText phoneNumberText;
private EditText passwordText;
private Button submitButton;
private ImageButton uploadAvatarButton;
private File rawImageFile;
private File avatarImageFile;
private SignupTask signupTask;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signup);
nameText = (EditText)findViewById(R.id.et_name);
phoneNumberText = (EditText)findViewById(R.id.et_phone_number);
passwordText = (EditText)findViewById(R.id.et_password);
uploadAvatarButton = (ImageButton)findViewById(R.id.btn_upload_avatar);
submitButton = (Button)findViewById(R.id.btn_submit);
submitButton.setOnClickListener(this);
uploadAvatarButton.setOnClickListener(this);
File dir = FileUtils.getDiskCacheDir(this, "temp");
if (!dir.exists()) {
dir.mkdirs();
}
rawImageFile = new File(dir, RAW_PHOTO_FILE_NAME);
avatarImageFile = new File(dir, AVATAR_FILE_NAME);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onClick(View v) {
if (v == submitButton) {
String phoneNumber = phoneNumberText.getText().toString();
String password = passwordText.getText().toString();
String name = nameText.getText().toString();
if (phoneNumber.trim().length() == 0 || password.trim().length() == 0 ||
name.trim().length() == 0) {
Toast.makeText(this, R.string.incomplete_signup_info, Toast.LENGTH_SHORT).show();
return;
}
signupTask = new SignupTask(this, this, phoneNumber, password, name, getAvatarBytes());
signupTask.execute();
} else if(v == uploadAvatarButton) {
chooseAction();
}
}
private void chooseAction() {
Intent captureImageIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
captureImageIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(rawImageFile));
Intent pickIntent = new Intent(Intent.ACTION_GET_CONTENT);
pickIntent.setType("image/*");
Intent chooserIntent = Intent.createChooser(pickIntent, getString(R.string.profile_photo));
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] {captureImageIntent});
startActivityForResult(chooserIntent, REQUEST_CODE_SELECT_PICTURE);
}
#Override
public void onResponse(Boolean result) {
if (result) {
Toast.makeText(this, R.string.login_success, Toast.LENGTH_SHORT).show();
startActivity(new Intent(this, MainActivity.class));
setResult(RESULT_OK);
finish();
}
}
#Override
public void onErrorResponse(Exception exception) {
Toast.makeText(this, R.string.create_account_error, Toast.LENGTH_SHORT).show();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_CODE_SELECT_PICTURE:
boolean isCamera;
if (data == null) {
isCamera = true;
} else {
String action = data.getAction();
if (action == null) {
isCamera = false;
} else {
isCamera = action.equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
}
}
if (isCamera) {
startCropImage(Uri.fromFile(rawImageFile));
} else {
startCropImage(data == null ? null : data.getData());
}
break;
case REQUEST_CODE_CROP_IMAGE:
Bitmap bitmap = BitmapFactory.decodeFile(avatarImageFile.getAbsolutePath());
RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(getResources(), bitmap);
drawable.setCircular(true);
uploadAvatarButton.setImageDrawable(drawable);
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void startCropImage(Uri source) {
if (source != null) {
int size = getResources().getDimensionPixelSize(R.dimen.default_avatar_size);
CropImageIntentBuilder cropImage = new CropImageIntentBuilder(size, size, Uri.fromFile(avatarImageFile));
cropImage.setSourceImage(source);
startActivityForResult(cropImage.getIntent(this), REQUEST_CODE_CROP_IMAGE);
}
}
private byte[] getAvatarBytes() {
if (!avatarImageFile.exists()) return null;
InputStream inputStream = null;
try {
inputStream = new FileInputStream(avatarImageFile);
} catch (FileNotFoundException e) {
AppLog.e("avatar file not found", e);
}
byte[] buffer = new byte[1024];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
while ((bytesRead = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
return output.toByteArray();
}
#Override
protected void onDestroy() {
super.onDestroy();
if (signupTask != null) {
signupTask.dismissDialogAndCancel();
}
}
}
SignupTaskActivity as follows:
public class SignupTask extends BaseAsyncTask<Void, Void, Boolean> {
private String user;
private String name;
private String password;
private byte[] avatar;
private ProgressDialog dialog;
public SignupTask(Listener<Boolean> listener, Context context, String user, String password, String name, byte[] avatar) {
super(listener, context);
this.user = user;
this.name = name;
this.password = password;
this.avatar = avatar;
dialog = ProgressDialog.show(context, null, context.getResources().getString(R.string.signup));
}
#Override
public Response<Boolean> doInBackground(Void... params) {
Context context = getContext();
if (context != null) {
try {
SmackHelper.getInstance(context).signupAndLogin(user, password, name, avatar);
if (avatar != null) {
ImageCache.addAvatarToFile(context, user, BitmapFactory.decodeByteArray(avatar, 0, avatar.length));
}
PreferenceUtils.setLoginUser(context, user, password, name);
return Response.success(true);
} catch(SmackInvocationException e) {
AppLog.e(String.format("sign up error %s", e.toString()), e);
return Response.error(e);
}
}
return null;
}
#Override
protected void onPostExecute(Response<Boolean> response) {
dismissDialog();
super.onPostExecute(response);
}
#Override
protected void onCancelled() {
super.onCancelled();
dismissDialog();
}
public void dismissDialog() {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}
public void dismissDialogAndCancel() {
dismissDialog();
cancel(false);
}
}
SmackHelper class as follows:
public class SmackHelper {
private static final String LOG_TAG = "SmackHelper";
private static final int PORT = 5222;
public static final String RESOURCE_PART = "Smack";
private XMPPConnection con;
private ConnectionListener connectionListener;
private Context context;
private State state;
private PacketListener messagePacketListener;
private PacketListener presencePacketListener;
private SmackAndroid smackAndroid;
private static SmackHelper instance;
private SmackContactHelper contactHelper;
private SmackVCardHelper vCardHelper;
private FileTransferManager fileTransferManager;
private PingManager pingManager;
private long lastPing = new Date().getTime();
public static final String ACTION_CONNECTION_CHANGED = "com.mstr.letschat.intent.action.CONNECTION_CHANGED";
public static final String EXTRA_NAME_STATE = "com.mstr.letschat.State";
private SmackHelper(Context context) {
this.context = context;
smackAndroid = SmackAndroid.init(context);
messagePacketListener = new MessagePacketListener(context);
presencePacketListener = new PresencePacketListener(context);
SmackConfiguration.setDefaultPacketReplyTimeout(20 * 1000);
Roster.setDefaultSubscriptionMode(SubscriptionMode.manual);
ProviderManager.addExtensionProvider(UserLocation.ELEMENT_NAME, UserLocation.NAMESPACE, new LocationMessageProvider());
}
public static synchronized SmackHelper getInstance(Context context) {
if (instance == null) {
instance = new SmackHelper(context.getApplicationContext());
}
return instance;
}
public void setState(State state) {
if (this.state != state) {
Log.d(LOG_TAG, "enter state: " + state.name());
this.state = state;
}
}
public void signupAndLogin(String user, String password, String nickname, byte[] avatar) throws SmackInvocationException {
connect();
Map<String, String> attributes = new HashMap<String, String>();
attributes.put("name", nickname);
try {
AccountManager.getInstance(con).createAccount(user, password, attributes);
} catch (Exception e) {
throw new SmackInvocationException(e);
}
login(user, password);
vCardHelper.save(nickname, avatar);
}
public void sendChatMessage(String to, String body, PacketExtension packetExtension) throws SmackInvocationException {
Message message = new Message(to, Message.Type.chat);
message.setBody(body);
if (packetExtension != null) {
message.addExtension(packetExtension);
}
try {
con.sendPacket(message);
} catch (NotConnectedException e) {
throw new SmackInvocationException(e);
}
}
public List<RosterEntry> getRosterEntries() {
List<RosterEntry> result = new ArrayList<RosterEntry>();
Roster roster = con.getRoster();
Collection<RosterGroup> groups = roster.getGroups();
for (RosterGroup group : groups) {
result.addAll(group.getEntries());
}
return result;
}
and finally my menifest file
public UserProfile search(String username) throws SmackInvocationException {
String name = StringUtils.parseName(username);
String jid = null;
if (name == null || name.trim().length() == 0) {
jid = username + "#" + con.getServiceName();
} else {
jid = StringUtils.parseBareAddress(username);
}
if (vCardHelper == null) {
return null;
}
VCard vCard = vCardHelper.loadVCard(jid);
String nickname = vCard.getNickName();
return nickname == null ? null : new UserProfile(jid, vCard);
}
public String getNickname(String jid) throws SmackInvocationException {
VCard vCard = vCardHelper.loadVCard(jid);
return vCard.getNickName();
}
private void connect() throws SmackInvocationException {
if (!isConnected()) {
setState(State.CONNECTING);
if (con == null) {
con = createConnection();
}
try {
con.connect();
}catch (SmackException.NoResponseException er){
Log.e(LOG_TAG,"Norespponse exception");
}
catch(Exception e) {
Log.e(LOG_TAG, String.format("Unhandled exception %s", e.toString()), e);
startReconnectIfNecessary();
throw new SmackInvocationException(e);
}
}
}
#SuppressLint("TrulyRandom")
private XMPPConnection createConnection() {
ConnectionConfiguration config = new ConnectionConfiguration(PreferenceUtils.getServerHost(context), PORT);
SSLContext sc = null;
MemorizingTrustManager mtm = null;
try {
mtm = new MemorizingTrustManager(context);
sc = SSLContext.getInstance("TLS");
sc.init(null, new X509TrustManager[] { mtm }, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
} catch (KeyManagementException e) {
throw new IllegalStateException(e);
}
config.setCustomSSLContext(sc);
config.setHostnameVerifier(mtm.wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier()));
config.setSecurityMode(SecurityMode.required);
config.setReconnectionAllowed(false);
config.setSendPresence(false);
config.setSecurityMode(SecurityMode.disabled);
List<HostAddress> list = config.getHostAddresses();
boolean data = config.isSendPresence();
return new XMPPTCPConnection(config);
}
public void cleanupConnection() {
if (con != null) {
con.removePacketListener(messagePacketListener);
con.removePacketListener(presencePacketListener);
if (connectionListener != null) {
con.removeConnectionListener(connectionListener);
}
}
if (isConnected()) {
try {
con.disconnect();
} catch (NotConnectedException e) {}
}
}
private void onConnectionEstablished() {
if (state != State.CONNECTED) {
//processOfflineMessages();
try {
con.sendPacket(new Presence(Presence.Type.available));
} catch (NotConnectedException e) {}
contactHelper = new SmackContactHelper(context, con);
vCardHelper = new SmackVCardHelper(context, con);
fileTransferManager = new FileTransferManager(con);
OutgoingFileTransfer.setResponseTimeout(30000);
addFileTransferListener();
pingManager = PingManager.getInstanceFor(con);
pingManager.registerPingFailedListener(new PingFailedListener() {
#Override
public void pingFailed() {
// Note: remember that maybeStartReconnect is called from a different thread (the PingTask) here, it may causes synchronization problems
long now = new Date().getTime();
if (now - lastPing > 30000) {
Log.e(LOG_TAG, "Ping failure, reconnect");
startReconnectIfNecessary();
lastPing = now;
} else {
Log.e(LOG_TAG, "Ping failure reported too early. Skipping this occurrence.");
}
}
});
con.addPacketListener(messagePacketListener, new MessageTypeFilter(Message.Type.chat));
con.addPacketListener(presencePacketListener, new PacketTypeFilter(Presence.class));
con.addConnectionListener(createConnectionListener());
setState(State.CONNECTED);
broadcastState(State.CONNECTED);
MessageService.reconnectCount = 0;
}
}
private void broadcastState(State state) {
Intent intent = new Intent(ACTION_CONNECTION_CHANGED);
intent.putExtra(EXTRA_NAME_STATE, state.toString());
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
public void login(String username, String password) throws SmackInvocationException {
connect();
try {
if (!con.isAuthenticated()) {
con.login(username, password, RESOURCE_PART);
}
onConnectionEstablished();
} catch(Exception e) {
SmackInvocationException exception = new SmackInvocationException(e);
// this is caused by wrong username/password, do not reconnect
if (exception.isCausedBySASLError()) {
cleanupConnection();
} else {
startReconnectIfNecessary();
}
throw exception;
}
}
public String getLoginUserNickname() throws SmackInvocationException {
try {
return AccountManager.getInstance(con).getAccountAttribute("name");
} catch (Exception e) {
throw new SmackInvocationException(e);
}
}
private void processOfflineMessages() {
Log.i(LOG_TAG, "Begin retrieval of offline messages from server");
OfflineMessageManager offlineMessageManager = new OfflineMessageManager(con);
try {
if (!offlineMessageManager.supportsFlexibleRetrieval()) {
Log.d(LOG_TAG, "Offline messages not supported");
return;
}
List<Message> msgs = offlineMessageManager.getMessages();
for (Message msg : msgs) {
Intent intent = new Intent(MessageService.ACTION_MESSAGE_RECEIVED, null, context, MessageService.class);
intent.putExtra(MessageService.EXTRA_DATA_NAME_FROM, StringUtils.parseBareAddress(msg.getFrom()));
intent.putExtra(MessageService.EXTRA_DATA_NAME_MESSAGE_BODY, msg.getBody());
context.startService(intent);
}
offlineMessageManager.deleteMessages();
} catch (Exception e) {
Log.e(LOG_TAG, "handle offline messages error ", e);
}
Log.i(LOG_TAG, "End of retrieval of offline messages from server");
}
private ConnectionListener createConnectionListener() {
connectionListener = new ConnectionListener() {
#Override
public void authenticated(XMPPConnection arg0) {}
#Override
public void connected(XMPPConnection arg0) {}
#Override
public void connectionClosed() {
Log.e(LOG_TAG, "connection closed");
}
#Override
public void connectionClosedOnError(Exception arg0) {
// it may be due to network is not available or server is down, update state to WAITING_TO_CONNECT
// and schedule an automatic reconnect
Log.e(LOG_TAG, "connection closed due to error ", arg0);
startReconnectIfNecessary();
}
#Override
public void reconnectingIn(int arg0) {}
#Override
public void reconnectionFailed(Exception arg0) {}
#Override
public void reconnectionSuccessful() {}
};
return connectionListener;
}
private void startReconnectIfNecessary() {
cleanupConnection();
setState(State.WAITING_TO_CONNECT);
if (NetworkUtils.isNetworkConnected(context)) {
context.startService(new Intent(MessageService.ACTION_RECONNECT, null, context, MessageService.class));
}
}
private boolean isConnected() {
return con != null && con.isConnected();
}
public void onNetworkDisconnected() {
setState(State.WAITING_FOR_NETWORK);
}
public void requestSubscription(String to, String nickname) throws SmackInvocationException {
contactHelper.requestSubscription(to, nickname);
}
public void approveSubscription(String to, String nickname, boolean shouldRequest) throws SmackInvocationException {
contactHelper.approveSubscription(to);
if (shouldRequest) {
requestSubscription(to, nickname);
}
}
public void delete(String jid) throws SmackInvocationException {
contactHelper.delete(jid);
}
public String loadStatus() throws SmackInvocationException {
if (vCardHelper == null) {
throw new SmackInvocationException("server not connected");
}
return vCardHelper.loadStatus();
}
public VCard loadVCard(String jid) throws SmackInvocationException {
if (vCardHelper == null) {
throw new SmackInvocationException("server not connected");
}
return vCardHelper.loadVCard(jid);
}
public VCard loadVCard() throws SmackInvocationException {
if (vCardHelper == null) {
throw new SmackInvocationException("server not connected");
}
return vCardHelper.loadVCard();
}
public void saveStatus(String status) throws SmackInvocationException {
if (vCardHelper == null) {
throw new SmackInvocationException("server not connected");
}
vCardHelper.saveStatus(status);
contactHelper.broadcastStatus(status);
}
public SubscribeInfo processSubscribe(String from) throws SmackInvocationException {
SubscribeInfo result = new SubscribeInfo();
RosterEntry rosterEntry = contactHelper.getRosterEntry(from);
ItemType rosterType = rosterEntry != null ? rosterEntry.getType() : null;
if (rosterEntry == null || rosterType == ItemType.none) {
result.setType(SubscribeInfo.TYPE_WAIT_FOR_APPROVAL);
result.setNickname(getNickname(from));
} else if (rosterType == ItemType.to) {
result.setType(SubscribeInfo.TYPE_APPROVED);
result.setNickname(rosterEntry.getName());
approveSubscription(from, null, false);
}
result.setFrom(from);
return result;
}
public void sendImage(File file, String to) throws SmackInvocationException {
if (fileTransferManager == null || !isConnected()) {
throw new SmackInvocationException("server not connected");
}
String fullJid = to + "/" + RESOURCE_PART;
OutgoingFileTransfer transfer = fileTransferManager.createOutgoingFileTransfer(fullJid);
try {
transfer.sendFile(file, file.getName());
} catch (SmackException e) {
Log.e(LOG_TAG, "send file error");
throw new SmackInvocationException(e);
}
while(!transfer.isDone()) {
if(transfer.getStatus().equals(Status.refused) || transfer.getStatus().equals(Status.error)
|| transfer.getStatus().equals(Status.cancelled)){
throw new SmackInvocationException("send file error, " + transfer.getError());
}
}
Log.d(LOG_TAG, "send file status: " + transfer.getStatus());
if(transfer.getStatus().equals(Status.refused) || transfer.getStatus().equals(Status.error)
|| transfer.getStatus().equals(Status.cancelled)){
throw new SmackInvocationException("send file error, " + transfer.getError());
}
}
private void addFileTransferListener() {
fileTransferManager.addFileTransferListener(new FileTransferListener() {
public void fileTransferRequest(final FileTransferRequest request) {
new Thread() {
#Override
public void run() {
IncomingFileTransfer transfer = request.accept();
String fileName = String.valueOf(System.currentTimeMillis());
File file = new File(FileUtils.getReceivedImagesDir(context), fileName + FileUtils.IMAGE_EXTENSION);
try {
transfer.recieveFile(file);
} catch (SmackException e) {
Log.e(LOG_TAG, "receive file error", e);
return;
}
while (!transfer.isDone()) {
if(transfer.getStatus().equals(Status.refused) || transfer.getStatus().equals(Status.error)
|| transfer.getStatus().equals(Status.cancelled)){
Log.e(LOG_TAG, "receive file error, " + transfer.getError());
return;
}
}
// start service to save the image to sqlite
if (transfer.getStatus().equals(Status.complete)) {
Intent intent = new Intent(MessageService.ACTION_MESSAGE_RECEIVED, null, context, MessageService.class);
intent.putExtra(MessageService.EXTRA_DATA_NAME_FROM, StringUtils.parseBareAddress(request.getRequestor()));
intent.putExtra(MessageService.EXTRA_DATA_NAME_MESSAGE_BODY, context.getString(R.string.image_message_body));
intent.putExtra(MessageService.EXTRA_DATA_NAME_FILE_PATH, file.getAbsolutePath());
intent.putExtra(MessageService.EXTRA_DATA_NAME_TYPE, ChatMessageTableHelper.TYPE_INCOMING_IMAGE);
context.startService(intent);
}
}
}.start();
}
});
}
public void onDestroy() {
cleanupConnection();
smackAndroid.onDestroy();
}
public static enum State {
CONNECTING,
CONNECTED,
DISCONNECTED,
// this is a state that client is trying to reconnect to server
WAITING_TO_CONNECT,
WAITING_FOR_NETWORK;
}
}
but i could not found any progress.please help me out. thanks in advance.
After struggle i found solution of this kind of problem. we need to do server side changes like:
step1:
step2:
step3:
after doing all these steps we will able to register new user on ejabberd server.

Establish DataChannel between Android app and Chrome client

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.

Stream from Android app to browser client app via socket.io-client and libjingle

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);
}
}
}

Categories

Resources