[*] 服务端录制
This commit is contained in:
@@ -239,7 +239,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
/**
|
||||
* 录制按钮
|
||||
* 录像按钮
|
||||
*
|
||||
* @param message 消息
|
||||
*/
|
||||
|
||||
@@ -63,7 +63,7 @@ public class MediaService extends Service {
|
||||
*/
|
||||
RECONNECT,
|
||||
/**
|
||||
* 屏幕录制
|
||||
* 屏幕录像
|
||||
*/
|
||||
SCREEN_CAPTURE;
|
||||
|
||||
@@ -222,7 +222,7 @@ public class MediaService extends Service {
|
||||
}
|
||||
|
||||
/**
|
||||
* 屏幕录制
|
||||
* 屏幕录像
|
||||
*
|
||||
* @param intent Intent
|
||||
*/
|
||||
@@ -232,8 +232,8 @@ public class MediaService extends Service {
|
||||
final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, TAOYAO)
|
||||
.setSmallIcon(R.mipmap.ic_launcher_foreground)
|
||||
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher_foreground))
|
||||
.setContentTitle("录制屏幕")
|
||||
.setContentText("桃夭正在录制屏幕")
|
||||
.setContentTitle("屏幕录像")
|
||||
.setContentText("桃夭正在屏幕录像")
|
||||
.setContentIntent(pendingIntent);
|
||||
final Notification notification = notificationBuilder.build();
|
||||
this.startForeground((int) System.currentTimeMillis(), notification);
|
||||
@@ -279,13 +279,16 @@ public class MediaService extends Service {
|
||||
private void settingAudio() {
|
||||
final AudioManager audioManager = this.getApplicationContext().getSystemService(AudioManager.class);
|
||||
audioManager.setSpeakerphoneOn(true);
|
||||
// audioManager.setMicrophoneMute(true);
|
||||
audioManager.setMode(AudioManager.MODE_IN_CALL);
|
||||
Log.d(MediaService.class.getSimpleName(), "当前音频模式:" + audioManager.getMode());
|
||||
Log.d(MediaService.class.getSimpleName(), "当前音频音量:" + audioManager.getStreamVolume(audioManager.getMode()));
|
||||
Log.d(MediaService.class.getSimpleName(), "当前最大音频音量:" + audioManager.getStreamMaxVolume(audioManager.getMode()));
|
||||
Log.d(MediaService.class.getSimpleName(), "当前蓝牙是否打开:" + audioManager.isBluetoothScoOn());
|
||||
// Log.d(MediaService.class.getSimpleName(), "当前耳机是否打开:" + audioManager.isWiredHeadsetOn());
|
||||
Log.d(MediaService.class.getSimpleName(), "当前扬声器是否打开:" + audioManager.isSpeakerphoneOn());
|
||||
audioManager.setStreamVolume(AudioManager.MODE_IN_COMMUNICATION, audioManager.getStreamMaxVolume(AudioManager.MODE_IN_COMMUNICATION), AudioManager.FLAG_PLAY_SOUND);
|
||||
audioManager.setStreamVolume(AudioManager.MODE_IN_CALL, audioManager.getStreamMaxVolume(AudioManager.MODE_IN_CALL), AudioManager.FLAG_PLAY_SOUND);
|
||||
// audioManager.setStreamVolume(AudioManager.MODE_IN_COMMUNICATION, audioManager.getStreamMaxVolume(AudioManager.MODE_IN_COMMUNICATION), AudioManager.FLAG_PLAY_SOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -786,7 +786,7 @@ public final class Taoyao implements ITaoyao {
|
||||
}
|
||||
|
||||
/**
|
||||
* 录制
|
||||
* 录像
|
||||
*
|
||||
* @param message 信令消息
|
||||
* @param body 信令主体
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- 是否预览视频 -->
|
||||
<bool name="preview">true</bool>
|
||||
<bool name="preview">false</bool>
|
||||
<!-- 是否开启音频播放 -->
|
||||
<bool name="playAudio">true</bool>
|
||||
<!-- 是否开启视频播放 -->
|
||||
|
||||
@@ -148,7 +148,7 @@ public final class MediaManager {
|
||||
*/
|
||||
private VideoSource shareVideoSource;
|
||||
/**
|
||||
* 录制终端
|
||||
* 录像终端
|
||||
*/
|
||||
private RecordClient recordClient;
|
||||
/**
|
||||
@@ -217,7 +217,7 @@ public final class MediaManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否正在录制
|
||||
* @return 是否正在录像
|
||||
*/
|
||||
public boolean isRecording() {
|
||||
return this.recordClient != null;
|
||||
@@ -440,25 +440,25 @@ public final class MediaManager {
|
||||
.setAudioRecordErrorCallback(new JavaAudioDeviceModule.AudioRecordErrorCallback() {
|
||||
@Override
|
||||
public void onWebRtcAudioRecordInitError(String errorMessage) {
|
||||
Log.e(MediaManager.class.getSimpleName(), "WebRTC本地音频录制加载异常:" + errorMessage);
|
||||
Log.e(MediaManager.class.getSimpleName(), "WebRTC本地音频录像加载异常:" + errorMessage);
|
||||
}
|
||||
@Override
|
||||
public void onWebRtcAudioRecordStartError(JavaAudioDeviceModule.AudioRecordStartErrorCode errorCode, String errorMessage) {
|
||||
Log.e(MediaManager.class.getSimpleName(), "WebRTC本地音频录制开始异常:" + errorMessage);
|
||||
Log.e(MediaManager.class.getSimpleName(), "WebRTC本地音频录像开始异常:" + errorMessage);
|
||||
}
|
||||
@Override
|
||||
public void onWebRtcAudioRecordError(String errorMessage) {
|
||||
Log.e(MediaManager.class.getSimpleName(), "WebRTC本地音频录制异常:" + errorMessage);
|
||||
Log.e(MediaManager.class.getSimpleName(), "WebRTC本地音频录像异常:" + errorMessage);
|
||||
}
|
||||
})
|
||||
.setAudioRecordStateCallback(new JavaAudioDeviceModule.AudioRecordStateCallback() {
|
||||
@Override
|
||||
public void onWebRtcAudioRecordStart() {
|
||||
Log.i(MediaManager.class.getSimpleName(), "WebRTC本地音频录制开始");
|
||||
Log.i(MediaManager.class.getSimpleName(), "WebRTC本地音频录像开始");
|
||||
}
|
||||
@Override
|
||||
public void onWebRtcAudioRecordStop() {
|
||||
Log.i(MediaManager.class.getSimpleName(), "WebRTC本地音频录制结束");
|
||||
Log.i(MediaManager.class.getSimpleName(), "WebRTC本地音频录像结束");
|
||||
}
|
||||
})
|
||||
// .setUseHardwareNoiseSuppressor(true)
|
||||
@@ -942,7 +942,7 @@ public final class MediaManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 屏幕录制回调
|
||||
* 屏幕录像回调
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
|
||||
@@ -33,7 +33,7 @@ public class MixerProcesser extends Thread implements JavaAudioDeviceModule.Samp
|
||||
|
||||
/**
|
||||
* 音频数据来源
|
||||
* 其实可以不用切换可以两个同时录制,但是有点浪费资源。
|
||||
* 其实可以不用切换可以两个同时录像,但是有点浪费资源。
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
|
||||
@@ -45,19 +45,19 @@ public class RecordClient extends Client implements VideoSink {
|
||||
private static final long WAIT_TIME_US = WAIT_TIME_MS * 1000;
|
||||
|
||||
/**
|
||||
* 音频录制准备完成
|
||||
* 音频录像准备完成
|
||||
*/
|
||||
private volatile boolean audioActive;
|
||||
/**
|
||||
* 视频录制准备完成
|
||||
* 视频录像准备完成
|
||||
*/
|
||||
private volatile boolean videoActive;
|
||||
/**
|
||||
* 录制文件名称
|
||||
* 录像文件名称
|
||||
*/
|
||||
private final String filename;
|
||||
/**
|
||||
* 录制文件路径
|
||||
* 录像文件路径
|
||||
*/
|
||||
private final String filepath;
|
||||
/**
|
||||
@@ -123,8 +123,8 @@ public class RecordClient extends Client implements VideoSink {
|
||||
*/
|
||||
private Handler videoHandler;
|
||||
/**
|
||||
* 是否已经开始录制
|
||||
* 不能使用多线程wait/notify录制音频没有结束
|
||||
* 是否已经开始录像
|
||||
* 不能使用多线程wait/notify录像音频没有结束
|
||||
*/
|
||||
private boolean muxerActive = false;
|
||||
/**
|
||||
@@ -180,16 +180,16 @@ public class RecordClient extends Client implements VideoSink {
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始录制
|
||||
* 开始录像
|
||||
*
|
||||
* @return 录制文件路径
|
||||
* @return 录像文件路径
|
||||
*/
|
||||
public String start() {
|
||||
synchronized (this) {
|
||||
if(this.init) {
|
||||
return this.filepath;
|
||||
}
|
||||
Log.i(RecordClient.class.getSimpleName(), "录制视频文件:" + this.filepath);
|
||||
Log.i(RecordClient.class.getSimpleName(), "录像视频文件:" + this.filepath);
|
||||
super.init();
|
||||
this.mediaManager.newClient();
|
||||
this.initMediaMuxer();
|
||||
@@ -235,7 +235,7 @@ public class RecordClient extends Client implements VideoSink {
|
||||
this.audioCodec = MediaCodec.createEncoderByType(audioType);
|
||||
this.audioCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
|
||||
} catch (Exception e) {
|
||||
Log.e(RecordClient.class.getSimpleName(), "加载音频录制线程异常", e);
|
||||
Log.e(RecordClient.class.getSimpleName(), "加载音频录像线程异常", e);
|
||||
}
|
||||
this.audioThread = new HandlerThread("AudioRecordThread");
|
||||
this.audioThread.start();
|
||||
@@ -260,9 +260,9 @@ public class RecordClient extends Client implements VideoSink {
|
||||
} else if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
synchronized (this) {
|
||||
trackIndex = this.mediaMuxer.addTrack(this.audioCodec.getOutputFormat());
|
||||
Log.i(RecordClient.class.getSimpleName(), "开始录制音频:" + trackIndex);
|
||||
Log.i(RecordClient.class.getSimpleName(), "开始录像音频:" + trackIndex);
|
||||
if (!this.close && this.videoActive) {
|
||||
Log.i(RecordClient.class.getSimpleName(), "开始录制文件:" + this.filename);
|
||||
Log.i(RecordClient.class.getSimpleName(), "开始录像文件:" + this.filename);
|
||||
this.mediaMuxer.start();
|
||||
this.muxerActive = true;
|
||||
} else {
|
||||
@@ -283,7 +283,7 @@ public class RecordClient extends Client implements VideoSink {
|
||||
bufferInfo.presentationTimeUs -= pts;
|
||||
this.mediaMuxer.writeSampleData(trackIndex, outputBuffer, bufferInfo);
|
||||
this.audioCodec.releaseOutputBuffer(outputIndex, false);
|
||||
// Log.d(RecordClient.class.getSimpleName(), "录制音频帧(时间戳):" + (bufferInfo.presentationTimeUs / 1_000_000F));
|
||||
// Log.d(RecordClient.class.getSimpleName(), "录像音频帧(时间戳):" + (bufferInfo.presentationTimeUs / 1_000_000F));
|
||||
// if (bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME == MediaCodec.BUFFER_FLAG_KEY_FRAME) {
|
||||
// } else if (bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG == MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
|
||||
// } else if (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
|
||||
@@ -298,14 +298,14 @@ public class RecordClient extends Client implements VideoSink {
|
||||
}
|
||||
synchronized (this) {
|
||||
if (this.audioCodec != null && this.audioActive) {
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录制音频:" + this.filename);
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录像音频:" + this.filename);
|
||||
this.audioCodec.stop();
|
||||
this.audioCodec.release();
|
||||
this.audioCodec = null;
|
||||
}
|
||||
this.audioActive = false;
|
||||
if (this.mediaMuxer != null && !this.videoActive) {
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录制文件:" + this.filename);
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录像文件:" + this.filename);
|
||||
this.muxerActive = false;
|
||||
// this.mediaMuxer.stop();
|
||||
this.mediaMuxer.release();
|
||||
@@ -330,7 +330,7 @@ public class RecordClient extends Client implements VideoSink {
|
||||
this.videoCodec = MediaCodec.createEncoderByType(videoType);
|
||||
this.videoCodec.configure(videoFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
|
||||
} catch (Exception e) {
|
||||
Log.e(RecordClient.class.getSimpleName(), "加载视频录制线程异常", e);
|
||||
Log.e(RecordClient.class.getSimpleName(), "加载视频录像线程异常", e);
|
||||
}
|
||||
this.videoThread = new HandlerThread("VideoRecordThread");
|
||||
this.videoThread.start();
|
||||
@@ -355,9 +355,9 @@ public class RecordClient extends Client implements VideoSink {
|
||||
} else if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
synchronized (this) {
|
||||
trackIndex = this.mediaMuxer.addTrack(this.videoCodec.getOutputFormat());
|
||||
Log.i(RecordClient.class.getSimpleName(), "开始录制视频:" + trackIndex);
|
||||
Log.i(RecordClient.class.getSimpleName(), "开始录像视频:" + trackIndex);
|
||||
if (!this.close && this.audioActive) {
|
||||
Log.i(RecordClient.class.getSimpleName(), "开始录制文件:" + this.filename);
|
||||
Log.i(RecordClient.class.getSimpleName(), "开始录像文件:" + this.filename);
|
||||
this.mediaMuxer.start();
|
||||
this.muxerActive = true;
|
||||
} else {
|
||||
@@ -379,7 +379,7 @@ public class RecordClient extends Client implements VideoSink {
|
||||
bufferInfo.presentationTimeUs -= pts;
|
||||
this.mediaMuxer.writeSampleData(trackIndex, outputBuffer, bufferInfo);
|
||||
this.videoCodec.releaseOutputBuffer(outputIndex, false);
|
||||
// Log.d(RecordClient.class.getSimpleName(), "录制视频帧(时间戳):" + (bufferInfo.presentationTimeUs / 1_000_000F));
|
||||
// Log.d(RecordClient.class.getSimpleName(), "录像视频帧(时间戳):" + (bufferInfo.presentationTimeUs / 1_000_000F));
|
||||
// if (bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME == MediaCodec.BUFFER_FLAG_KEY_FRAME) {
|
||||
// } else if (bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG == MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
|
||||
// } else if (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
|
||||
@@ -394,14 +394,14 @@ public class RecordClient extends Client implements VideoSink {
|
||||
}
|
||||
synchronized (this) {
|
||||
if (this.videoCodec != null && this.videoActive) {
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录制视频:" + this.filename);
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录像视频:" + this.filename);
|
||||
this.videoCodec.stop();
|
||||
this.videoCodec.release();
|
||||
this.videoCodec = null;
|
||||
}
|
||||
this.videoActive = false;
|
||||
if (this.mediaMuxer != null && !this.audioActive) {
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录制文件:" + this.filename);
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录像文件:" + this.filename);
|
||||
this.muxerActive = false;
|
||||
// this.mediaMuxer.stop();
|
||||
this.mediaMuxer.release();
|
||||
@@ -411,7 +411,7 @@ public class RecordClient extends Client implements VideoSink {
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载录制来源
|
||||
* 加载录像来源
|
||||
*
|
||||
* @param videoSource 视频来源
|
||||
* @param javaAudioDeviceModule 音频设备模块
|
||||
@@ -440,7 +440,7 @@ public class RecordClient extends Client implements VideoSink {
|
||||
return;
|
||||
}
|
||||
super.close();
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录制:" + this.filepath);
|
||||
Log.i(RecordClient.class.getSimpleName(), "结束录像:" + this.filepath);
|
||||
if(this.javaAudioDeviceModule != null) {
|
||||
this.javaAudioDeviceModule.removeMixerProcesser();
|
||||
this.javaAudioDeviceModule = null;
|
||||
@@ -464,7 +464,7 @@ public class RecordClient extends Client implements VideoSink {
|
||||
}
|
||||
final File file = new File(this.filepath);
|
||||
if(file.length() <= 0) {
|
||||
Log.i(RecordClient.class.getSimpleName(), "删除没有录制数据文件:" + this.filepath);
|
||||
Log.i(RecordClient.class.getSimpleName(), "删除没有录像数据文件:" + this.filepath);
|
||||
file.delete();
|
||||
}
|
||||
this.mediaManager.closeClient();
|
||||
|
||||
@@ -12,7 +12,7 @@ public class Config {
|
||||
*/
|
||||
public static final int WHAT_SCREEN_CAPTURE = 1000;
|
||||
/**
|
||||
* 视频录制
|
||||
* 视频录像
|
||||
*/
|
||||
public static final int WHAT_RECORD = 1001;
|
||||
/**
|
||||
|
||||
@@ -318,11 +318,11 @@ public class JavaAudioDeviceModule implements AudioDeviceModule {
|
||||
/** Called when new audio samples are ready. This should only be set for debug purposes */
|
||||
public static interface SamplesReadyCallback {
|
||||
/**
|
||||
* 本地录制
|
||||
* 本地录像
|
||||
*/
|
||||
void startNative();
|
||||
/**
|
||||
* 远程录制
|
||||
* 远程录像
|
||||
*/
|
||||
void startWebRTC();
|
||||
/**
|
||||
|
||||
@@ -117,12 +117,12 @@ class WebRtcAudioRecord {
|
||||
* @Taoyao
|
||||
*/
|
||||
public void setMixerProcesser(SamplesReadyCallback samplesReadyCallback) {
|
||||
// 不用处理这个逻辑设置为空表示关闭录制
|
||||
// 不用处理这个逻辑设置为空表示关闭录像
|
||||
// if(this.audioSamplesReadyCallback != null && samplesReadyCallback == null) {
|
||||
// this.audioSamplesReadyCallback.startNative();
|
||||
// }
|
||||
this.audioSamplesReadyCallback = samplesReadyCallback;
|
||||
// 下面逻辑最好加锁防止关闭录制导致异常
|
||||
// 下面逻辑最好加锁防止关闭录像导致异常
|
||||
if(this.audioSamplesReadyCallback != null) {
|
||||
if(this.audioThread == null) {
|
||||
this.audioSamplesReadyCallback.startNative();
|
||||
|
||||
Reference in New Issue
Block a user