启动mediaRecorder onActivityResult()

时间:2017-11-14 08:59:49

标签: java android video-recording screen-recording

当我们进行视频通话时,我有建立屏幕录制功能的问题。我的意思是我想同时开始录制屏幕和视频通话。尝试在此https://www.simplifiedcoding.net/video-call-android-tutorial/和此http://www.truiton.com/2015/05/capture-record-android-screen-using-mediaprojection-apis/之间合并源代码,但在视频通话时启动记录屏幕时,应用会突然崩溃。 代码如下所示

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode != REQUEST_CODE) {
        Log.e(TAG, "Unknown request code: " + requestCode);
        return;
    }
    if (resultCode != RESULT_OK) {
        Toast.makeText(this,
                "Screen Cast Permission Denied", Toast.LENGTH_SHORT).show();
        mToggleButton.setChecked(false);
        return;
    }
    mMediaProjectionCallback = new MediaProjectionCallback();
    mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
    mMediaProjection.registerCallback(mMediaProjectionCallback, null);
    mVirtualDisplay = createVirtualDisplay();
    mMediaRecorder.start();
}

这是logcat

  

11-14 16:51:55.265 13200-13200 / com.example.prasetyo.videocallapp E / AndroidRuntime:FATAL EXCEPTION:main                                                                                      过程:com.example.prasetyo.videocallapp,PID:13200                                                                                      java.lang.RuntimeException:将结果ResultInfo {who = null,request = 1000,result = -1,data = Intent {(has extras)}}传递给activity {com.example.prasetyo.videocallapp / com.example.prasetyo .videocallapp.Activities.CallScreenActivity}:java.lang.IllegalStateException                                                                                          在android.app.ActivityThread.deliverResults(ActivityThread.java:3574)                                                                                          在android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)                                                                                          在android.app.ActivityThread.access $ 1300(ActivityThread.java:151)                                                                                          在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1352)                                                                                          在android.os.Handler.dispatchMessage(Handler.java:102)                                                                                          在android.os.Looper.loop(Looper.java:135)                                                                                          在android.app.ActivityThread.main(ActivityThread.java:5254)                                                                                          at java.lang.reflect.Method.invoke(Native Method)                                                                                          在java.lang.reflect.Method.invoke(Method.java:372)                                                                                          在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:903)                                                                                          在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)                                                                                       引起:java.lang.IllegalStateException                                                                                          在android.media.MediaRecorder.start(Native方法)                                                                                          at com.example.prasetyo.videocallapp.Activities.CallScreenActivity.onActivityResult(CallScreenActivity.java:214)                                                                                          在android.app.Activity.dispatchActivityResult(Activity.java:6192)                                                                                          在android.app.ActivityThread.deliverResults(ActivityThread.java:3570)                                                                                          在android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)                                                                                          在android.app.ActivityThread.access $ 1300(ActivityThread.java:151)                                                                                          在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1352)                                                                                          在android.os.Handler.dispatchMessage(Handler.java:102)                                                                                          在android.os.Looper.loop(Looper.java:135)                                                                                          在android.app.ActivityThread.main(ActivityThread.java:5254)                                                                                          at java.lang.reflect.Method.invoke(Native Method)                                                                                          在java.lang.reflect.Method.invoke(Method.java:372)                                                                                          在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:903)                                                                                          在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

最后,这是完整的java类

public class CallScreenActivity extends BaseActivity {

static final String TAG = CallScreenActivity.class.getSimpleName();
static final String CALL_START_TIME = "callStartTime";
static final String ADDED_LISTENER = "addedListener";

private AudioPlayer mAudioPlayer;
private Timer mTimer;
private UpdateCallDurationTask mDurationTask;

private String mCallId;
private long mCallStart = 0;
private boolean mAddedListener = false;
private boolean mVideoViewsAdded = false;

private TextView mCallDuration;
private TextView mCallState;
private TextView mCallerName;

private static final int REQUEST_CODE = 1000;
private int mScreenDensity;
private MediaProjectionManager mProjectionManager;
private static final int DISPLAY_WIDTH = 720;
private static final int DISPLAY_HEIGHT = 1280;
private MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private MediaProjectionCallback mMediaProjectionCallback;
private ToggleButton mToggleButton;
private MediaRecorder mMediaRecorder;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final int REQUEST_PERMISSIONS = 10;

static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
}

