[*] 每日优化

配置没有改变不要重连信令
忽略房间重复邀请
This commit is contained in:
acgist
2023-05-13 12:09:16 +08:00
parent 825fa907e5
commit 8430fa78a8
17 changed files with 707 additions and 383 deletions

View File

@@ -2,6 +2,7 @@ package com.acgist.taoyao.client;
import android.Manifest; import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
@@ -18,6 +19,7 @@ import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.GridLayout; import android.widget.GridLayout;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts; import androidx.activity.result.contract.ActivityResultContracts;
@@ -51,7 +53,7 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
protected void onCreate(Bundle bundle) { protected void onCreate(Bundle bundle) {
Log.i(MainActivity.class.getSimpleName(), "onCreate"); Log.d(MainActivity.class.getSimpleName(), "onCreate");
super.onCreate(bundle); super.onCreate(bundle);
final Window window = this.getWindow(); final Window window = this.getWindow();
// 强制横屏 // 强制横屏
@@ -76,19 +78,19 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
protected void onStart() { protected void onStart() {
Log.i(MainActivity.class.getSimpleName(), "onStart"); Log.d(MainActivity.class.getSimpleName(), "onStart");
super.onStart(); super.onStart();
} }
@Override @Override
protected void onStop() { protected void onStop() {
Log.i(MainActivity.class.getSimpleName(), "onStop"); Log.d(MainActivity.class.getSimpleName(), "onStop");
super.onStop(); super.onStop();
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
Log.i(MainActivity.class.getSimpleName(), "onDestroy"); Log.d(MainActivity.class.getSimpleName(), "onDestroy");
super.onDestroy(); super.onDestroy();
// 资源释放 // 资源释放
} }
@@ -123,10 +125,12 @@ public class MainActivity extends AppCompatActivity {
Manifest.permission.RECEIVE_BOOT_COMPLETED, Manifest.permission.RECEIVE_BOOT_COMPLETED,
Manifest.permission.WRITE_EXTERNAL_STORAGE Manifest.permission.WRITE_EXTERNAL_STORAGE
}; };
if (Stream.of(permissions).map(this.getApplicationContext()::checkSelfPermission).allMatch(v -> v == PackageManager.PERMISSION_GRANTED)) { final Context context = this.getApplicationContext();
Log.i(MediaService.class.getSimpleName(), "授权成功"); if (Stream.of(permissions).map(context::checkSelfPermission).allMatch(v -> v == PackageManager.PERMISSION_GRANTED)) {
Log.d(MediaService.class.getSimpleName(), "授权成功");
} else { } else {
ActivityCompat.requestPermissions(this, permissions, IdUtils.nextInt()); ActivityCompat.requestPermissions(this, permissions, IdUtils.nextInt());
Toast.makeText(context, "授权失败", Toast.LENGTH_SHORT).show();
} }
} }
@@ -158,7 +162,7 @@ public class MainActivity extends AppCompatActivity {
new ActivityResultContracts.StartActivityForResult(), new ActivityResultContracts.StartActivityForResult(),
result -> { result -> {
if (result.getResultCode() == Activity.RESULT_OK) { if (result.getResultCode() == Activity.RESULT_OK) {
Log.i(MediaManager.class.getSimpleName(), "屏幕捕获成功"); Log.d(MediaManager.class.getSimpleName(), "屏幕捕获成功");
final Intent intent = new Intent(this, MediaService.class); final Intent intent = new Intent(this, MediaService.class);
intent.setAction(MediaService.Action.SCREEN_CAPTURE.name()); intent.setAction(MediaService.Action.SCREEN_CAPTURE.name());
intent.putExtra("data", result.getData()); intent.putExtra("data", result.getData());
@@ -290,6 +294,7 @@ public class MainActivity extends AppCompatActivity {
layoutParams.width = 0; layoutParams.width = 0;
layoutParams.height = 0; layoutParams.height = 0;
} else { } else {
// 复用布局
layoutParams = this.removeLayoutParams.remove(0); layoutParams = this.removeLayoutParams.remove(0);
} }
final SurfaceView surfaceView = (SurfaceView) message.obj; final SurfaceView surfaceView = (SurfaceView) message.obj;
@@ -312,8 +317,9 @@ public class MainActivity extends AppCompatActivity {
return; return;
} }
video.removeViewAt(index); video.removeViewAt(index);
// 缓存布局
this.removeLayoutParams.add(surfaceView.getLayoutParams()); this.removeLayoutParams.add(surfaceView.getLayoutParams());
} }
} }
} }

