diff --git a/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e05d571cc_1.0.0_xTTS_CnCn_xiaoyan_2018_fix_arm.dat b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e05d571cc_1.0.0_xTTS_CnCn_xiaoyan_2018_fix_arm.dat new file mode 100644 index 00000000..66cd22bf Binary files /dev/null and b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e05d571cc_1.0.0_xTTS_CnCn_xiaoyan_2018_fix_arm.dat differ diff --git a/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e3fe94474_1.0.0_xTTS_CnCn_xiaoyan_2018_arm.irf b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e3fe94474_1.0.0_xTTS_CnCn_xiaoyan_2018_arm.irf new file mode 100644 index 00000000..4fff5ba5 Binary files /dev/null and b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e3fe94474_1.0.0_xTTS_CnCn_xiaoyan_2018_arm.irf differ diff --git a/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e4b08c6f3_1.0.0_xTTS_CnCn_xiaofeng_2018_fix_arm.dat b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e4b08c6f3_1.0.0_xTTS_CnCn_xiaofeng_2018_fix_arm.dat new file mode 100644 index 00000000..cb840a97 Binary files /dev/null and b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e4b08c6f3_1.0.0_xTTS_CnCn_xiaofeng_2018_fix_arm.dat differ diff --git a/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e4caee636_1.0.2_xTTS_CnCn_front_Emb_arm_2017.irf b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e4caee636_1.0.2_xTTS_CnCn_front_Emb_arm_2017.irf new file mode 100644 index 00000000..83c17c1f Binary files /dev/null and b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/e4caee636_1.0.2_xTTS_CnCn_front_Emb_arm_2017.irf differ diff --git a/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/ebdbd61ae_1.0.0_xTTS_CnCn_xiaofeng_2018_arm.irf b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/ebdbd61ae_1.0.0_xTTS_CnCn_xiaofeng_2018_arm.irf new file mode 100644 index 00000000..83d93a04 Binary files /dev/null and b/android-sdk-v5-uxsdk/src/main/assets/aikit_resources/ebdbd61ae_1.0.0_xTTS_CnCn_xiaofeng_2018_arm.irf differ diff --git a/app/build.gradle b/app/build.gradle index 490d8dca..06576545 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -243,12 +243,12 @@ dependencies { //vlc拉流 - implementation 'org.videolan.android:libvlc-all:3.6.0' - + //implementation 'org.videolan.android:libvlc-all:3.6.0' //TTS - implementation files('libs/AIKit.aar') + //implementation(name: 'AIKit', ext: 'aar') + //implementation files('libs/AIKit.aar') } diff --git a/app/libs/AIKit.aar b/app/libs/AIKit.aar new file mode 100644 index 00000000..58384f06 Binary files /dev/null and b/app/libs/AIKit.aar differ diff --git a/app/src/main/java/com/aros/apron/activity/ConfigActivity.kt b/app/src/main/java/com/aros/apron/activity/ConfigActivity.kt index fd829095..0abe3d9d 100644 --- a/app/src/main/java/com/aros/apron/activity/ConfigActivity.kt +++ b/app/src/main/java/com/aros/apron/activity/ConfigActivity.kt @@ -129,7 +129,8 @@ class ConfigActivity : BaseActivity() { configBinding.rbCameraCenter.isChecked = PreferenceUtils.getInstance().cameraLocationType ==1//中间 configBinding.rbCameraRight.isChecked = PreferenceUtils.getInstance().cameraLocationType ==2//右边 configBinding.rbCameraNull.isChecked = PreferenceUtils.getInstance().cameraLocationType ==3//下视 - configBinding.rbCameraMix.isChecked = PreferenceUtils.getInstance().cameraLocationType ==4//融合 + configBinding.rbCameraMix.isChecked = PreferenceUtils.getInstance().cameraLocationType ==4//融右 + configBinding.rbCameraMixCenter.isChecked = PreferenceUtils.getInstance().cameraLocationType ==5//融中 configBinding.btnConfig.setOnClickListener { config() } @@ -238,7 +239,7 @@ class ConfigActivity : BaseActivity() { } } - if (!configBinding.rbCameraRight.isChecked && !configBinding.rbCameraCenter.isChecked && !configBinding.rbCameraNull.isChecked && !configBinding.rbCameraMix.isChecked) { + if (!configBinding.rbCameraRight.isChecked && !configBinding.rbCameraCenter.isChecked && !configBinding.rbCameraNull.isChecked && !configBinding.rbCameraMix.isChecked&& !configBinding.rbCameraMixCenter.isChecked) { ToastUtil.showToast("未配置主相机位置") return } @@ -382,6 +383,8 @@ class ConfigActivity : BaseActivity() { PreferenceUtils.getInstance().cameraLocationType = 3 } else if(configBinding.rbCameraMix.isChecked){ PreferenceUtils.getInstance().cameraLocationType = 4 + }else if(configBinding.rbCameraMixCenter.isChecked){ + PreferenceUtils.getInstance().cameraLocationType = 5 } ToastUtil.showToast("配置已保存") diff --git a/app/src/main/java/com/aros/apron/activity/ConnectionActivity.kt b/app/src/main/java/com/aros/apron/activity/ConnectionActivity.kt index 00a9f4fb..f413dbfd 100644 --- a/app/src/main/java/com/aros/apron/activity/ConnectionActivity.kt +++ b/app/src/main/java/com/aros/apron/activity/ConnectionActivity.kt @@ -90,8 +90,8 @@ open class ConnectionActivity : BaseActivity() { } if (TextUtils.isEmpty(PreferenceUtils.getInstance().mqttServerUri)){ PreferenceUtils.getInstance().mqttServerUri = - "tcp://192.168.20.90:2883" - // "tcp://broker.emqx.io" + //"tcp://192.168.20.90:2883" + "tcp://broker.emqx.io" } if (TextUtils.isEmpty(PreferenceUtils.getInstance().mqttUserName)){ diff --git a/app/src/main/java/com/aros/apron/activity/MainActivity.kt b/app/src/main/java/com/aros/apron/activity/MainActivity.kt index 839ba3fc..d65b5471 100644 --- a/app/src/main/java/com/aros/apron/activity/MainActivity.kt +++ b/app/src/main/java/com/aros/apron/activity/MainActivity.kt @@ -40,10 +40,13 @@ import com.aros.apron.manager.OSDManager import com.aros.apron.manager.PayloadWidgetManager import com.aros.apron.manager.PerceptionManager import com.aros.apron.manager.RTKManager +import com.aros.apron.manager.SpeakerManager import com.aros.apron.manager.StickManager import com.aros.apron.manager.StreamManager import com.aros.apron.manager.UdpStreamManager import com.aros.apron.manager.WirelessLinkManager +import com.aros.apron.mix.Aprondown +import com.aros.apron.mix.Aprongim import com.aros.apron.tools.AlternateArucoDetect import com.aros.apron.tools.ApronArucoDetect import com.aros.apron.tools.ApronArucoDetectPort @@ -529,6 +532,8 @@ open class MainActivity : BaseActivity() { } + + private fun initView() { fpvParentView = findViewById(R.id.fpv_holder) mDrawerLayout = findViewById(R.id.root_view) @@ -704,6 +709,7 @@ open class MainActivity : BaseActivity() { enableStream() initFpvStream() startVtxHeartbeat() + SpeakerManager.getInstance().initMegaphoneInfo() //PayloadWidgetManager.getInstance().initPayloadInfo(); @@ -763,8 +769,7 @@ open class MainActivity : BaseActivity() { LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType) } - } else if (PreferenceUtils.getInstance().cameraLocationType == 4) { - + } else if (PreferenceUtils.getInstance().cameraLocationType == 4||PreferenceUtils.getInstance().cameraLocationType == 5) { if ((isFlightControllerConnect == null || isFlightControllerConnect != true) && (isCameraConnect == null || isCameraConnect != true)) { handler.postDelayed({ initDJIManager() @@ -802,6 +807,8 @@ open class MainActivity : BaseActivity() { initMixedStream() startVtxHeartbeat() + SpeakerManager.getInstance().initMegaphoneInfo() + GeoidManager.getInstance().init(this); //开启雷达监听器 @@ -904,6 +911,8 @@ open class MainActivity : BaseActivity() { initCameraStream() startVtxHeartbeat() // + SpeakerManager.getInstance().initMegaphoneInfo() + GeoidManager.getInstance().init(this); @@ -978,8 +987,8 @@ open class MainActivity : BaseActivity() { @SuppressLint("SuspiciousIndentation") private fun initMixedStream() { // 初始化融合视觉降落识别器 - val mixedLanding = MixedVisionLanding.getInstance() - + //val mixedLanding = MixedVisionLanding.getInstance() + // 为 PORT_1(云台相机)添加帧监听器 cameraManager.addFrameListener( ComponentIndexType.PORT_1, @@ -989,7 +998,34 @@ open class MainActivity : BaseActivity() { updateVtxHeartbeat() streamReceive = true // 使用融合视觉识别器处理云台相机帧 - mixedLanding.processGimbalFrame(height, width, frameData, dictionary) + //mixedLanding.processGimbalFrame(height, width, frameData, dictionary) + //使用云台 + synchronized(Synchronizedstatus.LOCK_OBJ) { + if (!Synchronizedstatus.isIsruningframe() && Synchronizedstatus.isAprongim() && Synchronizedstatus.isSwitchtime()) { + try { + Synchronizedstatus.setIsruningframe(true) + if (startArucoType == 1) { + Aprongim.getInstance()?.detectArucoTags( + height, + width, + frameData, + dictionary + ) + } else if (startArucoType == 2) { + AlternateArucoDetect.getInstance()?.detectArucoTags( + height, + width, + frameData, + dictionary + ) + } + } finally { + Synchronizedstatus.setIsruningframe(false) + } + + } + } + } // 为 FPV(下视相机)添加帧监听器 @@ -1001,7 +1037,33 @@ open class MainActivity : BaseActivity() { updateVtxHeartbeat() streamReceive = true // 使用融合视觉识别器处理下视相机帧 - mixedLanding.processDownwardFrame(height, width, frameData, dictionary) + //mixedLanding.processDownwardFrame(height, width, frameData, dictionary) + //使用下视觉 + synchronized(Synchronizedstatus.LOCK_OBJ) { + if (!Synchronizedstatus.isIsruningframe() && !Synchronizedstatus.isAprongim() && Synchronizedstatus.isSwitchtime()) { + try { + Synchronizedstatus.setIsruningframe(true) + if (startArucoType == 1) { + Aprondown.getInstance()?.detectArucoTags( + height, + width, + frameData, + dictionary + ) + } else if (startArucoType == 2) { + AlternateArucoDetect.getInstance()?.detectArucoTags( + height, + width, + frameData, + dictionary + ) + } + } finally { + Synchronizedstatus.setIsruningframe(false) + } + + } + } } } @@ -1086,13 +1148,6 @@ open class MainActivity : BaseActivity() { } - - - - - - - // private val mLoaderCallback: BaseLoaderCallback = object : BaseLoaderCallback(this) { // override fun onManagerConnected(status: Int) { // if (status == SUCCESS) { @@ -1114,7 +1169,6 @@ open class MainActivity : BaseActivity() { object : CommonCallbacks.CompletionCallbackWithParam { override fun onSuccess(emptyMsg: EmptyMsg?) { LogUtil.log(TAG, "取消降落,识别机库二维码") - if (PreferenceUtils.getInstance().cameraLocationType == 3) { Handler().postDelayed(Runnable { if (!ApronArucoDetect.getInstance().isTriggerSuccess) { @@ -1123,6 +1177,14 @@ open class MainActivity : BaseActivity() { AlternateLandingManager.getInstance().startTaskProcess(null) } }, 6000) + } else if (PreferenceUtils.getInstance().cameraLocationType == 4 ||PreferenceUtils.getInstance().cameraLocationType == 5) { + Handler().postDelayed(Runnable { + if (!Aprongim.getInstance().isTriggerSuccess) { + LogUtil.log(TAG, "图传异常:飞往备降点") + //测试图传丢失 + AlternateLandingManager.getInstance().startTaskProcess(null) + } + }, 6000) } else { Handler().postDelayed(Runnable { if (!ApronArucoDetectPort.getInstance().isTriggerSuccess) { @@ -1138,12 +1200,15 @@ open class MainActivity : BaseActivity() { startArucoType = 1 ApronArucoDetect.getInstance().setDetectedBigMarkers() ApronArucoDetectPort.getInstance().setDetectedBigMarkers() + Aprongim.getInstance().setDetectedBigMarkers() + Aprondown.getInstance().setDetectedBigMarkers() + + DroneHelper.getInstance().setGimbalPitchDegree() //每次触发识别二维码时,为避免获取控制权失败,使多次获取控制权 DroneHelper.getInstance().isVirtualStickEnable = false DroneHelper.getInstance().setVerticalModeToVelocity() } - override fun onFailure(error: IDJIError) { if (startArucoType == 1) { return @@ -1152,6 +1217,10 @@ open class MainActivity : BaseActivity() { LogUtil.log(TAG, "取消降落,识别机库二维码失败:" + Gson().toJson(error)) ApronArucoDetect.getInstance().setDetectedBigMarkers() ApronArucoDetectPort.getInstance().setDetectedBigMarkers() + Aprongim.getInstance().setDetectedBigMarkers() + Aprondown.getInstance().setDetectedBigMarkers() + + DroneHelper.getInstance().setGimbalPitchDegree() //每次触发识别二维码时,为避免获取控制权失败,使多次获取控制权 DroneHelper.getInstance().isVirtualStickEnable = false @@ -1167,20 +1236,28 @@ open class MainActivity : BaseActivity() { LogUtil.log(TAG, "取消降落,识别备降点二维码") if (PreferenceUtils.getInstance().cameraLocationType == 3) { Handler().postDelayed(Runnable { - if (!AlternateArucoDetect.getInstance().isTriggerSuccess) { - LogUtil.log(TAG, "图传异常:备降点直接降落") + if (!ApronArucoDetect.getInstance().isTriggerSuccess) { + LogUtil.log(TAG, "图传异常:飞往备降点") //测试图传丢失 - FlightManager.getInstance().startAutoLanding(null) + AlternateLandingManager.getInstance().startTaskProcess(null) } - }, 4000) + }, 6000) + } else if (PreferenceUtils.getInstance().cameraLocationType == 4|| PreferenceUtils.getInstance().cameraLocationType==5) { + Handler().postDelayed(Runnable { + if (!Aprongim.getInstance().isTriggerSuccess) { + LogUtil.log(TAG, "图传异常:飞往备降点") + //测试图传丢失 + AlternateLandingManager.getInstance().startTaskProcess(null) + } + }, 6000) } else { Handler().postDelayed(Runnable { - if (!AlternateArucoDetect.getInstance().isTriggerSuccess) { - LogUtil.log(TAG, "图传异常:备降点直接降落") + if (!ApronArucoDetectPort.getInstance().isTriggerSuccess) { + LogUtil.log(TAG, "图传异常:飞往备降点") //测试图传丢失 - FlightManager.getInstance().startAutoLanding(null) + AlternateLandingManager.getInstance().startTaskProcess(null) } - }, 4000) + }, 6000) } if (startArucoType == 2) { return @@ -1208,12 +1285,13 @@ open class MainActivity : BaseActivity() { } }) - FLAG_DOWN_LAND -> - { - + FLAG_DOWN_LAND -> { //重置降落变量 ApronArucoDetect.getInstance().setStartAruco(false); ApronArucoDetectPort.getInstance().setStartAruco(false); + Aprongim.getInstance().setStartAruco(false); + Aprondown.getInstance().setStartAruco(false); + KeyManager.getInstance().performAction( KeyTools.createKey(FlightControllerKey.KeyStartAutoLanding), diff --git a/app/src/main/java/com/aros/apron/app/ApronApp.kt b/app/src/main/java/com/aros/apron/app/ApronApp.kt index 0d682234..851e5bc7 100644 --- a/app/src/main/java/com/aros/apron/app/ApronApp.kt +++ b/app/src/main/java/com/aros/apron/app/ApronApp.kt @@ -1,54 +1,129 @@ package com.aros.apron.app +import android.R import android.app.Application import android.content.Context +import android.os.Handler +import android.os.Looper +import android.util.Log +import android.widget.Toast import com.aros.apron.models.MSDKManagerVM import com.aros.apron.models.globalViewModels import com.aros.apron.tools.LogUtil +import com.aros.apron.tools.XTtsPcmGenerator +import com.aros.apron.tts.CopyAsset import com.aros.apron.xclog.CrashHandler import com.aros.apron.xclog.XcFileLog import com.aros.apron.xclog.XcLogConfig -import com.dji.wpmzsdk.manager.WPMZManager +import com.iflytek.aikit.core.AiHelper +import com.iflytek.aikit.core.BaseLibrary +import com.iflytek.aikit.core.CoreListener +import com.iflytek.aikit.core.ErrType +import com.iflytek.aikit.core.LogLvl import com.orhanobut.logger.AndroidLogAdapter import com.orhanobut.logger.Logger import com.orhanobut.logger.PrettyFormatStrategy -import dji.v5.common.utils.GeoidManager -import dji.v5.utils.common.ContextUtil import org.opencv.android.OpenCVLoader open class ApronApp : Application() { - companion object { fun getApplication(): Context? { return context } - var context: Context? = null + + var context: Context? = null + + // 参数别改(你的密钥) + const val APP_ID = "753fd711" + const val API_KEY = "35099a7d31abf2259f5ee58cbf8b6791" + const val API_SECRET = "ZTdiMDIwYzEwNTA1NjllYjJlYjdmYWFi" + const val ABILITY_ID = "e2e44feff" // XTTS 能力 ID + const val WORK_DIR = "/storage/self/primary/DJIDemo/cache/tts/" // SDK工作目录 + + private var authResult = -1 + + fun getAuthResult(): Int { + return authResult + } } private val msdkManagerVM: MSDKManagerVM by globalViewModels() override fun onCreate() { super.onCreate() - context=this + context = this initConfig() msdkManagerVM.initMobileSDK(this) + // 复制资源文件到指定目录 + CopyAsset.getInstance(context).copyAssetsToSdcard() + // 科大讯飞初始化 + initXunfeiSDK() } override fun attachBaseContext(base: Context?) { super.attachBaseContext(base) com.cySdkyc.clx.Helper.install(this) - } + /** + * 初始化科大讯飞SDK + */ + private fun initXunfeiSDK() { + // 设置日志信息 + AiHelper.getInst().setLogInfo(LogLvl.VERBOSE, 1, "$WORK_DIR/aeeLog.txt") + + // 设定初始化参数 + val params = BaseLibrary.Params.builder() + .appId(APP_ID) // 应用ID + .apiKey(API_KEY) // APIKEY + .apiSecret(API_SECRET) // APISECRET + .workDir(WORK_DIR) // SDK工作目录 + .build() + + // 初始化SDK(在子线程中执行) + Thread { + AiHelper.getInst().initEntry(applicationContext, params) + }.start() + + // 注册SDK初始化状态监听 + AiHelper.getInst().registerListener(coreListener) + } + + // 授权结果回调 + private val coreListener = object : CoreListener { + override fun onAuthStateChange(type: ErrType, code: Int) { + Log.i("AEELog", "core listener code:$code") + + // 使用Handler在主线程中执行UI操作 + Handler(Looper.getMainLooper()).post { + when (type) { + ErrType.AUTH -> { + authResult = code + if (code == 0) { + Toast.makeText(applicationContext, "SDK授权成功", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(applicationContext, "SDK授权失败,授权码为:$authResult", Toast.LENGTH_SHORT).show() + } + } + ErrType.HTTP -> { + Toast.makeText(applicationContext, "SDK状态:HTTP认证结果$code", Toast.LENGTH_SHORT).show() + } + else -> { + Toast.makeText(applicationContext, "SDK状态:其他错误$code", Toast.LENGTH_SHORT).show() + } + } + } + } + } /** * Logger 初始化配置 */ private fun initConfig() { - var formatStrategy = PrettyFormatStrategy.newBuilder() + val formatStrategy = PrettyFormatStrategy.newBuilder() .showThreadInfo(false) // 隐藏线程信息 默认:显示 .methodCount(0) // 决定打印多少行(每一行代表一个方法)默认:2 .methodOffset(7) // (Optional) Hides internal method calls up to offset. Default 5 @@ -65,12 +140,23 @@ open class ApronApp : Application() { CrashHandler.getInstance().init() // 初始化 OpenCV if (OpenCVLoader.initLocal()) { - LogUtil.log("qwq","opencv" + - "初始化完成") + LogUtil.log( + "qwq", "opencv" + + "初始化完成" + ) return; - }else{ - LogUtil.log("qwq","opencv" + - "初始化失败") + } else { + LogUtil.log( + "qwq", "opencv" + + "初始化失败" + ) } + + } + + override fun onTerminate() { + super.onTerminate() + // 逆初始化SDK + AiHelper.getInst().unInit() } } \ No newline at end of file diff --git a/app/src/main/java/com/aros/apron/callback/MqttCallBack.java b/app/src/main/java/com/aros/apron/callback/MqttCallBack.java index e94bd447..deb1a172 100644 --- a/app/src/main/java/com/aros/apron/callback/MqttCallBack.java +++ b/app/src/main/java/com/aros/apron/callback/MqttCallBack.java @@ -29,6 +29,8 @@ import com.aros.apron.manager.StickManager; import com.aros.apron.manager.StreamManager; import com.aros.apron.manager.SystemManager; import com.aros.apron.manager.TakeOffToPointManager; +import com.aros.apron.mix.Aprondown; +import com.aros.apron.mix.Aprongim; import com.aros.apron.tools.ApronArucoDetect; import com.aros.apron.tools.ApronArucoDetectPort; import com.aros.apron.tools.Generakmztools; @@ -52,7 +54,7 @@ import dji.v5.common.callback.CommonCallbacks; import dji.v5.common.error.IDJIError; import dji.v5.manager.KeyManager; -public class MqttCallBack extends BaseManager implements MqttCallbackExtended { +public class MqttCallBack extends BaseManager implements MqttCallbackExtended { private String TAG = "MqttCallBack"; Object lock = Synchronizedstatus.LOCK_OBJ; @@ -60,11 +62,12 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { @Override public void connectionLost(Throwable cause) { - LogUtil.log(TAG, "MQtt connectionLost:"+cause.toString()); + LogUtil.log(TAG, "MQtt connectionLost:" + cause.toString()); //短线也要清空这个 clearVirtualStickHeartbeat(); } + //断线重连 public void reConnect() throws Exception { if (null != MqttManager.getInstance().mqttAndroidClient) { @@ -78,7 +81,9 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { private Runnable vsTimeoutCheck; private static final long TIMEOUT_MS = 500; // 500ms 无数据触发 - /** 每次收到控制指令都调 */ + /** + * 每次收到控制指令都调 + */ private void resetVirtualStickHeartbeat() { lastDrControlTime = System.currentTimeMillis(); @@ -97,7 +102,9 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { vsHandler.postDelayed(vsTimeoutCheck, TIMEOUT_MS); } - /** 清理虚拟摇杆心跳(断网/退出/销毁时调) */ + /** + * 清理虚拟摇杆心跳(断网/退出/销毁时调) + */ private void clearVirtualStickHeartbeat() { if (vsTimeoutCheck != null) { vsHandler.removeCallbacks(vsTimeoutCheck); @@ -107,11 +114,10 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { } - @Override public void messageArrived(String topic, MqttMessage mqttMessage) { String jsonString = null; - Log.e(TAG, "入口打印:" +mqttMessage.toString()); + Log.e(TAG, "入口打印:" + mqttMessage.toString()); try { jsonString = new String(mqttMessage.getPayload(), "UTF-8"); @@ -122,9 +128,9 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { MessageDown message = new Gson().fromJson(jsonString, MessageDown.class); //LogUtil.log(TAG,message.getMethod()); - if(topic.equals(AMSConfig.DOWN_UAV_PSDK_EVENT)){ + if (topic.equals(AMSConfig.DOWN_UAV_PSDK_EVENT)) { //负载设置控件 - }else { + } else { switch (message.getMethod()) { case Constant.PILOT_ON: // LogUtil.log(TAG, "收到:遥控器是否开机" + jsonString); @@ -159,19 +165,19 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { CameraManager.getInstance().setCameraVideoStreamSource(message); break; case Constant.FLIGHTTASK_EXECUTE: - synchronized(lock){ + synchronized (lock) { // 检查是否是第一次收到航线指令 - if(Synchronizedstatus.isIsruning()){ + if (Synchronizedstatus.isIsruning()) { LogUtil.log(TAG, "自检正在运行"); return; - } else if(!Synchronizedstatus.getInitStatus()){ + } else if (!Synchronizedstatus.getInitStatus()) { Synchronizedstatus.setIsruning(true); //自检 - MissionV3Manager.getInstance().checkVtxWithDelay(()->{ + MissionV3Manager.getInstance().checkVtxWithDelay(() -> { Synchronizedstatus.setIsruning(false); Synchronizedstatus.setInitStatus(true); }); - }else if(Synchronizedstatus.getInitStatus()){ + } else if (Synchronizedstatus.getInitStatus()) { LogUtil.log(TAG, "收到:航线" + jsonString); //设置modecode Movement.getInstance().setMode_code(1); @@ -197,7 +203,7 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { LogUtil.log(TAG, "收到:返航" + jsonString); //自动返航 (如果调用方法失败了 这个设置就有一个问题但是为了方便看懂我就放这里了没放成功的回调里面) Movement.getInstance().setMode_code(9); - if(!Movement.getInstance().isAlternate()&&!ApronArucoDetectPort.getInstance().isStartAruco()&&!ApronArucoDetect.getInstance().isStartAruco()){ + if (!Movement.getInstance().isAlternate() && !ApronArucoDetectPort.getInstance().isStartAruco() && !ApronArucoDetect.getInstance().isStartAruco() && !Aprongim.getInstance().isStartAruco() && !Aprondown.getInstance().isStartAruco()) { // if(Movement.getInstance().getElevation()<15){ // // @@ -207,9 +213,9 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { // } FlightManager.getInstance().startGoHome(message); - }else{ + } else { sendMsg2Server(message); - sendEvent2Server("正在视觉或飞往备降不允许返航",1); + sendEvent2Server("正在视觉或飞往备降不允许返航", 1); } break; case Constant.INBOUND: @@ -237,18 +243,18 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { // MissionDataBean data = new Gson().fromJson(new Gson().toJson(message.getData()), MissionDataBean.class); // Boolean generateKmz = Generakmztools.getInstance().generateKmz(data); - synchronized(lock){ - if(Synchronizedstatus.isIsruning()){ + synchronized (lock) { + if (Synchronizedstatus.isIsruning()) { LogUtil.log(TAG, "自检正在运行"); return; - } else if(!Synchronizedstatus.getInitStatus()){ + } else if (!Synchronizedstatus.getInitStatus()) { Synchronizedstatus.setIsruning(true); //自检 - TakeOffToPointManager.getInstance().checkVtxWithDelay(()->{ + TakeOffToPointManager.getInstance().checkVtxWithDelay(() -> { Synchronizedstatus.setIsruning(false); Synchronizedstatus.setInitStatus(true); }); - }else if(Synchronizedstatus.getInitStatus()){ + } else if (Synchronizedstatus.getInitStatus()) { LogUtil.log(TAG, "收到:一键起飞" + jsonString); //设置modecode Movement.getInstance().setMode_code(1); @@ -321,46 +327,46 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { break; case Constant.CAMERA_SCREEN_DRAG: LogUtil.log(TAG, "收到:负载控制—画面拖动控制" + jsonString); - if(ApronArucoDetect.getInstance().isStartAruco()||ApronArucoDetectPort.getInstance().isStartAruco()){ - sendEvent2Server("自动降落不可以动负载",1); + if (ApronArucoDetect.getInstance().isStartAruco() || ApronArucoDetectPort.getInstance().isStartAruco() || Aprongim.getInstance().isStartAruco() || Aprondown.getInstance().isStartAruco()) { + sendEvent2Server("自动降落不可以动负载", 1); return; - }else{ + } else { GimbalManager.getInstance().camera_screen_drag(message); } break; case Constant.CAMERA_AIM: LogUtil.log(TAG, "收到:负载控制—双击成为 AIM" + jsonString); - if(ApronArucoDetect.getInstance().isStartAruco()||ApronArucoDetectPort.getInstance().isStartAruco()){ - sendEvent2Server("自动降落不可以动负载",1); + if (ApronArucoDetect.getInstance().isStartAruco() || ApronArucoDetectPort.getInstance().isStartAruco() || Aprongim.getInstance().isStartAruco() || Aprondown.getInstance().isStartAruco()) { + sendEvent2Server("自动降落不可以动负载", 1); return; - }else{ + } else { CameraManager.getInstance().tapZoomAtTarget(message); } break; case Constant.CAMERA_FOCAL_LENGTH_SET: LogUtil.log(TAG, "收到:负载控制—变焦" + jsonString); - if(ApronArucoDetect.getInstance().isStartAruco()||ApronArucoDetectPort.getInstance().isStartAruco()){ - sendEvent2Server("自动降落不可以动负载",1); + if (ApronArucoDetect.getInstance().isStartAruco() || ApronArucoDetectPort.getInstance().isStartAruco() || Aprongim.getInstance().isStartAruco() || Aprondown.getInstance().isStartAruco()) { + sendEvent2Server("自动降落不可以动负载", 1); return; - }else{ + } else { CameraManager.getInstance().setCameraZoomRatios(message); } break; case Constant.GIMBAL_RESET: LogUtil.log(TAG, "收到:负载控制—重置云台" + jsonString); - if(ApronArucoDetect.getInstance().isStartAruco()||ApronArucoDetectPort.getInstance().isStartAruco()){ - sendEvent2Server("自动降落不可以动负载",1); + if (ApronArucoDetect.getInstance().isStartAruco() || ApronArucoDetectPort.getInstance().isStartAruco() || Aprongim.getInstance().isStartAruco() || Aprondown.getInstance().isStartAruco()) { + sendEvent2Server("自动降落不可以动负载", 1); return; - }else{ + } else { GimbalManager.getInstance().gimbalReset(message); } break; case Constant.CAMERA_LOOK_AT: LogUtil.log(TAG, "收到:负载控制—Look At" + jsonString); - if(ApronArucoDetect.getInstance().isStartAruco()||ApronArucoDetectPort.getInstance().isStartAruco()){ - sendEvent2Server("自动降落不可以动负载",1); + if (ApronArucoDetect.getInstance().isStartAruco() || ApronArucoDetectPort.getInstance().isStartAruco() || Aprongim.getInstance().isStartAruco() || Aprondown.getInstance().isStartAruco()) { + sendEvent2Server("自动降落不可以动负载", 1); return; - }else{ + } else { GimbalManager.getInstance().gimbalLookAt(message); } break; @@ -410,51 +416,139 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { break; case Constant.CAMERA_FRAME_ZOOM: LogUtil.log(TAG, "收到:框选变焦" + jsonString); - if(ApronArucoDetect.getInstance().isStartAruco()||ApronArucoDetectPort.getInstance().isStartAruco()){ - sendEvent2Server("自动降落不可以动负载",1); + if (ApronArucoDetect.getInstance().isStartAruco() || ApronArucoDetectPort.getInstance().isStartAruco() || Aprongim.getInstance().isStartAruco() || Aprondown.getInstance().isStartAruco()) { + sendEvent2Server("自动降落不可以动负载", 1); return; - }else{ + } else { CameraManager.getInstance().camera_frame_zoom(message); } break; case Constant.SPEAKER_AUDIO_PLAY_START: LogUtil.log(TAG, "收到:喊话器-开始播放音频" + jsonString); SpeakerProgressReporter.getInstance().startAudioReport(2); - SpeakerManager.getInstance().speakerAudioPlayStart(message); + synchronized (lock) { + if (!Synchronizedstatus.isSpeakrunning()) { + SpeakerManager.getInstance().speakerAudioPlayStart(message); + Synchronizedstatus.setSpeakrunning(true); + }else{ + sendMsg2Server(message); + return; + } + } break; case Constant.SPEAKER_TTS_PLAY_START: LogUtil.log(TAG, "收到:喊话器-开始播放TTS文本" + jsonString); SpeakerProgressReporter.getInstance().startTTSReport(2); - SpeakerManager.getInstance().speakerTTSPlayStart(message, 0); + synchronized (lock) { + if (!Synchronizedstatus.isSpeakrunning()) { + SpeakerManager.getInstance().speakerTTSPlayStart(message, 0); + Synchronizedstatus.setSpeakTTSrunning(true); + }else{ + sendMsg2Server(message); + return; + } + } break; case Constant.SPEAKER_REPLAY: LogUtil.log(TAG, "收到:喊话器-重新播放" + jsonString); - SpeakerManager.getInstance().speakerReply(message); + synchronized (lock) { + if (!Synchronizedstatus.isSpeakrunning()) { + SpeakerManager.getInstance().speakerReply(message); + Synchronizedstatus.setSpeaksetrunning(true); + }else{ + sendMsg2Server(message); + return; + } + } break; case Constant.SPEAKER_PLAY_STOP: LogUtil.log(TAG, "收到:喊话器-停止播放" + jsonString); - SpeakerManager.getInstance().speakerStop(message); + synchronized (lock) { + if (!Synchronizedstatus.isSpeakrunning()) { + SpeakerManager.getInstance().speakerStop(message); + Synchronizedstatus.setSpeaksetrunning(true); + }else{ + sendMsg2Server(message); + return; + } + } + break; case Constant.SPEAKER_PLAY_MODE_SET: LogUtil.log(TAG, "收到:喊话器-设置播放模式" + jsonString); - SpeakerManager.getInstance().speakerPlayModeSet(message); + synchronized (lock) { + if (!Synchronizedstatus.isSpeakrunning()) { + SpeakerManager.getInstance().speakerPlayModeSet(message); + Synchronizedstatus.setSpeaksetrunning(true); + }else{ + sendMsg2Server(message); + return; + } + } + break; case Constant.SPEAKER_PLAY_VOLUME_SET: LogUtil.log(TAG, "收到:喊话器-设置音量" + jsonString); - SpeakerManager.getInstance().speakerPlayVolumeSet(message); + synchronized (lock) { + if (!Synchronizedstatus.isSpeakrunning()) { + SpeakerManager.getInstance().speakerPlayVolumeSet(message); + Synchronizedstatus.setSpeaksetrunning(true); + }else{ + sendMsg2Server(message); + return; + } + } + break; case Constant.DRC_SPEAKER_TTS_SET: LogUtil.log(TAG, "收到:喊话器-TTS喊话设置" + jsonString); - SpeakerManager.getInstance().speakerTTSPlayStart(message, 1); + + synchronized (lock) { + if (!Synchronizedstatus.isSpeakrunning()) { + SpeakerManager.getInstance().speakerTTSPlayStart(message, 1); + Synchronizedstatus.setSpeaksetrunning(true); + }else{ + sendMsg2Server(message); + return; + } + } + break; case Constant.UAV_LIVE_FPV: //LogUtil.log(TAG, "收到:切换推流fpv" + jsonString); - StreamManager.getInstance().switchptspfpv(ComponentIndexType.FPV,message); + StreamManager.getInstance().switchptspfpv(ComponentIndexType.FPV, message); break; case Constant.UAV_LIVE_CAMERA: //LogUtil.log(TAG, "收到:切换推流camera" + jsonString); - StreamManager.getInstance().switchptspport(ComponentIndexType.PORT_1,message); + StreamManager.getInstance().switchptspport(ComponentIndexType.PORT_1, message); break; + case Constant.DRC_LIGHT_BRIGHTNESS_SET: + synchronized (lock) { + if (Synchronizedstatus.isLight_brightnessrunning()){ + return; + }else { + + } + } + // LogUtil.log(TAG, "收到:A1亮度设置 " + jsonString); + // 处理亮度设置逻辑 + break; + + case Constant.DRC_LIGHT_MODE_SET: + // LogUtil.log(TAG, "收到:A1模式设置 " + jsonString); + // 处理模式设置逻辑 + break; + + case Constant.DRC_LIGHT_FINE_TUNING_SET: + // LogUtil.log(TAG, "收到:A1左右角度微调 " + jsonString); + // 处理左右角度微调逻辑 + break; + + case Constant.DRC_LIGHT_CALIBRATION: + // LogUtil.log(TAG, "收到:A1云台校准 " + jsonString); + // 处理云台校准逻辑 + break; + // //获取控制权 // case 60007: @@ -808,21 +902,23 @@ public class MqttCallBack extends BaseManager implements MqttCallbackExtended { public void deliveryComplete(IMqttDeliveryToken token) { } - String[] topics = new String[] { + + String[] topics = new String[]{ AMSConfig.getInstance().DOWN_UAV_EVENT_REPLY, AMSConfig.getInstance().DOWN_UAV_SERVICES, }; - int[] qos = new int[] { + int[] qos = new int[]{ 1, 1 }; + @Override public void connectComplete(boolean reconnect, String serverURI) { try { // if (reconnect) {//重新订阅 - LogUtil.log(TAG, "MQtt ConnectComplete:" + serverURI); - MqttManager.getInstance().mqttAndroidClient.subscribe(topics, qos);//订阅主题:注册 + LogUtil.log(TAG, "MQtt ConnectComplete:" + serverURI); + MqttManager.getInstance().mqttAndroidClient.subscribe(topics, qos);//订阅主题:注册 // MqttManager.getInstance().mqttAndroidClient.subscribe(AMSConfig.DOWN_UAV_EVENT_REPLY, 1);//订阅主题:注册 - // publish(topic,"注册",0); + // publish(topic,"注册",0); // } } catch (Exception e) { LogUtil.log(TAG, "MQtt ConnectException:" + e.toString()); diff --git a/app/src/main/java/com/aros/apron/constant/Constant.java b/app/src/main/java/com/aros/apron/constant/Constant.java index b2be62fc..a2b2033e 100644 --- a/app/src/main/java/com/aros/apron/constant/Constant.java +++ b/app/src/main/java/com/aros/apron/constant/Constant.java @@ -330,4 +330,21 @@ public class Constant { * 推流切换camera */ public static final String UAV_LIVE_CAMERA="uav_live_camera"; + + + + + public static final String DRC_LIGHT_BRIGHTNESS_SET="drc_light_brightness_set"; + //A1模式设置 + public static final String DRC_LIGHT_MODE_SET="drc_light_mode_set"; + //A1左右角度微调 + public static final String DRC_LIGHT_FINE_TUNING_SET="drc_light_fine_tuning_set"; + //A1云台校准 + public static final String DRC_LIGHT_CALIBRATION="drc_light_calibration"; + + + + + + } diff --git a/app/src/main/java/com/aros/apron/entity/MessageDown.java b/app/src/main/java/com/aros/apron/entity/MessageDown.java index 4962ebce..3d1f18af 100644 --- a/app/src/main/java/com/aros/apron/entity/MessageDown.java +++ b/app/src/main/java/com/aros/apron/entity/MessageDown.java @@ -117,11 +117,68 @@ public class MessageDown { private int volume; private int type; private int language; - - - private Tts tts; + //探照灯 + private int group; + // brightness: 亮度 1-100 (int) + private int brightness; + // mode: 模式 0-关闭 1-常亮 2-爆闪 3-快速爆闪 4-交替爆闪 (enum_int) + private int mode; + // position: 灯位置 0-左灯 1-右灯 (enum_int) + private int position; + // value: 左右角度微调值 -3° 到 +3° (int) + private int value; + // saved: 是否保存 0-否 1-是 (bool) + private boolean saved; + + public int getGroup() { + return group; + } + + public void setGroup(int group) { + this.group = group; + } + + public int getBrightness() { + return brightness; + } + + public void setBrightness(int brightness) { + this.brightness = brightness; + } + + public int getMode() { + return mode; + } + + public void setMode(int mode) { + this.mode = mode; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public boolean isSaved() { + return saved; + } + + public void setSaved(boolean saved) { + this.saved = saved; + } public Tts getTts() { return tts; diff --git a/app/src/main/java/com/aros/apron/entity/Synchronizedstatus.java b/app/src/main/java/com/aros/apron/entity/Synchronizedstatus.java index 655c9761..2774dc76 100644 --- a/app/src/main/java/com/aros/apron/entity/Synchronizedstatus.java +++ b/app/src/main/java/com/aros/apron/entity/Synchronizedstatus.java @@ -17,10 +17,76 @@ public class Synchronizedstatus { private static volatile boolean isruningframe=false; + private static volatile boolean aprongim=true; + + + private static volatile boolean switchtime=true; + + //探照灯线程 + private static volatile boolean light_brightnessrunning=false; + + //喊话器线程 + private static volatile boolean speakrunning=false; + + + private static volatile boolean speakTTSrunning=false; + private static volatile boolean speaksetrunning=false; + + + public static boolean isSpeaksetrunning() { + return speaksetrunning; + } + + public static void setSpeaksetrunning(boolean speaksetrunning) { + Synchronizedstatus.speaksetrunning = speaksetrunning; + } + + public static boolean isSpeakTTSrunning() { + return speakTTSrunning; + } + + public static void setSpeakTTSrunning(boolean speakTTSrunning) { + Synchronizedstatus.speakTTSrunning = speakTTSrunning; + } + + public static boolean isSpeakrunning() { + return speakrunning; + } + + public static void setSpeakrunning(boolean speakrunning) { + Synchronizedstatus.speakrunning = speakrunning; + } + + public static boolean isLight_brightnessrunning() { + return light_brightnessrunning; + } + + public static void setLight_brightnessrunning(boolean light_brightnessrunning) { + Synchronizedstatus.light_brightnessrunning = light_brightnessrunning; + } + + public static boolean isSwitchtime() { + return switchtime; + } + + public static void setSwitchtime(boolean switchtime) { + Synchronizedstatus.switchtime = switchtime; + } + + public static boolean isAprongim() { + return aprongim; + } + + public static void setAprongim(boolean aprongim) { + Synchronizedstatus.aprongim = aprongim; + } + public static boolean isIsruningframe() { return isruningframe; } + + public static void setIsruningframe(boolean isruningframe) { Synchronizedstatus.isruningframe = isruningframe; } diff --git a/app/src/main/java/com/aros/apron/entity/XTTSParams.java b/app/src/main/java/com/aros/apron/entity/XTTSParams.java index 1a22a964..824fb54d 100644 --- a/app/src/main/java/com/aros/apron/entity/XTTSParams.java +++ b/app/src/main/java/com/aros/apron/entity/XTTSParams.java @@ -1,12 +1,123 @@ package com.aros.apron.entity; - public class XTTSParams { - public String vcn = "xiaoyan"; - public int language =1 ; - public int pitch = 50; - public int speed = 50; - public int volume = 100; + // 默认参数值 + public static final String DEFAULT_VCN = "xiaoyan"; + public static final int DEFAULT_LANGUAGE = 1; + public static final int DEFAULT_PITCH = 50; + public static final int DEFAULT_SPEED = 50; + public static final int DEFAULT_VOLUME = 100; -} + // 参数范围 + public static final int MIN_PITCH = 0; + public static final int MAX_PITCH = 100; + public static final int MIN_SPEED = 0; + public static final int MAX_SPEED = 100; + public static final int MIN_VOLUME = 0; + public static final int MAX_VOLUME = 100; + + public String vcn = DEFAULT_VCN; + public int language = DEFAULT_LANGUAGE; + public int pitch = DEFAULT_PITCH; + public int speed = DEFAULT_SPEED; + public int volume = DEFAULT_VOLUME; + + // 默认构造方法 + public XTTSParams() { + } + + // 全参数构造方法 + public XTTSParams(String vcn, int language, int pitch, int speed, int volume) { + setVcn(vcn); + setLanguage(language); + setPitch(pitch); + setSpeed(speed); + setVolume(volume); + } + + // Getter 和 Setter 方法 + public String getVcn() { + return vcn; + } + + public void setVcn(String vcn) { + if (vcn != null && !vcn.isEmpty()) { + this.vcn = vcn; + } + } + + public int getLanguage() { + return language; + } + + public void setLanguage(int language) { + // 确保语言代码为正数 + if (language > 0) { + this.language = language; + } + } + + public int getPitch() { + return pitch; + } + + public void setPitch(int pitch) { + // 确保语调在有效范围内 + this.pitch = Math.max(MIN_PITCH, Math.min(MAX_PITCH, pitch)); + } + + public int getSpeed() { + return speed; + } + + public void setSpeed(int speed) { + // 确保语速在有效范围内 + this.speed = Math.max(MIN_SPEED, Math.min(MAX_SPEED, speed)); + } + + public int getVolume() { + return volume; + } + + public void setVolume(int volume) { + // 确保音量在有效范围内 + this.volume = Math.max(MIN_VOLUME, Math.min(MAX_VOLUME, volume)); + } + + // 预设配置方法 + public static XTTSParams createDefault() { + return new XTTSParams(); + } + + public static XTTSParams createFemaleVoice() { + return new XTTSParams("xiaoyan", 1, 50, 50, 100); + } + + public static XTTSParams createMaleVoice() { + return new XTTSParams("xiaofeng", 1, 50, 50, 100); + } + + public static XTTSParams createFastSpeed() { + XTTSParams params = new XTTSParams(); + params.setSpeed(70); + return params; + } + + public static XTTSParams createSlowSpeed() { + XTTSParams params = new XTTSParams(); + params.setSpeed(30); + return params; + } + + @Override + public String toString() { + return "XTTSParams{" + + "vcn='" + vcn + '\'' + + ", language=" + language + + ", pitch=" + pitch + + ", speed=" + speed + + ", volume=" + volume + + '}'; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aros/apron/manager/A1Manager.java b/app/src/main/java/com/aros/apron/manager/A1Manager.java new file mode 100644 index 00000000..0e68a871 --- /dev/null +++ b/app/src/main/java/com/aros/apron/manager/A1Manager.java @@ -0,0 +1,49 @@ +package com.aros.apron.manager; + +public class A1Manager { + + private String TAG = this.getClass().getSimpleName(); + public A1Manager() { + } + private static class A1Managerholder { + private static final A1Manager INSTANCE = new A1Manager(); + } + + public static A1Manager getInstance() { + return A1Manager.A1Managerholder.INSTANCE; + } + + + //探照灯亮度设置 + public void setdrc_light_brightness_set(){ + + + + } + //探照灯模式设置 + public void setdrc_light_mode_set(){ + + + + } + //探照灯左右角度微调 + public void setdrc_light_fine_tuning_set(){ + + + + } + // 探照灯云台校准 + public void setdrc_light_calibrationt(){ + + + } + + + + + + + + + +} diff --git a/app/src/main/java/com/aros/apron/manager/CameraManager.java b/app/src/main/java/com/aros/apron/manager/CameraManager.java index 5d2dd387..060ef712 100644 --- a/app/src/main/java/com/aros/apron/manager/CameraManager.java +++ b/app/src/main/java/com/aros/apron/manager/CameraManager.java @@ -86,6 +86,7 @@ public class CameraManager extends BaseManager { panoHandler.removeCallbacks(panoRunnable); sendCameraPhotoTakeProgress2Server(); // 最后报一次 + Movement.getInstance().setMode_code(3); } @@ -139,11 +140,12 @@ public void initCameraInfo() { // Movement.getInstance().setPhoto_status("fail"); } else if (t1 == VisionPhotoPanoramaMissionState.PROCESSING) { Movement.getInstance().setPhoto_current_step(3005); - } else if (t1 == VisionPhotoPanoramaMissionState.FORBIDDEN) { - Movement.getInstance().setPhoto_result(1); - Movement.getInstance().setPhoto_current_step(3000); - Movement.getInstance().setPhoto_status("fail"); } +// else if (t1 == VisionPhotoPanoramaMissionState.FORBIDDEN) { +// Movement.getInstance().setPhoto_result(1); +// Movement.getInstance().setPhoto_current_step(3000); +// Movement.getInstance().setPhoto_status("fail"); +// } } } }); @@ -663,6 +665,10 @@ public void setCameraMode(MessageDown message) { } else if (cameraMode == 3) { cameraModevalue = 12; } +// if(cameraMode == 3){ +// //退出回放模式 +// MediaManager.getInstance().disablePlayback(); +// } KeyManager.getInstance().setValue(KeyTools.createKey(CameraKey.KeyCameraMode, ComponentIndexType.PORT_1), CameraMode.find(cameraModevalue), diff --git a/app/src/main/java/com/aros/apron/manager/FlightManager.java b/app/src/main/java/com/aros/apron/manager/FlightManager.java index 82f83553..ff96c110 100644 --- a/app/src/main/java/com/aros/apron/manager/FlightManager.java +++ b/app/src/main/java/com/aros/apron/manager/FlightManager.java @@ -16,6 +16,8 @@ import com.aros.apron.constant.AMSConfig; import com.aros.apron.entity.ApronExecutionStatus; import com.aros.apron.entity.MessageDown; import com.aros.apron.entity.Movement; +import com.aros.apron.mix.Aprondown; +import com.aros.apron.mix.Aprongim; import com.aros.apron.tools.AlternateArucoDetect; import com.aros.apron.tools.ApronArucoDetect; import com.aros.apron.tools.ApronArucoDetectPort; @@ -1164,6 +1166,7 @@ public class FlightManager extends BaseManager { // 释放控制权失败时的处理 LogUtil.log(TAG, "释放控制权失败,无法执行自动降落: " + error.toString()); // 可以添加重试逻辑或其他错误处理 + EventBus.getDefault().post(FLAG_DOWN_LAND); } }); } @@ -1178,7 +1181,7 @@ public class FlightManager extends BaseManager { if (PreferenceUtils.getInstance().getNeedTriggerAlterArucoLand()) { return !isTriggerLanding && (isFlying || isMotorsOn) && AlternateArucoDetect.getInstance().isCanLanding(); } else { - return !isTriggerLanding && (isFlying || isMotorsOn) && (ApronArucoDetect.getInstance().isCanLanding() || ApronArucoDetectPort.getInstance().isCanLanding()); + return !isTriggerLanding && (isFlying || isMotorsOn) && (ApronArucoDetect.getInstance().isCanLanding() || ApronArucoDetectPort.getInstance().isCanLanding()|| Aprongim.getInstance().isCanLanding()|| Aprondown.getInstance().isCanLanding()); } } @@ -1199,6 +1202,9 @@ public class FlightManager extends BaseManager { sendCloseCabinDoorMsg = false; ApronArucoDetect.getInstance().setCanLanding(false); ApronArucoDetectPort.getInstance().setCanLanding(false); + Aprondown.getInstance().setCanLanding(false); + Aprongim.getInstance().setCanLanding(false); + // 发布事件,通知其他组件停止Aruco检测 EventBus.getDefault().post(FLAG_STOP_ARUCO); diff --git a/app/src/main/java/com/aros/apron/manager/GimbalManager.java b/app/src/main/java/com/aros/apron/manager/GimbalManager.java index 784fd152..d19bf106 100644 --- a/app/src/main/java/com/aros/apron/manager/GimbalManager.java +++ b/app/src/main/java/com/aros/apron/manager/GimbalManager.java @@ -11,6 +11,7 @@ import androidx.annotation.Nullable; import com.aros.apron.base.BaseManager; import com.aros.apron.entity.MessageDown; import com.aros.apron.entity.Movement; +import com.aros.apron.mix.Aprongim; import com.aros.apron.tools.ApronArucoDetect; import com.aros.apron.tools.ApronArucoDetectPort; import com.aros.apron.tools.LogUtil; @@ -59,6 +60,12 @@ public class GimbalManager extends BaseManager { public void initGimbalInfo() { ApronArucoDetect.getInstance().setDoublePayload(PreferenceUtils.getInstance().getCameraLocationType() == 2); ApronArucoDetectPort.getInstance().setDoublePayload(PreferenceUtils.getInstance().getCameraLocationType() == 2); + + + Aprongim.getInstance().setDoublePayload(PreferenceUtils.getInstance().getCameraLocationType() == 4); + + + LogUtil.log(TAG, "主摄像头位置:" + PreferenceUtils.getInstance().getCameraLocationType()); Boolean isConnect = KeyManager.getInstance().getValue(KeyTools.createKey(FlightControllerKey.KeyConnection)); diff --git a/app/src/main/java/com/aros/apron/manager/SpeakerManager.java b/app/src/main/java/com/aros/apron/manager/SpeakerManager.java index 641d9fa0..acb3ae9a 100644 --- a/app/src/main/java/com/aros/apron/manager/SpeakerManager.java +++ b/app/src/main/java/com/aros/apron/manager/SpeakerManager.java @@ -8,6 +8,7 @@ import androidx.annotation.NonNull; import com.aros.apron.base.BaseManager; import com.aros.apron.entity.MessageDown; import com.aros.apron.entity.Movement; +import com.aros.apron.entity.Synchronizedstatus; import com.aros.apron.entity.XTTSParams; import com.aros.apron.tools.LogUtil; import com.aros.apron.tools.SpeakerProgressReporter; @@ -45,6 +46,7 @@ public class SpeakerManager extends BaseManager { return SpeakerHolder.INSTANCE; } private int megaphoneStatus; + private XTtsPcmGenerator ttsGenerator; public void initMegaphoneInfo() { MegaphoneManager.getInstance().addMegaphoneInfoListener(new MegaphoneInfoListener() { @Override @@ -65,10 +67,16 @@ public class SpeakerManager extends BaseManager { LogUtil.log(TAG,"喊话器位置设置失败:"+getIDJIErrorMsg(error)); } }); + } public void speakerAudioPlayStart(MessageDown message) { + sendMsg2Server(message); + //暂停播放 + stop(); + if (TextUtils.isEmpty(message.getData().getFile().getUrl())) { sendFailMsg2Server(message, "喊话文件下载地址为空"); + LogUtil.log(TAG,"喊话文件下载地址为空"); return; } Request request = new Request.Builder().url(message.getData().getFile().getUrl()).build(); @@ -76,6 +84,7 @@ public class SpeakerManager extends BaseManager { @Override public void onFailure(Call call, IOException e) { sendEvent2Server(".pcm文件下载失败:" + e.toString(), 2); + LogUtil.log(TAG,"pcm文件下载失败"); } @Override @@ -86,7 +95,7 @@ public class SpeakerManager extends BaseManager { int len = 0; FileOutputStream fos = null; // 储存下载文件的目录 - File dir = new File(Environment.getExternalStorageDirectory().getPath()); + File dir = new File("/storage/self/primary/DJIDemo/cache/tts/output/"); if (!dir.exists()) { dir.mkdirs(); } @@ -98,8 +107,14 @@ public class SpeakerManager extends BaseManager { fos.write(buf, 0, len); } fos.flush(); + // 检查 PCM 文件大小 + LogUtil.log(TAG, "PCM 文件大小: " + file.length() + " bytes"); sendEvent2Server("喊话.pcm文件下载成功", 1); String opusFilePath = PCMTools.INSTANCE.convertToOpusFileSync(file.getAbsolutePath()); + // 检查 opus 文件路径和大小 + File opusFile = new File(opusFilePath); + LogUtil.log(TAG, "Opus 文件路径: " + opusFilePath); + LogUtil.log(TAG, "Opus 文件大小: " + (opusFile.exists() ? opusFile.length() : 0) + " bytes"); Movement.getInstance().setStep_key("download"); Movement.getInstance().setTTS_status("in_progress"); @@ -109,6 +124,8 @@ public class SpeakerManager extends BaseManager { null); MegaphoneManager.getInstance().startPushingFileToMegaphone(fileInfo, new CommonCallbacks.CompletionCallbackWithProgress() { + private boolean isCallbackExecuted = false; // 确保回调只执行一次 + @Override public void onProgressUpdate(Integer integer) { @@ -119,6 +136,12 @@ public class SpeakerManager extends BaseManager { @Override public void onSuccess() { + // 确保回调只执行一次 + if (isCallbackExecuted) { + return; + } + isCallbackExecuted = true; + LogUtil.log(TAG, "喊话器内容上传成功"); new Handler().postDelayed(new Runnable() { @Override @@ -127,13 +150,16 @@ public class SpeakerManager extends BaseManager { @Override public void onSuccess() { Movement.getInstance().setTTS_status("ok"); - sendEvent2Server("喊话器播放音频成功", 1); + LogUtil.log(TAG,"喊话器播放音频成功"); + Synchronizedstatus.setSpeakrunning(false); } @Override public void onFailure(@NonNull IDJIError error) { sendEvent2Server("喊话器播放音频失败:" + getIDJIErrorMsg(error), 2); + Synchronizedstatus.setSpeakrunning(false); + LogUtil.log(TAG,"喊话器播放音频失败"+ getIDJIErrorMsg(error)); } }); } @@ -142,17 +168,22 @@ public class SpeakerManager extends BaseManager { @Override public void onFailure(@NonNull IDJIError error) { + // 确保回调只执行一次 + if (isCallbackExecuted) { + return; + } + isCallbackExecuted = true; + sendFailMsg2Server(message, "喊话器内容上传失败:" + getIDJIErrorMsg(error)); } }); - - } catch (Exception e) { sendEvent2Server("喊话.pcm文件下载失败:" + e.toString(), 2); } } } }); + } @@ -160,14 +191,17 @@ public class SpeakerManager extends BaseManager { MegaphoneManager.getInstance().startPlay(new CommonCallbacks.CompletionCallback() { @Override public void onSuccess() { + Synchronizedstatus.setSpeaksetrunning(false); sendMsg2Server(message); } @Override public void onFailure(@NonNull IDJIError error) { + Synchronizedstatus.setSpeaksetrunning(false); sendFailMsg2Server(message, "喊话器播放音频失败:" + getIDJIErrorMsg(error)); } }); + } public void speakerStop(MessageDown message) { @@ -176,6 +210,7 @@ public class SpeakerManager extends BaseManager { public void onSuccess() { SpeakerProgressReporter.getInstance().stopAudioReport(); SpeakerProgressReporter.getInstance().stopTTSReport(); + Synchronizedstatus.setSpeaksetrunning(false); sendMsg2Server(message); } @@ -183,23 +218,41 @@ public class SpeakerManager extends BaseManager { public void onFailure(@NonNull IDJIError error) { SpeakerProgressReporter.getInstance().stopAudioReport(); SpeakerProgressReporter.getInstance().stopTTSReport(); - sendMsg2Server(message); sendFailMsg2Server(message, "喊话器停止播放失败:" + getIDJIErrorMsg(error)); + Synchronizedstatus.setSpeaksetrunning(false); } }); } + public void stop(){ + MegaphoneManager.getInstance().stopPlay(new CommonCallbacks.CompletionCallback() { + @Override + public void onSuccess() { + SpeakerProgressReporter.getInstance().stopAudioReport(); + SpeakerProgressReporter.getInstance().stopTTSReport(); + } + + @Override + public void onFailure(@NonNull IDJIError error) { + SpeakerProgressReporter.getInstance().stopAudioReport(); + SpeakerProgressReporter.getInstance().stopTTSReport(); + } + }); + + } public void speakerPlayModeSet(MessageDown message) { MegaphoneManager.getInstance().setPlayMode(message.getData().getPlay_mode() == 0 ? PlayMode.SINGLE : PlayMode.LOOP, new CommonCallbacks.CompletionCallback() { @Override public void onSuccess() { - Movement.getInstance().setStep_key("change_work_mode"); sendMsg2Server(message); + Movement.getInstance().setStep_key("change_work_mode"); + Synchronizedstatus.setSpeaksetrunning(false); } @Override public void onFailure(@NonNull IDJIError error) { + Synchronizedstatus.setSpeaksetrunning(false); sendFailMsg2Server(message, "喊话器播放模式设置失败:" + getIDJIErrorMsg(error)); } }); @@ -217,60 +270,105 @@ public class SpeakerManager extends BaseManager { sendFailMsg2Server(message, "喊话器音量设置失败:" + getIDJIErrorMsg(error)); } }); + Synchronizedstatus.setSpeaksetrunning(false); } private String text; public void speakerTTSPlayStart(MessageDown message, int type) { + //暂停播放 + stop(); + + LogUtil.log(TAG, "开始执行 speakerTTSPlayStart 方法,type: " + type); + // 检查是否正在运行 + if (Synchronizedstatus.isSpeakTTSrunning()) { + LogUtil.log(TAG, "喊话器TTS播放正在运行,跳过本次请求"); + sendFailMsg2Server(message, "喊话器TTS播放正在运行"); + return; + } + // 设置为正在运行 + Synchronizedstatus.setSpeakTTSrunning(true); + LogUtil.log(TAG, "设置 speakTTSrunning 为 true"); + message.getData().getTts().getMd5(); + // 使用 com.aros.apron.entity.XTTSParams 类型 XTTSParams params = new XTTSParams(); if (type == 0) { text = message.getData().getTts().getText(); + // 设置默认参数值 + params.setVcn("xiaofeng"); + params.setLanguage(1); + params.setSpeed(50); + params.setVolume(100); + LogUtil.log(TAG, "type == 0,text: " + text + ", vcn: " + params.getVcn() + ", language: " + params.getLanguage() + ", speed: " + params.getSpeed() + ", volume: " + params.getVolume()); } else { if (megaphoneStatus == 2) { + LogUtil.log(TAG, "type != 0,megaphoneStatus == 2,执行 stopPlay"); MegaphoneManager.getInstance().stopPlay(new CommonCallbacks.CompletionCallback() { @Override public void onSuccess() { - - LogUtil.log(TAG, "终止喊话"); + LogUtil.log(TAG, "终止喊话成功"); } @Override public void onFailure(@NonNull IDJIError error) { LogUtil.log(TAG, "终止喊话失败:" + getIDJIErrorMsg(error)); - } }); } - params.vcn = message.getData().getType() == 0 ? "xiaofeng" : "xiaoyan"; - params.language = message.getData().getLanguage() == 0 ? 1 : 2; - params.speed = message.getData().getSpeed(); - params.volume = message.getData().getVolume(); + params.setVcn(message.getData().getType() == 0 ? "xiaofeng" : "xiaoyan"); + params.setLanguage(message.getData().getLanguage() == 0 ? 1 : 2); + params.setSpeed(message.getData().getSpeed()); + params.setVolume(message.getData().getVolume()); + LogUtil.log(TAG, "type != 0,vcn: " + params.getVcn() + ", language: " + params.getLanguage() + ", speed: " + params.getSpeed() + ", volume: " + params.getVolume()); } if (TextUtils.isEmpty(text)) { + LogUtil.log(TAG, "喊话内容为空,跳过本次请求"); sendFailMsg2Server(message, "喊话失败:喊话内容为空"); + Synchronizedstatus.setSpeakTTSrunning(false); + LogUtil.log(TAG, "设置 speakTTSrunning 为 false"); return; } - XTtsPcmGenerator tts = new XTtsPcmGenerator(); - AiListener listener = tts.buildListener(); - tts.init(listener); + LogUtil.log(TAG, "创建 XTtsPcmGenerator 实例"); + ttsGenerator = new XTtsPcmGenerator(); + LogUtil.log(TAG, "准备 PCM 文件"); - File pcmFile = new File(Utils.getSDCardPath() + "/pcm", "tts_output_local.pcm"); + // 使用固定的文件夹路径 + String fixedDirPath = "/storage/self/primary/DJIDemo/cache/tts/output/"; + File outputDir = new File(fixedDirPath); + if (!outputDir.exists()) { + LogUtil.log(TAG, "创建输出目录: " + fixedDirPath); + outputDir.mkdirs(); + } + // 使用带时间戳的文件名,避免覆盖 + String fileName = "output_" + System.currentTimeMillis() + ".pcm"; + File pcmFile = new File(outputDir, fileName); + LogUtil.log(TAG, "创建 PCM 文件: " + pcmFile.getAbsolutePath()); - int synthToPcm = tts.synthToPcm( - text, - params, - pcmFile - ); - if (synthToPcm == 0) { + // 合成文本到固定路径 + LogUtil.log(TAG, "开始调用 synthToPcm 方法,text: " + text); + File pcmFileResult = ttsGenerator.synthToPcm(text, params, pcmFile); + if (pcmFileResult != null && pcmFileResult.length() > 0) { + LogUtil.log(TAG, "合成完成,PCM 文件路径: " + pcmFileResult.getAbsolutePath()); sendMsg2Server(message); - String opusFilePath = PCMTools.INSTANCE.convertToOpusFileSync(pcmFile.getAbsolutePath()); + // 检查 PCM 文件大小 + LogUtil.log(TAG, "TTS PCM 文件大小: " + pcmFileResult.length() + " bytes"); + // 转换为 OPUS 格式 + LogUtil.log(TAG, "开始转换为 OPUS 格式"); + String opusFilePath = PCMTools.INSTANCE.convertToOpusFileSync(pcmFileResult.getAbsolutePath()); + // 检查 opus 文件路径和大小 + File opusFile = new File(opusFilePath); + LogUtil.log(TAG, "TTS Opus 文件路径: " + opusFilePath); + LogUtil.log(TAG, "TTS Opus 文件大小: " + (opusFile.exists() ? opusFile.length() : 0) + " bytes"); FileInfo fileInfo = new FileInfo(UploadType.VOICE_FILE, new File(opusFilePath), null); + LogUtil.log(TAG, "开始上传文件到喊话器"); MegaphoneManager.getInstance().startPushingFileToMegaphone(fileInfo, new CommonCallbacks.CompletionCallbackWithProgress() { + private boolean isCallbackExecuted = false; // 确保回调只执行一次 + @Override public void onProgressUpdate(Integer integer) { Movement.getInstance().setTTS_status("in_progress"); @@ -281,21 +379,32 @@ public class SpeakerManager extends BaseManager { @Override public void onSuccess() { + // 确保回调只执行一次 + if (isCallbackExecuted) { + return; + } + isCallbackExecuted = true; + LogUtil.log(TAG, "喊话器内容上传成功"); new Handler().postDelayed(new Runnable() { @Override public void run() { + LogUtil.log(TAG, "开始播放音频"); MegaphoneManager.getInstance().startPlay(new CommonCallbacks.CompletionCallback() { @Override public void onSuccess() { Movement.getInstance().setTTS_status("ok"); Movement.getInstance().setStep_key("play"); sendEvent2Server("喊话器播放TTS音频成功", 1); + LogUtil.log(TAG,"喊话器播放TTS音频成功"); + Synchronizedstatus.setSpeakTTSrunning(false); } @Override public void onFailure(@NonNull IDJIError error) { sendEvent2Server("喊话器播放TTS音频失败:" + getIDJIErrorMsg(error), 2); + LogUtil.log(TAG,"喊话器播放TTS音频失败qwq" + getIDJIErrorMsg(error)); + Synchronizedstatus.setSpeakTTSrunning(false); } }); } @@ -304,11 +413,22 @@ public class SpeakerManager extends BaseManager { @Override public void onFailure(@NonNull IDJIError error) { + // 确保回调只执行一次 + if (isCallbackExecuted) { + return; + } + isCallbackExecuted = true; + sendFailMsg2Server(message, "喊话器内容上传失败:" + getIDJIErrorMsg(error)); + LogUtil.log(TAG, "喊话器内容上传失败:" + getIDJIErrorMsg(error)); } }); } else { - sendFailMsg2Server(message, "tts合成失败"); + LogUtil.log(TAG, "合成失败,PCM 文件为空"); + sendFailMsg2Server(message, "合成失败,PCM 文件为空"); } + + LogUtil.log(TAG, "设置 speakTTSrunning 为 false"); + LogUtil.log(TAG, "speakerTTSPlayStart 方法执行完成"); } } \ No newline at end of file diff --git a/app/src/main/java/com/aros/apron/manager/TakeOffToPointManager.java b/app/src/main/java/com/aros/apron/manager/TakeOffToPointManager.java index ccc7f256..3c4439c4 100644 --- a/app/src/main/java/com/aros/apron/manager/TakeOffToPointManager.java +++ b/app/src/main/java/com/aros/apron/manager/TakeOffToPointManager.java @@ -79,10 +79,13 @@ public class TakeOffToPointManager extends BaseManager { Movement.getInstance().setIstakeoffex(true); PreferenceUtils.getInstance().setFlightId(message.getData().getFlight_id()); + PreferenceUtils.getInstance().setAlternatePointLon(message.getData().getAlternate_land_point().getLongitude() + ""); PreferenceUtils.getInstance().setAlternatePointLat(message.getData().getAlternate_land_point().getLatitude() + ""); + PreferenceUtils.getInstance().setAlternatePointSecurityHeight( message.getData().getAlternate_land_point().getSafe_land_height() + ""); + Movement.getInstance().setTask_current_step(5); LogUtil.log(TAG, "生成"); diff --git a/app/src/main/java/com/aros/apron/manager/VlcRtspManager.java b/app/src/main/java/com/aros/apron/manager/VlcRtspManager.java index 1e8586d2..be758bfe 100644 --- a/app/src/main/java/com/aros/apron/manager/VlcRtspManager.java +++ b/app/src/main/java/com/aros/apron/manager/VlcRtspManager.java @@ -1,133 +1,133 @@ -package com.aros.apron.manager; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; - -import com.aros.apron.tools.LogUtil; - -import org.videolan.libvlc.LibVLC; -import org.videolan.libvlc.Media; -import org.videolan.libvlc.MediaPlayer; - -import java.util.ArrayList; -import java.util.List; - -/** - * RTSP流检测工具(严格匹配LibVLC 3.6.0源码) - * 核心:单例、初始化、拉流检测、成功/失败回调(无任何冗余) - */ -public class VlcRtspManager { - private static volatile VlcRtspManager instance; - private static final long CHECK_TIMEOUT = 5000L; // 5秒超时 - - private LibVLC libVLC; - private MediaPlayer mediaPlayer; - private Handler handler = new Handler(Looper.getMainLooper()); - private OnRtspCheckListener checkListener; - private boolean isChecking = false; - - // 仅保留成功/失败回调 - public interface OnRtspCheckListener { - void onSuccess(); // 拉流成功 - void onFailed(); // 拉流失败 - } - - // 单例 - private VlcRtspManager() {} - public static VlcRtspManager getInstance() { - if (instance == null) { - synchronized (VlcRtspManager.class) { - if (instance == null) { - instance = new VlcRtspManager(); - } - } - } - return instance; - } - - // 初始化(3.6.0 源码级配置) - public void init(Context context) { - if (libVLC != null) return; - - List options = new ArrayList<>(); - options.add("--rtsp-tcp"); - options.add("--network-caching=500"); - options.add("--vout=none"); - options.add("--aout=none"); - options.add("--quiet"); - - libVLC = new LibVLC(context.getApplicationContext(), options); - mediaPlayer = new MediaPlayer(libVLC); - - // ====================== 核心修正:3.6.0 事件判定(源码级) ====================== - // 参考3.6.0源码:MediaPlayer.Event的type是int型,对应EventType枚举的ordinal() - mediaPlayer.setEventListener(new MediaPlayer.EventListener() { - @Override - public void onEvent(MediaPlayer.Event event) { - // 3.6.0源码中: - // EventType.Playing.ordinal() = 0 - // EventType.Error.ordinal() = 1 - // 直接用整型判定,避开枚举引用错误 - if (event.type == 0) { // Playing事件 - if (checkListener != null) checkListener.onSuccess(); - stopCheck(); - } else if (event.type == 1) { // Error事件 - if (checkListener != null) checkListener.onFailed(); - stopCheck(); - } - } - }); - } - - // 检测RTSP流(拉流测试) - public void checkRtspStream(String rtspUrl, OnRtspCheckListener listener) { - stopCheck(); - - this.checkListener = listener; - this.isChecking = true; - - // 超时检测 - handler.postDelayed(() -> { - if (isChecking) { - if (checkListener != null) checkListener.onFailed(); - stopCheck(); - } - }, CHECK_TIMEOUT); - - // 拉流(3.6.0 源码级写法) - try { - Media media = new Media(libVLC, rtspUrl); - mediaPlayer.setMedia(media); - media.release(); - mediaPlayer.play(); - } catch (Exception e) { - LogUtil.log("VlcRtspManager", "拉流异常:" + e.getMessage()); - if (checkListener != null) checkListener.onFailed(); - stopCheck(); - } - } - - // 停止检测(私有) - private void stopCheck() { - isChecking = false; - handler.removeCallbacksAndMessages(null); - if (mediaPlayer != null && mediaPlayer.isPlaying()) { - mediaPlayer.stop(); - } - } - - // 释放资源(可选) - public void release() { - stopCheck(); - if (mediaPlayer != null) { - mediaPlayer.release(); - mediaPlayer = null; - } - if (libVLC != null) { - libVLC.release(); - libVLC = null; - } - instance = null; - } -} \ No newline at end of file +//package com.aros.apron.manager; +// +//import android.content.Context; +//import android.os.Handler; +//import android.os.Looper; +// +//import com.aros.apron.tools.LogUtil; +// +//import org.videolan.libvlc.LibVLC; +//import org.videolan.libvlc.Media; +//import org.videolan.libvlc.MediaPlayer; +// +//import java.util.ArrayList; +//import java.util.List; +// +///** +// * RTSP流检测工具(严格匹配LibVLC 3.6.0源码) +// * 核心:单例、初始化、拉流检测、成功/失败回调(无任何冗余) +// */ +//public class VlcRtspManager { +// private static volatile VlcRtspManager instance; +// private static final long CHECK_TIMEOUT = 5000L; // 5秒超时 +// +// private LibVLC libVLC; +// private MediaPlayer mediaPlayer; +// private Handler handler = new Handler(Looper.getMainLooper()); +// private OnRtspCheckListener checkListener; +// private boolean isChecking = false; +// +// // 仅保留成功/失败回调 +// public interface OnRtspCheckListener { +// void onSuccess(); // 拉流成功 +// void onFailed(); // 拉流失败 +// } +// +// // 单例 +// private VlcRtspManager() {} +// public static VlcRtspManager getInstance() { +// if (instance == null) { +// synchronized (VlcRtspManager.class) { +// if (instance == null) { +// instance = new VlcRtspManager(); +// } +// } +// } +// return instance; +// } +// +// // 初始化(3.6.0 源码级配置) +// public void init(Context context) { +// if (libVLC != null) return; +// +// List options = new ArrayList<>(); +// options.add("--rtsp-tcp"); +// options.add("--network-caching=500"); +// options.add("--vout=none"); +// options.add("--aout=none"); +// options.add("--quiet"); +// +// libVLC = new LibVLC(context.getApplicationContext(), options); +// mediaPlayer = new MediaPlayer(libVLC); +// +// // ====================== 核心修正:3.6.0 事件判定(源码级) ====================== +// // 参考3.6.0源码:MediaPlayer.Event的type是int型,对应EventType枚举的ordinal() +// mediaPlayer.setEventListener(new MediaPlayer.EventListener() { +// @Override +// public void onEvent(MediaPlayer.Event event) { +// // 3.6.0源码中: +// // EventType.Playing.ordinal() = 0 +// // EventType.Error.ordinal() = 1 +// // 直接用整型判定,避开枚举引用错误 +// if (event.type == 0) { // Playing事件 +// if (checkListener != null) checkListener.onSuccess(); +// stopCheck(); +// } else if (event.type == 1) { // Error事件 +// if (checkListener != null) checkListener.onFailed(); +// stopCheck(); +// } +// } +// }); +// } +// +// // 检测RTSP流(拉流测试) +// public void checkRtspStream(String rtspUrl, OnRtspCheckListener listener) { +// stopCheck(); +// +// this.checkListener = listener; +// this.isChecking = true; +// +// // 超时检测 +// handler.postDelayed(() -> { +// if (isChecking) { +// if (checkListener != null) checkListener.onFailed(); +// stopCheck(); +// } +// }, CHECK_TIMEOUT); +// +// // 拉流(3.6.0 源码级写法) +// try { +// Media media = new Media(libVLC, rtspUrl); +// mediaPlayer.setMedia(media); +// media.release(); +// mediaPlayer.play(); +// } catch (Exception e) { +// LogUtil.log("VlcRtspManager", "拉流异常:" + e.getMessage()); +// if (checkListener != null) checkListener.onFailed(); +// stopCheck(); +// } +// } +// +// // 停止检测(私有) +// private void stopCheck() { +// isChecking = false; +// handler.removeCallbacksAndMessages(null); +// if (mediaPlayer != null && mediaPlayer.isPlaying()) { +// mediaPlayer.stop(); +// } +// } +// +// // 释放资源(可选) +// public void release() { +// stopCheck(); +// if (mediaPlayer != null) { +// mediaPlayer.release(); +// mediaPlayer = null; +// } +// if (libVLC != null) { +// libVLC.release(); +// libVLC = null; +// } +// instance = null; +// } +//} \ No newline at end of file diff --git a/app/src/main/java/com/aros/apron/tools/MixedVisionLanding.java b/app/src/main/java/com/aros/apron/tools/MixedVisionLanding.java index 4f53b273..dae98788 100644 --- a/app/src/main/java/com/aros/apron/tools/MixedVisionLanding.java +++ b/app/src/main/java/com/aros/apron/tools/MixedVisionLanding.java @@ -61,6 +61,7 @@ public class MixedVisionLanding { private static final int MAX_SWITCH_COUNT = 2; private boolean isLanding = false; private boolean isDoublePayload = false; + private int startArucoType = 0; // 1执行机库二维码识别 2执行备降点二维码识别 // ========== 云台相机参数 ========== private static double GIMBAL_LENS_OFFSET_X = 0; @@ -105,6 +106,7 @@ public class MixedVisionLanding { private boolean downwardDropTimesTag = false; private long downwardStartTime = 0; private long downwardEndTime = 0; + private boolean downwardIsYawAligned = false; // ========== 执行器 ========== private ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); @@ -134,19 +136,24 @@ public class MixedVisionLanding { } public void startLanding() { - LogUtil.log(TAG_LOG, "开始融合视觉降落"); - isLanding = true; - currentMode = LandingMode.GIMBAL_CAMERA; - switchCount = 0; - resetGimbalState(); - resetDownwardState(); + synchronized (this) { + LogUtil.log(TAG_LOG, "开始融合视觉降落"); + isLanding = true; + currentMode = LandingMode.GIMBAL_CAMERA; + switchCount = 0; + resetGimbalState(); + resetDownwardState(); + } } public void stopLanding() { - LogUtil.log(TAG_LOG, "停止融合视觉降落"); - isLanding = false; - resetGimbalState(); - resetDownwardState(); + synchronized (this) { + LogUtil.log(TAG_LOG, "停止融合视觉降落"); + isLanding = false; + startArucoType = 0; + resetGimbalState(); + resetDownwardState(); + } } public LandingMode getCurrentMode() { @@ -161,84 +168,100 @@ public class MixedVisionLanding { return isLanding; } + public int getStartArucoType() { + return startArucoType; + } + + public void setStartArucoType(int type) { + startArucoType = type; + } + // ========== 云台相机帧处理 ========== public void processGimbalFrame(int height, int width, byte[] data, Dictionary dictionary) { - if (!isLanding || currentMode != LandingMode.GIMBAL_CAMERA) { - return; - } - - gimbalIsTriggerSuccess = true; - Movement.getInstance().setVirtualStickEnableReason(2); - - if (gimbalIsStartAruco || gimbalStartFastStick) { - return; - } - - int currentFrame = gimbalFrameCounter++; - if (currentFrame % 3 != 0) { - return; - } - - if (currentFrame % 30 != 0) { - DroneHelper.getInstance().setGimbalPitchdown(); - } - - gimbalIsStartAruco = true; - if (lastGimbalFuture != null && !lastGimbalFuture.isDone()) { - lastGimbalFuture.cancel(true); - } - - int ultHeight = Movement.getInstance().getUltrasonicHeight(); - updateGimbalLensOffset(ultHeight); - - final int finalUltHeight = ultHeight; - lastGimbalFuture = executor.schedule(() -> { - try { - processGimbalFrameInternal(height, width, data, dictionary, finalUltHeight); - } catch (Exception e) { - LogUtil.log(TAG_LOG, "云台相机处理异常: " + e); - gimbalIsStartAruco = false; - handleLandingFailure(); + synchronized (this) { + if (!isLanding || currentMode != LandingMode.GIMBAL_CAMERA || startArucoType == 0) { + return; } - }, 0, TimeUnit.MILLISECONDS); + + gimbalIsTriggerSuccess = true; + Movement.getInstance().setVirtualStickEnableReason(2); + + if (gimbalIsStartAruco || gimbalStartFastStick) { + return; + } + + int currentFrame = gimbalFrameCounter++; + if (currentFrame % 3 != 0) { + return; + } + + if (currentFrame % 30 != 0) { + DroneHelper.getInstance().setGimbalPitchdown(); + } + + gimbalIsStartAruco = true; + if (lastGimbalFuture != null && !lastGimbalFuture.isDone()) { + lastGimbalFuture.cancel(true); + } + + int ultHeight = Movement.getInstance().getUltrasonicHeight(); + updateGimbalLensOffset(ultHeight); + + final int finalUltHeight = ultHeight; + lastGimbalFuture = executor.schedule(() -> { + try { + processGimbalFrameInternal(height, width, data, dictionary, finalUltHeight); + } catch (Exception e) { + LogUtil.log(TAG_LOG, "云台相机处理异常: " + e); + synchronized (MixedVisionLanding.this) { + gimbalIsStartAruco = false; + } + handleLandingFailure(); + } + }, 0, TimeUnit.MILLISECONDS); + } } // ========== 下视相机帧处理 ========== public void processDownwardFrame(int height, int width, byte[] data, Dictionary dictionary) { - if (!isLanding || currentMode != LandingMode.DOWNWARD_CAMERA) { - return; - } - - downwardIsTriggerSuccess = true; - Movement.getInstance().setVirtualStickEnableReason(2); - - if (downwardIsStartAruco || downwardStartFastStick) { - return; - } - - int currentFrame = downwardFrameCounter++; - if (currentFrame % 2 != 0) { - return; - } - - downwardIsStartAruco = true; - if (lastDownwardFuture != null && !lastDownwardFuture.isDone()) { - lastDownwardFuture.cancel(true); - } - - int ultHeight = Movement.getInstance().getUltrasonicHeight(); - updateDownwardLensOffset(ultHeight); - - final int finalUltHeight = ultHeight; - lastDownwardFuture = executor.schedule(() -> { - try { - processDownwardFrameInternal(height, width, data, dictionary, finalUltHeight); - } catch (Exception e) { - LogUtil.log(TAG_LOG, "下视相机处理异常: " + e); - downwardIsStartAruco = false; - handleLandingFailure(); + synchronized (this) { + if (!isLanding || currentMode != LandingMode.DOWNWARD_CAMERA || startArucoType == 0) { + return; } - }, 0, TimeUnit.MILLISECONDS); + + downwardIsTriggerSuccess = true; + Movement.getInstance().setVirtualStickEnableReason(2); + + if (downwardIsStartAruco || downwardStartFastStick) { + return; + } + + int currentFrame = downwardFrameCounter++; + if (currentFrame % 2 != 0) { + return; + } + + downwardIsStartAruco = true; + if (lastDownwardFuture != null && !lastDownwardFuture.isDone()) { + lastDownwardFuture.cancel(true); + } + + int ultHeight = Movement.getInstance().getUltrasonicHeight(); + updateDownwardLensOffset(ultHeight); + + final int finalUltHeight = ultHeight; + lastDownwardFuture = executor.schedule(() -> { + try { + processDownwardFrameInternal(height, width, data, dictionary, finalUltHeight); + } catch (Exception e) { + LogUtil.log(TAG_LOG, "下视相机处理异常: " + e); + synchronized (MixedVisionLanding.this) { + downwardIsStartAruco = false; + } + handleLandingFailure(); + } + }, 0, TimeUnit.MILLISECONDS); + } } // ========== 云台相机内部处理 ========== @@ -397,8 +420,24 @@ public class MixedVisionLanding { } } - // 正常修正 - moveOnArucoDetected(new ArucoMarker(1, corner6, 0.24f), rgbMat.width(), rgbMat.height()); + // 旋转处理 + if (ultHeight > 30 && !downwardIsYawAligned) { + double yawError = calculateYawErrorFromCorners(points); + double absYaw = Math.abs(yawError); + + if (absYaw < 10.0) { + downwardIsYawAligned = true; + LogUtil.log(TAG_LOG, "【下视旋转到位】偏航已对准"); + DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, 0f, 0f); + } else { + float yawRate = calculateYawRate(yawError, ultHeight); + LogUtil.log(TAG_LOG, String.format("【下视执行】纯旋转 yawRate=%.1f avgYaw=%.1f", yawRate, yawError)); + DroneHelper.getInstance().moveVxVyYawrateHeight(0f, 0f, yawRate, 0f); + } + } else { + // 正常修正 + moveOnArucoDetected(new ArucoMarker(1, corner6, 0.24f), rgbMat.width(), rgbMat.height()); + } } } else { handleDownwardLostMarker(ultHeight); @@ -817,30 +856,32 @@ public class MixedVisionLanding { // ========== 降落失败处理(切换相机) ========== private void handleLandingFailure() { - if (!isLanding) { - return; - } + synchronized (this) { + if (!isLanding) { + return; + } - switchCount++; - LogUtil.log(TAG_LOG, "切换相机,当前切换次数: " + switchCount); + switchCount++; + LogUtil.log(TAG_LOG, "切换相机,当前切换次数: " + switchCount); - // 切换到另一个相机 - if (currentMode == LandingMode.GIMBAL_CAMERA) { - currentMode = LandingMode.DOWNWARD_CAMERA; - LogUtil.log(TAG_LOG, "切换到下视相机"); - resetDownwardState(); - } else { - currentMode = LandingMode.GIMBAL_CAMERA; - LogUtil.log(TAG_LOG, "切换到云台相机"); - resetGimbalState(); - } + // 切换到另一个相机 + if (currentMode == LandingMode.GIMBAL_CAMERA) { + currentMode = LandingMode.DOWNWARD_CAMERA; + LogUtil.log(TAG_LOG, "切换到下视相机"); + resetDownwardState(); + } else { + currentMode = LandingMode.GIMBAL_CAMERA; + LogUtil.log(TAG_LOG, "切换到云台相机"); + resetGimbalState(); + } - // 如果达到最大切换次数,触发备降 - if (switchCount >= MAX_SWITCH_COUNT) { - LogUtil.log(TAG_LOG, "达到最大切换次数,触发备降"); - stopLanding(); - AlternateLandingManager.getInstance().startTaskProcess(null); - Movement.getInstance().setAlternate(true); + // 如果达到最大切换次数,触发备降 + if (switchCount >= MAX_SWITCH_COUNT) { + LogUtil.log(TAG_LOG, "达到最大切换次数,触发备降"); + stopLanding(); + AlternateLandingManager.getInstance().startTaskProcess(null); + Movement.getInstance().setAlternate(true); + } } } @@ -876,6 +917,7 @@ public class MixedVisionLanding { downwardDropTimesTag = false; downwardStartTime = 0; downwardEndTime = 0; + downwardIsYawAligned = false; } // ========== 更新云台相机镜头偏移 ========== diff --git a/app/src/main/java/com/aros/apron/tools/XTtsPcmGenerator.java b/app/src/main/java/com/aros/apron/tools/XTtsPcmGenerator.java index d675cf6f..0bc21af2 100644 --- a/app/src/main/java/com/aros/apron/tools/XTtsPcmGenerator.java +++ b/app/src/main/java/com/aros/apron/tools/XTtsPcmGenerator.java @@ -14,6 +14,10 @@ import java.io.File; import java.io.FileOutputStream; import java.util.List; +/** + * TTS 文本转 PCM 工具类 + * 使用同步方式实现,避免依赖回调机制 + */ public class XTtsPcmGenerator { private static final String TAG = "XTTS"; @@ -21,31 +25,40 @@ public class XTtsPcmGenerator { private AiHandle aiHandle; private FileOutputStream pcmOut; - - - public void init(AiListener listener) { - AiHelper.getInst().registerListener(ABILITY_ID, listener); - } + private boolean isSynthesisComplete = false; /** - * 合成文本为 PCM 文件 + * 合成文本为 PCM 文件(同步方法) */ - public int synthToPcm( - String text, - XTTSParams params, - File pcmFile - ) { + public File synthToPcm(String text, XTTSParams params, File pcmFile) { + LogUtil.log(TAG, "开始执行 synthToPcm 方法,text: " + text); + + // 参数验证 + if (text == null || text.length() == 0 || params == null || pcmFile == null) { + LogUtil.log(TAG, "参数无效"); + return null; + } + + // 重置合成完成标志 + isSynthesisComplete = false; + + // 准备文件输出流 File parent = pcmFile.getParentFile(); if (parent != null && !parent.exists()) { parent.mkdirs(); - } - try { - pcmOut = new FileOutputStream(pcmFile, false); - } catch (Exception e) { - e.printStackTrace(); - return -1; + LogUtil.log(TAG, "创建输出目录: " + parent.getAbsolutePath()); } + try { + pcmOut = new FileOutputStream(pcmFile, false); + LogUtil.log(TAG, "文件输出流创建成功: " + pcmFile.getAbsolutePath()); + } catch (Exception e) { + LogUtil.log(TAG, "创建文件输出流失败: " + e.getMessage()); + e.printStackTrace(); + return null; + } + + // 构建参数 AiInput.Builder paramBuilder = AiInput.builder(); paramBuilder.param("vcn", params.vcn); paramBuilder.param("language", params.language); @@ -54,44 +67,79 @@ public class XTtsPcmGenerator { paramBuilder.param("speed", params.speed); paramBuilder.param("volume", params.volume); - aiHandle = AiHelper.getInst().start( - ABILITY_ID, - paramBuilder.build(), - null - ); + // 构建监听器 + AiListener listener = buildListener(); + LogUtil.log(TAG, "监听器创建成功"); - if (aiHandle.getCode() != 0) { - LogUtil.log(TAG, "start failed: " + aiHandle.getCode()); - return aiHandle.getCode(); + // 注册监听器 + try { + AiHelper.getInst().registerListener(ABILITY_ID, listener); + LogUtil.log(TAG, "监听器注册成功"); + } catch (Exception e) { + LogUtil.log(TAG, "监听器注册失败: " + e.getMessage()); + e.printStackTrace(); + close(); + return null; } - AiText aiText = AiText.get("text") - .data(text) - .valid(); + // 启动 TTS 引擎 + aiHandle = AiHelper.getInst().start(ABILITY_ID, paramBuilder.build(), null); + if (aiHandle.getCode() != 0) { + LogUtil.log(TAG, "启动 TTS 引擎失败: " + aiHandle.getCode()); + close(); + return null; + } + LogUtil.log(TAG, "TTS 引擎启动成功"); - AiRequest request = AiRequest.builder() - .payload(aiText) - .build(); + // 构建请求 + AiText aiText = AiText.get("text").data(text).valid(); + AiRequest request = AiRequest.builder().payload(aiText).build(); + // 发送请求 int ret = AiHelper.getInst().write(request, aiHandle); if (ret != 0) { - LogUtil.log(TAG, "write failed: " + ret); - return ret; + LogUtil.log(TAG, "发送 TTS 请求失败: " + ret); + close(); + return null; + } + LogUtil.log(TAG, "TTS 请求发送成功,开始合成"); + + // 等待合成完成(最多等待 30 秒) + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < 30000) { + if (isSynthesisComplete) { + LogUtil.log(TAG, "合成完成标志已设置"); + break; + } + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } } - return 0; + // 关闭资源 + close(); + + // 检查 PCM 文件大小 + if (pcmFile.exists() && pcmFile.length() > 0) { + LogUtil.log(TAG, "合成成功,PCM 文件大小: " + pcmFile.length() + " bytes"); + return pcmFile; + } else { + LogUtil.log(TAG, "合成失败,PCM 文件为空"); + return null; + } } /** - * 内部使用的监听器 + * 构建监听器 */ - public AiListener buildListener() { + private AiListener buildListener() { return new AiListener() { - @Override public void onResult(int handleID, List list, Object usrContext) { - if (list == null){ - LogUtil.log(TAG,"list == null"); + if (list == null) { + LogUtil.log(TAG, "onResult: list == null"); return; } @@ -99,6 +147,7 @@ public class XTtsPcmGenerator { if ("audio".equals(resp.getKey())) { byte[] pcm = resp.getValue(); if (pcm != null && pcm.length > 0) { + LogUtil.log(TAG, "接收到 PCM 数据,长度: " + pcm.length + " bytes"); writePcm(pcm); } } @@ -107,48 +156,59 @@ public class XTtsPcmGenerator { @Override public void onEvent(int handleID, int event, List eventData, Object usrContext) { + LogUtil.log(TAG, "收到事件: " + event); if (event == AeeEvent.AEE_EVENT_END.getValue()) { - close(); + LogUtil.log(TAG, "合成完成事件"); + isSynthesisComplete = true; } } @Override public void onError(int handleID, int err, String msg, Object usrContext) { - LogUtil.log(TAG, "XTTS error: " + err + ", " + msg); - close(); + LogUtil.log(TAG, "合成错误: " + err + ", " + msg); + isSynthesisComplete = true; } }; } + /** + * 写入 PCM 数据 + */ private synchronized void writePcm(byte[] data) { - try { - if (pcmOut != null) { + if (pcmOut != null) { + try { pcmOut.write(data); + } catch (Exception e) { + LogUtil.log(TAG, "写入 PCM 数据失败: " + e.getMessage()); + e.printStackTrace(); } - } catch (Exception e) { - e.printStackTrace(); } } + /** + * 关闭资源 + */ private void close() { + LogUtil.log(TAG, "关闭资源"); try { if (pcmOut != null) { pcmOut.flush(); pcmOut.close(); pcmOut = null; + LogUtil.log(TAG, "文件输出流已关闭"); } - } catch (Exception ignored) {} + } catch (Exception e) { + LogUtil.log(TAG, "关闭文件输出流失败: " + e.getMessage()); + } - if (aiHandle != null) { - AiHelper.getInst().end(aiHandle); - aiHandle = null; + try { + if (aiHandle != null) { + AiHelper.getInst().end(aiHandle); + aiHandle = null; + LogUtil.log(TAG, "AI 引擎已关闭"); + } + } catch (Exception e) { + LogUtil.log(TAG, "关闭 AI 引擎失败: " + e.getMessage()); } } - - /** - * 释放引擎(App 退出时调用) - */ -// public void release() { -// AiHelper.getInst().engineUnInit(ABILITY_ID); -// } } \ No newline at end of file diff --git a/app/src/main/java/com/aros/apron/tts/CopyAsset.java b/app/src/main/java/com/aros/apron/tts/CopyAsset.java new file mode 100644 index 00000000..2e6b9ee1 --- /dev/null +++ b/app/src/main/java/com/aros/apron/tts/CopyAsset.java @@ -0,0 +1,66 @@ +package com.aros.apron.tts; + +import android.content.Context; +import android.content.res.AssetManager; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class CopyAsset { + + private static volatile CopyAsset instance; + private Context context; + + // 私有构造方法 + private CopyAsset(Context context) { + // 使用Application Context避免内存泄漏 + this.context = context.getApplicationContext(); + } + + // 获取单例实例 + public static CopyAsset getInstance(Context context) { + if (instance == null) { + synchronized (CopyAsset.class) { + if (instance == null) { + instance = new CopyAsset(context); + } + } + } + return instance; + } + + public void copyAssetsToSdcard() { + // 修改目标路径 + String sdcardPath = "/storage/self/primary/DJIDemo/cache/tts/"; + File sdcardDir = new File(sdcardPath); + if (!sdcardDir.exists()) { + // 创建目录,包括所有父目录 + sdcardDir.mkdirs(); + } + + try { + AssetManager assetManager = context.getAssets(); + String[] files = assetManager.list("aikit_resources"); + if (files != null) { // 防止assets目录不存在导致的空指针 + for (String file : files) { + File destFile = new File(sdcardPath + file); + if (!destFile.exists()) { // 仅在文件不存在时复制 + InputStream in = assetManager.open("aikit_resources/" + file); + FileOutputStream out = new FileOutputStream(destFile); + byte[] buffer = new byte[1024]; + int read; + while ((read = in.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + in.close(); + out.close(); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_config.xml b/app/src/main/res/layout-land/activity_config.xml index ee11cb9a..e0bbf3ab 100644 --- a/app/src/main/res/layout-land/activity_config.xml +++ b/app/src/main/res/layout-land/activity_config.xml @@ -738,26 +738,33 @@ android:id="@+id/rb_camera_right" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="右侧" /> + android:text="右" /> + android:layout_marginLeft="0dp" + android:text="中" /> + + android:layout_marginLeft="0dp" + android:text="下" /> + android:layout_marginLeft="0dp" + android:text="融右" /> + diff --git a/app/src/main/res/layout/activity_config.xml b/app/src/main/res/layout/activity_config.xml index d4789cb8..fd2234f8 100644 --- a/app/src/main/res/layout/activity_config.xml +++ b/app/src/main/res/layout/activity_config.xml @@ -738,27 +738,33 @@ android:id="@+id/rb_camera_right" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="右侧" /> + android:text="右" /> + android:layout_marginLeft="0dp" + android:text="中" /> + android:layout_marginLeft="0dp" + android:text="下" /> + android:layout_marginLeft="0dp" + android:text="融右" /> + diff --git a/build.gradle b/build.gradle index 4ca22703..45d09d77 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,7 @@ allprojects { repositories { google() jcenter() + //flatDir { dirs 'libs' } jcenter(){ url 'https://jcenter.bintray.com/'} maven { url 'https://jitpack.io' } maven {