From 9dd46840cb25b1acb55a9c2f378718cf75a13c5a Mon Sep 17 00:00:00 2001 From: HBiSoft Date: Tue, 14 Jan 2020 15:57:27 +0200 Subject: [PATCH] improved error catching (HBRecorderOnError) --- .../hbrecorderexample/MainActivity.java | 32 +---- .../com/hbisoft/hbrecorder/HBRecorder.java | 5 +- .../hbrecorder/HBRecorderListener.java | 2 +- .../hbrecorder/ScreenRecordService.java | 131 +++++++++++------- 4 files changed, 88 insertions(+), 82 deletions(-) diff --git a/app/src/main/java/com/hbisoft/hbrecorderexample/MainActivity.java b/app/src/main/java/com/hbisoft/hbrecorderexample/MainActivity.java index 7e40226..e765152 100644 --- a/app/src/main/java/com/hbisoft/hbrecorderexample/MainActivity.java +++ b/app/src/main/java/com/hbisoft/hbrecorderexample/MainActivity.java @@ -5,8 +5,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.media.MediaCodecInfo; -import android.media.MediaCodecList; import android.media.projection.MediaProjectionManager; import android.os.Build; import android.os.Environment; @@ -109,9 +107,6 @@ protected void onCreate(Bundle savedInstanceState) { recordAudioCheckBoxListener(); notificationCheckboxListener(); - MediaCodecInfo mediaCodecInfo = selectCodec("video/mp4"); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //Init HBRecorder hbRecorder = new HBRecorder(this, this); @@ -128,25 +123,6 @@ protected void onCreate(Bundle savedInstanceState) { } - private static MediaCodecInfo selectCodec(String mimeType) { - int numCodecs = MediaCodecList.getCodecCount(); - for (int i = 0; i < numCodecs; i++) { - MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); - - if (!codecInfo.isEncoder()) { - continue; - } - - String[] types = codecInfo.getSupportedTypes(); - for (int j = 0; j < types.length; j++) { - if (types[j].equalsIgnoreCase(mimeType)) { - return codecInfo; - } - } - } - return null; - } - //Create Folder private void createFolder() { File f1 = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), "HBRecorder"); @@ -247,14 +223,20 @@ public void HBRecorderOnComplete() { } @Override - public void HBRecorderOnError(int errorCode) { + public void HBRecorderOnError(int errorCode, String reason) { // Error 38 happens when // - the selected video encoder is not supported // - the output format is not supported // - if another app is using the microphone + + //It is best to use device default + if (errorCode == 38){ showLongToast("Some settings are not supported by your device"); + }else{ + Log.e("HBRecorderOnError", reason); } + startbtn.setText(R.string.start_recording); } diff --git a/hbrecorder/src/main/java/com/hbisoft/hbrecorder/HBRecorder.java b/hbrecorder/src/main/java/com/hbisoft/hbrecorder/HBRecorder.java index e711499..ec86095 100644 --- a/hbrecorder/src/main/java/com/hbisoft/hbrecorder/HBRecorder.java +++ b/hbrecorder/src/main/java/com/hbisoft/hbrecorder/HBRecorder.java @@ -234,11 +234,10 @@ private void startService(Intent data) { protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); if (resultCode == Activity.RESULT_OK) { - String result = resultData.getString("error"); + String result = resultData.getString("errorReason"); if (result != null) { - int errorCode = Integer.parseInt(result); observer.stopWatching(); - hbRecorderListener.HBRecorderOnError(errorCode); + hbRecorderListener.HBRecorderOnError(100, result); Intent mservice = new Intent(context, ScreenRecordService.class); context.stopService(mservice); } diff --git a/hbrecorder/src/main/java/com/hbisoft/hbrecorder/HBRecorderListener.java b/hbrecorder/src/main/java/com/hbisoft/hbrecorder/HBRecorderListener.java index 1d832a6..efa410a 100644 --- a/hbrecorder/src/main/java/com/hbisoft/hbrecorder/HBRecorderListener.java +++ b/hbrecorder/src/main/java/com/hbisoft/hbrecorder/HBRecorderListener.java @@ -2,5 +2,5 @@ public interface HBRecorderListener { void HBRecorderOnComplete(); - void HBRecorderOnError(int errorCode); + void HBRecorderOnError(int errorCode, String reason); } diff --git a/hbrecorder/src/main/java/com/hbisoft/hbrecorder/ScreenRecordService.java b/hbrecorder/src/main/java/com/hbisoft/hbrecorder/ScreenRecordService.java index 8deb201..9bae34f 100755 --- a/hbrecorder/src/main/java/com/hbisoft/hbrecorder/ScreenRecordService.java +++ b/hbrecorder/src/main/java/com/hbisoft/hbrecorder/ScreenRecordService.java @@ -27,7 +27,6 @@ import android.os.ResultReceiver; import android.util.Log; -import java.io.IOException; import java.sql.Date; import java.text.SimpleDateFormat; import java.util.Locale; @@ -54,24 +53,19 @@ public class ScreenRecordService extends Service { private int audioSamplingRate; private static String filePath; private static String fileName; - private String audioSource; private int audioSourceAsInt; - private String videoEncoder; private int videoEncoderAsInt; private boolean isCustomSettingsEnabled; private int videoFrameRate; private int videoBitrate; - private String outputFormat; private int outputFormatAsInt; public final static String BUNDLED_LISTENER = "listener"; @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override - public int onStartCommand(Intent intent, int flags, int startId) { - /* - * Notification Start - */ + public int onStartCommand(final Intent intent, int flags, int startId) { + //Get intent extras byte[] notificationSmallIcon = intent.getByteArrayExtra("notificationSmallBitmap"); String notificationTitle = intent.getStringExtra("notificationTitle"); String notificationDescription = intent.getStringExtra("notificationDescription"); @@ -86,36 +80,39 @@ public int onStartCommand(Intent intent, int flags, int startId) { isAudioEnabled = intent.getBooleanExtra("audio", true); path = intent.getStringExtra("path"); name = intent.getStringExtra("fileName"); - audioSource = intent.getStringExtra("audioSource"); - videoEncoder = intent.getStringExtra("videoEncoder"); + String audioSource = intent.getStringExtra("audioSource"); + String videoEncoder = intent.getStringExtra("videoEncoder"); videoFrameRate = intent.getIntExtra("videoFrameRate",30); videoBitrate = intent.getIntExtra("videoBitrate",40000000); + setAudioSourceAsInt(audioSource); setvideoEncoderAsInt(videoEncoder); filePath = name; audioBitrate = intent.getIntExtra("audioBitrate", 128000); audioSamplingRate = intent.getIntExtra("audioSamplingRate", 44100); - outputFormat = intent.getStringExtra("outputFormat"); + String outputFormat = intent.getStringExtra("outputFormat"); setOutputformatAsInt(outputFormat); isCustomSettingsEnabled = intent.getBooleanExtra("enableCustomSettings", false); + //Set notification notification button text if developer did not if (notificationButtonText==null){ notificationButtonText = "STOP RECORDING"; } - + //Set notification bitrate if developer did not if (audioBitrate == 0){ audioBitrate = 128000; } + //Set notification sampling rate if developer did not if (audioSamplingRate == 0){ audioSamplingRate = 44100; } - + //Set notification title if developer did not if (notificationTitle == null || notificationTitle.equals("")){ notificationTitle = "Recording your screen"; } - + //Set notification description if developer did not if (notificationDescription == null || notificationDescription.equals("")){ notificationDescription = "Drag down to stop the recording"; } @@ -150,7 +147,6 @@ public int onStartCommand(Intent intent, int flags, int startId) { } else { //Modify notification badge notification = new Notification.Builder(getApplicationContext(), channelId).setOngoing(true).setSmallIcon(R.drawable.icon).setContentTitle(notificationTitle).setContentText(notificationDescription).addAction(action).build(); - } startForeground(101, notification); } @@ -158,35 +154,62 @@ public int onStartCommand(Intent intent, int flags, int startId) { startForeground(101, new Notification()); } } - /* - * Notification End - */ + //Notification End if (path == null) { path = String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)); } - mMediaProjection = createMediaProjection(); - mMediaRecorder = createMediaRecorder(); - mVirtualDisplay = createVirtualDisplay(); + //Init MediaRecorder + try { + initRecorder(); + }catch (Exception e){ + ResultReceiver receiver = intent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER); + Bundle bundle = new Bundle(); + bundle.putString("errorReason", Log.getStackTraceString(e)); + receiver.send(Activity.RESULT_OK, bundle); + } + //Init MediaProjection + try { + initMediaProjection(); + }catch (Exception e){ + ResultReceiver receiver = intent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER); + Bundle bundle = new Bundle(); + bundle.putString("errorReason", Log.getStackTraceString(e)); + receiver.send(Activity.RESULT_OK, bundle); + } + //Init VirtualDisplay + try { + initVirtualDisplay(); + }catch (Exception e){ + ResultReceiver receiver = intent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER); + Bundle bundle = new Bundle(); + bundle.putString("errorReason", Log.getStackTraceString(e)); + receiver.send(Activity.RESULT_OK, bundle); + } mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() { @Override public void onError(MediaRecorder mediaRecorder, int i, int i1) { - //TODO - Implement onError listener - Log.e("ERROR", "WAS CALLED"); + ResultReceiver receiver = intent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER); + Bundle bundle = new Bundle(); + bundle.putString("error", "38"); + bundle.putString("errorReason", String.valueOf(i)); + receiver.send(Activity.RESULT_OK, bundle); } }); + //Start Recording try { mMediaRecorder.start(); - }catch (IllegalStateException e){ + }catch (Exception e){ // From the tests I've done, this can happen if another application is using the mic or if an unsupported video encoder was selected ResultReceiver receiver = intent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER); Bundle bundle = new Bundle(); bundle.putString("error", "38"); + bundle.putString("errorReason", Log.getStackTraceString(e)); receiver.send(Activity.RESULT_OK, bundle); } @@ -194,6 +217,8 @@ public void onError(MediaRecorder mediaRecorder, int i, int i1) { return Service.START_STICKY; } + //Set output format as int based on what developer has provided + //It is important to provide one of the following and nothing else. private void setOutputformatAsInt(String outputFormat) { switch (outputFormat) { case "DEFAULT": @@ -228,6 +253,8 @@ private void setOutputformatAsInt(String outputFormat) { } } + //Set video encoder as int based on what developer has provided + //It is important to provide one of the following and nothing else. private void setvideoEncoderAsInt(String encoder) { switch (encoder) { case "DEFAULT": @@ -251,6 +278,8 @@ private void setvideoEncoderAsInt(String encoder) { } } + //Set audio source as int based on what developer has provided + //It is important to provide one of the following and nothing else. private void setAudioSourceAsInt(String audioSource) { switch (audioSource) { case "DEFAULT": @@ -290,22 +319,22 @@ private void setAudioSourceAsInt(String audioSource) { } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - private MediaProjection createMediaProjection() { - return ((MediaProjectionManager) Objects.requireNonNull(getSystemService(Context.MEDIA_PROJECTION_SERVICE))). - getMediaProjection(mResultCode, mResultData); + private void initMediaProjection(){ + mMediaProjection = ((MediaProjectionManager) Objects.requireNonNull(getSystemService(Context.MEDIA_PROJECTION_SERVICE))).getMediaProjection(mResultCode, mResultData); } + //Return the output file path as string public static String getFilePath() { return filePath; } + //Return the name of the output file public static String getFileName() { return fileName; } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - private MediaRecorder createMediaRecorder() { + private void initRecorder() throws Exception{ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault()); Date curDate = new Date(System.currentTimeMillis()); String curTime = formatter.format(curDate).replace(" ", ""); @@ -321,50 +350,46 @@ private MediaRecorder createMediaRecorder() { fileName = name + ".mp4"; - MediaRecorder mediaRecorder = new MediaRecorder(); + mMediaRecorder = new MediaRecorder(); if (isAudioEnabled) { - mediaRecorder.setAudioSource(audioSourceAsInt); + mMediaRecorder.setAudioSource(audioSourceAsInt); } - mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); - mediaRecorder.setOutputFormat(outputFormatAsInt); + mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); + mMediaRecorder.setOutputFormat(outputFormatAsInt); if (isAudioEnabled) { - mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); - mediaRecorder.setAudioEncodingBitRate(audioBitrate); - mediaRecorder.setAudioSamplingRate(audioSamplingRate); + mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); + mMediaRecorder.setAudioEncodingBitRate(audioBitrate); + mMediaRecorder.setAudioSamplingRate(audioSamplingRate); } - mediaRecorder.setVideoEncoder(videoEncoderAsInt); - mediaRecorder.setOutputFile(path + "/" + name + ".mp4"); - mediaRecorder.setVideoSize(mScreenWidth, mScreenHeight); + mMediaRecorder.setVideoEncoder(videoEncoderAsInt); + mMediaRecorder.setOutputFile(path + "/" + name + ".mp4"); + mMediaRecorder.setVideoSize(mScreenWidth, mScreenHeight); if (!isCustomSettingsEnabled) { if (!isVideoHD) { - mediaRecorder.setVideoEncodingBitRate(12000000); - mediaRecorder.setVideoFrameRate(30); + mMediaRecorder.setVideoEncodingBitRate(12000000); + mMediaRecorder.setVideoFrameRate(30); } else { - mediaRecorder.setVideoEncodingBitRate(5 * mScreenWidth * mScreenHeight); - mediaRecorder.setVideoFrameRate(60); //after setVideoSource(), setOutFormat() + mMediaRecorder.setVideoEncodingBitRate(5 * mScreenWidth * mScreenHeight); + mMediaRecorder.setVideoFrameRate(60); //after setVideoSource(), setOutFormat() } }else{ - mediaRecorder.setVideoEncodingBitRate(videoBitrate); - mediaRecorder.setVideoFrameRate(videoFrameRate); + mMediaRecorder.setVideoEncodingBitRate(videoBitrate); + mMediaRecorder.setVideoFrameRate(videoFrameRate); } - try { - mediaRecorder.prepare(); - } catch (IllegalStateException | IOException e) { - Log.e(TAG, "createMediaRecorder: e = " + e.toString()); - } + mMediaRecorder.prepare(); - return mediaRecorder; + //return mediaRecorder; } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - private VirtualDisplay createVirtualDisplay() { - return mMediaProjection.createVirtualDisplay(TAG, mScreenWidth, mScreenHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null); + private void initVirtualDisplay(){ + mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG, mScreenWidth, mScreenHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)