[*] 每日优化
配置没有改变不要重连信令 忽略房间重复邀请
This commit is contained in:
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||||
<!-- 视频关键帧频率 -->
|
<!-- 视频关键帧频率 -->
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
// TODO:close
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 执行结果
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,9 +14,12 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改最佳空间层和时间层信令
|
* 修改最佳空间层和时间层信令
|
||||||
|
*
|
||||||
* 空间层(spatialLayer):分辨率
|
* 空间层(spatialLayer):分辨率
|
||||||
* 时间层(temporalLayer):帧率
|
* 时间层(temporalLayer):帧率
|
||||||
|
*
|
||||||
* 码率:数据大小和时间的比值
|
* 码率:数据大小和时间的比值
|
||||||
|
*
|
||||||
* 注意:只有simulcast和SVC消费者有效
|
* 注意:只有simulcast和SVC消费者有效
|
||||||
*
|
*
|
||||||
* @author acgist
|
* @author acgist
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
|
|||||||
/**
|
/**
|
||||||
* 设置消费者优先级信令
|
* 设置消费者优先级信令
|
||||||
*
|
*
|
||||||
|
* TODO:unsetPriority
|
||||||
|
*
|
||||||
* @author acgist
|
* @author acgist
|
||||||
*/
|
*/
|
||||||
@Protocol
|
@Protocol
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user