private class UpdateCallDurationTask extends TimerTask {

    @Override
    public void run() {
        CallScreenActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                updateCallDuration();
            }
        });
    }
}

@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putLong(CALL_START_TIME, mCallStart);
    savedInstanceState.putBoolean(ADDED_LISTENER, mAddedListener);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    mCallStart = savedInstanceState.getLong(CALL_START_TIME);
    mAddedListener = savedInstanceState.getBoolean(ADDED_LISTENER);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_call_screen);

    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    mScreenDensity = metrics.densityDpi;
    mMediaRecorder = new MediaRecorder();

    mProjectionManager = (MediaProjectionManager) getSystemService
            (Context.MEDIA_PROJECTION_SERVICE);
    mAudioPlayer = new AudioPlayer(this);
    mCallDuration = (TextView) findViewById(R.id.callDuration);
    mCallerName = (TextView) findViewById(R.id.remoteUser);
    mCallState = (TextView) findViewById(R.id.callState);
    ImageButton endCallButton = (ImageButton) findViewById(R.id.hangupButton);

    mToggleButton = (ToggleButton) findViewById(R.id.toggle);
    mToggleButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (ContextCompat.checkSelfPermission(CallScreenActivity.this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE) + ContextCompat
                    .checkSelfPermission(CallScreenActivity.this,
                            Manifest.permission.RECORD_AUDIO)
                    != PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.shouldShowRequestPermissionRationale
                        (CallScreenActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ||
                        ActivityCompat.shouldShowRequestPermissionRationale
                                (CallScreenActivity.this, Manifest.permission.RECORD_AUDIO)) {
                    mToggleButton.setChecked(false);
                    Snackbar.make(findViewById(android.R.id.content), R.string.label_permissions,
                            Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
                            new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    ActivityCompat.requestPermissions(CallScreenActivity.this,
                                            new String[]{Manifest.permission
                                                    .WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                                            REQUEST_PERMISSIONS);
                                }
                            }).show();
                } else {
                    ActivityCompat.requestPermissions(CallScreenActivity.this,
                            new String[]{Manifest.permission
                                    .WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                            REQUEST_PERMISSIONS);
                }
            } else {
                onToggleScreenShare(v);
            }
        }
    });

    mCallId = getIntent().getStringExtra(SinchService.CALL_ID);
    if (savedInstanceState == null) {
        mCallStart = System.currentTimeMillis();
    }

    endCallButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            endCall();
            mToggleButton.setChecked(false);
            onToggleScreenShare(mToggleButton);
        }
    });


}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode != REQUEST_CODE) {
        Log.e(TAG, "Unknown request code: " + requestCode);
        return;
    }
    if (resultCode != RESULT_OK) {
        Toast.makeText(this,
                "Screen Cast Permission Denied", Toast.LENGTH_SHORT).show();
        mToggleButton.setChecked(false);
        return;
    }
    mMediaProjectionCallback = new MediaProjectionCallback();
    mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
    mMediaProjection.registerCallback(mMediaProjectionCallback, null);
    mVirtualDisplay = createVirtualDisplay();
    mMediaRecorder.start();
}

public void onToggleScreenShare(View view) {
    if (((ToggleButton) view).isChecked()) {
        initRecorder();
        shareScreen();
    } else {
        mMediaRecorder.stop();
        mMediaRecorder.reset();
        Log.v(TAG, "Stopping Recording");
        stopScreenSharing();
    }
}

