diff --git a/app/build.gradle b/app/build.gradle index 893960a5..f1e41991 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ plugins { // 10,00,000 major-minor-build def AppMajorVersion = 1 def AppMinorVersion = 3 -def AppBuildNumber = 39 +def AppBuildNumber = 62 def AppVersionName = AppMajorVersion + "." + AppMinorVersion + "." + AppBuildNumber def AppVersionCode = AppMajorVersion * 100000 + AppMinorVersion * 1000 + AppBuildNumber diff --git a/app/libs/arm64-v8a/libavcodec.so b/app/libs/arm64-v8a/libavcodec.so new file mode 100644 index 00000000..42246066 Binary files /dev/null and b/app/libs/arm64-v8a/libavcodec.so differ diff --git a/app/libs/arm64-v8a/libavdevice.so b/app/libs/arm64-v8a/libavdevice.so new file mode 100644 index 00000000..b9e8a65b Binary files /dev/null and b/app/libs/arm64-v8a/libavdevice.so differ diff --git a/app/libs/arm64-v8a/libavfilter.so b/app/libs/arm64-v8a/libavfilter.so new file mode 100644 index 00000000..bd1c4e5c Binary files /dev/null and b/app/libs/arm64-v8a/libavfilter.so differ diff --git a/app/libs/arm64-v8a/libavformat.so b/app/libs/arm64-v8a/libavformat.so new file mode 100644 index 00000000..07f6c139 Binary files /dev/null and b/app/libs/arm64-v8a/libavformat.so differ diff --git a/app/libs/arm64-v8a/libavutil.so b/app/libs/arm64-v8a/libavutil.so new file mode 100644 index 00000000..485ea360 Binary files /dev/null and b/app/libs/arm64-v8a/libavutil.so differ diff --git a/app/libs/arm64-v8a/libswresample.so b/app/libs/arm64-v8a/libswresample.so new file mode 100644 index 00000000..de0f2b25 Binary files /dev/null and b/app/libs/arm64-v8a/libswresample.so differ diff --git a/app/libs/arm64-v8a/libswscale.so b/app/libs/arm64-v8a/libswscale.so new file mode 100644 index 00000000..1301fac8 Binary files /dev/null and b/app/libs/arm64-v8a/libswscale.so differ diff --git a/app/libs/arm64-v8a/libx264.so b/app/libs/arm64-v8a/libx264.so new file mode 100644 index 00000000..15f9d75b Binary files /dev/null and b/app/libs/arm64-v8a/libx264.so differ diff --git a/app/libs/armeabi-v7a/libavcodec.so b/app/libs/armeabi-v7a/libavcodec.so new file mode 100644 index 00000000..e0e7a188 Binary files /dev/null and b/app/libs/armeabi-v7a/libavcodec.so differ diff --git a/app/libs/armeabi-v7a/libavdevice.so b/app/libs/armeabi-v7a/libavdevice.so new file mode 100644 index 00000000..304f7564 Binary files /dev/null and b/app/libs/armeabi-v7a/libavdevice.so differ diff --git a/app/libs/armeabi-v7a/libavfilter.so b/app/libs/armeabi-v7a/libavfilter.so new file mode 100644 index 00000000..d0d5dc13 Binary files /dev/null and b/app/libs/armeabi-v7a/libavfilter.so differ diff --git a/app/libs/armeabi-v7a/libavformat.so b/app/libs/armeabi-v7a/libavformat.so new file mode 100644 index 00000000..5e4c9f22 Binary files /dev/null and b/app/libs/armeabi-v7a/libavformat.so differ diff --git a/app/libs/armeabi-v7a/libavutil.so b/app/libs/armeabi-v7a/libavutil.so new file mode 100644 index 00000000..e15b72cb Binary files /dev/null and b/app/libs/armeabi-v7a/libavutil.so differ diff --git a/app/libs/armeabi-v7a/libswresample.so b/app/libs/armeabi-v7a/libswresample.so new file mode 100644 index 00000000..50f860cd Binary files /dev/null and b/app/libs/armeabi-v7a/libswresample.so differ diff --git a/app/libs/armeabi-v7a/libswscale.so b/app/libs/armeabi-v7a/libswscale.so new file mode 100644 index 00000000..0663239a Binary files /dev/null and b/app/libs/armeabi-v7a/libswscale.so differ diff --git a/app/libs/armeabi-v7a/libx264.so b/app/libs/armeabi-v7a/libx264.so new file mode 100644 index 00000000..139305c5 Binary files /dev/null and b/app/libs/armeabi-v7a/libx264.so differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cdab483d..58d9f162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -86,6 +86,7 @@ + #include "GPIOControl.h" -#include #ifdef _DEBUG #include @@ -62,7 +61,7 @@ size_t GpioControl::turnOnImpl(const IOT_PARAM& param) SetCamerastatus(param.cmd, true); } - if (oldRef == 0) + if (oldRef == 0 || param.cmd != CMD_SET_3V3_PWR_EN) { fd = open(GPIO_NODE_MP, O_RDONLY); if( fd > 0 ) @@ -210,6 +209,10 @@ size_t GpioControl::TurnOn(const std::vector& cmds) m_locker.lock(); for (it = cmds.cbegin(); it != cmds.cend(); ++it) { + if (*it == 0) + { + continue; + } param.cmd = *it; turnOnImpl(param); } diff --git a/app/src/main/cpp/GPIOControl.h b/app/src/main/cpp/GPIOControl.h index c46a174d..52261117 100644 --- a/app/src/main/cpp/GPIOControl.h +++ b/app/src/main/cpp/GPIOControl.h @@ -13,6 +13,7 @@ #include #include +#include #ifndef USING_N938 @@ -50,21 +51,25 @@ #define CMD_SET_3V3_PWR_EN 132 #endif +#define CMD_GET_CAMERA_STATUS 310 +#define CMD_SET_INIT_STATUS 401 + #else // defined(USING_PLZ) #define CMD_SET_OTG_STATE 107 #define CMD_GET_OTG_STATE 108 #define CMD_SET_SPI_POWER 129 +#define CMD_SET_MADA_MOVE_STATUS 311 #define CMD_SET_12V_EN_STATE 0 // TO BE ADDED #define CMD_SET_SYSTEM_RESET 202 #define CMD_GET_LIGHT_ADC 101 #define CMD_SET_LIGHT_ADC 102 -// #define CMD_GET_CHARGING_BUS_VOLTAGE_STATE 112 -// #define CMD_GET_BAT_BUS_VOLTAGE_STATE 117 -#define CMD_GET_CHARGING_BUS_VOLTAGE_STATE 117 -#define CMD_GET_BAT_BUS_VOLTAGE_STATE 112 + #define CMD_GET_CHARGING_BUS_VOLTAGE_STATE 112 + #define CMD_GET_BAT_BUS_VOLTAGE_STATE 117 +//#define CMD_GET_CHARGING_BUS_VOLTAGE_STATE 117 +//#define CMD_GET_BAT_BUS_VOLTAGE_STATE 112 #define CMD_SET_SPI_MODE 0 // TO BE ADDED #define CMD_SET_SPI_BITS_PER_WORD 0 // TO BE ADDED #define CMD_SET_SPI_MAXSPEEDHZ 0 // TO BE ADDED @@ -98,6 +103,9 @@ #define CMD_SET_LIGHT1_RESISTOR_ENABLE 524 #define CMD_SET_100M_RESET 526 +#define CMD_GET_CAMERA_STATUS 310 +#define CMD_SET_INIT_STATUS 401 + #endif // USING_PLZ #else // defined(USING_N938) @@ -501,14 +509,50 @@ public: TurnOn(); } + PowerControl(int cmd1, int cmd2, int cmd3, int cmd4, int cmd5, int cmd6, int cmd7, int cmd8, uint32_t closeDelayTime) : m_delayCloseTime(closeDelayTime) + { + m_cmds.resize(8, cmd1); + m_cmds[1] = cmd2; + m_cmds[2] = cmd3; + m_cmds[3] = cmd4; + m_cmds[4] = cmd5; + m_cmds[5] = cmd6; + m_cmds[6] = cmd7; + m_cmds[7] = cmd8; + TurnOn(); + } + virtual ~PowerControl() { GpioControl::TurnOff(m_cmds, m_delayCloseTime); +#ifdef OUTPUT_DBG_INFO + std::string status = GetStatus(); + XYLOG(XYLOG_SEVERITY_INFO, "PWR After TurnOff %s", status.c_str()); +#endif + } + + std::string GetStatus() + { + std::string result; + for (auto it = m_cmds.cbegin(); it != m_cmds.cend(); ++it) + { + if (*it == 0) + { + continue; + } + result += std::to_string(*it) + "=" + std::to_string(GpioControl::getInt(*it)) + " "; + } + + return result; } protected: void TurnOn() { +#ifdef OUTPUT_DBG_INFO + std::string status = GetStatus(); + XYLOG(XYLOG_SEVERITY_INFO, "PWR Before TurnOn %s", status.c_str()); +#endif GpioControl::TurnOn(m_cmds); } @@ -545,7 +589,7 @@ public: PowerControl(CMD_SET_12V_EN_STATE, closeDelayTime) #else // USING_PLZ // MicroPhoto - PowerControl(CMD_SET_12V_EN_STATE, closeDelayTime) + PowerControl(CMD_SET_12V_EN_STATE, CMD_SET_OTG_STATE, closeDelayTime) #endif // USING_PLZ #endif // USING_N938 { @@ -560,7 +604,7 @@ public: PowerControl(CMD_SET_OTG_STATE, CMD_SET_NETWORK_POWER_EN, CMD_SET_PIC1_POWER, CMD_SET_485_EN_STATE, closeDelayTime) #else // USING_N938 #ifdef USING_PLZ - PowerControl(CMD_SET_3V3_PWR_EN, CMD_SET_485_ENABLE, CMD_SET_PTZ_PWR_ENABLE, CMD_SET_12V_EN_STATE, closeDelayTime) + PowerControl(CMD_SET_3V3_PWR_EN, CMD_SET_5V_PWR_ENABLE, CMD_SET_OTG_STATE, CMD_SET_485_ENABLE, CMD_SET_100M_ENABLE, CMD_SET_PTZ_PWR_ENABLE, CMD_SET_12V_EN_STATE, CMD_SET_100M_SWITCH_PWR_ENABLE, closeDelayTime) #else // USING_PLZ PowerControl(CMD_SET_OTG_STATE, CMD_SET_12V_EN_STATE, closeDelayTime) #endif // USING_PLZ @@ -577,9 +621,10 @@ public: PowerControl(CMD_SET_OTG_STATE, CMD_SET_NETWORK_POWER_EN, closeDelayTime) #else // USING_N938 #ifdef USING_PLZ - PowerControl(CMD_SET_3V3_PWR_EN, CMD_SET_OTG_STATE, CMD_SET_100M_ENABLE, CMD_SET_100M_SWITCH_PWR_ENABLE, closeDelayTime) + PowerControl(CMD_SET_3V3_PWR_EN, CMD_SET_OTG_STATE, CMD_SET_5V_PWR_ENABLE, CMD_SET_100M_ENABLE, CMD_SET_100M_SWITCH_PWR_ENABLE, closeDelayTime) #else // USING_PLZ - PowerControl(CMD_SET_OTG_STATE, closeDelayTime) + // Micro Photo + PowerControl(CMD_SET_OTG_STATE, CMD_SET_485_EN_STATE/* Only for wp6*/, closeDelayTime) #endif // USING_PLZ #endif // USING_N938 { diff --git a/app/src/main/cpp/MicroPhoto.cpp b/app/src/main/cpp/MicroPhoto.cpp index b3577e12..97dbe010 100644 --- a/app/src/main/cpp/MicroPhoto.cpp +++ b/app/src/main/cpp/MicroPhoto.cpp @@ -23,6 +23,10 @@ #include "client/linux/handler/minidump_descriptor.h" #endif +#ifdef USING_MQTT +#include +#endif + #include #include @@ -227,9 +231,22 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) curl_global_init(CURL_GLOBAL_ALL); +#ifdef USING_MQTT + mosquitto_lib_init(); +#endif + return result; } +JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) +{ +#ifdef USING_MQTT + mosquitto_lib_cleanup(); +#endif + + curl_global_cleanup(); +} + bool GetJniEnv(JavaVM *vm, JNIEnv **env, bool& didAttachThread) { didAttachThread = false; @@ -1362,7 +1379,6 @@ Java_com_xypower_mpapp_MicroPhotoService_updateEhernet( return JNI_TRUE; } - extern "C" JNIEXPORT jboolean JNICALL Java_com_xypower_mpapp_MicroPhotoService_updateActiveNetwork( JNIEnv* env, jobject pThis, jlong handle, jlong networkHandle, jboolean available) { @@ -1381,4 +1397,27 @@ Java_com_xypower_mpapp_MicroPhotoService_updateActiveNetwork( } return JNI_TRUE; -} \ No newline at end of file +} + + +extern "C" JNIEXPORT jlong JNICALL +Java_com_xypower_mpapp_MicroPhotoService_requestPowerControl( + JNIEnv* env, jclass cls, jint type) { + if (type == 1) // Net + { + NetCameraPowerCtrl* powerControl = new NetCameraPowerCtrl(2); + return reinterpret_cast(powerControl); + } + + return 0L; +} + +extern "C" JNIEXPORT jboolean JNICALL +Java_com_xypower_mpapp_MicroPhotoService_releasePowerControl( + JNIEnv* env, jclass cls, jlong powerControlHandle) { + + PowerControl* powerControl = reinterpret_cast(powerControlHandle); + delete powerControl; + + return JNI_TRUE; +} diff --git a/app/src/main/cpp/PhoneDevice.cpp b/app/src/main/cpp/PhoneDevice.cpp index 8ebaf19d..8295a111 100644 --- a/app/src/main/cpp/PhoneDevice.cpp +++ b/app/src/main/cpp/PhoneDevice.cpp @@ -10,6 +10,8 @@ #include "PositionHelper.h" #include "DngCreator.h" +#include "media/RTSPRecorder.h" + #include #include #include @@ -1156,16 +1158,11 @@ bool CPhoneDevice::Reboot(int resetType, bool manually, const std::string& reaso return false; } } - std::thread t([manually, timeout]() - { - XYLOG(XYLOG_SEVERITY_WARNING, "Recv REBOOT command Manually=%d", manually ? 1 : 0); - std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); - if (manually) - { - GpioControl::reboot(); - } - }); - t.detach(); + if (manually) + { + // GpioControl::reboot(); + RestartApp(resetType, timeout, reason); + } } else { @@ -1346,15 +1343,12 @@ void CPhoneDevice::handleRebootTimer(union sigval v) } #endif CPhoneDevice* pDevice = (CPhoneDevice*)(v.sival_ptr); + const IDevice::PHOTO_INFO& photoInfo = pDevice->mPhotoInfo; // Reboot APP - XYLOG(XYLOG_SEVERITY_ERROR, "Camera Close Thread is DEAD, will RESTART app"); - pDevice->RestartApp(REBOOT_TYPE_APP, 30000, "Camera Can't Close"); + XYLOG(XYLOG_SEVERITY_ERROR, "Camera Close Thread is DEAD, will RESTART app CH=%u PR=%X", photoInfo.channel, photoInfo.preset); + pDevice->RestartApp(REBOOT_TYPE_APP, 30000, "Camera Cant Close"); } -// void CPhoneDevice::handleRebootTimerImpl() -// { -// } - IDevice::timer_uid_t CPhoneDevice::RegisterTimer(unsigned int timerType, unsigned int timeout, void* data, uint64_t times/* = 0*/) { struct sigevent evp = { 0 }; @@ -1533,7 +1527,9 @@ bool CPhoneDevice::TakePhotoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c } XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power ON"); - std::shared_ptr ethernetPowerCtrl = std::make_shared(1); + + uint32_t netWaitTime = (localPhotoInfo.cameraType == CAM_TYPE_PLZ) ? 20 : 4; + std::shared_ptr ethernetPowerCtrl = std::make_shared(netWaitTime); net_handle_t netHandle = GetEthnetHandle(); if (netHandle == 0) @@ -1554,16 +1550,30 @@ bool CPhoneDevice::TakePhotoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c if (netHandle == 0) { // timeout - XYLOG(XYLOG_SEVERITY_ERROR, "Ethernet not existing CH=%u PR=%X PHOTOID=%u", (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset, localPhotoInfo.photoId); + std::string pwrStatus = powerCtrlPtr->GetStatus(); + pwrStatus += ethernetPowerCtrl->GetStatus(); + XYLOG(XYLOG_SEVERITY_ERROR, "Ethernet Not Existing CH=%u PR=%X PHOTOID=%u PWR:%s", + (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset, localPhotoInfo.photoId, pwrStatus.c_str()); TakePhotoCb(0, localPhotoInfo, "", 0); return false; } else { - XYLOG(XYLOG_SEVERITY_INFO, "Ethernet is Available CH=%u PR=%X PHOTOID=%u", (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset, localPhotoInfo.photoId); + unsigned int ip = 0; + unsigned int netMask = 0; + unsigned int gateway = 0; + char buf[32] = { 0 }; + if (GetNetInfo("eth0", ip, netMask, gateway)) + { + // const + sockaddr_in addrIn = { AF_INET, 0, ip}; + inet_ntop(AF_INET, &addrIn.sin_addr, buf, sizeof(buf)); //其中recvAddr为SOCKADDR_IN类型 + } + + XYLOG(XYLOG_SEVERITY_INFO, "Ethernet is Available Handle=%ld IP=%s CH=%u PR=%X PHOTOID=%u", (uint64_t)netHandle, buf, (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset, localPhotoInfo.photoId); } - SetStaticIp(); + // SetStaticIp(); std::this_thread::sleep_for(std::chrono::milliseconds(256)); NET_PHOTO_INFO netPhotoInfo = { netHandle, 0 }; @@ -1620,7 +1630,7 @@ bool CPhoneDevice::TakePhotoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c std::vector img; bool netCaptureResult = false; - for (int idx = 0; idx < 3; idx++) + for (int idx = 0; idx < 64; idx++) { netHandle = GetEthnetHandle(); netPhotoInfo.netHandle = netHandle; @@ -1634,7 +1644,7 @@ bool CPhoneDevice::TakePhotoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c img.clear(); netCaptureResult = requestCapture(localPhotoInfo.channel, localPhotoInfo.preset, netPhotoInfo, img); - if (netCaptureResult) + if (netCaptureResult && !img.empty()) { XYLOG(XYLOG_SEVERITY_INFO, "NetCapture Succeeded PHOTOID=%u Img Size=%u", localPhotoInfo.photoId, (uint32_t)img.size()); break; @@ -1686,6 +1696,147 @@ bool CPhoneDevice::TakePhotoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c return true; } + +bool CPhoneDevice::TakeVideoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, const std::string& path, std::vector& osds, std::shared_ptr powerCtrlPtr) +{ + // AutoEnv autoEnv(pThis->m_vm); + time_t ts = time(NULL); + uint32_t waitTime = localPhotoInfo.selfTestingTime; + if(!GpioControl::GetSelftestStatus(waitTime)) + { + m_isSelfTesting.store(true); + waitTime = (waitTime != 0) ? (waitTime * 1024) : 10240; + std::this_thread::sleep_for(std::chrono::milliseconds(waitTime)); + m_isSelfTesting.store(false); + } + + XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power ON"); + // std::shared_ptr ethernetPowerCtrl = std::make_shared(1); + std::shared_ptr ethernetPowerCtrl; + + net_handle_t netHandle = GetEthnetHandle(); + if (netHandle == 0) + { + // Wait about 10s + for (int idx = 0; idx < 84; idx++) + { + std::this_thread::sleep_for(std::chrono::milliseconds(128)); + netHandle = GetEthnetHandle(); + + if (netHandle != 0) + { + break; + } + } + } + + if (netHandle == 0) + { + // timeout + XYLOG(XYLOG_SEVERITY_ERROR, "Ethernet not existing CH=%u PR=%X PHOTOID=%u", (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset, localPhotoInfo.photoId); +#ifdef NDEBUG + TakePhotoCb(0, localPhotoInfo, "", 0); + return false; +#endif + } + else + { + XYLOG(XYLOG_SEVERITY_INFO, "Ethernet is Available CH=%u PR=%X PHOTOID=%u", (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset, localPhotoInfo.photoId); + } + + // SetStaticIp(); + std::this_thread::sleep_for(std::chrono::milliseconds(256)); + + NET_PHOTO_INFO netPhotoInfo = { netHandle, 0 }; + if (localPhotoInfo.vendor == 1) + { + // Hai Kang + netPhotoInfo.authType = HTTP_AUTH_TYPE_DIGEST; + snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/ISAPI/Streaming/channels/1/picture?"); + } + else if (localPhotoInfo.vendor == 2) + { + // Hang Yu + strcpy(netPhotoInfo.url, "/cgi-bin/snapshot.cgi"); + } + else if (localPhotoInfo.vendor == 3) + { + // Yu Shi + netPhotoInfo.authType = HTTP_AUTH_TYPE_DIGEST; + int streamSid = 0; // should put into config + // rtsp://192.168.0.13:554/media/video1 + snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/media/video%u", (uint32_t)localPhotoInfo.cameraId); + // strcpy(netPhotoInfo.url, "rtsp://192.168.50.224/live/0"); + } + else if (localPhotoInfo.vendor == 5) + { + // Hang Yu - New + netPhotoInfo.authType = HTTP_AUTH_TYPE_BASIC; + // http://192.168.1.46/Snapshot/%u/RemoteImageCapture?ImageFormat=2&HorizontalPixel=1920&VerticalPixel=1080 + // http://192.168.1.101/Snapshot/1/2/RemoteImageCaptureV2?ImageFormat=jpg + // http://192.168.1.101/Snapshot/1/1/RemoteImageCaptureV2?ImageFormat=jpg + snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/Snapshot/%u/1/RemoteImageCaptureV2?ImageFormat=jpg", (uint32_t)localPhotoInfo.cameraId); + } + else + { + XYLOG(XYLOG_SEVERITY_ERROR, "Vendor(%u) not Supported CH=%u PR=%X PHOTOID=%u", (uint32_t)localPhotoInfo.vendor, (uint32_t)localPhotoInfo.channel, (unsigned int)localPhotoInfo.preset, localPhotoInfo.photoId); + TakePhotoCb(0, localPhotoInfo, "", 0); + return false; + } + + struct in_addr addr; + addr.s_addr = localPhotoInfo.ip; + strcpy(netPhotoInfo.ip, inet_ntoa(addr)); + strcpy(netPhotoInfo.outputPath, path.c_str()); + if (!localPhotoInfo.userName.empty()) + { + size_t len = std::min(sizeof(netPhotoInfo.userName) - 1, localPhotoInfo.userName.size()); + strncpy(netPhotoInfo.userName, localPhotoInfo.userName.c_str(), len); + } + if (!localPhotoInfo.password.empty()) + { + size_t len = std::min(sizeof(netPhotoInfo.password) - 1, localPhotoInfo.password.size()); + strncpy(netPhotoInfo.password, localPhotoInfo.password.c_str(), len); + } + // strcpy(netPhotoInfo.interface, "eth0"); + + localPhotoInfo.photoTime = time(NULL); + std::string tmpFile = m_appPath + (APP_PATH_TMP DIR_SEP_STR) + std::to_string(localPhotoInfo.photoId) + ".mp4"; + // RTSPToMP4 dumper(netPhotoInfo.url, tmpFile.c_str(), localPhotoInfo.duration * 1000); + // dumper.start(); + dumpRtspToMp4(netPhotoInfo.url, tmpFile.c_str(), localPhotoInfo.duration * 1000); + + ethernetPowerCtrl.reset(); + XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power OFF"); + + std::string fullPath = endsWith(mPath, ".mp4") ? mPath : (mPath + CTerminal::BuildPhotoFileName(mPhotoInfo)); + + if (existsFile(tmpFile)) + { + std::rename(tmpFile.c_str(), fullPath.c_str()); + TakePhotoCb(3, localPhotoInfo, "", localPhotoInfo.photoTime); + } + else + { + TakePhotoCb(0, localPhotoInfo, "", 0); + XYLOG(XYLOG_SEVERITY_ERROR, "Failed to TP on NET Camera CH=%u PR=%X PHOTOID=%u URL=http://%s%s", (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset, + localPhotoInfo.photoId, netPhotoInfo.ip, netPhotoInfo.url); + } + // Notify to take next photo + // TakePhotoCb(1, localPhotoInfo, "", takingTime); + + // XYLOG(XYLOG_SEVERITY_ERROR, "Failed to TP on NET Camera CH=%u PR=%X PHOTOID=%u URL=http://%s%s", (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset, + // localPhotoInfo.photoId, netPhotoInfo.ip, netPhotoInfo.url); + // TakePhotoCb(0, localPhotoInfo, "", 0); + + return true; +} + +bool CPhoneDevice::StartPushStreaming(IDevice::PHOTO_INFO& localPhotoInfo, const std::string& url, std::vector& osds, std::shared_ptr powerCtrlPtr) +{ + return true; +} + bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector& osds, const std::string& path) { if (photoInfo.width == 0 || photoInfo.height == 0) @@ -1973,6 +2124,89 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector< t.detach(); } + else if ((mPhotoInfo.mediaType == XY_MEDIA_TYPE_STREAM || mPhotoInfo.mediaType == XY_MEDIA_TYPE_STREAM_OFF) && (mPhotoInfo.cameraType == CAM_TYPE_NET || mPhotoInfo.cameraType == CAM_TYPE_PLZ)) + { + XYLOG(XYLOG_SEVERITY_INFO, "Start TP(Streaming) CH=%u PR=%X PHOTOID=%u", (uint32_t)mPhotoInfo.channel, (uint32_t)mPhotoInfo.preset, mPhotoInfo.photoId); + + // Start Thread + CPhoneDevice* pThis = this; + + vector osds; + osds.swap(mOsds); + IDevice::PHOTO_INFO localPhotoInfo = mPhotoInfo; + + std::thread t([localPhotoInfo, path, pThis, osds, powerCtrlPtr]() mutable + { + pThis->StartPushStreaming(localPhotoInfo, path, osds, powerCtrlPtr); + }); + + t.detach(); + } + else if (mPhotoInfo.mediaType == 1 && (mPhotoInfo.cameraType == CAM_TYPE_PLZ)) + { + uint64_t wid_serial = RequestWakelock(0); + CPhoneDevice* pThis = this; + IDevice::PHOTO_INFO localPhotoInfo = mPhotoInfo; + IDevice::SerialsPhotoParam param = { "", 0, 0 }; + GetPhotoSerialsParamCb(param); + vector osds; + osds.swap(mOsds); + + std::thread t([localPhotoInfo, param, pThis, path, osds, wid_serial, powerCtrlPtr]() mutable + { + uint32_t waitTime = localPhotoInfo.selfTestingTime; + if(!GpioControl::GetSelftestStatus(waitTime)) + { + pThis->m_isSelfTesting.store(true); + time_t remaintime = GpioControl::GetSelfTestRemain(waitTime); + XYLOG(XYLOG_SEVERITY_INFO, "Camera is SeltTesting,remaining selfTestingtime=%u", remaintime); + remaintime = (remaintime != 0) ? (remaintime * 1024) : 10240; + std::this_thread::sleep_for(std::chrono::milliseconds(remaintime)); + pThis->m_isSelfTesting.store(false); + XYLOG(XYLOG_SEVERITY_INFO, "Camera SeltTesting is over"); + } + + if (localPhotoInfo.preset != 0 && localPhotoInfo.preset != 0xFF) + { + XYLOG(XYLOG_SEVERITY_INFO,"Recv CameraCtrl Command, action= MOVE_PRESETNO, preset = %u", localPhotoInfo.preset); + CameraPhotoCmd(time(NULL), localPhotoInfo.channel, MOVE_PRESETNO, 0, localPhotoInfo.preset, param.serfile, param.baud, param.addr); + std::this_thread::sleep_for(std::chrono::seconds(10)); + } + + pThis->TakeVideoWithNetCamera(localPhotoInfo, path, osds, powerCtrlPtr); + pThis->ReleaseWakelock(wid_serial); + }); + + t.detach(); + } + else if (mPhotoInfo.mediaType == 1 && (mPhotoInfo.cameraType == CAM_TYPE_NET)) + { + uint64_t wid_serial = RequestWakelock(0); + CPhoneDevice* pThis = this; + IDevice::PHOTO_INFO localPhotoInfo = mPhotoInfo; + vector osds; + osds.swap(mOsds); + + std::thread t([localPhotoInfo, pThis, path, osds, wid_serial, powerCtrlPtr]() mutable + { + uint32_t waitTime = localPhotoInfo.selfTestingTime; + if(!GpioControl::GetSelftestStatus(waitTime)) + { + pThis->m_isSelfTesting.store(true); + time_t remaintime = GpioControl::GetSelfTestRemain(waitTime); + XYLOG(XYLOG_SEVERITY_INFO, "Camera is SeltTesting,remaining selfTestingtime=%u", remaintime); + remaintime = (remaintime != 0) ? (remaintime * 1024) : 10240; + std::this_thread::sleep_for(std::chrono::milliseconds(remaintime)); + pThis->m_isSelfTesting.store(false); + XYLOG(XYLOG_SEVERITY_INFO, "Camera SeltTesting is over"); + } + + pThis->TakeVideoWithNetCamera(localPhotoInfo, path, osds, powerCtrlPtr); + pThis->ReleaseWakelock(wid_serial); + }); + + t.detach(); + } else if (mPhotoInfo.usingSysCamera == 1) { JNIEnv* env = NULL; @@ -3360,8 +3594,17 @@ bool CPhoneDevice::OnImageReady(cv::Mat mat) #endif #endif // OUTPUT_DBG_INFO + bool imgExisted = std::filesystem::exists(std::filesystem::path(fullPath)); + if (imgExisted) + { + size_t imgFileSize = getFileSize(fullPath); + if (imgFileSize == 0 || imgFileSize == (size_t)-1) + { + imgExisted = false; + } + } - if (!std::filesystem::exists(std::filesystem::path(fullPath)) || getFileSize(fullPath) == 0) + if (!imgExisted) { bool res = cv::imwrite(fullPath.c_str(), mat, params); if (!res) @@ -3620,7 +3863,16 @@ bool CPhoneDevice::PostProcessPhoto(const PHOTO_INFO& photoInfo, const vector& osds, std::shared_ptr powerCtrlPtr); + bool TakeVideoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, const std::string& path, std::vector& osds, std::shared_ptr powerCtrlPtr); + bool StartPushStreaming(IDevice::PHOTO_INFO& localPhotoInfo, const std::string& url, std::vector& osds, std::shared_ptr powerCtrlPtr); bool PostProcessPhoto(const PHOTO_INFO& photoInfo, const vector& osds, const std::string& path, const std::string& cameraInfo, cv::Mat mat); inline bool TakePhotoCb(int res, const IDevice::PHOTO_INFO& photoInfo, const string& path, time_t photoTime, const std::vector& objects) const { diff --git a/app/src/main/cpp/SensorsProtocol.cpp b/app/src/main/cpp/SensorsProtocol.cpp index 9693cf1c..75735802 100644 --- a/app/src/main/cpp/SensorsProtocol.cpp +++ b/app/src/main/cpp/SensorsProtocol.cpp @@ -117,111 +117,12 @@ void Gm_CloseSensorsPower() /* 关闭电源*/ //switch(port) /* 根据硬件具体布置最后调整,目前是微拍板子的来控制*/ -/* set12VEnable(false); - setCam3V3Enable(false); - setRS485Enable(false); -#if 0 - setInt(CMD_SET_WTH_POWER, 0); - setInt(CMD_SET_PULL_POWER, 0); - setInt(CMD_SET_ANGLE_POWER, 0); - setInt(CMD_SET_OTHER_POWER, 0); - setInt(CMD_SET_PIC1_POWER, 0); - - sleep(3); - igpio = getInt(CMD_SET_WTH_POWER); - igpio = getInt(CMD_SET_PULL_POWER); - igpio = getInt(CMD_SET_ANGLE_POWER); - igpio = getInt(CMD_SET_OTHER_POWER); - igpio = getInt(CMD_SET_PIC1_POWER); -#endif -#if 1 - setInt(CMD_SET_SPI_POWER, 1); - setInt(CMD_SET_485_EN0, 1); - setInt(CMD_SET_485_EN1, 1); - setInt(CMD_SET_485_EN2, 1); - setInt(CMD_SET_485_EN3, 1); - setInt(CMD_SET_485_EN4, 1); -#else - setInt(CMD_SET_SPI_POWER, 0); - setInt(CMD_SET_485_EN0, 0); - setInt(CMD_SET_485_EN1, 0); - setInt(CMD_SET_485_EN2, 0); - setInt(CMD_SET_485_EN3, 0); - setInt(CMD_SET_485_EN4, 0); - sleep(3); - igpio = getInt(CMD_SET_SPI_POWER); - igpio = getInt(CMD_SET_485_EN0); - igpio = getInt(CMD_SET_485_EN1); - igpio = getInt(CMD_SET_485_EN2); - igpio = getInt(CMD_SET_485_EN3); - igpio = getInt(CMD_SET_485_EN4); -#endif -*/ } // 打开传感器电源 void Gm_OpenSensorsPower() { - //char iIoNo; -/* int igpio; - char szbuf[128]; - - //if(0 == port) - // return; - //sprintf(szbuf, "Open Sensors port %d Power!", port); - - //set12VEnable(true); - setCam3V3Enable(true); - setRS485Enable(true); - -#if 0 - setInt(CMD_SET_WTH_POWER, 0); - setInt(CMD_SET_PULL_POWER, 0); - setInt(CMD_SET_ANGLE_POWER, 0); - setInt(CMD_SET_OTHER_POWER, 0); - setInt(CMD_SET_PIC1_POWER, 0); -#else - setInt(CMD_SET_WTH_POWER, 1); - setInt(CMD_SET_PULL_POWER, 1); - setInt(CMD_SET_ANGLE_POWER, 1); - setInt(CMD_SET_OTHER_POWER, 1); - setInt(CMD_SET_PIC1_POWER, 1); - //sleep(3); - igpio = getInt(CMD_SET_WTH_POWER); - igpio = getInt(CMD_SET_PULL_POWER); - igpio = getInt(CMD_SET_ANGLE_POWER); - igpio = getInt(CMD_SET_OTHER_POWER); - igpio = getInt(CMD_SET_PIC1_POWER); - -#endif -#if 1 - setInt(CMD_SET_SPI_POWER, 1); - setInt(CMD_SET_485_EN0, 1); - setInt(CMD_SET_485_EN1, 1); - setInt(CMD_SET_485_EN2, 1); - setInt(CMD_SET_485_EN3, 1); - setInt(CMD_SET_485_EN4, 1); - - //sleep(3); - igpio = getInt(CMD_SET_SPI_POWER); - igpio = getInt(CMD_SET_485_EN0); - igpio = getInt(CMD_SET_485_EN1); - igpio = getInt(CMD_SET_485_EN2); - igpio = getInt(CMD_SET_485_EN3); - igpio = getInt(CMD_SET_485_EN4); - -#else - setInt(CMD_SET_485_EN0, 0); - setInt(CMD_SET_485_EN1, 0); - setInt(CMD_SET_485_EN2, 0); - setInt(CMD_SET_485_EN3, 0); - setInt(CMD_SET_485_EN4, 0); -#endif - - // 打开电源 - //switch(port) -*/ } // 查询传感器电源状态 diff --git a/app/src/main/cpp/camera2/ndkcamera.cpp b/app/src/main/cpp/camera2/ndkcamera.cpp index b52afcc0..70c15b64 100644 --- a/app/src/main/cpp/camera2/ndkcamera.cpp +++ b/app/src/main/cpp/camera2/ndkcamera.cpp @@ -166,6 +166,7 @@ NdkCamera::NdkCamera(int32_t width, int32_t height, const NdkCamera::CAMERA_PARA mCaptureTriggered = false; mFocusTriggered = false; + mCaptureDispatched = false; maxFrameDuration = 0; afSupported = false; @@ -225,6 +226,7 @@ NdkCamera::NdkCamera(int32_t width, int32_t height, const NdkCamera::CAMERA_PARA NdkCamera::~NdkCamera() { + XYLOG(XYLOG_SEVERITY_DEBUG, "NdkCamera::~NdkCamera %s", mCameraId.c_str()); close(); } @@ -999,6 +1001,8 @@ void NdkCamera::close() } */ + mPreviewResults.reset(); + mCaptureResults.clear(); mCaptureFrames.clear(); if ((ACameraManager *)camera_manager != NULL) @@ -1008,7 +1012,8 @@ void NdkCamera::close() if (capture_session) { - // res = ACameraCaptureSession_stopRepeating(capture_session); + res = ACameraCaptureSession_stopRepeating(capture_session); + std::this_thread::sleep_for(std::chrono::milliseconds(512)); ACameraCaptureSession_close(capture_session); capture_session = 0; } @@ -1050,11 +1055,24 @@ void NdkCamera::close() if (mPreviewImageReader != NULL) { +#ifdef _DEBUG + ALOGD("Will Free mPreviewImageReader"); +#endif + AImage* image = NULL; + media_status_t mstatus; + while ((mstatus = AImageReader_acquireNextImage(mPreviewImageReader, &image)) == AMEDIA_OK) + { + AImage_delete(image); + image = NULL; + } AImageReader_setImageListener(mPreviewImageReader, NULL); //XYLOG(XYLOG_SEVERITY_DEBUG, "CameraStatus::AImageReader_delete %s", mCameraId.c_str()); AImageReader_delete(mPreviewImageReader); //XYLOG(XYLOG_SEVERITY_DEBUG, "CameraStatus::End AImageReader_delete %s", mCameraId.c_str()); mPreviewImageReader = 0; +#ifdef _DEBUG + ALOGD("After Free mPreviewImageReader"); +#endif } if (mOutputTarget != NULL) @@ -1071,9 +1089,13 @@ void NdkCamera::close() if (mImageReader != NULL) { +#ifdef _DEBUG + ALOGD("Will Free mImageReader"); +#endif AImage* image = NULL; - int32_t status; - while ((status = AImageReader_acquireNextImage(mImageReader, &image)) == AMEDIA_OK) { + media_status_t mstatus; + while ((mstatus = AImageReader_acquireNextImage(mImageReader, &image)) == AMEDIA_OK) + { AImage_delete(image); image = NULL; } @@ -1084,6 +1106,9 @@ void NdkCamera::close() //XYLOG(XYLOG_SEVERITY_DEBUG, "CameraStatus::End AImageReader_delete %s", mCameraId.c_str()); mImageReader = 0; +#ifdef _DEBUG + ALOGD("After Free mImageReader"); +#endif } if (mOutputTarget2 != NULL) { @@ -1300,16 +1325,24 @@ void NdkCamera::onImageAvailable(AImageReader* reader) std::shared_ptr result; bool captureCompleted = false; + bool captureDispatchable = false; m_locker.lock(); if (!mCaptureResults.empty()) { captureCompleted = true; result = mCaptureResults[0]; } + if (captureCompleted && !mCaptureDispatched) + { + mCaptureDispatched = true; + captureDispatchable = true; + } m_locker.unlock(); - if (captureCompleted) + if (captureCompleted && captureDispatchable) { + XYLOG(XYLOG_SEVERITY_INFO,"onOneCapture from onImageAvailable"); + camera_status_t status = ACameraCaptureSession_stopRepeating(capture_session); onOneCapture(mCharacteristics, result, mFinalLdr, ts - m_startTime, mOneFrame); } } @@ -1340,17 +1373,23 @@ void NdkCamera::onImageAvailable(AImageReader* reader) } bool captureCompleted = false; + bool captureDispatchable = false; + size_t expectedTimes = mCaptureRequests.size() - 1; m_locker.lock(); captureCompleted = mCaptureResults.size() >= expectedTimes && mCaptureFrames.size() >= expectedTimes; + if (captureCompleted && !mCaptureDispatched) + { + mCaptureDispatched = true; + captureDispatchable = true; + } m_locker.unlock(); - if (captureCompleted) + if (captureCompleted && captureDispatchable) { FireBurstCapture(); } } - } } @@ -1765,6 +1804,7 @@ void NdkCamera::onCaptureCompleted(ACameraCaptureSession* session, ACaptureReque ACameraMetadata* pCopy = ACameraMetadata_copy(result); bool captureCompleted = false; + bool captureDispatchable = false; size_t expectedTimes = mCaptureRequests.size() - 1; std::shared_ptr captureResult(pCopy, ACameraMetadata_free); @@ -1773,10 +1813,17 @@ void NdkCamera::onCaptureCompleted(ACameraCaptureSession* session, ACaptureReque m_locker.lock(); mCaptureResults.push_back(captureResult); captureCompleted = !mOneFrame.empty(); + if (captureCompleted && !mCaptureDispatched) + { + mCaptureDispatched = true; + captureDispatchable = true; + } m_locker.unlock(); - if (captureCompleted) + if (captureCompleted && captureDispatchable) { + XYLOG(XYLOG_SEVERITY_INFO,"onOneCapture from onCaptureCompleted"); + camera_status_t status = ACameraCaptureSession_stopRepeating(capture_session); onOneCapture(mCharacteristics, captureResult, mFinalLdr, ts - m_startTime, mOneFrame); } } @@ -1785,9 +1832,14 @@ void NdkCamera::onCaptureCompleted(ACameraCaptureSession* session, ACaptureReque m_locker.lock(); mCaptureResults.push_back(captureResult); captureCompleted = mCaptureFrames.size() >= expectedTimes && mCaptureResults.size() >= expectedTimes; + if (captureCompleted && !mCaptureDispatched) + { + mCaptureDispatched = true; + captureDispatchable = true; + } m_locker.unlock(); - if (captureCompleted) + if (captureCompleted && captureDispatchable) { FireBurstCapture(); } @@ -1798,6 +1850,8 @@ void NdkCamera::onCaptureCompleted(ACameraCaptureSession* session, ACaptureReque void NdkCamera::FireBurstCapture() { + camera_status_t status = ACameraCaptureSession_stopRepeating(capture_session); + unsigned long long ts = GetMicroTimeStamp(); size_t expectedTimes = mCaptureRequests.size() - 1; @@ -1885,7 +1939,7 @@ void NdkCamera::onCaptureFailed(ACameraCaptureSession* session, ACaptureRequest* { bool isPreview = (request == mCaptureRequests[PREVIEW_REQUEST_IDX]->request); - XYLOG(XYLOG_SEVERITY_WARNING, "onCaptureFailed session=%p request=%p reason=%d PhotoTaken=%d Preview=%d", session, request, failure->reason, m_photoTaken ? 1 : 0, isPreview ? 1 : 0); + XYLOG(XYLOG_SEVERITY_WARNING, "onCaptureFailed session=%p request=%p reason=%d CameraId=%s PhotoTaken=%d Preview=%d", session, request, failure->reason, mCameraId.c_str(), m_photoTaken ? 1 : 0, isPreview ? 1 : 0); if (isPreview) { diff --git a/app/src/main/cpp/camera2/ndkcamera.h b/app/src/main/cpp/camera2/ndkcamera.h index 72b3a77f..dd42b651 100644 --- a/app/src/main/cpp/camera2/ndkcamera.h +++ b/app/src/main/cpp/camera2/ndkcamera.h @@ -236,6 +236,7 @@ protected: bool mCaptureTriggered; bool mFocusTriggered; + bool mCaptureDispatched; CAPTURE_RESULT mResult; unsigned long long m_startTime; @@ -267,6 +268,8 @@ protected: std::shared_ptr mCharacteristics; std::vector mCaptureRequests; + ACameraCaptureSession* capture_session; + std::shared_ptr mPreviewResults; std::vector > mCaptureResults; uint32_t mLdr; @@ -278,8 +281,6 @@ protected: cv::Mat mOneFrame; std::vector > mRawFrames; - ACameraCaptureSession* capture_session; - // AImageReader* image_reader; // ANativeWindow* image_reader_surface; // ACameraOutputTarget* image_reader_target; diff --git a/app/src/main/cpp/media/RTSPRecorder.cpp b/app/src/main/cpp/media/RTSPRecorder.cpp new file mode 100644 index 00000000..11edccfa --- /dev/null +++ b/app/src/main/cpp/media/RTSPRecorder.cpp @@ -0,0 +1,231 @@ +// +// Created by Matthew on 2025/3/1. +// + +#include "RTSPRecorder.h" +#include +#include +#include +extern "C" { +#include +#include +#include +#include +} + + +#define LOG_TAG "libcurl" + +#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) + + +void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration) +{ + AVFormatContext* inputFormatContext = nullptr; + AVFormatContext* outputFormatContext = nullptr; + AVPacket packet; + + av_register_all(); + avformat_network_init(); + + // Open input RTMP stream + if (avformat_open_input(&inputFormatContext, rtmpUrl, nullptr, nullptr) != 0) { + fprintf(stderr, "Could not open input file '%s'\n", rtmpUrl); + return; + } + + // Retrieve input stream information + if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) { + fprintf(stderr, "Could not find stream information\n"); + avformat_close_input(&inputFormatContext); + return; + } + + // Open output MP4 file + if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "mp4", outputPath) < 0) { + fprintf(stderr, "Could not create output context\n"); + avformat_close_input(&inputFormatContext); + return; + } + + // Copy stream information from input to output + for (unsigned int i = 0; i < inputFormatContext->nb_streams; i++) { + AVStream* inStream = inputFormatContext->streams[i]; + AVStream* outStream = avformat_new_stream(outputFormatContext, nullptr); + if (!outStream) { + fprintf(stderr, "Failed to allocate output stream\n"); + avformat_close_input(&inputFormatContext); + avformat_free_context(outputFormatContext); + return; + } + + if (avcodec_parameters_copy(outStream->codecpar, inStream->codecpar) < 0) { + fprintf(stderr, "Failed to copy codec parameters\n"); + avformat_close_input(&inputFormatContext); + avformat_free_context(outputFormatContext); + return; + } + outStream->codecpar->codec_tag = 0; + } + + // Open output file + if (!(outputFormatContext->oformat->flags & AVFMT_NOFILE)) { + if (avio_open(&outputFormatContext->pb, outputPath, AVIO_FLAG_WRITE) < 0) { + fprintf(stderr, "Could not open output file '%s'\n", outputPath); + avformat_close_input(&inputFormatContext); + avformat_free_context(outputFormatContext); + return; + } + } + + // Write output file header + if (avformat_write_header(outputFormatContext, nullptr) < 0) { + fprintf(stderr, "Error occurred when writing header to output file\n"); + avformat_close_input(&inputFormatContext); + avformat_free_context(outputFormatContext); + return; + } + + // Start a thread to stop the streaming after the specified duration + std::thread stop_thread([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(duration)); + av_read_pause(inputFormatContext); + }); + + // Read packets from input and write them to output + while (av_read_frame(inputFormatContext, &packet) >= 0) { + AVStream* inStream = inputFormatContext->streams[packet.stream_index]; + AVStream* outStream = outputFormatContext->streams[packet.stream_index]; + + packet.pts = av_rescale_q_rnd(packet.pts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + packet.dts = av_rescale_q_rnd(packet.dts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + packet.duration = av_rescale_q(packet.duration, inStream->time_base, outStream->time_base); + packet.pos = -1; + + if (av_interleaved_write_frame(outputFormatContext, &packet) < 0) { + fprintf(stderr, "Error muxing packet\n"); + break; + } + + av_packet_unref(&packet); + } + + stop_thread.join(); + + // Write output file trailer + av_write_trailer(outputFormatContext); + + // Clean up + avformat_close_input(&inputFormatContext); + if (outputFormatContext && !(outputFormatContext->oformat->flags & AVFMT_NOFILE)) { + avio_closep(&outputFormatContext->pb); + } + avformat_free_context(outputFormatContext); +} + + +void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration) +{ + AVFormatContext* inputFormatContext = nullptr; + AVFormatContext* outputFormatContext = nullptr; + AVPacket packet; + + av_register_all(); + avformat_network_init(); + + // Open input RTSP stream + if (avformat_open_input(&inputFormatContext, rtspUrl, nullptr, nullptr) != 0) { + fprintf(stderr, "Could not open input file '%s'\n", rtspUrl); + return; + } + + // Retrieve input stream information + if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) { + fprintf(stderr, "Could not find stream information\n"); + avformat_close_input(&inputFormatContext); + return; + } + + // Open output MP4 file + if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "mp4", outputPath) < 0) { + fprintf(stderr, "Could not create output context\n"); + avformat_close_input(&inputFormatContext); + return; + } + + // Copy stream information from input to output + for (unsigned int i = 0; i < inputFormatContext->nb_streams; i++) { + AVStream* inStream = inputFormatContext->streams[i]; + AVStream* outStream = avformat_new_stream(outputFormatContext, nullptr); + if (!outStream) { + fprintf(stderr, "Failed to allocate output stream\n"); + avformat_close_input(&inputFormatContext); + avformat_free_context(outputFormatContext); + return; + } + + if (avcodec_parameters_copy(outStream->codecpar, inStream->codecpar) < 0) { + fprintf(stderr, "Failed to copy codec parameters\n"); + avformat_close_input(&inputFormatContext); + avformat_free_context(outputFormatContext); + return; + } + outStream->codecpar->codec_tag = 0; + } + + // Open output file + if (!(outputFormatContext->oformat->flags & AVFMT_NOFILE)) { + if (avio_open(&outputFormatContext->pb, outputPath, AVIO_FLAG_WRITE) < 0) { + fprintf(stderr, "Could not open output file '%s'\n", outputPath); + avformat_close_input(&inputFormatContext); + avformat_free_context(outputFormatContext); + return; + } + } + + // Write output file header + if (avformat_write_header(outputFormatContext, nullptr) < 0) { + fprintf(stderr, "Error occurred when writing header to output file\n"); + avformat_close_input(&inputFormatContext); + avformat_free_context(outputFormatContext); + return; + } + + // Start a thread to stop the streaming after the specified duration + std::thread stop_thread([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(duration)); + av_read_pause(inputFormatContext); + }); + + // Read packets from input and write them to output + while (av_read_frame(inputFormatContext, &packet) >= 0) { + AVStream* inStream = inputFormatContext->streams[packet.stream_index]; + AVStream* outStream = outputFormatContext->streams[packet.stream_index]; + + packet.pts = av_rescale_q_rnd(packet.pts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + packet.dts = av_rescale_q_rnd(packet.dts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + packet.duration = av_rescale_q(packet.duration, inStream->time_base, outStream->time_base); + packet.pos = -1; + + if (av_interleaved_write_frame(outputFormatContext, &packet) < 0) { + fprintf(stderr, "Error muxing packet\n"); + break; + } + + av_packet_unref(&packet); + } + + stop_thread.join(); + + // Write output file trailer + av_write_trailer(outputFormatContext); + + // Clean up + avformat_close_input(&inputFormatContext); + if (outputFormatContext && !(outputFormatContext->oformat->flags & AVFMT_NOFILE)) { + avio_closep(&outputFormatContext->pb); + } + avformat_free_context(outputFormatContext); +} diff --git a/app/src/main/cpp/media/RTSPRecorder.h b/app/src/main/cpp/media/RTSPRecorder.h new file mode 100644 index 00000000..1133c8e0 --- /dev/null +++ b/app/src/main/cpp/media/RTSPRecorder.h @@ -0,0 +1,19 @@ +// +// Created by Matthew on 2025/3/1. +// + +#ifndef MICROPHOTO_RTSPRECORDER_H +#define MICROPHOTO_RTSPRECORDER_H + +#include + +// void dumpRtspToMp4(const std::string &rtspUrl, const std::string &outputPath, uint32_t durationInMs); +void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration); +void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration); + +class RTSPRecorder { + +}; + + +#endif //MICROPHOTO_RTSPRECORDER_H diff --git a/app/src/main/cpp/media/RTSPToMP4.cpp b/app/src/main/cpp/media/RTSPToMP4.cpp new file mode 100644 index 00000000..26b096a2 --- /dev/null +++ b/app/src/main/cpp/media/RTSPToMP4.cpp @@ -0,0 +1,186 @@ +// +// Created by Matthew on 2025/2/28. +// + +#include "RTSPToMP4.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int32_t getMaxInputSize(AMediaExtractor* extractor, size_t trackIndex) +{ + AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, trackIndex); + int32_t maxInputSize = 0; + if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, &maxInputSize)) { + // LOGI("Max input size for track %zu: %d", trackIndex, maxInputSize); + } else { + // LOGE("Failed to get max input size for track %zu", trackIndex); + } + AMediaFormat_delete(format); + return maxInputSize; +} + +RTSPToMP4::RTSPToMP4(const char* rtspUrl, const char* outputPath, uint64_t durationInMs/* = 0*/) + : fd(-1), codec(nullptr), extractor(nullptr), muxer(nullptr), videoTrackIndex(-1), durationInMs(durationInMs), running(false) { + initExtractor(rtspUrl); + initCodec("video/avc"); + initMuxer(outputPath); +} + +RTSPToMP4::~RTSPToMP4() { + if (codec) AMediaCodec_delete(codec); + if (extractor) AMediaExtractor_delete(extractor); + if (muxer) AMediaMuxer_delete(muxer); + + if (fd != -1) + { + fdatasync(fd); + close(fd); + fd = -1; + } +} + +void RTSPToMP4::initCodec(const char* mime) { + codec = AMediaCodec_createDecoderByType(mime); + AMediaFormat* format = AMediaFormat_new(); + AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mime); + // Set other format parameters as needed + // ... + AMediaCodec_configure(codec, format, nullptr, nullptr, 0); + AMediaFormat_delete(format); +} + +void RTSPToMP4::initExtractor(const char* rtspUrl) { + extractor = AMediaExtractor_new(); + media_status_t status = AMediaExtractor_setDataSource(extractor, rtspUrl); + if (status != AMEDIA_OK) { + // Handle error + // ... + } +} + +void RTSPToMP4::initMuxer(const char* outputPath) { + fd = open(outputPath, O_CREAT | O_WRONLY, 0644); + muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4); + + int numTracks = AMediaExtractor_getTrackCount(extractor); + if (numTracks <= 0) { + // LOGE("No tracks found in RTSP stream"); + AMediaExtractor_delete(extractor); + return; + } + + for (int i = 0; i < numTracks; ++i) { + AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, i); + const char* mime; + if (AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime) && strncmp(mime, "video/", 6) == 0) { + videoTrackIndex = AMediaMuxer_addTrack(muxer, format); + AMediaExtractor_selectTrack(extractor, i); + } + AMediaFormat_delete(format); + } + + if (videoTrackIndex == -1) { + // LOGE("No video track found in RTSP stream"); + AMediaExtractor_delete(extractor); + AMediaMuxer_delete(muxer); + return; + } + + int32_t maxInputSize = getMaxInputSize(extractor, videoTrackIndex); + if (maxInputSize <= 0) { + // LOGE("Invalid max input size"); + // releaseMediaExtractor(extractor); + sampleData.resize(1920 * 1080 * 4, 0); + return; + } + + sampleData.resize(maxInputSize, 0); +} + +void RTSPToMP4::startDecodingAndMuxing() { + AMediaCodec_start(codec); + size_t bufferSize = sampleData.size(); + uint8_t* buffer = &sampleData[0]; + int64_t sampleTime = 0; + int64_t startTime = 0; + bool firstSampleData = true; + + int64_t durationTime = (durationInMs == 0) ? std::numeric_limits::max() : (int64_t)durationInMs * 1000; + + + while (running) { + // Extract data from RTSP stream + ssize_t sampleSize = AMediaExtractor_readSampleData(extractor, buffer, bufferSize); + if (sampleSize < 0) { + break; // End of stream + } + + sampleTime = AMediaExtractor_getSampleTime(extractor); + if (firstSampleData) + { + startTime = sampleTime; + firstSampleData = false; + } + + sampleTime -= startTime; + + // Feed data to codec + size_t inputBufferIndex; + uint8_t* inputBuffer = AMediaCodec_getInputBuffer(codec, inputBufferIndex, &bufferSize); + memcpy(inputBuffer, buffer, sampleSize); + AMediaCodec_queueInputBuffer(codec, inputBufferIndex, 0, sampleSize, sampleTime, 0); + + // Retrieve decoded frames and write to muxer + AMediaCodecBufferInfo bufferInfo; + ssize_t outputBufferIndex = AMediaCodec_dequeueOutputBuffer(codec, &bufferInfo, 0); + if (outputBufferIndex >= 0) { + + bufferInfo.offset = 0; + bufferInfo.size = sampleSize; + bufferInfo.presentationTimeUs = sampleTime; + bufferInfo.flags = AMediaExtractor_getSampleFlags(extractor); + + uint8_t* outputBuffer = AMediaCodec_getOutputBuffer(codec, outputBufferIndex, &bufferSize); + AMediaMuxer_writeSampleData(muxer, videoTrackIndex, outputBuffer, &bufferInfo); + AMediaCodec_releaseOutputBuffer(codec, outputBufferIndex, false); + } + + AMediaExtractor_advance(extractor); + + if (sampleTime > durationTime) + { + break; + } + } + + AMediaCodec_stop(codec); + AMediaMuxer_stop(muxer); + + if (fd != -1) + { + fdatasync(fd); + close(fd); + fd = -1; + } +} + +void RTSPToMP4::start() { + // Add video track to muxer + AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, 0); + videoTrackIndex = AMediaMuxer_addTrack(muxer, format); + running = true; + AMediaMuxer_start(muxer); + + startDecodingAndMuxing(); +} + +void RTSPToMP4::stop() { + running = false; +} diff --git a/app/src/main/cpp/media/RTSPToMP4.h b/app/src/main/cpp/media/RTSPToMP4.h new file mode 100644 index 00000000..6759a8fd --- /dev/null +++ b/app/src/main/cpp/media/RTSPToMP4.h @@ -0,0 +1,38 @@ +// +// Created by Matthew on 2025/2/28. +// + +#ifndef MICROPHOTO_RTSPTOMP4_H +#define MICROPHOTO_RTSPTOMP4_H + +#include +#include +#include +#include + +class RTSPToMP4 { +public: + RTSPToMP4(const char* rtspUrl, const char* outputPath, uint64_t durationInMs = 0); + ~RTSPToMP4(); + void start(); + void stop(); + +private: + void initCodec(const char* mime); + void initExtractor(const char* rtspUrl); + void initMuxer(const char* outputPath); + void startDecodingAndMuxing(); + + int fd; + AMediaCodec* codec; + AMediaExtractor* extractor; + AMediaMuxer* muxer; + int videoTrackIndex; + uint64_t durationInMs; + bool running; + + std::vector sampleData; +}; + + +#endif //MICROPHOTO_RTSPTOMP4_H diff --git a/app/src/main/cpp/netcamera/VendorCtrl.cpp b/app/src/main/cpp/netcamera/VendorCtrl.cpp new file mode 100644 index 00000000..81f5d1c8 --- /dev/null +++ b/app/src/main/cpp/netcamera/VendorCtrl.cpp @@ -0,0 +1,20 @@ +// +// Created by Matthew on 2025/3/4. +// +#include "VendorCtrl.h" + +VendorCtrl::VendorCtrl(const std::string& ip, const std::string& userName, const std::string& password) : + m_ip(ip), m_userName(userName), m_password(password), m_channel(channel) +{ +} +std::string VendorCtrl::CvtJSONToString(const Json::Value& data) +{ + Json::StreamWriterBuilder builder; +#ifndef NDEBUG + builder["indentation"] = "\t"; // assume default for comments is None + builder["emitUTF8"] = true; +#else + builder["indentation"] = ""; +#endif + return Json::writeString(builder, data); +} \ No newline at end of file diff --git a/app/src/main/cpp/netcamera/VendorCtrl.h b/app/src/main/cpp/netcamera/VendorCtrl.h new file mode 100644 index 00000000..66a18e4a --- /dev/null +++ b/app/src/main/cpp/netcamera/VendorCtrl.h @@ -0,0 +1,34 @@ +// +// Created by Matthew on 2025/3/4. +// + +#ifndef MICROPHOTO_VENDORCTRL_H +#define MICROPHOTO_VENDORCTRL_H + +#include +#include + +class VendorCtrl { +public: + VendorCtrl(const std::string& ip, const std::string& userName, const std::string& password, uint8_t channel); + virtual ~VendorCtrl() = 0; + + virtual bool SetOsd() = 0; + virtual void EnableOsd(bool enable) = 0; + virtual std::string GetStreamingUrl(uint8_t channel) = 0; + virtual bool UpdateTime(time_t ts) = 0; + virtual bool TakePhoto(std::vector& img) = 0; + +protected: + + std::string CvtJSONToString(const Json::Value& data); + +protected: + std::string m_ip; + std::string m_userName; + std::string m_password; + uint8_t m_channel; +}; + + +#endif //MICROPHOTO_VENDORCTRL_H diff --git a/app/src/main/cpp/netcamera/YuShiCtrl.cpp b/app/src/main/cpp/netcamera/YuShiCtrl.cpp new file mode 100644 index 00000000..9c51f8f0 --- /dev/null +++ b/app/src/main/cpp/netcamera/YuShiCtrl.cpp @@ -0,0 +1,47 @@ +// +// Created by Matthew on 2025/3/4. +// + +#include "YuShiCtrl.h" +#include "httpclient.h" + +YuShiCtrl::~YuShiCtrl() +{ + +} + +bool YuShiCtrl::SetOsd() +{ + // /LAPI/V1.0/Channels//Media/OSDs/Contents +} + +void YuShiCtrl::EnableOsd(bool enable) +{ + return false; +} + +std::string GetStreamingUrl(uint8_t channel) +{ + // /LAPI/V1.0/Channels//Media/Video/Streams//LiveStreamURL?TransType=&TransProtocol= + return ""; +} + +bool YuShiCtrl::UpdateTime(time_t ts) +{ + /LAPI/V1.0/System/Time + + Json::Value jsonData(Json::objectValue); + + jsonData["TimeZone"] = "GMT+08:00"; + jsonData["DeviceTime"] = ts; + jsonData["DateFormat"] = 0; // YYYY-MM-DD + jsonData["HourFormat"] = 1; // 24H + + return false; +} + +bool YuShiCtrl::TakePhoto(std::vector& img) +{ + return false; +} \ No newline at end of file diff --git a/app/src/main/cpp/netcamera/YuShiCtrl.h b/app/src/main/cpp/netcamera/YuShiCtrl.h new file mode 100644 index 00000000..d5da62ad --- /dev/null +++ b/app/src/main/cpp/netcamera/YuShiCtrl.h @@ -0,0 +1,27 @@ +// +// Created by Matthew on 2025/3/4. +// + +#ifndef MICROPHOTO_YUSHICTRL_H +#define MICROPHOTO_YUSHICTRL_H + +#include "VendorCtrl.h" + +class YuShiCtrl : public VendorCtrl +{ +public: + using VendorCtrl::VendorCtrl; + virtual ~YuShiCtrl(); + + virtual bool SetOsd(); + virtual void EnableOsd(bool enable); + virtual std::string GetStreamingUrl(uint8_t channel); + virtual bool UpdateTime(time_t ts); + virtual bool TakePhoto(std::vector& img); + +private: + +}; + + +#endif //MICROPHOTO_YUSHICTRL_H diff --git a/app/src/main/cpp/netcamera/httpclient.cpp b/app/src/main/cpp/netcamera/httpclient.cpp index cd239f0e..532b5353 100644 --- a/app/src/main/cpp/netcamera/httpclient.cpp +++ b/app/src/main/cpp/netcamera/httpclient.cpp @@ -10,6 +10,7 @@ static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid) std::vector* data = (std::vector*)lpVoid; if( NULL == data || NULL == buffer ) { + XYLOG(XYLOG_SEVERITY_ERROR,"OnWriteData callback -1"); return -1; } uint8_t* begin = (uint8_t *)buffer; @@ -27,6 +28,7 @@ static int SockOptCallback(void *clientp, curl_socket_t curlfd, curlsocktype pur { int errcode = errno; printf("android_setsocknetwork errno=%d", errcode); + XYLOG(XYLOG_SEVERITY_ERROR,"setsocknetwork -1, errcode=%d",errcode); } return res == 0 ? CURL_SOCKOPT_OK : CURL_SOCKOPT_ERROR; } diff --git a/app/src/main/cpp/serial/WeatherComm.cpp b/app/src/main/cpp/serial/WeatherComm.cpp index dabd6b61..b755d58d 100644 --- a/app/src/main/cpp/serial/WeatherComm.cpp +++ b/app/src/main/cpp/serial/WeatherComm.cpp @@ -112,37 +112,6 @@ int set_port_attr (int fd, int baudrate, int databit, const char *stopbit, char return (tcsetattr (fd, TCSANOW, &opt)); } -static void setInt(int cmd, int value) -{ - int fd = open("/dev/mtkgpioctrl", O_RDONLY); - IOT_PARAM param; - param.cmd = cmd; - param.value = value; - // LOGE("set_int fd=%d,cmd=%d,value=%d\r\n",fd, cmd, value); - if( fd > 0 ) - { - int res = ioctl(fd, IOT_PARAM_WRITE, ¶m); - // LOGE("set_int22 cmd=%d,value=%d,result=%d\r\n",param.cmd, param.value, param.result); - close(fd); - } - return; -} -static void setRS485Enable(bool z) { - setInt(CMD_SET_485_EN_STATE, z ? 1 : 0); -} - -static void set485WriteMode() { - setInt(CMD_SET_485_STATE, 1); -} - -static void set485ReadMode() { - setInt(CMD_SET_485_STATE, 0); -} -static void set12VEnable(bool z) { - setInt(CMD_SET_12V_EN_STATE, z ? 1 : 0); -} - - /********************************************************************************* * 气象数据处理 * **********************************************************************************/ diff --git a/app/src/main/cpp/serial/WeatherComm.h b/app/src/main/cpp/serial/WeatherComm.h index 80c47f98..cd189441 100644 --- a/app/src/main/cpp/serial/WeatherComm.h +++ b/app/src/main/cpp/serial/WeatherComm.h @@ -8,10 +8,6 @@ #include #include "GPIOControl.h" -#define MAX_STRING_LEN 32 -#define IOT_PARAM_WRITE 0xAE -#define IOT_PARAM_READ 0xAF - #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, "serial_port_comm", fmt, ##args) // 串口参数 @@ -34,14 +30,6 @@ typedef struct unsigned char m_au8RecvBuf[128];/* */ } SIO_PARAM_SERIAL_DEF; -typedef struct -{ - int cmd; - int value; - int result; - long value2; - char str[MAX_STRING_LEN]; -}IOT_PARAM; void PortDataProcess( void ); int serial_port_comm(); diff --git a/app/src/main/java/com/xypower/mpapp/BridgeProvider.java b/app/src/main/java/com/xypower/mpapp/BridgeProvider.java index 87ad2a67..8fee79c1 100644 --- a/app/src/main/java/com/xypower/mpapp/BridgeProvider.java +++ b/app/src/main/java/com/xypower/mpapp/BridgeProvider.java @@ -46,6 +46,9 @@ public class BridgeProvider extends ContentProvider { private final static String PATH_RECOG_PIC = "/recogPic"; + private final static String PATH_REQUEST_PWR_CTRL = "/requestPwrCtrl"; + private final static String PATH_RELEASE_PWR_CTRL = "/releasePwrCtrl"; + public BridgeProvider() { Log.i(TAG, "BridgeProvider"); } @@ -85,6 +88,9 @@ public class BridgeProvider extends ContentProvider { matcher.addURI(AUTHORITY, PATH_QUERY_SEC_VERSION, 1); matcher.addURI(AUTHORITY, PATH_QUERY_BATTERY_VOLTAGE, 2); matcher.addURI(AUTHORITY, PATH_RECOG_PIC, 3); + matcher.addURI(AUTHORITY, PATH_REQUEST_PWR_CTRL, 4); + matcher.addURI(AUTHORITY, PATH_RELEASE_PWR_CTRL, 5); + Cursor cursor = null; int matched = matcher.match(uri); @@ -98,6 +104,12 @@ public class BridgeProvider extends ContentProvider { case 3: cursor = recoganizePicture(uri, selection, selectionArgs); break; + case 4: + cursor = requestPowerControl(uri, selection, selectionArgs); + break; + case 5: + cursor = recoganizePicture(uri, selection, selectionArgs); + break; default: break; } @@ -169,6 +181,48 @@ public class BridgeProvider extends ContentProvider { return matrixCursor; } + private Cursor requestPowerControl(Uri uri, String selection, String[] selectionArgs) { + String decodedSelection = stringFromBase64(selection); + int type = 0; + if (!TextUtils.isEmpty(decodedSelection)) { + Uri u = Uri.parse("http://a.com/?" + decodedSelection); + String val = u.getQueryParameter("type"); + try { + type = Integer.parseInt(val); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + long nativeHandle = MicroPhotoService.requestPowerControl(type); + + String[] columns = { "pwrCtrl" }; + MatrixCursor matrixCursor = new MatrixCursor(columns, 1); + matrixCursor.addRow(new Object[] { Long.valueOf(nativeHandle) }); + return matrixCursor; + } + + private Cursor releasePowerControl(Uri uri, String selection, String[] selectionArgs) { + String decodedSelection = stringFromBase64(selection); + long nativeHandle = 0; + if (!TextUtils.isEmpty(decodedSelection)) { + Uri u = Uri.parse("http://a.com/?" + decodedSelection); + String val = u.getQueryParameter("handle"); + try { + nativeHandle = Long.parseLong(val); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + boolean res = MicroPhotoService.releasePowerControl(nativeHandle); + + String[] columns = { "result" }; + MatrixCursor matrixCursor = new MatrixCursor(columns, 1); + matrixCursor.addRow(new Object[] { Integer.valueOf(res ? 1 : 0) }); + return matrixCursor; + } + private Cursor recoganizePicture(Uri uri, String selection, String[] selectionArgs) { String decodedSelection = stringFromBase64(selection); diff --git a/app/src/main/java/com/xypower/mpapp/MainActivity.java b/app/src/main/java/com/xypower/mpapp/MainActivity.java index 66153a3a..5fa35cc0 100644 --- a/app/src/main/java/com/xypower/mpapp/MainActivity.java +++ b/app/src/main/java/com/xypower/mpapp/MainActivity.java @@ -174,12 +174,13 @@ public class MainActivity extends AppCompatActivity { } if (MicroPhotoContext.hasMpAppConfig(appContext)) { - Runnable runnable = new Runnable() { + final Runnable runnable = new Runnable() { @Override public void run() { if (!MicroPhotoService.isRunning && !TextUtils.isEmpty(appConfig.cmdid) && !TextUtils.isEmpty(appConfig.server) && appConfig.port != 0) { if (binding.btnStartServ.isEnabled()) { + Log.i(TAG, "Perform AutoStart"); binding.btnStartServ.performClick(); } } @@ -189,10 +190,11 @@ public class MainActivity extends AppCompatActivity { long timeout = 500; if (SystemClock.elapsedRealtime() < 180000) { // In 3 minutes - timeout = 30000; // in 30 seconds + timeout = 10000; // in 10 seconds } Handler handler = new Handler(); handler.postDelayed(runnable, timeout); + Log.i(TAG, "Set AutoStart after " + Long.toString(timeout) + "ms"); } } @@ -232,6 +234,7 @@ public class MainActivity extends AppCompatActivity { startMicroPhotoService(appContext, curAppConfig, mMessenger); + Log.i(TAG, "Service auto-started"); binding.btnStartServ.setEnabled(false); binding.btnStopServ.setEnabled(true); } diff --git a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java index 374eb8e9..b26a5d06 100644 --- a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java +++ b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java @@ -91,6 +91,7 @@ public class MicroPhotoService extends Service { // Used to load the 'microphoto' library on application startup. static { + loadLibrary("microphoto"); } @@ -316,6 +317,7 @@ public class MicroPhotoService extends Service { intentFilter.addAction(ACTION_UPDATE_CONFIGS); intentFilter.addAction(ACTION_IMP_PUBKRY); intentFilter.addAction(ACTION_TAKE_PHOTO_MANUALLY); + intentFilter.addAction(ACTION_HEARTBEAT_MANUALLY); intentFilter.addAction(ACTION_GPS_TIMEOUT); intentFilter.addAction(ACTION_RESTART); getApplicationContext().registerReceiver(mAlarmReceiver, intentFilter, Context.RECEIVER_EXPORTED | Context.RECEIVER_VISIBLE_TO_INSTANT_APPS); @@ -455,8 +457,7 @@ public class MicroPhotoService extends Service { ex.printStackTrace(); } } - - private void restartSelf(Context context, String reason) { + private void restartSelfImpl(Context context, String reason) { Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); int noDelay = 1; intent.putExtra("noDelay", noDelay); @@ -549,7 +550,7 @@ public class MicroPhotoService extends Service { int restart = intent.getIntExtra("restart", 0); Log.i(TAG, "UPD CFG Fired ACTION=" + action + " restart=" + restart); if (restart != 0) { - restartSelf(context, "Cfg Updated"); + restartSelfImpl(context, "Cfg Updated"); } else if (mService.mNativeHandle != 0) { mService.reloadConfigs(mService.mNativeHandle); } @@ -670,7 +671,7 @@ public class MicroPhotoService extends Service { } catch (Exception ex) { ex.printStackTrace(); } - restartSelf(context, reason); + restartSelfImpl(context, reason); } } } @@ -1679,6 +1680,9 @@ cellSignalStrengthGsm.getDbm(); public static native boolean exportPublicKeyFile(int index, String outputPath); public static native boolean exportPrivateFile(int index, String outputPath); + public static native long requestPowerControl(int type); + public static native boolean releasePowerControl(long powerControlHandle); + ////////////////////////GPS//////////////////// // private static final String GPS_LOCATION_NAME = android.location.LocationManager.GPS_PROVIDER; private LocationManager mLocationManager; diff --git a/app/src/main/res/values/protocols.xml b/app/src/main/res/values/protocols.xml index a3a76cd8..f3ffb2b2 100644 --- a/app/src/main/res/values/protocols.xml +++ b/app/src/main/res/values/protocols.xml @@ -6,8 +6,8 @@ 65282-江苏 65283-湖南 65284-浙江 - 65285-河南 65286-郑州 + 65290-河南 65298-宁夏 \ No newline at end of file diff --git a/common/src/main/java/com/xypower/common/CameraUtils.java b/common/src/main/java/com/xypower/common/CameraUtils.java index 2cdb082d..818a2ceb 100644 --- a/common/src/main/java/com/xypower/common/CameraUtils.java +++ b/common/src/main/java/com/xypower/common/CameraUtils.java @@ -6,7 +6,6 @@ import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.params.StreamConfigurationMap; -import android.text.TextUtils; import android.util.Log; import android.util.Size; @@ -45,6 +44,16 @@ public class CameraUtils { Integer orientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); builder.append(orientation == null ? "" : orientation.toString()); + int[] capabilities = cameraCharacteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); + boolean hasRaw = false; + for (int capability : capabilities) { + if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW) { + hasRaw = true; + break; + } + } + builder.append(" raw=" + (hasRaw ? "1" : "0")); + StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size[] sizes = map.getOutputSizes(ImageFormat.YUV_420_888); diff --git a/common/src/main/java/com/xypower/common/MicroPhotoContext.java b/common/src/main/java/com/xypower/common/MicroPhotoContext.java index 55d2a369..2decd30e 100644 --- a/common/src/main/java/com/xypower/common/MicroPhotoContext.java +++ b/common/src/main/java/com/xypower/common/MicroPhotoContext.java @@ -418,19 +418,6 @@ public class MicroPhotoContext { */ try { - if (TextUtils.equals(packageName, PACKAGE_NAME_MPAPP)) { - - Intent intent = new Intent(ACTION_RESTART_MP); - intent.putExtra("noDelay", 1); - if (!TextUtils.isEmpty(reason)) { - intent.putExtra("reason", reason); - } - intent.setPackage(PACKAGE_NAME_MPAPP); - - context.sendBroadcast(intent); - } else { - SysApi.forceStopApp(context, packageName); - } Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName); if (intent != null) { intent.putExtra("noDelay", 1); diff --git a/mpmaster/build.gradle b/mpmaster/build.gradle index ac9e5d59..a816e021 100644 --- a/mpmaster/build.gradle +++ b/mpmaster/build.gradle @@ -4,7 +4,7 @@ plugins { def AppMajorVersion = 1 def AppMinorVersion = 1 -def AppBuildNumber = 1 +def AppBuildNumber = 8 def AppVersionName = AppMajorVersion + "." + AppMinorVersion + "." + AppBuildNumber def AppVersionCode = AppMajorVersion * 100000 + AppMinorVersion * 1000 + AppBuildNumber diff --git a/mpmaster/src/main/java/com/xypower/mpmaster/MainActivity.java b/mpmaster/src/main/java/com/xypower/mpmaster/MainActivity.java index 64b9ac19..a25bfa8e 100644 --- a/mpmaster/src/main/java/com/xypower/mpmaster/MainActivity.java +++ b/mpmaster/src/main/java/com/xypower/mpmaster/MainActivity.java @@ -19,6 +19,7 @@ import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; +import com.dev.devapi.api.SysApi; import com.xypower.common.MicroPhotoContext; import java.text.SimpleDateFormat; @@ -182,7 +183,17 @@ public class MainActivity extends AppCompatActivity { Context context = getApplicationContext(); MicroPhotoContext.AppConfig appConfig = MicroPhotoContext.getMpAppConfig(context); StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("CMDID:" + (TextUtils.isEmpty(appConfig.cmdid) ? "" : appConfig.cmdid)); + if (TextUtils.isEmpty(appConfig.cmdid)) { + String sn = SysApi.getSerialNo(getApplicationContext()); + if (TextUtils.isEmpty(sn)) { + stringBuilder.append("CMDID:"); + } else { + stringBuilder.append("CMDID:" + sn + " (SN)"); + } + } else { + stringBuilder.append("CMDID:" + appConfig.cmdid); + } + MicroPhotoContext.MasterConfig masterConfig = MicroPhotoContext.getMasterConfig(context); stringBuilder.append("\r\n"); diff --git a/mpmaster/src/main/java/com/xypower/mpmaster/MpMasterService.java b/mpmaster/src/main/java/com/xypower/mpmaster/MpMasterService.java index c5b90bbb..da06972b 100644 --- a/mpmaster/src/main/java/com/xypower/mpmaster/MpMasterService.java +++ b/mpmaster/src/main/java/com/xypower/mpmaster/MpMasterService.java @@ -19,6 +19,7 @@ import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; +import android.os.SystemClock; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -81,6 +82,7 @@ public class MpMasterService extends Service { private static final String ACTION_HEARTBEAT = "com.xypower.mpmaster.ACT_HB"; private static final String ACTION_TAKE_PHOTO = "com.xypower.mpapp.ACT_TP"; + private static final String ACTION_MP_HEARTBEAT_MANUALLY = "com.xypower.mpapp.ACT_HB_M"; public static final String ACTION_MP_RESTART = "com.xypower.mpapp.ACT_RESTART"; public static final String ACTION_IMP_PUBKRY = "com.xypower.mpapp.ACT_IMP_PUBKEY"; @@ -391,20 +393,34 @@ public class MpMasterService extends Service { public boolean shouldSyncTime() { return mSyncTime; } public void detectMpAppAlive() { + final MpMasterService thisObj = this; + Thread th = new Thread(new Runnable() { + @Override + public void run() { + thisObj.detectMpAppAliveImpl(); + } + }); + th.start(); + } + + private void detectMpAppAliveImpl() { try { final Context context = getApplicationContext(); long ts = System.currentTimeMillis(); try { - boolean isMpAppRunning = detectMpAppRunning(); - if (!isMpAppRunning) { - try { - Thread.sleep(1000); - } catch (Exception ex) { - ex.printStackTrace(); - } - // Check twice + int detectionCnt = 4; + if (SystemClock.elapsedRealtime() < 180000) { + // In 3 minutes after device reboot + detectionCnt = 16; + } + boolean isMpAppRunning = false; + for (int idx = 0; idx < detectionCnt; idx++) { isMpAppRunning = detectMpAppRunning(); + if (isMpAppRunning) { + break; + } + sleep(1000); } if (!isMpAppRunning) { @@ -1060,7 +1076,7 @@ public class MpMasterService extends Service { public static String getBatteryVoltage() { int val = 0; for (int idx = 0; idx < 3; idx++) { - val = MpMasterService.getInt(115); + val = MpMasterService.getInt(117); if (val > 0) { return Integer.toString(val / 1000) + "." + Integer.toString((val % 1000) / 100); } @@ -1192,6 +1208,20 @@ public class MpMasterService extends Service { } else { SysApi.selectSimCard4Data(context, num); } + + if (num == 1) { + // If it's back to card 1, let MpAPP send heartbeat manully after 10s + mHander.postDelayed(new Runnable() { + @Override + public void run() { + Intent intent = new Intent(); + intent.setAction(ACTION_MP_HEARTBEAT_MANUALLY); + intent.setPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP); + sendBroadcast(intent); + } + }, 10000); + + } } private void setDefaultDataSubId(int subId) { @@ -1293,11 +1323,8 @@ public class MpMasterService extends Service { @Override public void run() { - try { - Thread.sleep(5000); - } catch (Exception ex) { + sleep(5000); - } File tmpDestPath = new File(MicroPhotoContext.buildMasterAppDir(context)); tmpDestPath = new File(tmpDestPath, "mpdata"); if (tmpDestPath.exists()) { @@ -1415,6 +1442,13 @@ public class MpMasterService extends Service { } } + private static void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (Exception ex) { + } + } + public native static int getInt(int cmd); public native static int setInt(int cmd, int val); public native static int[] getStats(long ts); diff --git a/mpmaster/src/main/java/com/xypower/mpmaster/sms/SimUtil.java b/mpmaster/src/main/java/com/xypower/mpmaster/sms/SimUtil.java index 4dde7d55..801a19fe 100644 --- a/mpmaster/src/main/java/com/xypower/mpmaster/sms/SimUtil.java +++ b/mpmaster/src/main/java/com/xypower/mpmaster/sms/SimUtil.java @@ -81,7 +81,6 @@ public class SimUtil { } int slot = smsInfo.getSlot();//那张卡收到的短信 String sender = smsInfo.getSender();//收到的短信的手机号 - String sendmessage = "ERROR";//要回复的短信 List abslist = new ArrayList<>();//收到的短信内容拆分包装成数组 boolean ifmessageCorrect = false;//用来判断收到的短信内容是否正确 if (StringUtils.isEmpty(content)) { @@ -122,21 +121,21 @@ public class SimUtil { String s = split1[1]; String[] split2 = StringUtils.splitString2(s); int spilt2len = split2.length; - if (split2 != null && spilt2len > 1 && spilt2len % 2 == 1) { + if (split2 != null && spilt2len > 0) { String num = split2[0]; Integer integer = StringUtils.convert2Int(num); if (integer != null) { if (integer == 0) {//删除所有运维 ifmessageCorrect = true; } else { - if (spilt2len == integer * 2 + 1) { - int times = 0; - for (int i = 0; i < spilt2len; i++) { - if (i == 0) { - continue; - } - String ts = split2[i]; - Integer time = StringUtils.convert2Int(ts); + int times = 0; + for (int i = 0; i < spilt2len; i++) { + if (i == 0) { + continue; + } + String ts = split2[i]; + Integer time = StringUtils.convert2Int(ts); + if (time != null) { if (i % 2 == 1) { if (time > 23) { ifmessageCorrect = false; @@ -181,11 +180,14 @@ public class SimUtil { String[] split1 = StringUtils.splitString1(content); if (split1 != null && split1.length > 1) { String s = split1[1]; - Integer integer = StringUtils.convert2Int(s); - if (integer != null) { - if (integer == 0 || integer == 1) { - ifmessageCorrect = true; - UpdateSysConfigUtil.setMntnMode(context, integer); + String[] strings = StringUtils.splitString2(s); + if (strings != null && strings.length >= 1) { + Integer integer = StringUtils.convert2Int(strings[0]); + if (integer != null) { + if (integer == 0 || integer == 1) { + ifmessageCorrect = true; + UpdateSysConfigUtil.setMntnMode(context, integer); + } } } } @@ -230,8 +232,14 @@ public class SimUtil { String[] split1 = StringUtils.splitString1(content); if (split1 != null && split1.length > 1) { ifmessageCorrect = true; - String cmdid = split1[1]; - UpdateSysConfigUtil.setCmdid(context, cmdid); + String s = split1[1]; + String[] strings = StringUtils.splitString2(s); + if (strings != null && strings.length >= 1) { + String cmdid = strings[0]; + if (cmdid != null) { + UpdateSysConfigUtil.setCmdid(context, cmdid); + } + } } sendmessage = getSendString(content, ifmessageCorrect); } else if (content.contains(SmsTypeEnum.GET_CMDID.value())) { @@ -242,32 +250,32 @@ public class SimUtil { restartType = 1; String[] split1 = StringUtils.splitString1(content); if (split1 != null && split1.length > 1) { + String server = null; + Integer port = null; + Integer utcp = null; + Integer encrypto = null; String s = split1[1]; String[] split2 = StringUtils.splitString2(s); - if (split2 != null && (split2.length == 2 || split2.length == 4)) { - String server; - Integer integer; - server = split2[0]; - String port = split2[1]; - integer = StringUtils.convert2Int(port); - Integer utcp = -1; - Integer encrypto = -1; - if (integer != null) { - ifmessageCorrect = true; - if (split2.length == 4) { - String s1 = split2[2]; - utcp = StringUtils.convert2Int(s1); - utcp = getUtcp(utcp); - String s2 = split2[3]; - encrypto = StringUtils.convert2Int(s2); - encrypto = getEncrypto(encrypto); - if (utcp == -1 || encrypto == -1) { - ifmessageCorrect = false; - } - } + if (split2 != null && split2.length > 1) { + ifmessageCorrect = true; + if (split2.length > 0) { + server = split2[0]; + } + if (split2.length > 1) { + String s1 = split2[1]; + port = StringUtils.convert2Int(s1); + } + if (split2.length > 2) { + String s2 = split2[2]; + utcp = StringUtils.convert2Int(s2); + utcp = getUtcp(utcp); + } + if (split2.length > 3) { + String s3 = split2[3]; + encrypto = StringUtils.convert2Int(s3); } if (ifmessageCorrect) { - UpdateSysConfigUtil.setIP(context, server, integer, utcp, encrypto); + UpdateSysConfigUtil.setIP(context, server, port, utcp, encrypto); } } } @@ -279,13 +287,13 @@ public class SimUtil { restartType = 1; String[] split1 = StringUtils.splitString1(content); sendmessage = getSendString(content, ifmessageCorrect); - if (split1 != null && split1.length == 2) { + if (split1 != null && split1.length >= 2) { ifmessageCorrect = true; JSONObject osdmap = new JSONObject(); String s = split1[1]; String[] split2 = StringUtils.splitString2(s); int spilt2len = split2.length; - if (split2 != null && spilt2len > 1 && spilt2len % 2 == 1) { + if (split2 != null && spilt2len > 1) { String num = split2[0]; Integer integer = StringUtils.convert2Int(num); if (integer != null) { @@ -417,7 +425,7 @@ public class SimUtil { if (split1 != null && split1.length > 1) { String s = split1[1]; String[] split2 = StringUtils.splitString2(s); - if (split2 != null && split2.length == 2) { + if (split2 != null && split2.length > 1) { Integer channel = StringUtils.convert2Int(split2[0]); if (channel != null) { ifmessageCorrect = true; @@ -430,17 +438,21 @@ public class SimUtil { } else if (content.contains(SmsTypeEnum.GET_PHOTO_SCHEDULE_LIST.value())) { String[] split1 = StringUtils.splitString1(content); if (split1 != null && split1.length == 2) { - Integer channel = StringUtils.convert2Int(split1[1]); - String photoSchedules = UpdateSysConfigUtil.getPhotoSchedules(channel); - sendmessage = SmsTypeEnum.GET_PHOTO_SCHEDULE_LIST.value() + "=" + photoSchedules; + String s = split1[1]; + String[] strings = StringUtils.splitString2(s); + if (strings != null && strings.length >= 1) { + Integer integer = StringUtils.convert2Int(strings[0]); + String photoSchedules = UpdateSysConfigUtil.getPhotoSchedules(integer); + sendmessage = SmsTypeEnum.GET_PHOTO_SCHEDULE_LIST.value() + "=" + photoSchedules; + } } } else if (content.contains(SmsTypeEnum.SET_RESOLUTION.value())) { restartType = 1; String[] split1 = StringUtils.splitString1(content); if (split1 != null && split1.length > 1) { String s = split1[1]; - String[] split2 = StringUtils.splitString1(s); - if (split2 != null && split2.length == 5) { + String[] split2 = StringUtils.splitString2(s); + if (split2 != null && split2.length >= 5) { Integer channel = StringUtils.convert2Int(split2[0]); Integer resolutionCX = StringUtils.convert2Int(split2[1]); Integer resolutionCY = StringUtils.convert2Int(split2[2]); @@ -465,19 +477,23 @@ public class SimUtil { sendmessage = SmsTypeEnum.GET_RESOLUTION.value() + "=" + resolutionCX + "," + resolutionCY + "," + videoCX + "," + videoCY; } else if (content.contains(SmsTypeEnum.TAKE_PHOTO.value())) { String[] split = StringUtils.splitString1(content); - if (split != null && split.length == 3) { - ifmessageCorrect = true; - Integer channel = StringUtils.convert2Int(split[0]); - Integer preset = StringUtils.convert2Int(split[1]); - Integer type = StringUtils.convert2Int(split[2]); - if (channel != null) { - boolean photoOrVideo; - if (type == 0) { - photoOrVideo = true; - } else { - photoOrVideo = false; + if (split != null && split.length > 1) { + String s = split[1]; + String[] strings = StringUtils.splitString2(s); + if (strings != null && strings.length >= 3) { + ifmessageCorrect = true; + Integer channel = StringUtils.convert2Int(strings[0]); + Integer preset = StringUtils.convert2Int(strings[1]); + Integer type = StringUtils.convert2Int(strings[2]); + if (channel != null && preset != null && type != null) { + boolean photoOrVideo; + if (type == 0) { + photoOrVideo = true; + } else { + photoOrVideo = false; + } + UpdateSysConfigUtil.takePhotoOrVideo(context, channel, preset, photoOrVideo); } - UpdateSysConfigUtil.takePhotoOrVideo(context, channel, preset, photoOrVideo); } sendmessage = getSendString(content, ifmessageCorrect); } @@ -487,8 +503,11 @@ public class SimUtil { if (split1 != null && split1.length == 2) { ifmessageCorrect = true; String s = split1[1]; - Integer integer = StringUtils.convert2Int(s); - UpdateSysConfigUtil.setHB(context, integer); + String[] strings = StringUtils.splitString2(s); + if (strings != null && strings.length >= 1) { + Integer integer = StringUtils.convert2Int(strings[0]); + UpdateSysConfigUtil.setHB(context, integer); + } } sendmessage = getSendString(content, ifmessageCorrect); } else if (content.contains(SmsTypeEnum.GET_HEART.value())) { @@ -505,8 +524,11 @@ public class SimUtil { if (split1 != null && split1.length == 2) { ifmessageCorrect = true; String s = split1[1]; - Integer integer = StringUtils.convert2Int(s); - UpdateSysConfigUtil.setTB(context, integer); + String[] strings = StringUtils.splitString2(s); + if (strings != null && strings.length >= 1) { + Integer integer = StringUtils.convert2Int(strings[0]); + UpdateSysConfigUtil.setTB(context, integer); + } } sendmessage = getSendString(content, ifmessageCorrect); } else if (content.contains(SmsTypeEnum.GET_TP.value())) { @@ -518,8 +540,11 @@ public class SimUtil { if (split1 != null && split1.length == 2) { ifmessageCorrect = true; String s = split1[1]; - Integer integer = StringUtils.convert2Int(s); - UpdateSysConfigUtil.setPackage(context, integer); + String[] strings = StringUtils.splitString2(s); + if (strings != null && strings.length > 0) { + Integer integer = StringUtils.convert2Int(strings[0]); + UpdateSysConfigUtil.setPackage(context, integer); + } } sendmessage = getSendString(content, ifmessageCorrect); } else if (content.contains(SmsTypeEnum.GET_PACKAGE.value())) { @@ -557,21 +582,35 @@ public class SimUtil { return apputcp; } - private static int getEncrypto(Integer encrypto) { - int appencrypto = -1; - //短信文档中 1:密文,2:明文 3:不加密 app应用中 0:不加密 1:明文 2:加密 所以需要转换一下 - if (encrypto != null && (encrypto == 1 || encrypto == 2 || encrypto == 3)) { - if (encrypto == 1) { - appencrypto = 2; - } else if (encrypto == 2) { - appencrypto = 1; - } else if (encrypto == 3) { - appencrypto = 0; + public static int getSmsUtcp(Integer apputcp) { + int smsutcp = -1; + //短信文档中 0:udp 1:tcp app应用中 0:tcp 1:udp 所以需要转换一下 + if (apputcp != null && (apputcp == 0 || apputcp == 1)) { + if (apputcp == 0) { + smsutcp = 1; + } else if (apputcp == 1) { + smsutcp = 0; } } - return appencrypto; + return smsutcp; } +// private static int getEncrypto(Integer encrypto) { +// int appencrypto = -1; +// //短信文档中 1:密文,2:明文 3:不加密 app应用中 0:不加密 1:明文 2:加密 所以需要转换一下 +// if (encrypto != null && (encrypto == 1 || encrypto == 2 || encrypto == 3)) { +// if (encrypto == 1) { +// appencrypto = 2; +// } else if (encrypto == 2) { +// appencrypto = 1; +// } else if (encrypto == 3) { +// appencrypto = 0; +// } +// } +// return appencrypto; +// } + + private static String getSendString(String content, boolean ifmessageCorrect) { String sendmessage; String menssageBack = ""; @@ -774,19 +813,14 @@ public class SimUtil { } else if (configType == 3) { //数组 JSONArray objects = new JSONArray(configValue); JSONUtils.updateConfigFile(filePath, fileName, configName, configType, objects); + } else if (configType == 4) { //对象 + JSONObject objects = new JSONObject(configValue); + JSONUtils.updateConfigFile(filePath, fileName, configName, configType, objects); } } else { ifmessageCorrect = false; } } -// if (rebootMpApp != 0) { -// MicroPhotoContext.restartMpApp(context, "Config Updated From SMS"); -// } else { -// Intent intent = new Intent(); -// intent.setAction(MicroPhotoContext.ACTION_UPDATE_CONFIGS_MP); -// intent.setPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP); -// context.sendBroadcast(intent); -// } } else { ifmessageCorrect = false; } @@ -901,6 +935,8 @@ public class SimUtil { HashMap hashMap = ValueTypeUtil.checkFilePathAndName(fileType); filePath = hashMap.get(UpdateSysConfigUtil.FILEPATH); fileName = hashMap.get(UpdateSysConfigUtil.FILENAME); + + if (!TextUtils.isEmpty(filePath + fileName)) { File file = new File(filePath + fileName); if (file.exists()) { diff --git a/mpmaster/src/main/java/com/xypower/mpmaster/sms/SmsReceiver.java b/mpmaster/src/main/java/com/xypower/mpmaster/sms/SmsReceiver.java index 0a1cad05..3d44b4f5 100644 --- a/mpmaster/src/main/java/com/xypower/mpmaster/sms/SmsReceiver.java +++ b/mpmaster/src/main/java/com/xypower/mpmaster/sms/SmsReceiver.java @@ -21,7 +21,7 @@ import java.util.Date; public class SmsReceiver extends BroadcastReceiver { public static final String SMS_BUNDLE = "pdus"; - public static long mLastSmsTime = System.currentTimeMillis(); + public static long mLastSmsTime = 0; private static final SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override @@ -34,10 +34,9 @@ public class SmsReceiver extends BroadcastReceiver { // Log.i("SMS", "RECV " + mSimpleDateFormat.format(dt) + " " + smsMessage.getMessageBody()); - if (smsMessage.getTimestampMillis() < mLastSmsTime) { - + if (mLastSmsTime!= 0 &&smsMessage.getTimestampMillis() < mLastSmsTime) { Date dt = new Date(smsMessage.getTimestampMillis()); - Log.i("SMS", "MSG @" + mSimpleDateFormat.format(dt) + " Dropped: " + smsMessage.getMessageBody()); + Log.e("SMS", "MSG @" + mSimpleDateFormat.format(dt) + " Dropped: " + smsMessage.getMessageBody()+" mLastSmsTime:"+mLastSmsTime+" "+mSimpleDateFormat.format(mLastSmsTime)); SimUtil.setSmsMessageRead(context, smsMessage); continue; } diff --git a/mpmaster/src/main/java/com/xypower/mpmaster/sms/UpdateSysConfigUtil.java b/mpmaster/src/main/java/com/xypower/mpmaster/sms/UpdateSysConfigUtil.java index dccdc568..3edfa3f2 100644 --- a/mpmaster/src/main/java/com/xypower/mpmaster/sms/UpdateSysConfigUtil.java +++ b/mpmaster/src/main/java/com/xypower/mpmaster/sms/UpdateSysConfigUtil.java @@ -166,14 +166,18 @@ public class UpdateSysConfigUtil { } //修改app的ip - public static void setIP(Context context, String server, int port, int utcp, int encrypto) { + public static void setIP(Context context, String server, Integer port, Integer utcp, Integer encrypto) { MicroPhotoContext.AppConfig mpAppConfig = MicroPhotoContext.getMpAppConfig(context); + if (server!=null) { mpAppConfig.server = server; + } + if (port!=null && port!=-1) { mpAppConfig.port = port; - if (utcp != -1) { + } + if (utcp != null&& utcp!=-1 ) { mpAppConfig.networkProtocol = utcp; } - if (encrypto != -1) { + if (encrypto != null&& encrypto!=-1) { mpAppConfig.encryption = encrypto; } MicroPhotoContext.saveMpAppConfig(context, mpAppConfig); @@ -186,8 +190,9 @@ public class UpdateSysConfigUtil { String server = mpAppConfig.server; int port = mpAppConfig.port; int networkProtocol = mpAppConfig.networkProtocol; + int smsUtcp = SimUtil.getSmsUtcp(networkProtocol); int encryption = mpAppConfig.encryption; - return server + "," + port + "," + networkProtocol + "," + encryption; + return server + "," + port + "," + smsUtcp + "," + encryption; } //修改app的心跳 @@ -338,23 +343,23 @@ public class UpdateSysConfigUtil { //重启应用 public static void restartApp(Context context) { - Intent intent = new Intent(MicroPhotoContext.ACTION_RESTART_MP); - intent.putExtra("noDelay", 1); - intent.setPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP); - - context.sendBroadcast(intent); - try { - Thread.sleep(200); - } catch (Exception ex) { - ex.printStackTrace(); - } +// Intent intent = new Intent(MicroPhotoContext.ACTION_RESTART_MP); +// intent.putExtra("noDelay", 1); +// intent.setPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP); +// +// context.sendBroadcast(intent); +// try { +// Thread.sleep(200); +// } catch (Exception ex) { +// ex.printStackTrace(); +// } PackageManager packageManager = context.getPackageManager(); - intent = packageManager.getLaunchIntentForPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP); + Intent intent = packageManager.getLaunchIntentForPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP); intent.putExtra("noDelay", 1); // intent.putExtra("reboot", 1); - intent.addFlags(/*Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | */Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK ); context.startActivity(intent); } @@ -372,8 +377,8 @@ public class UpdateSysConfigUtil { List schedules = new ArrayList<>(); long ts = System.currentTimeMillis() / 1000; long val = 0; - val |= (channel << 16); - val |= (preset << 8); + val |= (channel << 12); + val |= (preset << 4); val |= photoOrVideo ? 0L : 1L; schedules.add(Long.valueOf(val)); diff --git a/mpmaster/src/main/java/com/xypower/mpmaster/sms/ValueTypeUtil.java b/mpmaster/src/main/java/com/xypower/mpmaster/sms/ValueTypeUtil.java index f9a8248d..a702e4b0 100644 --- a/mpmaster/src/main/java/com/xypower/mpmaster/sms/ValueTypeUtil.java +++ b/mpmaster/src/main/java/com/xypower/mpmaster/sms/ValueTypeUtil.java @@ -1,10 +1,13 @@ package com.xypower.mpmaster.sms; +import android.os.Environment; + import com.xypower.common.MicroPhotoContext; import org.json.JSONArray; +import java.io.File; import java.util.HashMap; public class ValueTypeUtil { @@ -37,18 +40,34 @@ public class ValueTypeUtil { * * */ public static HashMap checkFilePathAndName( int fileType) { + String path = Environment.getExternalStorageDirectory().getAbsolutePath(); + if (!path.endsWith(File.separator)) { + path += File.separator; + } HashMap hashMap = new HashMap<>(); String filePath = null; String fileName = null; switch (fileType) { case 1: - filePath =MicroPhotoContext.PACKAGE_NAME_MPAPP + "/data/"; + filePath =path+MicroPhotoContext.PACKAGE_NAME_MPAPP + "/data/"; fileName = "App.json"; break; case 2: filePath =MicroPhotoContext.PACKAGE_NAME_MPMASTER + "/data/"; fileName = "Master.json"; break; + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + filePath =path+MicroPhotoContext.PACKAGE_NAME_MPAPP + "/data/schedules/"; + fileName = Integer.toString(fileType - 80); + break; case 91: case 92: case 93: @@ -58,7 +77,7 @@ public class ValueTypeUtil { case 97: case 98: case 99: - filePath =MicroPhotoContext.PACKAGE_NAME_MPAPP + "/data/channels/"; + filePath =path+MicroPhotoContext.PACKAGE_NAME_MPAPP + "/data/channels/"; fileName = Integer.toString(fileType - 90) + ".json"; break; default: