[*] 每日优化

This commit is contained in:
acgist
2023-05-12 08:44:01 +08:00
parent 22c6970cbd
commit 825fa907e5
14 changed files with 298 additions and 227 deletions

View File

@@ -30,6 +30,7 @@ getter/setter
## 计划任务 ## 计划任务
* 开机自启
* 录制底噪 * 录制底噪
* 分辨率调整 * 分辨率调整
* 降低视频录制大小 * 降低视频录制大小

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest>
</manifest> </manifest>

View File

@@ -53,4 +53,11 @@ public final class IdUtils {
IdUtils.clientIndex = clientIndex; IdUtils.clientIndex = clientIndex;
} }
/**
* @return 随机INT
*/
public static final int nextInt() {
return (int) (System.nanoTime() % Integer.MAX_VALUE);
}
} }

View File

@@ -19,9 +19,10 @@
android:launchMode="singleTask" android:launchMode="singleTask"
android:theme="@style/Theme.Taoyao"> android:theme="@style/Theme.Taoyao">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.HOME" />
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.DEFAULT" /> <!--
<category android:name="android.intent.category.HOME" />
-->
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>

View File

@@ -2,7 +2,6 @@ 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;
@@ -26,14 +25,12 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import com.acgist.taoyao.boot.utils.IdUtils;
import com.acgist.taoyao.client.databinding.ActivityMainBinding; import com.acgist.taoyao.client.databinding.ActivityMainBinding;
import com.acgist.taoyao.media.MediaManager; import com.acgist.taoyao.media.MediaManager;
import com.acgist.taoyao.media.VideoSourceType;
import com.acgist.taoyao.media.config.Config; import com.acgist.taoyao.media.config.Config;
import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
import org.apache.commons.lang3.RandomUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -129,7 +126,7 @@ public class MainActivity extends AppCompatActivity {
if (Stream.of(permissions).map(this.getApplicationContext()::checkSelfPermission).allMatch(v -> v == PackageManager.PERMISSION_GRANTED)) { if (Stream.of(permissions).map(this.getApplicationContext()::checkSelfPermission).allMatch(v -> v == PackageManager.PERMISSION_GRANTED)) {
Log.i(MediaService.class.getSimpleName(), "授权成功"); Log.i(MediaService.class.getSimpleName(), "授权成功");
} else { } else {
ActivityCompat.requestPermissions(this, permissions, RandomUtils.nextInt()); ActivityCompat.requestPermissions(this, permissions, IdUtils.nextInt());
} }
} }
@@ -142,28 +139,10 @@ public class MainActivity extends AppCompatActivity {
} }
Log.i(MainActivity.class.getSimpleName(), "拉起媒体服务"); Log.i(MainActivity.class.getSimpleName(), "拉起媒体服务");
this.mainHandler = new MainHandler(); this.mainHandler = new MainHandler();
final Context context = this.getApplicationContext();
final Resources resources = this.getResources();
final MediaManager mediaManager = MediaManager.getInstance();
mediaManager.initContext(
this.mainHandler, context,
resources.getInteger(R.integer.imageQuantity),
resources.getString(R.string.audioQuantity),
resources.getString(R.string.videoQuantity),
resources.getInteger(R.integer.channelCount),
resources.getInteger(R.integer.iFrameInterval),
resources.getString(R.string.storagePathImage),
resources.getString(R.string.storagePathVideo),
resources.getString(R.string.watermark),
VideoSourceType.valueOf(resources.getString(R.string.videoSourceType))
);
if(resources.getBoolean(R.bool.broadcaster)) {
mediaManager.initTTS(context);
}
// 注意不能使用intent传递 // 注意不能使用intent传递
MediaService.mainHandler = this.mainHandler; MediaService.setMainHandler(this.mainHandler);
final Intent intent = new Intent(this, MediaService.class); final Intent intent = new Intent(this, MediaService.class);
intent.setAction(MediaService.Action.CONNECT.name()); intent.setAction(MediaService.Action.LAUNCH.name());
this.startService(intent); this.startService(intent);
} }
@@ -181,7 +160,7 @@ public class MainActivity extends AppCompatActivity {
if (result.getResultCode() == Activity.RESULT_OK) { if (result.getResultCode() == Activity.RESULT_OK) {
Log.i(MediaManager.class.getSimpleName(), "屏幕捕获成功"); Log.i(MediaManager.class.getSimpleName(), "屏幕捕获成功");
final Intent intent = new Intent(this, MediaService.class); final Intent intent = new Intent(this, MediaService.class);
intent.setAction(MediaService.Action.SCREEN_RECORD.name()); intent.setAction(MediaService.Action.SCREEN_CAPTURE.name());
intent.putExtra("data", result.getData()); intent.putExtra("data", result.getData());
intent.putExtra("code", result.getResultCode()); intent.putExtra("code", result.getResultCode());
this.startService(intent); this.startService(intent);

View File

@@ -10,6 +10,7 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.os.Binder; import android.os.Binder;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
@@ -19,8 +20,10 @@ import android.widget.Toast;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import com.acgist.taoyao.boot.utils.IdUtils;
import com.acgist.taoyao.client.signal.Taoyao; import com.acgist.taoyao.client.signal.Taoyao;
import com.acgist.taoyao.media.MediaManager; import com.acgist.taoyao.media.MediaManager;
import com.acgist.taoyao.media.VideoSourceType;
import com.acgist.taoyao.media.signal.ITaoyaoListener; import com.acgist.taoyao.media.signal.ITaoyaoListener;
import java.io.File; import java.io.File;
@@ -35,6 +38,7 @@ import java.nio.file.Paths;
public class MediaService extends Service { public class MediaService extends Service {
static { static {
Log.i(MediaService.class.getSimpleName(), "加载C++库文件");
System.loadLibrary("taoyao"); System.loadLibrary("taoyao");
System.loadLibrary("jingle_peerconnection_so"); System.loadLibrary("jingle_peerconnection_so");
} }
@@ -46,20 +50,28 @@ public class MediaService extends Service {
*/ */
public enum Action { public enum Action {
// 启动 /**
* 系统启动
*/
BOOT,
/**
* 连接信令
*/
LAUNCH, LAUNCH,
// 连接 /**
CONNECT, * 重连信令
// 重连 */
RECONNECT, RECONNECT,
// 屏幕录制 /**
SCREEN_RECORD; * 屏幕录制
*/
SCREEN_CAPTURE;
} }
public static Handler mainHandler;
private Taoyao taoyao; private Taoyao taoyao;
private static Handler mainHandler;
private static final String TAOYAO = "TAOYAO";
private final ITaoyaoListener taoyaoListener = new ITaoyaoListener() { private final ITaoyaoListener taoyaoListener = new ITaoyaoListener() {
}; };
@@ -79,6 +91,7 @@ public class MediaService extends Service {
final Resources resources = this.getResources(); final Resources resources = this.getResources();
this.mkdir(resources.getString(R.string.storagePathImage), Environment.DIRECTORY_PICTURES); this.mkdir(resources.getString(R.string.storagePathImage), Environment.DIRECTORY_PICTURES);
this.mkdir(resources.getString(R.string.storagePathVideo), Environment.DIRECTORY_MOVIES); this.mkdir(resources.getString(R.string.storagePathVideo), Environment.DIRECTORY_MOVIES);
this.settingAudio();
this.buildNotificationChannel(); this.buildNotificationChannel();
} }
@@ -91,16 +104,16 @@ public class MediaService extends Service {
@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.i(MediaService.class.getSimpleName(), "onStartCommand" + intent.getAction());
this.cleanAllNotification(); if (Action.BOOT.name().equals(intent.getAction())) {
if (Action.LAUNCH.name().equals(intent.getAction())) { this.boot();
this.launch(intent); this.openConnect();
this.openConnect(intent); } else if (Action.LAUNCH.name().equals(intent.getAction())) {
} else if (Action.CONNECT.name().equals(intent.getAction())) { this.launch();
this.openConnect(intent); this.openConnect();
} else if (Action.RECONNECT.name().equals(intent.getAction())) { } else if (Action.RECONNECT.name().equals(intent.getAction())) {
this.reconnect(); this.reconnect();
} else if (Action.SCREEN_RECORD.name().equals(intent.getAction())) { } else if (Action.SCREEN_CAPTURE.name().equals(intent.getAction())) {
this.screenRecord(intent); this.screenCapture(intent);
} else { } else {
Log.w(MediaService.class.getSimpleName(), "未知动作:" + intent.getAction()); Log.w(MediaService.class.getSimpleName(), "未知动作:" + intent.getAction());
} }
@@ -114,20 +127,48 @@ public class MediaService extends Service {
this.close(); this.close();
} }
private void launch(Intent intent) { /**
final Intent notificationIntent = new Intent(this, MediaService.class); * 启动
final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); */
final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "TAOYAO") private void boot() {
final Intent activityIntent = new Intent(this, MainActivity.class);
final PendingIntent pendingIntent = PendingIntent.getActivity(this, IdUtils.nextInt(), activityIntent, PendingIntent.FLAG_CANCEL_CURRENT);
final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, TAOYAO)
.setSmallIcon(R.mipmap.ic_launcher_foreground) .setSmallIcon(R.mipmap.ic_launcher_foreground)
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher_foreground)) .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher_foreground))
.setContentTitle("桃夭后台") .setContentTitle("桃夭后台")
.setContentText("桃夭正在后台运行") .setContentText("桃夭正在后台运行")
.setContentIntent(pendingIntent); .setContentIntent(pendingIntent);
final Notification notification = notificationBuilder.build(); final Notification notification = notificationBuilder.build();
this.startForeground((int) System.currentTimeMillis(), notification); this.startForeground(IdUtils.nextInt(), notification);
} }
private void openConnect(Intent intent) { /**
* 启动
*/
private void launch() {
final Context context = this.getApplicationContext();
final Resources resources = this.getResources();
final MediaManager mediaManager = MediaManager.getInstance();
mediaManager.initContext(
MediaService.mainHandler, context,
resources.getInteger(R.integer.imageQuantity),
resources.getString(R.string.audioQuantity),
resources.getString(R.string.videoQuantity),
resources.getInteger(R.integer.channelCount),
resources.getInteger(R.integer.iFrameInterval),
resources.getString(R.string.storagePathImage),
resources.getString(R.string.storagePathVideo),
resources.getBoolean(R.bool.broadcaster),
resources.getString(R.string.watermark),
VideoSourceType.valueOf(resources.getString(R.string.videoSourceType))
);
}
/**
* 连接信令
*/
private void openConnect() {
if (this.taoyao == null) { if (this.taoyao == null) {
Log.d(MediaService.class.getSimpleName(), "打开信令连接"); Log.d(MediaService.class.getSimpleName(), "打开信令连接");
this.connect(); this.connect();
@@ -136,6 +177,9 @@ public class MediaService extends Service {
} }
} }
/**
* 重连信令
*/
private void reconnect() { private void reconnect() {
Log.d(MediaService.class.getSimpleName(), "重新连接信令"); Log.d(MediaService.class.getSimpleName(), "重新连接信令");
this.connect(); this.connect();
@@ -153,9 +197,8 @@ public class MediaService extends Service {
final String clientId = sharedPreferences.getString("settings.clientId", "mobile"); final String clientId = sharedPreferences.getString("settings.clientId", "mobile");
final String username = sharedPreferences.getString("settings.username", "taoyao"); final String username = sharedPreferences.getString("settings.username", "taoyao");
final String password = sharedPreferences.getString("settings.password", "taoyao"); final String password = sharedPreferences.getString("settings.password", "taoyao");
final Resources resources = this.getResources();
// 系统服务
final Context context = this.getApplicationContext(); final Context context = this.getApplicationContext();
final Resources resources = this.getResources();
this.close(); this.close();
// 连接信令 // 连接信令
this.taoyao = new Taoyao( this.taoyao = new Taoyao(
@@ -165,9 +208,31 @@ public class MediaService extends Service {
this.mainHandler, context, this.taoyaoListener this.mainHandler, context, this.taoyaoListener
); );
MediaManager.getInstance().initTaoyao(this.taoyao); MediaManager.getInstance().initTaoyao(this.taoyao);
Toast.makeText(this.getApplicationContext(), "连接信令", Toast.LENGTH_SHORT).show(); Toast.makeText(context, "连接信令", Toast.LENGTH_SHORT).show();
} }
/**
* 屏幕录制
*
* @param intent Intent
*/
public void screenCapture(Intent intent) {
final Intent activityIntent = new Intent(this, MainActivity.class);
final PendingIntent pendingIntent = PendingIntent.getActivity(this, IdUtils.nextInt(), activityIntent, PendingIntent.FLAG_CANCEL_CURRENT);
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("桃夭正在录制屏幕")
.setContentIntent(pendingIntent);
final Notification notification = notificationBuilder.build();
this.startForeground((int) System.currentTimeMillis(), notification);
MediaManager.getInstance().initScreen(intent.getParcelableExtra("data"));
}
/**
* 关闭连接
*/
private synchronized void close() { private synchronized void close() {
if (this.taoyao == null) { if (this.taoyao == null) {
return; return;
@@ -177,22 +242,12 @@ public class MediaService extends Service {
this.taoyao = null; this.taoyao = null;
} }
public void screenRecord(Intent intent) { /**
final Intent notificationIntent = new Intent(this, MediaService.class); * 创建目录
final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); *
final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "TAOYAO") * @param path 路径
.setSmallIcon(R.mipmap.ic_launcher_foreground) * @param type 类型
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher_foreground)) */
// 自动清除
// .setAutoCancel(true)
.setContentTitle("录制屏幕")
.setContentText("桃夭正在录制屏幕")
.setContentIntent(pendingIntent);
final Notification notification = notificationBuilder.build();
this.startForeground((int) System.currentTimeMillis(), notification);
MediaManager.getInstance().initScreen(intent.getParcelableExtra("data"));
}
private void mkdir(String path, String type) { private void mkdir(String path, String type) {
final Path imagePath = Paths.get( final Path imagePath = Paths.get(
Environment.getExternalStoragePublicDirectory(type).getAbsolutePath(), Environment.getExternalStoragePublicDirectory(type).getAbsolutePath(),
@@ -201,23 +256,42 @@ public class MediaService extends Service {
final File file = imagePath.toFile(); final File file = imagePath.toFile();
if(file.exists()) { if(file.exists()) {
Log.d(MediaService.class.getSimpleName(), "目录已经存在:" + imagePath); Log.d(MediaService.class.getSimpleName(), "目录已经存在:" + imagePath);
} else if(file.mkdirs()) {
Log.d(MediaService.class.getSimpleName(), "新建目录成功:" + imagePath);
} else { } else {
Log.d(MediaService.class.getSimpleName(), "新建文件目录:" + imagePath); Log.d(MediaService.class.getSimpleName(), "新建目录失败" + imagePath);
file.mkdirs();
} }
} }
/**
* 设置音频
*/
private void settingAudio() {
final AudioManager audioManager = this.getApplicationContext().getSystemService(AudioManager.class);
Log.i(MediaService.class.getSimpleName(), "当前音频模式:" + audioManager.getMode());
Log.i(MediaService.class.getSimpleName(), "当前音频音量:" + audioManager.getStreamVolume(audioManager.getMode()));
// Log.i(MediaService.class.getSimpleName(), "当前蓝牙是否打开:" + audioManager.isBluetoothScoOn());
// Log.i(MediaService.class.getSimpleName(), "当前耳机是否打开:" + audioManager.isWiredHeadsetOn());
// Log.i(MediaService.class.getSimpleName(), "当前电话扬声器是否打开:" + audioManager.isSpeakerphoneOn());
// audioManager.setStreamVolume(AudioManager.MODE_IN_COMMUNICATION, audioManager.getStreamMaxVolume(AudioManager.MODE_IN_COMMUNICATION), AudioManager.FLAG_PLAY_SOUND);
}
/**
* 新建通知通道
*/
private void buildNotificationChannel() { private void buildNotificationChannel() {
final NotificationChannel channel = new NotificationChannel("TAOYAO", "桃夭通知", NotificationManager.IMPORTANCE_DEFAULT);
channel.setShowBadge(false);
channel.setDescription("桃夭系统通知");
final NotificationManager notificationManager = this.getSystemService(NotificationManager.class); final NotificationManager notificationManager = this.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel); final NotificationChannel notificationChannel = new NotificationChannel(TAOYAO, "桃夭通知", NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.setShowBadge(false);
notificationChannel.setDescription("桃夭通知");
notificationManager.createNotificationChannel(notificationChannel);
} }
private void cleanAllNotification() { /**
final NotificationManager notificationManager = this.getSystemService(NotificationManager.class); * @param mainHandler MainHandler
notificationManager.cancelAll(); */
public static final void setMainHandler(Handler mainHandler) {
MediaService.mainHandler = mainHandler;
} }
} }

View File

@@ -87,12 +87,13 @@ public class SettingsActivity extends AppCompatActivity {
editor.putString("settings.username", username); editor.putString("settings.username", username);
editor.putString("settings.password", password); editor.putString("settings.password", password);
editor.commit(); editor.commit();
// 重连 // 重连信令
final Intent intent = new Intent(this, MediaService.class); final Intent serviceIntent = new Intent(this, MediaService.class);
intent.setAction(MediaService.Action.RECONNECT.name()); serviceIntent.setAction(MediaService.Action.RECONNECT.name());
this.startService(intent); this.startService(serviceIntent);
// 返回预览页面 // 预览页面
this.startActivity(new Intent(this, MainActivity.class)); final Intent activityIntent = new Intent(this, MainActivity.class);
this.startActivity(activityIntent);
// 结束 // 结束
this.finish(); this.finish();
} }

View File

@@ -16,7 +16,7 @@ public class TaoyaoReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
Log.i(TaoyaoReceiver.class.getSimpleName(), "onReceive" + intent.getAction()); Log.i(TaoyaoReceiver.class.getSimpleName(), "onReceive" + intent.getAction());
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
this.launchPreview(context); this.bootTaoyao(context);
} else { } else {
} }
} }
@@ -26,11 +26,11 @@ public class TaoyaoReceiver extends BroadcastReceiver {
* *
* @param context 上下文 * @param context 上下文
*/ */
private void launchPreview(Context context) { private void bootTaoyao(Context context) {
final Intent intent = new Intent(context, MediaService.class); final Intent serviceIntent = new Intent(context, MediaService.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(MediaService.Action.LAUNCH.name()); serviceIntent.setAction(MediaService.Action.BOOT.name());
context.startForegroundService(intent); context.startForegroundService(serviceIntent);
} }
} }

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"> <resources>
<style name="Theme.Taoyao" parent="Theme.MaterialComponents.Light.DarkActionBar"> <style name="Theme.Taoyao" parent="Theme.MaterialComponents.Light.DarkActionBar">
<item name="colorPrimary">@color/purple_500</item> <item name="colorPrimary">@color/purple_500</item>

View File

@@ -210,6 +210,7 @@ public final class MediaManager {
return return
this.taoyao != null && this.taoyao != null &&
this.context != null && this.context != null &&
this.mainHandler != null &&
this.mediaProperties != null; this.mediaProperties != null;
} }
@@ -244,6 +245,7 @@ public final class MediaManager {
* @param iFrameInterval 关键帧频率 * @param iFrameInterval 关键帧频率
* @param imagePath 图片保存路径 * @param imagePath 图片保存路径
* @param videoPath 视频保存路径 * @param videoPath 视频保存路径
* @param tts 是否加载TTS
* @param watermark 水印信息 * @param watermark 水印信息
* @param videoSourceType 视频来源类型 * @param videoSourceType 视频来源类型
*/ */
@@ -251,7 +253,7 @@ public final class MediaManager {
Handler mainHandler, Context context, Handler mainHandler, Context context,
int imageQuantity, String audioQuantity, String videoQuantity, int imageQuantity, String audioQuantity, String videoQuantity,
int channelCount, int iFrameInterval, int channelCount, int iFrameInterval,
String imagePath, String videoPath, String imagePath, String videoPath, boolean tts,
String watermark, VideoSourceType videoSourceType String watermark, VideoSourceType videoSourceType
) { ) {
this.mainHandler = mainHandler; this.mainHandler = mainHandler;
@@ -265,6 +267,9 @@ public final class MediaManager {
this.videoPath = videoPath; this.videoPath = videoPath;
this.watermark = watermark; this.watermark = watermark;
this.videoSourceType = videoSourceType; this.videoSourceType = videoSourceType;
if(tts) {
this.initTTS(context);
}
} }
/** /**
@@ -274,7 +279,7 @@ public final class MediaManager {
this.taoyao = taoyao; this.taoyao = taoyao;
} }
public void initTTS(Context context) { private void initTTS(Context context) {
if(this.textToSpeech != null) { if(this.textToSpeech != null) {
return; return;
} }

View File

@@ -1,5 +1,8 @@
/** /**
* 音频默认配置 * 音频默认配置
* TODOMediaStreamTrack.applyConstraints()
* 播放音量、采集音量
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings
*/ */
const defaultAudioConfig = { const defaultAudioConfig = {
// 设备 // 设备