View File

@@ -77,7 +77,7 @@ public class MediaService extends Service {
@Override @Override
public void onCreate() { public void onCreate() {
Log.i(MediaService.class.getSimpleName(), "onCreate"); Log.d(MediaService.class.getSimpleName(), "onCreate");
Log.i(MediaService.class.getSimpleName(), """ Log.i(MediaService.class.getSimpleName(), """
庭院深深深几许,杨柳堆烟,帘幕无重数。玉勒雕鞍游冶处,楼高不见章台路。 庭院深深深几许,杨柳堆烟,帘幕无重数。玉勒雕鞍游冶处,楼高不见章台路。
雨横风狂三月暮,门掩黄昏,无计留春住。泪眼问花花不语,乱红飞过秋千去。 雨横风狂三月暮,门掩黄昏,无计留春住。泪眼问花花不语,乱红飞过秋千去。
@@ -97,13 +97,13 @@ public class MediaService extends Service {
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
Log.i(MediaService.class.getSimpleName(), "onBind"); Log.d(MediaService.class.getSimpleName(), "onBind");
return new Binder(); return new Binder();
} }
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(MediaService.class.getSimpleName(), "onStartCommand" + intent.getAction()); Log.d(MediaService.class.getSimpleName(), "onStartCommand" + intent.getAction());
if (Action.BOOT.name().equals(intent.getAction())) { if (Action.BOOT.name().equals(intent.getAction())) {
this.boot(); this.boot();
this.openConnect(); this.openConnect();
@@ -122,7 +122,7 @@ public class MediaService extends Service {
@Override @Override
public void onDestroy() { public void onDestroy() {
Log.i(MediaService.class.getSimpleName(), "onDestroy"); Log.d(MediaService.class.getSimpleName(), "onDestroy");
super.onDestroy(); super.onDestroy();
this.close(); this.close();
} }
@@ -155,11 +155,11 @@ public class MediaService extends Service {
resources.getInteger(R.integer.imageQuantity), resources.getInteger(R.integer.imageQuantity),
resources.getString(R.string.audioQuantity), resources.getString(R.string.audioQuantity),
resources.getString(R.string.videoQuantity), resources.getString(R.string.videoQuantity),
resources.getBoolean(R.bool.broadcaster),
resources.getInteger(R.integer.channelCount), resources.getInteger(R.integer.channelCount),
resources.getInteger(R.integer.iFrameInterval), resources.getInteger(R.integer.iFrameInterval),
resources.getString(R.string.storagePathImage), resources.getString(R.string.storagePathImage),
resources.getString(R.string.storagePathVideo), resources.getString(R.string.storagePathVideo),
resources.getBoolean(R.bool.broadcaster),
resources.getString(R.string.watermark), resources.getString(R.string.watermark),
VideoSourceType.valueOf(resources.getString(R.string.videoSourceType)) VideoSourceType.valueOf(resources.getString(R.string.videoSourceType))
); );
@@ -199,13 +199,20 @@ public class MediaService extends Service {
final String password = sharedPreferences.getString("settings.password", "taoyao"); final String password = sharedPreferences.getString("settings.password", "taoyao");
final Context context = this.getApplicationContext(); final Context context = this.getApplicationContext();
final Resources resources = this.getResources(); final Resources resources = this.getResources();
this.close(); if(this.taoyao != null) {
if(this.taoyao.needReconnect(port, host, name, clientId, username, password)) {
this.close();
} else {
Log.d(MediaService.class.getSimpleName(), "配置没有改变忽略重连");
return;
}
}
// 连接信令 // 连接信令
this.taoyao = new Taoyao( this.taoyao = new Taoyao(
port, host, resources.getString(R.string.version), resources.getString(R.string.version), resources.getString(R.string.clientType),
name, clientId, resources.getString(R.string.clientType), username, password, port, host, name, clientId, username, password,
resources.getInteger(R.integer.timeout), resources.getString(R.string.encrypt), resources.getString(R.string.encryptSecret), resources.getInteger(R.integer.timeout), resources.getString(R.string.encrypt), resources.getString(R.string.encryptSecret),
this.mainHandler, context, this.taoyaoListener MediaService.mainHandler, context, this.taoyaoListener
); );
MediaManager.getInstance().initTaoyao(this.taoyao); MediaManager.getInstance().initTaoyao(this.taoyao);
Toast.makeText(context, "连接信令", Toast.LENGTH_SHORT).show(); Toast.makeText(context, "连接信令", Toast.LENGTH_SHORT).show();
@@ -268,11 +275,11 @@ public class MediaService extends Service {
*/ */
private void settingAudio() { private void settingAudio() {
final AudioManager audioManager = this.getApplicationContext().getSystemService(AudioManager.class); final AudioManager audioManager = this.getApplicationContext().getSystemService(AudioManager.class);
Log.i(MediaService.class.getSimpleName(), "当前音频模式:" + audioManager.getMode()); Log.d(MediaService.class.getSimpleName(), "当前音频模式:" + audioManager.getMode());
Log.i(MediaService.class.getSimpleName(), "当前音频音量:" + audioManager.getStreamVolume(audioManager.getMode())); Log.d(MediaService.class.getSimpleName(), "当前音频音量:" + audioManager.getStreamVolume(audioManager.getMode()));
// Log.i(MediaService.class.getSimpleName(), "当前蓝牙是否打开:" + audioManager.isBluetoothScoOn()); // Log.d(MediaService.class.getSimpleName(), "当前蓝牙是否打开:" + audioManager.isBluetoothScoOn());
// Log.i(MediaService.class.getSimpleName(), "当前耳机是否打开:" + audioManager.isWiredHeadsetOn()); // Log.d(MediaService.class.getSimpleName(), "当前耳机是否打开:" + audioManager.isWiredHeadsetOn());
// Log.i(MediaService.class.getSimpleName(), "当前电话扬声器是否打开:" + audioManager.isSpeakerphoneOn()); // 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_COMMUNICATION, audioManager.getStreamMaxVolume(AudioManager.MODE_IN_COMMUNICATION), AudioManager.FLAG_PLAY_SOUND);
} }

View File

@@ -6,6 +6,7 @@ import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
@@ -22,18 +23,18 @@ public class SettingsActivity extends AppCompatActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
Log.i(SettingsActivity.class.getSimpleName(), "onCreate"); Log.d(SettingsActivity.class.getSimpleName(), "onCreate");
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// 布局
this.binding = ActivitySettingsBinding.inflate(this.getLayoutInflater()); this.binding = ActivitySettingsBinding.inflate(this.getLayoutInflater());
this.setContentView(this.binding.getRoot()); final View root = this.binding.getRoot();
// 设置按钮 root.setZ(100F);
this.setContentView(root);
this.binding.connect.setOnClickListener(this::settingsPersistent); this.binding.connect.setOnClickListener(this::settingsPersistent);
} }
@Override @Override
protected void onStart() { protected void onStart() {
Log.i(SettingsActivity.class.getSimpleName(), "onStart"); Log.d(SettingsActivity.class.getSimpleName(), "onStart");
super.onStart(); super.onStart();
// 回填配置 // 回填配置
final SharedPreferences sharedPreferences = this.getSharedPreferences("settings", Context.MODE_PRIVATE); final SharedPreferences sharedPreferences = this.getSharedPreferences("settings", Context.MODE_PRIVATE);
@@ -47,18 +48,18 @@ public class SettingsActivity extends AppCompatActivity {
@Override @Override
protected void onStop() { protected void onStop() {
Log.i(SettingsActivity.class.getSimpleName(), "onStop"); Log.d(SettingsActivity.class.getSimpleName(), "onStop");
super.onStop(); super.onStop();
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
Log.i(SettingsActivity.class.getSimpleName(), "onDestroy"); Log.d(SettingsActivity.class.getSimpleName(), "onDestroy");
super.onDestroy(); super.onDestroy();
} }
/** /**
* 持久化日志 * 保存配置
* *
* @param view View * @param view View
*/ */
@@ -86,16 +87,19 @@ public class SettingsActivity extends AppCompatActivity {
editor.putString("settings.clientId", clientId); editor.putString("settings.clientId", clientId);
editor.putString("settings.username", username); editor.putString("settings.username", username);
editor.putString("settings.password", password); editor.putString("settings.password", password);
editor.commit(); if(editor.commit()) {
// 重连信令 // 重连信令
final Intent serviceIntent = new Intent(this, MediaService.class); final Intent serviceIntent = new Intent(this, MediaService.class);
serviceIntent.setAction(MediaService.Action.RECONNECT.name()); serviceIntent.setAction(MediaService.Action.RECONNECT.name());
this.startService(serviceIntent); this.startService(serviceIntent);
// 预览页面 // 预览页面
final Intent activityIntent = new Intent(this, MainActivity.class); final Intent activityIntent = new Intent(this, MainActivity.class);
this.startActivity(activityIntent); this.startActivity(activityIntent);
// 结束 // 结束
this.finish(); this.finish();
} else {
Toast.makeText(this.getApplicationContext(), "配置保存失败", Toast.LENGTH_SHORT).show();
}
} }
} }

View File

@@ -6,7 +6,7 @@ import android.content.Intent;
import android.util.Log; import android.util.Log;
/** /**
* 开机启动 * 开机广播
* *
* @author acgist * @author acgist
*/ */
@@ -14,7 +14,7 @@ public class TaoyaoReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
Log.i(TaoyaoReceiver.class.getSimpleName(), "onReceive" + intent.getAction()); Log.d(TaoyaoReceiver.class.getSimpleName(), "onReceive" + intent.getAction());
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
this.bootTaoyao(context); this.bootTaoyao(context);
} else { } else {

View File

@@ -8,10 +8,10 @@
<bool name="playVideo">true</bool> <bool name="playVideo">true</bool>
<!-- 信令版本 --> <!-- 信令版本 -->
<string name="version">1.0.0</string> <string name="version">1.0.0</string>
<!-- 超时时间 -->
<integer name="timeout">5000</integer>
<!-- 终端类型CAMERA|MOBILE --> <!-- 终端类型CAMERA|MOBILE -->
<string name="clientType">MOBILE</string> <string name="clientType">MOBILE</string>
<!-- 超时时间 -->
<integer name="timeout">5000</integer>
<!-- 信令加密策略AES|DES --> <!-- 信令加密策略AES|DES -->
<string name="encrypt">DES</string> <string name="encrypt">DES</string>
<!-- 信令加密密钥 --> <!-- 信令加密密钥 -->
@@ -34,14 +34,14 @@
<bool name="audioProduce">true</bool> <bool name="audioProduce">true</bool>
<!-- 媒体配置:是否生产视频 --> <!-- 媒体配置:是否生产视频 -->
<bool name="videoProduce">true</bool> <bool name="videoProduce">true</bool>
<!-- 语音播报 -->
<bool name="broadcaster">false</bool>
<!-- 图片质量 --> <!-- 图片质量 -->
<integer name="imageQuantity">100</integer> <integer name="imageQuantity">100</integer>
<!-- 音频质量 --> <!-- 音频质量 -->
<string name="audioQuantity">fd-audio</string> <string name="audioQuantity">fd-audio</string>
<!-- 视频质量 --> <!-- 视频质量 -->
<string name="videoQuantity">fd-video</string> <string name="videoQuantity">fd-video</string>
<!-- 语音播报 -->
<bool name="broadcaster">false</bool>
<!-- 音频通道数量 --> <!-- 音频通道数量 -->
<integer name="channelCount">1</integer> <integer name="channelCount">1</integer>
<!-- 视频关键帧频率 --> <!-- 视频关键帧频率 -->

View File

@@ -47,11 +47,9 @@ import java.util.Locale;
import java.util.UUID; import java.util.UUID;
/** /**
* 媒体来源管理器 * 媒体管理器
* *
* @author acgist * @author acgist
*
* TODO动态码率BITRATE_MODE_VBR、BITRATE_MODE
*/ */
public final class MediaManager { public final class MediaManager {
@@ -85,6 +83,10 @@ public final class MediaManager {
* 视频质量 * 视频质量
*/ */
private String videoQuantity; private String videoQuantity;
/**
* 语音播报
*/
private boolean broadcaster;
/** /**
* 通道数量 * 通道数量
*/ */
@@ -161,14 +163,14 @@ public final class MediaManager {
* JavaAudioDeviceModule * JavaAudioDeviceModule
*/ */
private JavaAudioDeviceModule javaAudioDeviceModule; private JavaAudioDeviceModule javaAudioDeviceModule;
/**
* 语音播报
*/
private TextToSpeech textToSpeech;
/** /**
* 视频处理 * 视频处理
*/ */
private VideoProcesser videoProcesser; private VideoProcesser videoProcesser;
/**
* TTS
*/
private TextToSpeech textToSpeech;
/** /**
* 录屏等待锁 * 录屏等待锁
*/ */
@@ -241,34 +243,35 @@ public final class MediaManager {
* @param imageQuantity 图片质量 * @param imageQuantity 图片质量
* @param audioQuantity 音频质量 * @param audioQuantity 音频质量
* @param videoQuantity 视频质量 * @param videoQuantity 视频质量
* @param broadcaster 是否语音播报
* @param channelCount 音频通道数量 * @param channelCount 音频通道数量
* @param iFrameInterval 关键帧频率 * @param iFrameInterval 关键帧频率
* @param imagePath 图片保存路径 * @param imagePath 图片保存路径
* @param videoPath 视频保存路径 * @param videoPath 视频保存路径
* @param tts 是否加载TTS
* @param watermark 水印信息 * @param watermark 水印信息
* @param videoSourceType 视频来源类型 * @param videoSourceType 视频来源类型
*/ */
public void initContext( public void initContext(
Handler mainHandler, Context context, Handler mainHandler, Context context,
int imageQuantity, String audioQuantity, String videoQuantity, int imageQuantity, String audioQuantity, String videoQuantity,
int channelCount, int iFrameInterval, boolean broadcaster, int channelCount, int iFrameInterval,
String imagePath, String videoPath, boolean tts, String imagePath, String videoPath,
String watermark, VideoSourceType videoSourceType String watermark, VideoSourceType videoSourceType
) { ) {
this.mainHandler = mainHandler; this.mainHandler = mainHandler;
this.context = context; this.context = context;
this.imageQuantity = imageQuantity; this.imageQuantity = imageQuantity;
this.audioQuantity = audioQuantity; this.audioQuantity = audioQuantity;
this.videoQuantity = videoQuantity; this.videoQuantity = videoQuantity;
this.channelCount = channelCount; this.broadcaster = broadcaster;
this.iFrameInterval = iFrameInterval; this.channelCount = channelCount;
this.imagePath = imagePath; this.iFrameInterval = iFrameInterval;
this.videoPath = videoPath; this.imagePath = imagePath;
this.watermark = watermark; this.videoPath = videoPath;
this.watermark = watermark;
this.videoSourceType = videoSourceType; this.videoSourceType = videoSourceType;
if(tts) { synchronized (this) {
this.initTTS(context); this.notifyAll();
} }
} }
@@ -277,29 +280,21 @@ public final class MediaManager {
*/ */
public void initTaoyao(ITaoyao taoyao) { public void initTaoyao(ITaoyao taoyao) {
this.taoyao = taoyao; this.taoyao = taoyao;
synchronized (this) {
this.notifyAll();
}
} }
private void initTTS(Context context) { public synchronized void broadcast(String text) {
if(this.textToSpeech != null) { if(!this.broadcaster) {
return; return;
} }
Log.i(MediaManager.class.getSimpleName(), "加载TTS");
this.textToSpeech = new TextToSpeech(context, new MediaManager.TextToSpeechInitListener());
}
public void broadcast(String text) {
if(this.textToSpeech == null) { if(this.textToSpeech == null) {
return; this.textToSpeech = new TextToSpeech(this.context, new MediaManager.TextToSpeechInitListener());
} }
// this.textToSpeech.stop();
this.textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, UUID.randomUUID().toString()); this.textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, UUID.randomUUID().toString());
} // this.textToSpeech.stop();
// this.textToSpeech.shutdown();
public void closeTTS() {
if(this.textToSpeech == null) {
return;
}
this.textToSpeech.shutdown();
} }
/** /**
@@ -775,14 +770,16 @@ public final class MediaManager {
} }
} }
public void stopRecord() { public String stopRecord() {
synchronized (this) { synchronized (this) {
if(this.recordClient == null) { if(this.recordClient == null) {
return; return null;
} else { } else {
final String filepath = this.recordClient.getFilepath();
this.recordClient.close(); this.recordClient.close();
this.recordClient = null; this.recordClient = null;
this.mainHandler.obtainMessage(Config.WHAT_RECORD, Boolean.FALSE).sendToTarget(); this.mainHandler.obtainMessage(Config.WHAT_RECORD, Boolean.FALSE).sendToTarget();
return filepath;
} }
} }
} }
@@ -960,7 +957,7 @@ public final class MediaManager {
private class TextToSpeechInitListener implements TextToSpeech.OnInitListener { private class TextToSpeechInitListener implements TextToSpeech.OnInitListener {
@Override @Override
public void onInit(int status) { public void onInit(int status) {
Log.i(MediaManager.class.getSimpleName(), "加载TTS" + status); Log.i(MediaManager.class.getSimpleName(), "加载语音播报" + status);
if(status == TextToSpeech.SUCCESS) { if(status == TextToSpeech.SUCCESS) {
MediaManager.this.textToSpeech.setLanguage(Locale.CANADA); MediaManager.this.textToSpeech.setLanguage(Locale.CANADA);
MediaManager.this.textToSpeech.setPitch(1.0F); MediaManager.this.textToSpeech.setPitch(1.0F);

View File

@@ -183,8 +183,10 @@ public class RecordClient extends Client implements VideoSink {
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, this.audioBitRate); audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, this.audioBitRate);
// audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, AudioFormat.ENCODING_PCM_16BIT); // audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, AudioFormat.ENCODING_PCM_16BIT);
audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
// 动态码率
// audioFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR); // audioFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
// audioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1024 * 8 * 8); // 设置缓冲大小 // 设置缓冲大小
// audioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1024 * 8 * 8);
this.audioCodec = MediaCodec.createEncoderByType(audioType); this.audioCodec = MediaCodec.createEncoderByType(audioType);
this.audioCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); this.audioCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
} catch (Exception e) { } catch (Exception e) {

View File

@@ -46,6 +46,7 @@ public class Room extends CloseableClient implements RouterCallback {
private final boolean dataProduce; private final boolean dataProduce;
private final boolean audioProduce; private final boolean audioProduce;
private final boolean videoProduce; private final boolean videoProduce;
private boolean produce;
private final MediaProperties mediaProperties; private final MediaProperties mediaProperties;
private final WebrtcProperties webrtcProperties; private final WebrtcProperties webrtcProperties;
private final Map<String, RemoteClient> remoteClients; private final Map<String, RemoteClient> remoteClients;
@@ -57,8 +58,8 @@ public class Room extends CloseableClient implements RouterCallback {
private Object sctpCapabilities; private Object sctpCapabilities;
/** /**
* @param name 房间名称
* @param roomId 房间ID * @param roomId 房间ID
* @param name 终端名称
* @param clientId 当前终端ID * @param clientId 当前终端ID
* @param password 房间密码 * @param password 房间密码
* @param taoyao 信令 * @param taoyao 信令
@@ -76,17 +77,17 @@ public class Room extends CloseableClient implements RouterCallback {
* @param webrtcProperties WebRTC配置 * @param webrtcProperties WebRTC配置
*/ */
public Room( public Room(
String name, String roomId, String roomId, String name,
String clientId, String password, String clientId, String password,
ITaoyao taoyao, Handler mainHandler, ITaoyao taoyao, Handler mainHandler,
boolean preview, boolean playAudio, boolean playVideo, boolean preview, boolean playAudio, boolean playVideo,
boolean dataConsume, boolean audioConsume, boolean videoConsume, boolean dataConsume, boolean audioConsume, boolean videoConsume,
boolean dataProduce, boolean audioProduce, boolean videoProduce, boolean dataProduce, boolean audioProduce, boolean videoProduce,
MediaProperties mediaProperties, WebrtcProperties webrtcProperties MediaProperties mediaProperties, WebrtcProperties webrtcProperties
) { ) {
super(taoyao, mainHandler); super(taoyao, mainHandler);
this.name = name;
this.roomId = roomId; this.roomId = roomId;
this.name = name;
this.clientId = clientId; this.clientId = clientId;
this.password = password; this.password = password;
this.preview = preview; this.preview = preview;
@@ -98,9 +99,10 @@ public class Room extends CloseableClient implements RouterCallback {
this.dataProduce = dataProduce; this.dataProduce = dataProduce;
this.audioProduce = audioProduce; this.audioProduce = audioProduce;
this.videoProduce = videoProduce; this.videoProduce = videoProduce;
this.mediaProperties = mediaProperties; this.produce = false;
this.mediaProperties = mediaProperties;
this.webrtcProperties = webrtcProperties; this.webrtcProperties = webrtcProperties;
this.remoteClients = new ConcurrentHashMap<>(); this.remoteClients = new ConcurrentHashMap<>();
this.nativeRoomPointer = this.nativeNewRoom(roomId, this); this.nativeRoomPointer = this.nativeNewRoom(roomId, this);
} }
@@ -109,6 +111,7 @@ public class Room extends CloseableClient implements RouterCallback {
if (this.init) { if (this.init) {
return true; return true;
} }
Log.i(Room.class.getSimpleName(), "进入房间:" + this.roomId);
super.init(); super.init();
this.peerConnectionFactory = this.mediaManager.newClient(); this.peerConnectionFactory = this.mediaManager.newClient();
this.localClient = new LocalClient(this.name, this.clientId, this.taoyao, this.mainHandler); this.localClient = new LocalClient(this.name, this.clientId, this.taoyao, this.mainHandler);
@@ -141,6 +144,10 @@ public class Room extends CloseableClient implements RouterCallback {
} }
public void mediaProduce() { public void mediaProduce() {
if(this.produce) {
return;
}
this.produce = true;
if (this.audioProduce || this.videoProduce) { if (this.audioProduce || this.videoProduce) {
this.createSendTransport(); this.createSendTransport();
} }

View File

@@ -130,13 +130,13 @@ const signalChannel = {
// TODO电池信息 // TODO电池信息
me.push( me.push(
protocol.buildMessage("client::register", { protocol.buildMessage("client::register", {
clientId: config.signal.clientId,
name: config.signal.name, name: config.signal.name,
clientId: config.signal.clientId,
clientType: "MEDIA", clientType: "MEDIA",
battery: 100,
charging: true,
username: config.signal.username, username: config.signal.username,
password: config.signal.password, password: config.signal.password,
battery: 100,
charging: true,
}) })
); );
me.reconnectionTimeout = me.minReconnectionDelay; me.reconnectionTimeout = me.minReconnectionDelay;

View File

@@ -142,13 +142,13 @@ const signalChannel = {
const battery = await navigator.getBattery(); const battery = await navigator.getBattery();
me.push( me.push(
protocol.buildMessage("client::register", { protocol.buildMessage("client::register", {
clientId: me.taoyao.clientId,
name: me.taoyao.name, name: me.taoyao.name,
clientId: me.taoyao.clientId,
clientType: "WEB", clientType: "WEB",
battery: battery.level * 100,
charging: battery.charging,
username: me.taoyao.username, username: me.taoyao.username,
password: me.taoyao.password, password: me.taoyao.password,
battery: battery.level * 100,
charging: battery.charging,
}) })
); );
me.reconnectionTimeout = me.minReconnectionDelay; me.reconnectionTimeout = me.minReconnectionDelay;
@@ -1660,6 +1660,7 @@ class Taoyao extends RemoteClient {
const me = this; const me = this;
const { clientId } = message.body; const { clientId } = message.body;
me.remoteClients.delete(clientId); me.remoteClients.delete(clientId);
// TODOclose
console.info("终端离开:", clientId); console.info("终端离开:", clientId);
} }
/** /**
@@ -2240,7 +2241,7 @@ class Taoyao extends RemoteClient {
}) })
); );
const { name, sessionId } = response.body; const { name, sessionId } = response.body;
const session = new Session({name, clientId: response.body.clientId, sessionId}); const session = new Session({name, clientId, sessionId});
this.sessionClients.set(sessionId, session); this.sessionClients.set(sessionId, session);
} }

View File

@@ -99,6 +99,10 @@ public abstract class ProtocolAdapter implements Protocol {
if(id == null) { if(id == null) {
id = this.idService.buildId(); id = this.idService.buildId();
} }
// 设置主体
if(body == null) {
body = Map.of();
}
// 消息头部 // 消息头部
final Header header = Header.builder() final Header header = Header.builder()
.v(this.taoyaoProperties.getVersion()) .v(this.taoyaoProperties.getVersion())

View File

@@ -16,14 +16,21 @@ import com.acgist.taoyao.signal.protocol.ProtocolControlAdapter;
*/ */
@Protocol @Protocol
@Description( @Description(
body = """ body = {
{ """
"to": "目标终端ID" {
} "to": "目标终端ID"
""", }
""",
"""
{
"filepath": "图片文件路径"
}
"""
},
flow = { flow = {
"信令服务->终端", "信令服务->目标终端->信令服务",
"终端->信令服务->终端" "终端=>信令服务->目标终端->信令服务->终端"
} }
) )
public class ControlPhotographProtocol extends ProtocolControlAdapter { public class ControlPhotographProtocol extends ProtocolControlAdapter {

View File

@@ -17,15 +17,23 @@ import com.acgist.taoyao.signal.protocol.ProtocolControlAdapter;
*/ */
@Protocol @Protocol
@Description( @Description(
body = """ body = {
{ """
"to": "目标终端ID", {
"enabled": 是否录像true|false "to": "目标终端ID",
} "enabled": 是否录像true|false
""", }
""",
"""
{
"enabled": 是否录像true|false,
"filepath": "视频文件路径"
}
"""
},
flow = { flow = {
"信令服务->终端", "信令服务->目标终端->信令服务",
"终端=>信令服务->终端" "终端=>信令服务->目标终端->信令服务->终端"
} }
) )
public class ControlRecordProtocol extends ProtocolControlAdapter { public class ControlRecordProtocol extends ProtocolControlAdapter {
@@ -43,7 +51,7 @@ public class ControlRecordProtocol extends ProtocolControlAdapter {
/** /**
* @param clientId 终端ID * @param clientId 终端ID
* @param enabled 状态 * @param enabled 状态
* *
* @return 执行结果 * @return 执行结果
*/ */

View File

@@ -14,9 +14,12 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
/** /**
* 修改最佳空间层和时间层信令 * 修改最佳空间层和时间层信令
*
* 空间层spatialLayer分辨率 * 空间层spatialLayer分辨率
* 时间层temporalLayer帧率 * 时间层temporalLayer帧率
*
* 码率:数据大小和时间的比值 * 码率:数据大小和时间的比值
*
* 注意只有simulcast和SVC消费者有效 * 注意只有simulcast和SVC消费者有效
* *
* @author acgist * @author acgist

View File

@@ -13,6 +13,8 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
/** /**
* 设置消费者优先级信令 * 设置消费者优先级信令
* *
* TODOunsetPriority
*
* @author acgist * @author acgist
*/ */
@Protocol @Protocol

View File

@@ -45,7 +45,6 @@ public class SessionCloseProtocol extends ProtocolSessionAdapter implements Appl
@Override @Override
public void execute(String clientId, ClientType clientType, Session session, Client client, Message message, Map<String, Object> body) { public void execute(String clientId, ClientType clientType, Session session, Client client, Message message, Map<String, Object> body) {
session.push(message);
session.close(); session.close();
} }