Skip to content

Commit

Permalink
更新V1.1.14
Browse files Browse the repository at this point in the history
- 放开各页面竖屏锁定,允许自由选择
- 加入Opus优先选项
- 加入新的特殊地址符:*netAddress*,表示子网地址
- 音频相关优化
  • Loading branch information
mingzhixian committed Dec 8, 2023
1 parent c32691a commit dca27e9
Show file tree
Hide file tree
Showing 21 changed files with 217 additions and 131 deletions.
16 changes: 11 additions & 5 deletions HOW_TO_USE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,26 @@ adb tcpip 5555
## 软件使用

1. 简单使用
- 主控端安装易控,打开软件进行悬浮窗授权,添加设备,点击添加后的设备,被控端同意永久调试,开始投屏。
- 注意设备地址格式:192.168.43.1:5555、[2408:8462:2510:1e05:c39:3262:632d:1a3d]:5555、ex.com:5555、*gateway*:5555(特殊值表示网关地址)
- 主控端安装易控,打开软件进行悬浮窗授权,添加设备(地址为被控端地址加ADB端口号),点击添加后的设备,被控端同意永久调试,开始投屏。
- 设备地址格式:IPv4:192.168.43.1:5555、IPv6:[2408:8462:2510:1e05:c39:3262:632d:1a3d]:5555、域名:ex.com:5555
2. 高级使用
- 在添加设备时设置高级选项,可自定义编解码参数、开启自动修改被控端分辨率等。
- 设置中可设置编码参数等默认选项,添加设备时默认使用这些参数,如对单个设备进行了修改,则以该设备参数为准。
- 特殊地址标识符:网关地址:*gateway*(如网关为192.168.43.1,则“*gateway*:5555”表示“192.168.43.1:5555”)、子网地址:*netAddress*(如子网为192.168.43.0/24, 则“*netAddress*.1:5555”表示“192.168.43.1:5555”)
3. 工具栏
- 在小窗模式下点击上横条,可查看工具栏,包括发送导航按钮命令,发送电源键,最小化、全屏、关闭功能
- 在全屏模式下点击导航栏更多按钮,可查看工具栏,包括发送电源键,最小化、小窗、关闭、隐藏导航栏功能
- 在小窗模式下点击上横条,可查看工具栏,依次为:显示隐藏导航栏、向被控端按下电源键、最小化、全屏、关闭
- 在全屏模式下点击导航栏更多按钮,可查看工具栏,依次为:显示隐藏导航栏、向被控端按下电源键、最小化、小窗模式、关闭。
4. 小窗模式使用
- 可通过拖动横条移动小窗。
- 拖动右下角可更改小窗大小。
5. 最小化模式使用
- 可上下拖动
- 单击返回小窗模式
6. 中心服务器使用
6. 全屏模式使用
- 底部为导航栏,可向被控端发送多任务、桌面、返回按键
- 导航栏左边旋转按钮,可以控制主控端页面旋转,当设置中开启主控端自动旋转时,会根据手机方向自动旋转主控端页面。
- 在设置中开启被控端方向跟随功能后,当主控端页面旋转时,会请求被控端同样旋转,以保持同步,旋转不强制,具体看被控端当前应用是否允许旋转。
7. 中心服务器使用
- 确保主备控端均拥有IPv6地址
- 在设置中填写中心服务器地址、用户名和密码,进行连接
- 多设备在同一中心服务器登录同一账号后,会自动加载设备列表,并自动保持地址更新。(仅在设置页面填写本机ADB端口才会上报设备)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Gitee和GitHub代码将保持同步,请自行选择。软件发行版本将仅
[点击此处查看](https://gitee.com/mingzhixianweb/easycontrol/releases)

## 发行版本下载
因项目开发以及反馈群答疑给本人带来一定负担,本项目此后不会免费提供发行版本,请前往[易控下载群](https://gitee.com/mingzhixianweb/easycontrol/raw/master/pic/other/qq_download.webp))付费下载(捐赠10元及以上)。(项目代码仍为开源状态,若您有一定能力,可自行下载源码编译使用)
因项目开发以及反馈群答疑给本人带来一定负担,本项目此后不会免费提供发行版本,请前往[易控下载群](https://gitee.com/mingzhixianweb/easycontrol/raw/master/pic/other/qq_download.webp)付费下载(捐赠10元及以上)。(项目代码仍为开源状态,若您有一定能力,可自行下载源码编译使用)

## 截图
<img src="https://gitee.com/mingzhixianweb/easycontrol/raw/master/pic/screenshot/main.webp" width="200px">
Expand Down
2 changes: 1 addition & 1 deletion easycontrol/.idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 33 additions & 24 deletions easycontrol/.idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions easycontrol/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
applicationId "top.saymzx.easycontrol.app"
minSdk 21
targetSdk 34
versionCode 10113
versionName "1.1.13"
versionCode 10114
versionName "1.1.14"
resConfigs "zh"
resConfigs "xhdpi"
ndk {
Expand Down
15 changes: 5 additions & 10 deletions easycontrol/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,26 @@
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:screenOrientation="portrait">
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".IpActivity"
android:exported="false"
android:screenOrientation="portrait" />
android:exported="false" />
<activity
android:name=".SetActivity"
android:exported="false"
android:screenOrientation="portrait" />
android:exported="false" />
<activity
android:name=".CenterActivity"
android:exported="false"
android:screenOrientation="portrait" />
android:exported="false" />
<activity
android:name=".client.view.FullActivity"
android:exported="false"
android:hardwareAccelerated="true"
android:launchMode="singleTask"
android:screenOrientation="portrait" />
android:launchMode="singleTask" />

</application>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ private void drawUi() {
setActivity.setDefault.addView(PublicTools.createSpinnerCard(this, "最大码率", videoBitAdapter, new Pair<>(String.valueOf(AppData.setting.getDefaultMaxVideoBit()), Device.maxVideoBitDetail), str -> AppData.setting.setDefaultMaxVideoBit(Integer.parseInt(str))).getRoot());
setActivity.setDefault.addView(PublicTools.createSwitchCard(this, "修改分辨率", new Pair<>(AppData.setting.getDefaultSetResolution(), Device.setResolutionDetail), isChecked -> AppData.setting.setDefaultSetResolution(isChecked)).getRoot());
setActivity.setDefault.addView(PublicTools.createSwitchCard(this, "优先H265", new Pair<>(AppData.setting.getUseH265(), Device.useH265Detail), isChecked -> AppData.setting.setUseH265(isChecked)).getRoot());
setActivity.setDefault.addView(PublicTools.createSwitchCard(this, "优先Opus", new Pair<>(AppData.setting.getUseOpus(), Device.useOpusDetail), isChecked -> AppData.setting.setUseOpus(isChecked)).getRoot());
setActivity.setDefault.addView(PublicTools.createSwitchCard(this, "使用隧道传输", new Pair<>(AppData.setting.getUseTunnel(), Device.useTunnelDetail), isChecked -> AppData.setting.setUseTunnel(isChecked)).getRoot());
setActivity.setDefault.addView(PublicTools.createSwitchCard(this, "熄屏控制", new Pair<>(AppData.setting.getTurnOffScreen(), Device.turnOffScreenDetail), isChecked -> AppData.setting.setTurnOffScreen(isChecked)).getRoot());
setActivity.setDefault.addView(PublicTools.createSwitchCard(this, "自动屏幕控制", new Pair<>(AppData.setting.getAutoControlScreen(), Device.autoControlScreenDetail), isChecked -> AppData.setting.setAutoControlScreen(isChecked)).getRoot());
setActivity.setDefault.addView(PublicTools.createSwitchCard(this, "默认全屏启动", new Pair<>(AppData.setting.getDefaultFull(), Device.defaultFullDetail), isChecked -> AppData.setting.setDefaultFull(isChecked)).getRoot());
// 显示
setActivity.setDisplay.addView(PublicTools.createSwitchCard(this, "熄屏控制", new Pair<>(AppData.setting.getTurnOffScreen(), Device.turnOffScreenDetail), isChecked -> AppData.setting.setTurnOffScreen(isChecked)).getRoot());
setActivity.setDisplay.addView(PublicTools.createSwitchCard(this, "自动屏幕控制", new Pair<>(AppData.setting.getAutoControlScreen(), Device.autoControlScreenDetail), isChecked -> AppData.setting.setAutoControlScreen(isChecked)).getRoot());
setActivity.setDisplay.addView(PublicTools.createSwitchCard(this, "默认全屏启动", new Pair<>(AppData.setting.getDefaultFull(), Device.defaultFullDetail), isChecked -> AppData.setting.setDefaultFull(isChecked)).getRoot());
setActivity.setDisplay.addView(PublicTools.createSwitchCard(this, "主控端自动旋转", AppData.setting.getMasterAudoRotation(), isChecked -> AppData.setting.setMasterAudoRotation(isChecked)).getRoot());
setActivity.setDisplay.addView(PublicTools.createSwitchCard(this, "被控端跟随旋转", AppData.setting.getSlaveAudoRotation(), isChecked -> AppData.setting.setSlaveAudoRotation(isChecked)).getRoot());
setActivity.setDisplay.addView(PublicTools.createSwitchCard(this, "被控端方向跟随", AppData.setting.getSlaveAudoRotation(), isChecked -> AppData.setting.setSlaveAudoRotation(isChecked)).getRoot());
// 其他
setActivity.setOther.addView(PublicTools.createTextCard(this, "清除默认设备", () -> {
AppData.setting.setDefaultDevice("");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class AudioDecode {
public MediaCodec decodec;
public AudioTrack audioTrack;
public LoudnessEnhancer loudnessEnhancer;

public AudioDecode(byte[] csd0) throws IOException {
public AudioDecode(boolean useOpus, byte[] csd0) throws IOException {
// 创建Codec
setAudioDecodec(csd0);
setAudioDecodec(useOpus, csd0);
// 创建AudioTrack
setAudioTrack();
// 创建音频放大器
Expand All @@ -41,9 +42,9 @@ public void release() {

private final LinkedBlockingQueue<Integer> intputBufferQueue = new LinkedBlockingQueue<>();

public void decodeIn(byte[] data) {
public void decodeIn(byte[] data) throws InterruptedException {
try {
Integer inIndex = intputBufferQueue.poll();
Integer inIndex = intputBufferQueue.poll(20, TimeUnit.MILLISECONDS);
if (inIndex == null) return;
decodec.getInputBuffer(inIndex).put(data);
// 提交解码器解码
Expand All @@ -53,9 +54,9 @@ public void decodeIn(byte[] data) {
}

// 创建Codec
private void setAudioDecodec(byte[] csd0) throws IOException {
private void setAudioDecodec(boolean useOpus, byte[] csd0) throws IOException {
// 创建解码器
String codecMime = MediaFormat.MIMETYPE_AUDIO_AAC;
String codecMime = useOpus ? MediaFormat.MIMETYPE_AUDIO_OPUS : MediaFormat.MIMETYPE_AUDIO_AAC;
decodec = MediaCodec.createDecoderByType(codecMime);
// 音频参数
int sampleRate = 48000;
Expand All @@ -65,6 +66,11 @@ private void setAudioDecodec(byte[] csd0) throws IOException {
decodecFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
// 获取音频标识头
decodecFormat.setByteBuffer("csd-0", ByteBuffer.wrap(csd0));
if (useOpus) {
ByteBuffer csd12ByteBuffer = ByteBuffer.wrap(new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
decodecFormat.setByteBuffer("csd-1", csd12ByteBuffer);
decodecFormat.setByteBuffer("csd-2", csd12ByteBuffer);
}
// 异步解码
decodec.setCallback(new MediaCodec.Callback() {
@Override
Expand Down Expand Up @@ -121,7 +127,7 @@ private void setAudioTrack() {
// 创建音频放大器
private void setLoudnessEnhancer() {
loudnessEnhancer = new LoudnessEnhancer(audioTrack.getAudioSessionId());
loudnessEnhancer.setTargetGain(3500);
loudnessEnhancer.setTargetGain(3200);
loudnessEnhancer.setEnabled(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public class Client {
public Controller controller;
private final ClientView clientView;
private static final int timeoutDelay = 1000 * 10;
private static final boolean supportH265 = PublicTools.isH265DecoderSupport();
private static final boolean supportH265 = PublicTools.isDecoderSupport("hevc");
private static final boolean supportOpus = PublicTools.isDecoderSupport("opus");

public Client(Device device) {
// 初始化
Expand Down Expand Up @@ -88,7 +89,8 @@ private void startServer(Device device, Pair<String, Integer> address) throws Ex
+ " turnOffScreen=" + (device.turnOffScreen ? 1 : 0)
+ " autoControlScreen=" + (device.autoControlScreen ? 1 : 0)
+ " reSize=" + reSize
+ " useH265=" + ((device.useH265 && supportH265) ? 1 : 0) + " > /dev/null 2>&1 &", false);
+ " useH265=" + ((device.useH265 && supportH265) ? 1 : 0)
+ " useOpus=" + ((device.useOpus && supportOpus) ? 1 : 0) + " > /dev/null 2>&1 &", false);
}

// 连接Server
Expand Down Expand Up @@ -128,22 +130,21 @@ private void createSubService() throws IOException, InterruptedException {
// 控制
controller = new Controller(this);
// 是否支持H265编码
boolean isH265Support = mainClientStream.readByte() == 1;
boolean useH265 = mainClientStream.readByte() == 1;
// 视频大小
if (mainClientStream.readByte() != CHANGE_SIZE_EVENT) throw new IOException("启动Client失败:数据错误-应为CHANGE_SIZE_EVENT");
Pair<Integer, Integer> newVideoSize = new Pair<>(mainClientStream.readInt(), mainClientStream.readInt());
clientView.updateVideoSize(newVideoSize);
// 视频解码
Pair<byte[], Long> csd0 = new Pair<>(videoClientStream.readFrame(), videoClientStream.readLong());
Pair<byte[], Long> csd1 = null;
if (!isH265Support) {
csd1 = new Pair<>(videoClientStream.readFrame(), videoClientStream.readLong());
}
if (!useH265) csd1 = new Pair<>(videoClientStream.readFrame(), videoClientStream.readLong());
videoDecode = new VideoDecode(newVideoSize, csd0, csd1);
// 音频解码
if (mainClientStream.readByte() == 1) {
boolean useOpus = mainClientStream.readByte() == 1;
if (mainClientStream.readByte() != AUDIO_EVENT) throw new IOException("启动Client失败:数据错误-应为AUDIO_EVENT");
audioDecode = new AudioDecode(mainClientStream.readFrame());
audioDecode = new AudioDecode(useOpus,mainClientStream.readFrame());
}
threads.add(new Thread(this::executeMainStreamIn));
threads.add(new Thread(this::executeVideoStreamIn));
Expand Down Expand Up @@ -181,7 +182,7 @@ private void executeMainStreamIn() {
switch (mainClientStream.readByte()) {
case AUDIO_EVENT:
byte[] audioFrame = mainClientStream.readFrame();
if (clientView.checkIsNeedPlay()) audioDecode.decodeIn(audioFrame);
audioDecode.decodeIn(audioFrame);
break;
case CLIPBOARD_EVENT:
controller.nowClipboardText = new String(mainClientStream.readByteArray(mainClientStream.readInt()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,6 @@ public void changeToMini() {
miniView.show();
}

public boolean checkIsNeedPlay() {
return uiMode != UI_MODE_MINI;
}

public void hide(boolean isRelease) {
if (uiMode == UI_MODE_FULL) FullActivity.hide();
else if (uiMode == UI_MODE_SMALL) smallView.hide();
Expand Down
Loading

0 comments on commit dca27e9

Please sign in to comment.