private void shareScreen() {
    if (mMediaProjection == null) {
        startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
        return;
    }
    mVirtualDisplay = createVirtualDisplay();
    mMediaRecorder.start();
}

private VirtualDisplay createVirtualDisplay() {
    return mMediaProjection.createVirtualDisplay("CallScreenActivity",
            DISPLAY_WIDTH, DISPLAY_HEIGHT, mScreenDensity,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            mMediaRecorder.getSurface(), null /*Callbacks*/, null
            /*Handler*/);
}

private void initRecorder() {
    try {
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mMediaRecorder.setOutputFile(Environment
                .getExternalStorageDirectory().getAbsolutePath() + "/video.mp4");
        mMediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
        mMediaRecorder.setVideoFrameRate(30);
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        int orientation = ORIENTATIONS.get(rotation + 90);
        mMediaRecorder.setOrientationHint(orientation);
        mMediaRecorder.prepare();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private class MediaProjectionCallback extends MediaProjection.Callback {
    @Override
    public void onStop() {
        if (mToggleButton.isChecked()) {
            mToggleButton.setChecked(false);
            mMediaRecorder.stop();
            mMediaRecorder.reset();
            Log.v(TAG, "Recording Stopped");
        }
        mMediaProjection = null;
        stopScreenSharing();
    }
}

private void stopScreenSharing() {
    if (mVirtualDisplay == null) {
        return;
    }
    mVirtualDisplay.release();
    //mMediaRecorder.release(); //If used: mMediaRecorder object cannot
    // be reused again
    destroyMediaProjection();
}

@Override
public void onDestroy() {
    super.onDestroy();
    destroyMediaProjection();
}

private void destroyMediaProjection() {
    if (mMediaProjection != null) {
        mMediaProjection.unregisterCallback(mMediaProjectionCallback);
        mMediaProjection.stop();
        mMediaProjection = null;
    }
    Log.i(TAG, "MediaProjection Stopped");
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       @NonNull String permissions[],
                                       @NonNull int[] grantResults) {
    switch (requestCode) {
        case REQUEST_PERMISSIONS: {
            if ((grantResults.length > 0) && (grantResults[0] +
                    grantResults[1]) == PackageManager.PERMISSION_GRANTED) {
                onToggleScreenShare(mToggleButton);
            } else {
                mToggleButton.setChecked(false);
                Snackbar.make(findViewById(android.R.id.content), R.string.label_permissions,
                        Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
                        new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Intent intent = new Intent();
                                intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                intent.addCategory(Intent.CATEGORY_DEFAULT);
                                intent.setData(Uri.parse("package:" + getPackageName()));
                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                                startActivity(intent);
                            }
                        }).show();
            }
            return;
        }
    }
}

@Override
public void onServiceConnected() {
    Call call = getSinchServiceInterface().getCall(mCallId);
    if (call != null) {
        if (!mAddedListener) {
            call.addCallListener(new SinchCallListener());
            mAddedListener = true;
        }
    } else {
        Log.e(TAG, "Started with invalid callId, aborting.");
        finish();
    }

    updateUI();
}

//method to update video feeds in the UI
private void updateUI() {
    if (getSinchServiceInterface() == null) {
        return; // early
    }

    Call call = getSinchServiceInterface().getCall(mCallId);
    if (call != null) {
        mCallerName.setText(call.getRemoteUserId());
        mCallState.setText(call.getState().toString());
        if (call.getState() == CallState.ESTABLISHED) {
            //when the call is established, addVideoViews configures the video to  be shown
            addVideoViews();
        }
    }
}

//stop the timer when call is ended
@Override
public void onStop() {
    super.onStop();
    mDurationTask.cancel();
    mTimer.cancel();
    removeVideoViews();
}

//start the timer for the call duration here
@Override
public void onStart() {
    super.onStart();
    mTimer = new Timer();
    mDurationTask = new UpdateCallDurationTask();
    mTimer.schedule(mDurationTask, 0, 500);
    updateUI();
}

