package ai.suanzi.rtmpclient;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.IntentFilter;
-import android.graphics.ImageFormat;
-import android.graphics.SurfaceTexture;
-import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbManager;
-import android.os.Environment;
import android.support.design.widget.TextInputEditText;
-import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
-import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceHolder;
-import android.hardware.Camera;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.AsyncTask;
import java.io.File;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.io.IOException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import android.content.Intent;
-import java.io.OutputStream;
-import android.hardware.usb.UsbManager;
-import android.hardware.usb.UsbDeviceConnection;
-
import de.mindpipe.android.logging.log4j.LogConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import android.os.IBinder;
import android.net.ConnectivityManager;
-//"rtmp://gpussh.suanzi.ai:1935/myapp/suanzi_ac83f34ead90_cameraid";
+//"rtmp://gpussh.suanzi.ai:1935/myapp/suanzi_ac83f34ead90";
-public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, Camera.PreviewCallback, MyService.MyServiceEventListener{
+public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, MyService.MyServiceEventListener{
private static final String TAG = "MainActivity";
- //private Ffmpeg ffmpeg;
- //private Camera mCamera ;
- //private StreamTask mStreamTask;
- private SurfaceHolder mHolder;
- private SurfaceView mSufaceView;
- //private UVCCamera uvcCamera;
- //ExecutorService mExecutor = Executors.newSingleThreadExecutor();
- //Intent it = new Intent(getApplicationContext(), MyService.class);
- //Intent intent = new Intent();
-
- //private UsbManager usbManager;
- //private UsbDevice usbCamera;
-
private Logger gLogger;
+ private SurfaceHolder mHolder;
+ private SurfaceView mSufaceView;
private Button mBtnStart;
private TextInputEditText mTextServer;
private TextInputEditText mTextUser;
private TextInputEditText mTextCamera;
private String mMacAddr = "";
- //private CameraView mCameraView;
- private String mRtmpUrl;
private NetworkMonitor networkMonitor;
private UsbMonitor mUsbMonitor;
+ private ServiceHealthMonitor mServiceHealthMonitor;
+ private static final int INTERVAL = 2 * 60; // seconds
boolean mBounded;
MyService mServer;
Intent mIntent;
- // private ServiceReceiver mServiceReceiver;
-
private void configLog(){
try {
final LogConfigurator logConfigurator = new LogConfigurator();
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkMonitor, filter);
+
+ mServiceHealthMonitor = new ServiceHealthMonitor(new ServiceHealthMonitor.Callback() {
+ @Override
+ public void onNotHealthy() {
+ gLogger.error("onNotHealthy, in " + INTERVAL + " seconds, the publishing may stopped or have error ");
+ doUnbindService();
+ doBindService();
+
+ }
+ });
+ mServiceHealthMonitor.setInterval(INTERVAL); // 5 minutes
}
if(mServer.setRtmpUrl(UserInfo.getConfig().toUrl(mMacAddr))){
mServer.startPreview(mHolder);
}
+ gLogger.debug("onServiceConnected - start health monitor thread, interval " + INTERVAL);
+
}
};
private void doBindService(){
+ gLogger.debug("doBindService");
if(!mBounded && canStartService()) {
- gLogger.debug("doBindService");
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
}
}
private void doUnbindService() {
+ gLogger.debug("doUnbindService");
if(mBounded){
- gLogger.debug("doUnbindService");
unbindService(mConnection);
mBounded = false;
}
if(NetworkMonitor.isNetworkAvailable(this) && mUsbMonitor.hasUsbCamera()){
gLogger.error("Current network is available");
doBindService();
+
+
} else {
gLogger.error("Current network is NOT available");
}
public void onClick(View view){
gLogger.error("----------> onClick");
saveConfig();
- doUnbindService();
+
+ //unbindService(mConnection);
+ bindService(mIntent, mConnection, BIND_AUTO_CREATE);
+ //doUnbindService();
+ //doBindService();
}
});
+
+ if(!mServiceHealthMonitor.isAlive()) {
+ gLogger.debug("mServiceHealthMonitor start");
+ mServiceHealthMonitor.start();
+ }
}
@Override
gLogger.debug("onRestart ---------->");
}
+ @Override
+ public void onBackPressed() {
+ gLogger.error("onBackPressed --------->");
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_HOME);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ }
+
// SurfaceHolder.Callback implementation
@Override
public void surfaceCreated(final SurfaceHolder holder){
public void surfaceDestroyed(SurfaceHolder holder){ gLogger.debug("surfaceDestroyed");
}
- @Override
- public void onPreviewFrame(final byte[] data, Camera camera){
- gLogger.error("onPreviewFrame");
-
- }
-
-
private String getMacAddr() {
WifiManager manager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();
}
private boolean canStartService(){
- //gLogger.debug("canStartService - Camera: " + mUsbMonitor.hasUsbCamera() + ". Network: " + NetworkMonitor.isNetworkAvailable());
return mUsbMonitor.hasUsbCamera() && NetworkMonitor.isNetworkAvailable(this);
}
@Override
public void onCameraError(String msg){
gLogger.error("onCameraEvent " + msg);
+ if(mUsbMonitor.hasUsbCamera()){
+ mServer.reopenCamera();
+ }
}
@Override
}
@Override
- public void onIsPreviewing(String msg){
- gLogger.error("onIsPreviewing: " + msg);
+ public void onPublishing(String msg){
+ gLogger.error("onPublishing: " + msg);
+ mServiceHealthMonitor.record();
}
-
-
-// class ServiceReceiver extends BroadcastReceiver{
-// @Override
-// public void onReceive(Context context, Intent intent) {
-// String value = intent.getStringExtra("extra_data");
-// gLogger.error("ServiceReceiver onReceive - " + value);
-// }
-// }
-
-// private void changePermission(){
-// try {
-// Log.e(TAG, "change permission");
-// //Process sh = Runtime.getRuntime().exec(new String[]{"su", "-c", "chmod 666 /dev/video0"});
-//
-// Process sh = Runtime.getRuntime().exec("/system/xbin/su", null,null);
-// //Process sh = Runtime.getRuntime().exec("su", null,null);
-//
-// OutputStream os = sh.getOutputStream();
-// os.write(("/system/bin/chmod 666 /dev/video0").getBytes("ASCII"));
-// //os.write(("/system/bin/echo 'wowo' >> /data/local/test").getBytes("ASCII"));
-// os.flush();
-// os.close();
-// sh.waitFor();
-//
-//
-// }catch (Exception e){
-// e.printStackTrace();
-// }
-// }
-//
-// private boolean checkCameraHardware(Context context) {
-// return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
-// }
-//
-// private static Camera getCameraInstance(){
-// Camera c = null;
-// try {
-// Log.e(TAG, "Open Camera");
-// c = Camera.open(1);
-// } catch (Exception e){
-// e.printStackTrace();
-// }
-// return c;
-// }
-//
-// private void configCamera(Camera camera){
-// Camera.Parameters paras = camera.getParameters();
-// gLogger.error("Supported Picture Sizes:");
-// for (Camera.Size cc : paras.getSupportedPictureSizes()){
-// gLogger.error(cc.width + "x" + cc.height);
-// }
-// gLogger.error("Supported Preview fps range:");
-// for(int[] i : paras.getSupportedPreviewFpsRange()){
-// gLogger.error("[" + i[0] + "," + i[1] + "]");
-// }
-// gLogger.error("Set parameters");
-// camera.setParameters(paras);
-// camera.setDisplayOrientation(0);
-// gLogger.error("Preview Format: " + paras.getPreviewFormat() + ". Size: " + paras.getPreviewSize().width + "x" + paras.getPreviewSize().height);
-// gLogger.error("Picture Format: " + paras.getPictureFormat() + ". Size: " + paras.getPictureSize().width + "x" + paras.getPictureSize().height);
-//
-// try {
-// camera.setPreviewDisplay(mHolder);
-// } catch (IOException e){
-// e.printStackTrace();
-// }
-// //camera.setPreviewCallback(this);
-// }
-//
-// private void switchToBackground(){
-// Intent i = new Intent();
-// i.setAction(Intent.ACTION_MAIN);
-// i.addCategory(Intent.CATEGORY_HOME);
-// this.startActivity(i);
-// }
}
private static Logger gLogger = Logger.getLogger("MyService");
private Camera mCamera = null;
IBinder mBinder = new LocalBinder();
- private String rtmpUrl;
+ //private String rtmpUrl;
private long frameCount = 0;
// Preferred picture Size of the camera;
private void openCameraOriginal() {
try {
gLogger.error("openCameraOriginal");
- mCamera = Camera.open(1);
+ Camera.CameraInfo info = new Camera.CameraInfo();
+ int numCameras = Camera.getNumberOfCameras();
+ int backId = -1;
+ int frontId = -1;
+ int camerId = 0;
+ gLogger.debug("Number of Cameras is " + numCameras);
+ for(int i = 0; i < numCameras; i++){
+ Camera.getCameraInfo(i, info);
+ if(info.facing == Camera.CameraInfo.CAMERA_FACING_BACK){
+ gLogger.debug("CAMERA_FACING_BACK id is " + i);
+ backId = i;
+ } else if(info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
+ gLogger.debug("CAMERA_FACING_FRONT id is " + i);
+ frontId = i;
+ }
+ }
+ if(frontId != -1) camerId = frontId;
+ else if(backId != -1) camerId = backId;
+ mCamera = Camera.open(camerId);
} catch (Exception e) {
- gLogger.error("camera is not available. error: " + e.getMessage());
+ gLogger.error("openCameraOriginal - camera is not available. error: " + e.getMessage());
if(mListener != null) mListener.onCameraError("openCamera - error: " + e.getMessage());
}
}
try {
wait();
} catch (InterruptedException e) {
- gLogger.error("wait was interrupted");
+ gLogger.error("wait was interrupted, " + e.getMessage());
}
}
}
super.onCreate();
gLogger.error("onCreate ---> ");
createNotification();
- //Toast.makeText(this, "Started to Publish!", Toast.LENGTH_LONG).show();
+ Toast.makeText(this, "Started to Publish!", Toast.LENGTH_LONG).show();
mCamera = getCameraInstance();
if(mCamera != null){
configCamera(mCamera);
public void onPreviewFrame(final byte[] data, Camera camera){
if(frameCount % (15 * 60) == 0) {
gLogger.error("onPreviewFrame");
- if(mListener != null) mListener.onIsPreviewing("onPreviewFrame ");
}
- frameCount++;
if(FfmpegHelper.processFrame(data) != 0){
- gLogger.error("FfmpegHelper.processFrame error, close");
+ gLogger.error("onPreviewFrame, processFrame close");
FfmpegHelper.close();
if(mListener != null) mListener.onEncoderError("processFrame");
+ } else {
+ if(frameCount % (15 * 60) == 0){
+ if(mListener != null) mListener.onPublishing("processFrame OK");
+ }
}
+ frameCount++;
}
public void startPreview (SurfaceHolder holder){
- gLogger.error("startPreview");
+ gLogger.debug("startPreview");
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
}
+ public void reopenCamera() {
+ if(mCamera != null){
+ mCamera.stopPreview();
+ mCamera.release();
+ }
+ openCameraOriginal();
+ }
+
public boolean setRtmpUrl (String url){
- this.rtmpUrl = url;
+ //this.rtmpUrl = url;
if(mCamera == null) return false;
gLogger.error("setRtmpUrl - size: " + width + "x" + height + ". url: " + url);
int ret = FfmpegHelper.initEncoder(width, height, url);
+ if(ret != 0){
+ gLogger.error("setRtmpUrl, initEncoder error");
+ }
return ret == 0 ? true : false;
}
// Camaer.onError callback
@Override
public void onError(int error, Camera camera){
- //if(error == CAMERA_ERROR_SERVER_DIED)
- gLogger.error("onError, " + error);
+ gLogger.error("Camera.OnError, " + error);
+ switch (error) {
+ case Camera.CAMERA_ERROR_SERVER_DIED:
+ gLogger.error("CAMERA_ERROR_SERVER_DIED");
+ break;
+ case Camera.CAMERA_ERROR_UNKNOWN:
+ gLogger.error("CAMERA_ERROR_UNKNOWN");
+ break;
+ }
+
if(mListener != null) mListener.onCameraError("OnError, " + error);
}
public interface MyServiceEventListener {
void onCameraError(String err);
void onEncoderError(String msg);
- void onIsPreviewing(String msg); // notify mainActivity if preview is running well
-// void onIsPublishing(String msg); // notify main activity if encoder is running well;
+ //void onIsPreviewing(String msg); // notify mainActivity if preview is running well
+ void onPublishing(String msg); // notify main activity if encoder is running well;
}
}