I am working on Exoplayer Media Player in Android to Live Stream from an RTMP Media Source URL. I am new to this kind a development so I am following the official Tutorial. The live stream is working fine on all Android Devices! My Class for fetching the live stream is:
import android.annotation.SuppressLint;
import android.databinding.DataBindingUtil;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.example.juni1289.exoplayertest2.databinding.ActivityMainBinding;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.ext.rtmp.RtmpDataSourceFactory;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.util.Util;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private ExoPlayer player;
private boolean playWhenReady;
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
private ComponentListener componentListener;
private final String TAG = "MainActivity";
private MediaSource videoSource;
private AdaptiveTrackSelection.Factory adaptiveTrackSelectionFactory;
private TrackSelector trackSelector;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
componentListener = new ComponentListener();
initializePlayer();
}
private void initializePlayer() {
if (player == null) {
// a factory to create an AdaptiveVideoTrackSelection
adaptiveTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory);
player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
trackSelector,
new DefaultLoadControl());
binding.videoView.setPlayer(player);
RtmpDataSourceFactory rtmpDataSourceFactory = new RtmpDataSourceFactory();
// Produces Extractor instances for parsing the media data.
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// This is the MediaSource representing the media to be played.
videoSource = new ExtractorMediaSource(Uri.parse(""),
rtmpDataSourceFactory, extractorsFactory, null, null);
playWhenReady = true;
player.prepare(videoSource);
player.setPlayWhenReady(playWhenReady);
player.addListener(componentListener);
}
}
private void releasePlayer() {
if (player != null) {
player.removeListener(componentListener);
playWhenReady = player.getPlayWhenReady();
player.release();
player = null;
}
}
#Override
public void onPause() {
super.onPause();
if (Util.SDK_INT <= 23) {
releasePlayer();
}
}
#Override
public void onStop() {
super.onStop();
if (Util.SDK_INT > 23) {
releasePlayer();
}
}
#Override
public void onResume() {
super.onResume();
hideSystemUi();
if ((Util.SDK_INT <= 23 || player == null)) {
initializePlayer();
}
}
#SuppressLint("InlinedApi")
private void hideSystemUi() {
binding.videoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
private class ComponentListener extends Player.DefaultEventListener {
#Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
super.onTimelineChanged(timeline, manifest, reason);
}
#Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
super.onTracksChanged(trackGroups, trackSelections);
}
#Override
public void onLoadingChanged(boolean isLoading) {
super.onLoadingChanged(isLoading);
}
#Override
public void onRepeatModeChanged(int repeatMode) {
super.onRepeatModeChanged(repeatMode);
}
#Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
super.onShuffleModeEnabledChanged(shuffleModeEnabled);
}
#Override
public void onPlayerError(ExoPlaybackException error) {
super.onPlayerError(error);
}
#Override
public void onPositionDiscontinuity(int reason) {
super.onPositionDiscontinuity(reason);
}
#Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
super.onPlaybackParametersChanged(playbackParameters);
}
#Override
public void onSeekProcessed() {
super.onSeekProcessed();
}
#Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
super.onTimelineChanged(timeline, manifest);
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
String stateString;
switch (playbackState) {
case ExoPlayer.STATE_IDLE:
stateString = "ExoPlayer.STATE_IDLE -";
break;
case ExoPlayer.STATE_BUFFERING:
stateString = "ExoPlayer.STATE_BUFFERING -";
break;
case ExoPlayer.STATE_READY:
stateString = "ExoPlayer.STATE_READY -";
break;
case ExoPlayer.STATE_ENDED:
stateString = "ExoPlayer.STATE_ENDED -";
break;
default:
stateString = "UNKNOWN_STATE -";
break;
}
Log.e(TAG, "changed state to " + stateString
+ " playWhenReady: " + playWhenReady);
}
}
}
The Gradle Dependencies
implementation 'com.google.android.exoplayer:exoplayer-core:2.7.3'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.7.3'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.7.3'
implementation 'com.google.android.exoplayer:extension-rtmp:2.7.3'
The URL is from Nginx Server implemented in the background, the backend live streaming software used is Wirecast using MacBook.
The problem I am facing is that when I have lost the Wifi connection (working),the Live stream won't resume at all. Similarly is with the 3G/4G Mobile Network Connection that once it goes down the live stream won't resume back.
I have followed the given tutorial and searched many of the forums for the problem resolution! But I am unable to find any resource information in order to rectify the problem!
I purposed a solution for me that a Broadcast receiver is registered in the MainActivity that will check of Internet Connections, once it changes it state the Exoplayer will be re-initialized. But this has limitation, that it only works when the Wifi or the Mobile Data Connection will turn on or off!
I want Exoplayer to resume the live stream when Wifi or Mobile Data Connection goes down and then it got some life and the Exoplayer resume the live stream to be watch again!
Any help or guidance will be highly appreciated! As I am new to this development, any blunders can occur in my code.
I am also trying with the following code too:
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Surface;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.ext.rtmp.RtmpDataSourceFactory;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultAllocator;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.video.VideoRendererEventListener;
public class MainActivity extends AppCompatActivity implements VideoRendererEventListener {
private SimpleExoPlayerView exoPlayerView;
private final String logKEY = "MainActivity";
private SimpleExoPlayer player;
private MediaSource videoSource;
private final String url = "myurl";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initExoPlayer();
}
private void initExoPlayer() {
try {
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
AdaptiveTrackSelection.Factory videoSelectionFactory=new AdaptiveTrackSelection.Factory(bandwidthMeter);
//TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoSelectionFactory);
/////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//Create the player
DefaultAllocator defaultAllocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE);
DefaultLoadControl defaultLoadControl = new DefaultLoadControl(defaultAllocator, 30,
30, 10, DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS,
DefaultLoadControl.DEFAULT_TARGET_BUFFER_BYTES, DefaultLoadControl.DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS);
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, defaultLoadControl);
exoPlayerView.setPlayer(player);
exoPlayerView.setUseController(false);
RtmpDataSourceFactory rtmpDataSourceFactory = new RtmpDataSourceFactory();
// Produces Extractor instances for parsing the media data.
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// This is the MediaSource representing the media to be played.
videoSource = new ExtractorMediaSource(Uri.parse(url),
rtmpDataSourceFactory, extractorsFactory, null, null);
// Prepare the player with the source.
player.prepare(videoSource);
//auto start playing
player.setPlayWhenReady(true);
//adding listeners
player.addListener(new ExoPlayer.EventListener() {
#Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
}
#Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
#Override
public void onLoadingChanged(boolean isLoading) {
if (isLoading) {
Log.e(logKEY, "loadingChanged:::true");
} else {
Log.e(logKEY, "loadingChanged:::false");
}
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
}
#Override
public void onRepeatModeChanged(int repeatMode) {
}
#Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
Log.e(logKEY, "Listener-onPlayerError...");
player.stop();
player.prepare(videoSource);
player.setPlayWhenReady(true);
}
#Override
public void onPositionDiscontinuity(int reason) {
}
#Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
#Override
public void onSeekProcessed() {
}
});
} catch (Exception e) {
Log.e(logKEY, "error:::" + e.toString());
e.printStackTrace();
}
}
private void initView() {
exoPlayerView = findViewById(R.id.exoPlayerView);
}
#Override
public void onVideoEnabled(DecoderCounters counters) {
}
#Override
public void onVideoDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {
}
#Override
public void onVideoInputFormatChanged(Format format) {
}
#Override
public void onDroppedFrames(int count, long elapsedMs) {
}
#Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
Log.e(logKEY, "onVideoSizeChanged [" + " width: " + width + " height: " + height + "]");
Log.e(logKEY, "RES:(WxH):" + width + "X" + height + "\n " + height + "p");
}
#Override
public void onRenderedFirstFrame(Surface surface) {
}
#Override
public void onVideoDisabled(DecoderCounters counters) {
}
#Override
protected void onStop() {
super.onStop();
Log.e(logKEY, "onStop()...");
}
#Override
protected void onStart() {
super.onStart();
Log.e(logKEY, "onStart()...");
}
#Override
protected void onResume() {
super.onResume();
Log.e(logKEY, "onResume()...");
}
#Override
protected void onPause() {
super.onPause();
Log.e(logKEY, "onPause()...");
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.e(logKEY, "onDestroy()...");
player.release();
}
}
The above is also having the said issues!
Related
I'm trying to get several characteritics from a BLE device (an Arduino).
My activity manages an automatic connection to the device address and it works without problems.
package com.example.flyin_glass;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.*;
import android.bluetooth.le.*;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.content.Context;
import android.widget.TextView;
import android.widget.Toast;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
BluetoothAdapter mBluetoothAdapter;
BluetoothDevice device;
private boolean mScanning;
BluetoothGatt gatt;
BluetoothGattService commService;
BluetoothGattCharacteristic characteristic;
TextView display;
public int i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
display = (TextView) findViewById(R.id.TV_STATUS);
MyThread myThread = new MyThread();
myThread.start();
}
public class MyThread extends Thread {
public void run() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED) {
return;
}
//mBluetoothAdapter.startLeScan(mLeScanCallback);
device = mBluetoothAdapter.getRemoteDevice("4F:B8:A6:D3:F8:37");
device.connectGatt(getApplicationContext(), true, bluetoothGattCallback);
//gatt.discoverServices();
//commService = gatt.getService(UUID.fromString("00000000-0000-1000-8000-00805f9b34fb"));
//characteristic = commService.getCharacteristic(UUID.fromString("0001"));
// boolean ret = gatt.readCharacteristic(characteristic);
//final byte[] data = characteristic.getValue();
while (true) {
try {
Thread.sleep(1000); //refresh ?
/*runOnUiThread(new Runnable() {
public void run() {
display.setText("testBLE");
}
});*/
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) {
return;
}
if (device.getName() == null) {
runOnUiThread(new Runnable() {
public void run() {
display.setText("Nothing");
}
});
} else {
runOnUiThread(new Runnable() {
public void run() {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) {
return;
}
//display.setText(device.getName());
//display.setText(device.getAddress());
display.setText(String.valueOf(rssi));
}
});
}
}
};
private final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
// successfully connected to the GATT Server
runOnUiThread(new Runnable() {
public void run() {
display.setText("OK");
}
});
}
else if
(newState == BluetoothProfile.STATE_DISCONNECTED)
{
runOnUiThread(new Runnable()
{
public void run()
{
display.setText("NOK");
}
});
}
}
};
}
So it works until the line :
device.connectGatt(getApplicationContext(), true, bluetoothGattCallback);
The callBack returns OK, which means I am connected automaticaly to the device.
But when I add the next line for discover services, the application crashes.
gatt.discoverServices();
I do not know why. Have you some ideas ? I just would like be able to read and display some characteristics of my device.
Thank you in advance.
This is such a basic issue that I am not sure what I could possibly be doing wrong. Sinch is not starting for me and I don't know why. I don't have enough experience with Sinch to diagnose why a basic command is not doing what it is supposed to do. Here's what I have:
I am trying to start and making the call from the Calling.java class. The code is as follows:
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.sinch.android.rtc.calling.Call;
import com.squareup.picasso.Picasso;
import static android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP;
public class Calling extends CallActivity {
private String calleeID;
private TextView serviceName;
Bundle callDetails;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calling);
callDetails = getIntent().getBundleExtra("callDetails");
//Setup end button
Button endCallButton = findViewById(R.id.endcall);
endCallButton.setOnClickListener(v -> endCall());
}
private void endCall() {
if (getSinchServiceInterface() != null) {
getSinchServiceInterface().stopClient();
}
finishActivity(FLAG_ACTIVITY_PREVIOUS_IS_TOP);
finish();
}
// invoked when the connection with SinchServer is established
#Override
protected void onServiceConnected() {
//Setup Calling Screen
ImageView avatar = findViewById(R.id.dialingAvatar);
Picasso.get().load(callDetails.getString("Logo")).into(avatar);
TextView midScreenName = findViewById(R.id.memberName);
midScreenName.setText(callDetails.getString("Name"));
serviceName = findViewById(R.id.serviceName);
serviceName.setText(callDetails.getString("Service"));
TextView ratings = findViewById(R.id.rating);
ratings.setText(callDetails.getString("Rating") + " ★");
//Get CallerID and CalleeID
calleeID = callDetails.getString("CalleeID");
//Start sinch Service
if(!getSinchServiceInterface().isStarted()){
getSinchServiceInterface().startClient(callDetails.getString("CallerID"));
Call call = getSinchServiceInterface().callUserVideo(calleeID);
Intent callServiceScreen = new Intent(this, ServiceCallActivity.class);
callDetails.putString(SinchService.CALL_ID, call.getCallId());
callServiceScreen.putExtra("Call Details", callDetails);
startActivity(callServiceScreen);
}
}
#Override
public void onDestroy() {
if (getSinchServiceInterface() != null) {
getSinchServiceInterface().stopClient();
}
super.onDestroy();
}
}
I am coming to Calling.java from Precall.java the code for that is:
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.sinch.android.rtc.SinchError;
import com.squareup.picasso.Picasso;
import org.json.JSONObject;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class precall extends CallActivity implements SinchService.StartFailedListener {
private Bundle memberDetails;
private String url;
private Button cancel;
private Button call;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_precall);
//url
url = apiCallPoints.userInfo;
//Set Member Text
memberDetails = getIntent().getBundleExtra("Member");
//Populate screen
ImageView avatar = findViewById(R.id.avatar);
Picasso.get().load(memberDetails.getString("Logo")).into(avatar);
TextView memberName = findViewById(R.id.membername);
memberName.setText(memberDetails.getString("Name"));
TextView rating = findViewById(R.id.rating);
rating.setText(memberDetails.getString("Rating") + " ★");
TextView serviceName = findViewById(R.id.servicename);
serviceName.setText(memberDetails.getString("Service"));
TextView overview = findViewById(R.id.overview);
overview.setText(memberDetails.getString("Overview"));
//Add button clicks
cancel = findViewById(R.id.cancel_button);
cancel.setOnClickListener(view -> finish());
cancel.setEnabled(false);
call = findViewById(R.id.yes_button);
call.setOnClickListener(view -> {
goToCalling();
});
call.setEnabled(false);
setHomeBar();
}
//this method is invoked when the connection is established with the SinchService
#Override
protected void onServiceConnected() {
call.setEnabled(true);
cancel.setEnabled(true);
getSinchServiceInterface().setStartListener(this);
}
#Override
protected void onPause() {
super.onPause();
}
#Override
public void onStartFailed(SinchError error) {
}
//Invoked when just after the service is connected with Sinch
#Override
public void onStarted() {
}
private void goToCalling() {
//Async search
CallBackendSync callBackendSync = new CallBackendSync();
Object [] params = {url, memberDetails};
callBackendSync.execute(params);
}
private void setHomeBar() {
final Button home = findViewById(R.id.home_button);
home.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Code here executes on main thread after user presses button
startActivity(new Intent(precall.this, SecondActivity.class));
}
});
final Button favourites = findViewById(R.id.star_button);
favourites.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Code here executes on main thread after user presses button
startActivity(new Intent(precall.this, Favourite_Page.class));
}
});
final Button profile_page = findViewById(R.id.person_button);
profile_page.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Code here executes on main thread after user presses button
startActivity(new Intent(getApplicationContext(), Profile.class));
}
});
final Button notifications = findViewById(R.id.notification_button);
notifications.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Code here executes on main thread after user presses button
startActivity(new Intent(precall.this, Notification_Page.class));
}
});
final Button service = findViewById(R.id.service_button);
service.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Code here executes on main thread after user presses button
startActivity(new Intent(precall.this, services.class));
}
});
}
class CallBackendSync extends AsyncTask {
OkHttpClient client = new OkHttpClient();
#Override
protected Object doInBackground(Object [] objects) {
String url = (String) objects[0];
Bundle memberDetails = (Bundle) objects[1];
//Get access token from shared preference
isLoggedIn loggedIn = new isLoggedIn(getApplicationContext());
String token = loggedIn.getToken();
if(token != null){
//Create request
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer " + token)
.addHeader("Accept", "application/json")
.build();
try {
Response response = client.newCall(request).execute();
JSONObject results = new JSONObject(response.body().string());
String UserID = results.getString("UserId");
memberDetails.putString("CallerID", UserID);
Intent callIntent = new Intent(precall.this, Calling.class);
callIntent.putExtra("callDetails", memberDetails);
startActivity(callIntent);
return results;
}catch (Exception e){
e.printStackTrace();
}
} else {
startActivity(new Intent(precall.this, Login_page.class));
}
return null;
}
protected void onPostExecute(String s){
super.onPostExecute(s);
}
}
}
The failure is happening in SinchService.java
import com.sinch.android.rtc.AudioController;
import com.sinch.android.rtc.ClientRegistration;
import com.sinch.android.rtc.Sinch;
import com.sinch.android.rtc.SinchClient;
import com.sinch.android.rtc.SinchClientListener;
import com.sinch.android.rtc.SinchError;
import com.sinch.android.rtc.video.VideoController;
import com.sinch.android.rtc.calling.Call;
import com.sinch.android.rtc.calling.CallClient;
import com.sinch.android.rtc.calling.CallClientListener;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class SinchService extends Service {
private static final String APP_KEY = "is correct";
private static final String APP_SECRET = "is correct";
//private static final String ENVIRONMENT = "clientapi.sinch.com";
private static final String ENVIRONMENT = "sandbox.sinch.com";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient = null;
private String mUserId = "";
private StartFailedListener mListener;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
if(mSinchClient != null){
mSinchClient.terminate();
}
super.onDestroy();
}
private void start(String userName) {
mUserId = userName;
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext())
.applicationKey(APP_KEY)
.applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT)
.userId(userName)
.enableVideoCalls(true)
.build();
mSinchClient.setSupportCalling(true);
mSinchClient.startListeningOnActiveConnection();
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.checkManifest();
mSinchClient.start();
System.out.println("Is started: " + mSinchClient.isStarted());
}
private void stop() {
if(mSinchClient != null){
mSinchClient.terminate();
}
}
private boolean isStarted() {
if(mSinchClient != null){
return mSinchClient.isStarted();
} else {
return false;
}
}
#Override
public IBinder onBind(Intent intent) {
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public Call callUserVideo(String userId) {
return mSinchClient.getCallClient().callUserVideo(userId);
}
public String getUserName() {
return mUserId;
}
public boolean isStarted() {
return SinchService.this.isStarted();
}
public void startClient(String userName) {
start(userName);
}
public void stopClient() {
stop();
}
public void setStartListener(StartFailedListener listener) {
mListener = listener;
}
public Call getCall(String callId) {
return mSinchClient.getCallClient().getCall(callId);
}
public VideoController getVideoController() {
return mSinchClient.getVideoController();
}
public AudioController getAudioController() {
return mSinchClient.getAudioController();
}
}
public interface StartFailedListener {
void onStartFailed(SinchError error);
void onStarted();
}
private class MySinchClientListener implements SinchClientListener {
#Override
public void onClientFailed(SinchClient client, SinchError error) {
if (mListener != null) {
mListener.onStartFailed(error);
}
mSinchClient.terminate();
mSinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
Log.d(TAG, "SinchClient started");
if (mListener != null) {
mListener.onStarted();
}
}
#Override
public void onClientStopped(SinchClient client) {
Log.d(TAG, "SinchClient stopped");
}
#Override
public void onLogMessage(int level, String area, String message) {
switch (level) {
case Log.DEBUG:
Log.d(area, message);
break;
case Log.ERROR:
Log.e(area, message);
break;
case Log.INFO:
Log.i(area, message);
break;
case Log.VERBOSE:
Log.v(area, message);
break;
case Log.WARN:
Log.w(area, message);
break;
}
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client,
ClientRegistration clientRegistration) {
}
}
private class SinchCallClientListener implements CallClientListener {
#Override
public void onIncomingCall(CallClient callClient, Call call) {
Log.d(TAG, "Incoming call");
Intent intent = new Intent(SinchService.this, Calling.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchService.this.startActivity(intent);
}
}
}
And the base activity is CallActivity.java
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.sinch.android.rtc.calling.Call;
import com.squareup.picasso.Picasso;
import static android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP;
public class Calling extends CallActivity {
private String calleeID;
private TextView serviceName;
Bundle callDetails;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calling);
callDetails = getIntent().getBundleExtra("callDetails");
//Setup end button
Button endCallButton = findViewById(R.id.endcall);
endCallButton.setOnClickListener(v -> endCall());
}
private void endCall() {
if (getSinchServiceInterface() != null) {
getSinchServiceInterface().stopClient();
}
finishActivity(FLAG_ACTIVITY_PREVIOUS_IS_TOP);
finish();
}
// invoked when the connection with SinchServer is established
#Override
protected void onServiceConnected() {
//Setup Calling Screen
ImageView avatar = findViewById(R.id.dialingAvatar);
Picasso.get().load(callDetails.getString("Logo")).into(avatar);
TextView midScreenName = findViewById(R.id.memberName);
midScreenName.setText(callDetails.getString("Name"));
serviceName = findViewById(R.id.serviceName);
serviceName.setText(callDetails.getString("Service"));
TextView ratings = findViewById(R.id.rating);
ratings.setText(callDetails.getString("Rating") + " ★");
//Get CallerID and CalleeID
calleeID = callDetails.getString("CalleeID");
//Start sinch Service
if(!getSinchServiceInterface().isStarted()){
getSinchServiceInterface().startClient(callDetails.getString("CallerID"));
Call call = getSinchServiceInterface().callUserVideo(calleeID);
Intent callServiceScreen = new Intent(this, ServiceCallActivity.class);
callDetails.putString(SinchService.CALL_ID, call.getCallId());
callServiceScreen.putExtra("Call Details", callDetails);
startActivity(callServiceScreen);
}
}
#Override
public void onDestroy() {
if (getSinchServiceInterface() != null) {
getSinchServiceInterface().stopClient();
}
super.onDestroy();
}
}
I have been banging my head against this but I cannot figure out what's wrong. I sure it's something stupid and obvious that I can't see because I am too close to the code. But any ideas you guys have would be very helpful!
It looks like you are not waiting for it to start before you try to make a call. We recommend to start the service when the app starts. If you dont do that you need to wait or the onStarted event in the service for fire
I am trying to use the Android Camera2 api to create a preview, however my code does not execute the cameraCaptureSession.StateCallback. My code executes through cameraDevice.createCaptureSession(camConfig). Upon executing this, it should execute the StateCallback however from what I can tell it does not. I was wondering if anyone knows why this callback did not executed? And how to fix it.
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
import com.example.atlas2.R;
import com.example.atlas2.Util.BackgroundThreadFactory;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import static android.hardware.camera2.CameraMetadata.LENS_FACING_FRONT;
import static android.hardware.camera2.params.SessionConfiguration.SESSION_REGULAR;
public class ProfilePhotoFragment extends Fragment implements SurfaceHolder.Callback2, ThreadFactory
{
Button capture;
CameraManager cameraManager;
String[] cameraIDs;
String frontCamera;
String cameraId;
SurfaceView camPreview;
SurfaceHolder camHolder;
Size surfaceSize;
CameraDevice cameraDevice;
SessionConfiguration camConfig;
CameraCaptureSession cameraCaptureSessions;
CaptureRequest.Builder captureRequestBuilder;
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice camera) {
cameraDevice = camera;
previewSetUp();
}
#Override
public void onDisconnected(#NonNull CameraDevice camera) {
}
#Override
public void onError(#NonNull CameraDevice camera, int error) {
}
};
public ProfilePhotoFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View profilePhotoView = inflater.inflate(R.layout.fragment_profile_photo, container, false);
cameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
try {
cameraIDs = cameraManager.getCameraIdList();
Log.v("cameraIDs", cameraIDs[1]);
} catch (CameraAccessException e) {
e.printStackTrace();
}
camPreview = profilePhotoView.findViewById(R.id.camOutput);
camHolder = camPreview.getHolder();
openCamera();
capture = profilePhotoView.findViewById(R.id.capture);
capture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
// Inflate the layout for this fragment
return profilePhotoView;
}
public void openCamera() {
chooseCamera();
String frontFacing = frontCamera;
try {
cameraManager.openCamera(frontFacing, stateCallback, null); //permissions taken care of
in ProfilePhotoActivity
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
public void chooseCamera() {
//find front facing camera through getCameraCharacteristics(cameraId)
for(int i = 0; i < cameraIDs.length; i++) {
try {
if(cameraManager.getCameraCharacteristics(cameraIDs[1]).get(CameraCharacteristics.LENS_FACING) ==
LENS_FACING_FRONT) {
frontCamera = cameraIDs[i];
Log.v("frontfacing", frontCamera);
cameraId = cameraIDs[i];
break;
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
#Override
public void surfaceRedrawNeeded(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
public void previewSetUp() {
CameraCharacteristics characteristics = null;
try {
characteristics = cameraManager.getCameraCharacteristics(cameraId);
} catch (CameraAccessException e) {
e.printStackTrace();
}
StreamConfigurationMap map =
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
surfaceSize = map.getOutputSizes(SurfaceHolder.class)[0];
camHolder.setFixedSize(surfaceSize.getWidth(), surfaceSize.getHeight());
Surface surface = camHolder.getSurface();
try {
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
} catch (CameraAccessException e) {
e.printStackTrace();
}
captureRequestBuilder.addTarget(surface);
OutputConfiguration outputConfig = new OutputConfiguration(surface);
Log.v("outputconfig", outputConfig.toString());
ExecutorService executor = Executors.newFixedThreadPool(2, new BackgroundThreadFactory());
Log.v("executor", executor.toString());
camConfig = new SessionConfiguration(SESSION_REGULAR, Arrays.asList(outputConfig), executor,
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession session) {
cameraCaptureSessions = session;
Log.v("onConfigured", "onconfigured");
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession session) {
Log.v("onConfiguredFailed", session.toString());
Toast.makeText(getContext(), "Changed", Toast.LENGTH_SHORT).show();
}
});
String supported = cameraDevice.getId();
try {
cameraDevice.createCaptureSession(camConfig);
Log.v("createCaptureSession", supported);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
public void updatePreview() {
Log.v("createCaptureSession2", String.valueOf(cameraCaptureSessions));
if(cameraDevice == null)
Toast.makeText(getContext(), "Error", Toast.LENGTH_SHORT).show();
Log.v("createCaptureSession1", String.valueOf(cameraCaptureSessions));
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE,CaptureRequest.CONTROL_MODE_AUTO);
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
try{
Log.v("createCaptureSession", String.valueOf(cameraCaptureSessions));
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, null);
}catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}**/
public void switchCameras() {
//start a new cameracapturesession; this will stop the pre-existing one
}
#Override
public void onDetach() {
super.onDetach();
}
#Override
public void onDestroy() {
super.onDestroy();
//executor.shutdown(); //executor in previewSetUp needs to be global
}
}
I am trying use ffmpeg in android. Here is the code so far. I took reference from this project. It just lets me convert video file. But I want to play a video file using ffmpeg. Is it possible? If yes then how we can do that?
package com.ffmpeg;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import com.github.hiteshsondhi88.libffmpeg.ExecuteBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.FFmpeg;
import com.github.hiteshsondhi88.libffmpeg.LoadBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegCommandAlreadyRunningException;
import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegNotSupportedException;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
Boolean loadedFlag = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!loadedFlag) {
FFmpegInitLoader();
}
decodeVideo();
}
public void FFmpegInitLoader() {
FFmpeg ffmpeg = FFmpeg.getInstance(this);
try {
ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
#Override
public void onStart() {
}
#Override
public void onFailure() {
}
#Override
public void onSuccess() {
System.out.println("Successfully loaded FFmpeg!!!");
loadedFlag = true;
}
#Override
public void onFinish() {
}
});
} catch (FFmpegNotSupportedException e) {
System.out.println("Whatever....this thing is not supported :::::::::::::::::::: ");
}
}
public void decodeVideo() {
FFmpeg ffmpeg = FFmpeg.getInstance(this);
try {
ffmpeg.execute(new String[]{"-y", "-i", "/storage/sdcard0/AVSEQ02.mp4", "-c:v", "libx264", "/storage/sdcard0/conv.mp4"}, new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {
System.out.println("FFmpeg started for decoding");
}
#Override
public void onProgress(String message) {
System.out.println("progress message:::: " + message);
}
#Override
public void onFailure(String message) {
System.out.println("failure message:::: " + message);
}
#Override
public void onSuccess(String message) {
System.out.println("success message:::: " + message);
}
#Override
public void onFinish() {
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
System.out.println("already running::::::");
}
}
}
Yes it is possible.See the below links.
AndroidFFmpeg
FFmpegMediaPlayer
package fr.pchab.AndroidRTC;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Window;
import android.widget.Toast;
import org.json.JSONException;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.VideoRenderer;
import java.util.List;
public class RTCActivity extends Activity implements WebRtcClient.RTCListener{
private final static int VIDEO_CALL_SENT = 666;
private VideoStreamsView vsv;
private WebRtcClient client;
private String mSocketAddress;
private String callerId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
mSocketAddress = "http://" + getResources().getString(R.string.host);
mSocketAddress += (":"+getResources().getString(R.string.port)+"/");
PeerConnectionFactory.initializeAndroidGlobals(this);
// Camera display view
Point displaySize = new Point();
getWindowManager().getDefaultDisplay().getSize(displaySize);
vsv = new VideoStreamsView(this, displaySize);
client = new WebRtcClient(this, mSocketAddress);
final Intent intent = getIntent();
final String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
final List<String> segments = intent.getData().getPathSegments();
callerId = segments.get(0);
}
}
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
#Override
public void onPause() {
super.onPause();
vsv.onPause();
}
#Override
public void onResume() {
super.onResume();
vsv.onResume();
}
#Override
public void onCallReady(String callId) {
if(callerId != null) {
try {
answer(callerId);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
call(callId);
}
}
public void answer(String callerId) throws JSONException {
client.sendMessage(callerId, "init", null);
startCam();
}
public void call(String callId) {
Intent msg = new Intent(Intent.ACTION_SEND);
msg.putExtra(Intent.EXTRA_TEXT, mSocketAddress + callId);
msg.setType("text/plain");
startActivityForResult(Intent.createChooser(msg, "Call someone :"), VIDEO_CALL_SENT);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == VIDEO_CALL_SENT) {
startCam();
}
}
public void startCam() {
setContentView(vsv);
// Camera settings
client.setCamera("front", "640", "480");
client.start("android_test", true);
}
#Override
public void onStatusChanged(final String newStatus) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), newStatus, Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onLocalStream(MediaStream localStream) {
localStream.videoTracks.get(0).addRenderer(new VideoRenderer(new VideoCallbacks(vsv, 0)));
}
#Override
public void onAddRemoteStream(MediaStream remoteStream, int endPoint) {
remoteStream.videoTracks.get(0).addRenderer(new VideoRenderer(new VideoCallbacks(vsv, endPoint)));
vsv.shouldDraw[endPoint] = true;
}
#Override
public void onRemoveRemoteStream(MediaStream remoteStream, int endPoint) {
remoteStream.videoTracks.get(0).dispose();
vsv.shouldDraw[endPoint] = false;
}
// Implementation detail: bridge the VideoRenderer.Callbacks interface to the
// VideoStreamsView implementation.
private class VideoCallbacks implements VideoRenderer.Callbacks {
private final VideoStreamsView view;
private final int stream;
public VideoCallbacks(VideoStreamsView view, int stream) {
this.view = view;
this.stream = stream;
}
#Override
public void setSize(final int width, final int height) {
view.queueEvent(new Runnable() {
public void run() {
view.setSize(stream, width, height);
}
});
}
#Override
public void renderFrame(VideoRenderer.I420Frame frame) {
view.queueFrame(stream, frame);
}
}
}
I want to use webrtc in my android app.
https://github.com/pchab/AndroidRTC
after import project from this site video calling or voice calling or chatting is not working.
how can i use websocket library send data and receive for video or voice chatting?
can we interface WEBRTC API with webview.
or how can we do voice chatting and display view in chrom in any control of android.
now i am using webrtc in a native app but it is not working.
if u have any other code or project for webrtc in android than send me link.
I want to use webrtc in my android app.
https://github.com/pchab/AndroidRTC
after import project from this site video calling or voice calling or chatting is not working.
how can i use websocket library send data and receive for video or voice chatting?
can we interface WEBRTC API with webview.
To get this application working you need a server-side which will do the signaling job. If you don't want to develope yourself you can install the node.js server with its desktop client from the same project (just follow How To instructions from AndroidRTC and the Install instructions from ProjectRTC):
https://github.com/pchab/ProjectRTC
Hope it helps.