@Override
public void onBackPressed() {
    // User should exit activity by ending call, not by going back.
}

//method to end the call
private void endCall() {
    mAudioPlayer.stopProgressTone();
    Call call = getSinchServiceInterface().getCall(mCallId);
    if (call != null) {
        call.hangup();
    }
    finish();
}

private String formatTimespan(long timespan) {
    long totalSeconds = timespan / 1000;
    long minutes = totalSeconds / 60;
    long seconds = totalSeconds % 60;
    return String.format(Locale.US, "%02d:%02d", minutes, seconds);
}

//method to update live duration of the call
private void updateCallDuration() {
    if (mCallStart > 0) {
        mCallDuration.setText(formatTimespan(System.currentTimeMillis() - mCallStart));
    }
}

//method which sets up the video feeds from the server to the UI of the activity
private void addVideoViews() {
    if (mVideoViewsAdded || getSinchServiceInterface() == null) {
        return; //early
    }

    final VideoController vc = getSinchServiceInterface().getVideoController();
    if (vc != null) {
        RelativeLayout localView = (RelativeLayout) findViewById(R.id.localVideo);
        localView.addView(vc.getLocalView());

        localView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //this toggles the front camera to rear camera and vice versa
                vc.toggleCaptureDevicePosition();
            }
        });

        LinearLayout view = (LinearLayout) findViewById(R.id.remoteVideo);
        view.addView(vc.getRemoteView());
        mVideoViewsAdded = true;
    }
}

//removes video feeds from the app once the call is terminated
private void removeVideoViews() {
    if (getSinchServiceInterface() == null) {
        return; // early
    }

    VideoController vc = getSinchServiceInterface().getVideoController();
    if (vc != null) {
        LinearLayout view = (LinearLayout) findViewById(R.id.remoteVideo);
        view.removeView(vc.getRemoteView());

        RelativeLayout localView = (RelativeLayout) findViewById(R.id.localVideo);
        localView.removeView(vc.getLocalView());
        mVideoViewsAdded = false;
    }
}

private class SinchCallListener implements VideoCallListener {

    @Override
    public void onCallEnded(Call call) {
        CallEndCause cause = call.getDetails().getEndCause();
        Log.d(TAG, "Call ended. Reason: " + cause.toString());
        mAudioPlayer.stopProgressTone();
        setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE);
        String endMsg = "Call ended: " + call.getDetails().toString();
        Toast.makeText(CallScreenActivity.this, endMsg, Toast.LENGTH_LONG).show();

        endCall();

        mToggleButton.setChecked(false);
        onToggleScreenShare(mToggleButton);

    }

    @Override
    public void onCallEstablished(Call call) {
        Log.d(TAG, "Call established");
        mAudioPlayer.stopProgressTone();
        mCallState.setText(call.getState().toString());
        setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
        AudioController audioController = getSinchServiceInterface().getAudioController();
        audioController.enableSpeaker();
        mCallStart = System.currentTimeMillis();
        Log.d(TAG, "Call offered video: " + call.getDetails().isVideoOffered());
    }

    @Override
    public void onCallProgressing(Call call) {
        Log.d(TAG, "Call progressing");
        mAudioPlayer.playProgressTone();
    }

    @Override
    public void onShouldSendPushNotification(Call call, List pushPairs) {
        // Send a push through your push provider here, e.g. GCM
    }

    @Override
    public void onVideoTrackAdded(Call call) {
        Log.d(TAG, "Video track added");
        addVideoViews();
    }
}

}

希望有人可以帮助我,非常感谢!

1 个答案:

答案 0 :(得分:-1)

我面临着同样的问题。 java.lang.IllegalStateException是由于您正在从另一个线程(//播放拨号音mDialTone.start();)访问主线程视图,从而产生了异常。只需在主线程上调用initRecorder()即可。它将解决您的问题。