initial commit.

This commit is contained in:
luocai 2024-06-18 14:27:48 +08:00
commit cd788ded0a
39 changed files with 3044 additions and 0 deletions

17
.clang-format Normal file
View File

@ -0,0 +1,17 @@
BasedOnStyle: LLVM
ObjCBlockIndentWidth: 4
IndentWidth: 4
TabWidth: 4
AccessModifierOffset: -4
ColumnLimit: 130
#模板声明后换行
AlwaysBreakTemplateDeclarations: true
# 是否允许短if单行 If true, if (a) return; 可以放到同一行
AllowShortIfStatementsOnASingleLine: true
#短句 while (true) continue; 能被放到单行。
AllowShortLoopsOnASingleLine: true
AllowShortFunctionsOnASingleLine: false

41
.gitignore vendored Normal file
View File

@ -0,0 +1,41 @@
# C++ objects and libs
*.slo
*.lo
*.o
*.a
*.la
*.lai
*.so
*.dll
*.dylib
# Qt-es
object_script.*.Release
object_script.*.Debug
*_plugin_import.cpp
/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.qbs.user
*.qbs.user.*
*.moc
moc_*.h
*.qmlc
*.jsc
Makefile*
*build-*
# Qt unit tests
target_wrapper.*
# QtCreator
*.autosave
# QtCreator Qml
*.qmlproject.user
*.qmlproject.user.*
# QtCreator CMake
CMakeLists.txt.user*
build

23
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,23 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/opt/Libraries/boost_1_84_0/include",
"${workspaceFolder}/3rdparty/arm-linux-gnueabihf/mpp/inc",
"/opt/toolchains/Libraries/opus-1.4/include",
"ThirdParty/libjpegTurbo/inc",
"ThirdParty/libalsa/inc",
"${workspaceFolder}/build/_deps/kylin-src/Universal",
"${workspaceFolder}/build/_deps/kylin-src/HttpProxy"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c17",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}

30
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,30 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "FaceAccessDebug",
"type": "cppdbg",
"request": "launch",
"miDebuggerPath": "arm-linux-gnueabihf-gdb",
"miDebuggerServerAddress": "192.168.8.122:8080",
"program": "${workspaceFolder}/build/src/gate_face/GateFace",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"logging": {
"engineLogging": false
},
"MIMode": "gdb",
"useExtendedRemote": true,
"setupCommands": [
{
"text": "set remote exec-file /sdcard/GateFace",
"description": "设置嵌入式单板加载的程序",
"ignoreFailures": false
}
]
}
]
}

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"editor.formatOnSaveMode": "modificationsIfAvailable",
"editor.formatOnSave": false,
}

32
CMakeLists.txt Normal file
View File

@ -0,0 +1,32 @@
project(FaceAccess)
cmake_minimum_required(VERSION 3.27)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(OPENSSL_ROOT /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/openssl-1.0.2q)
set(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT}/include)
set(ALSA_ROOT /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/libalsa-1.1.5)
set(ALSA_INCLUDE_DIR ${ALSA_ROOT}/include)
set(ALSA_LIBRARY_DIRS ${ALSA_ROOT}/lib)
set(FFMPEG_ROOT /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/ffmpeg-4.1.3)
set(FFMPEG_INCLUDE_DIR ${FFMPEG_ROOT}/include)
set(FFMPEG_LIBRARY_DIRS ${FFMPEG_ROOT}/lib)
set(FFMPEG_LIBRARY avcodec avdevice avfilter avformat avutil postproc swresample swscale)
set(MPP_ROOT /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/rockchip_mpp)
set(MPP_INCLUDE_DIR ${MPP_ROOT}/include)
set(MPP_LIBRARY_DIRS ${MPP_ROOT}/rk-libs)
include(FetchContent)
FetchContent_Declare(Kylin
GIT_REPOSITORY https://gitea.amass.fun/amass/Kylin.git
)
FetchContent_MakeAvailable(Kylin)
add_subdirectory(GatePass)
add_subdirectory(Record)
add_subdirectory(VoucherVerifyServer)

12
GatePass/CMakeLists.txt Normal file
View File

@ -0,0 +1,12 @@
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Boost REQUIRED COMPONENTS json)
add_executable(GatePass
main.cpp
)
target_link_libraries(GatePass
PRIVATE Universal
)

54
GatePass/main.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "BoostLog.h"
#include <boost/asio.hpp>
#include <boost/json.hpp>
#include <chrono>
#include <iostream>
#include <thread>
using boost::asio::ip::udp;
int main(int argc, char const *argv[]) {
boost::log::initialize("/data/sdcard/logs/GatePass", "/data/sdcard/logs");
LOG(info) << "app start...";
std::cout << "hello word." << std::endl;
constexpr auto txt = R"({"cmd":"gate_status","status":1,"personIn":11638,"personOut":5123,"runCount":115370})";
constexpr auto txt1 = R"({"cmd":"gate_status","status":2,"personIn":-12345,"personOut":-12345,"runCount":115370})";
constexpr auto error = R"({"cmd":"fault_and_alarm","code":91})";
constexpr auto error1 = R"({"cmd":"fault_and_alarm","code":96})";
try {
// if (argc != 2) {
// std::cerr << "Usage: client <host>" << std::endl;
// return 1;
// }
udp::endpoint point(udp::v4(), 6787);
boost::asio::io_context io_context;
udp::socket socket(io_context);
socket.open(udp::v4());
socket.send_to(boost::asio::buffer(std::string(txt)), point);
LOG(info) << "udp send: " << txt;
std::this_thread::sleep_for(std::chrono::milliseconds(150));
socket.send_to(boost::asio::buffer(std::string(error)), point);
std::this_thread::sleep_for(std::chrono::milliseconds(150));
socket.send_to(boost::asio::buffer(std::string(error1)), point);
std::this_thread::sleep_for(std::chrono::milliseconds(150));
socket.send_to(boost::asio::buffer(std::string(txt1)), point);
} catch (std::exception &e) {
std::cerr << e.what() << std::endl;
}
return 0;
return 0;
}

469
Readme.md Normal file
View File

@ -0,0 +1,469 @@
```shell
amixer sset 'Master' 50% # 设置音量
mount -o remount rw /system/ # 读写挂载
keydata get mac # 操作mac
keydata set mac 6C:5C:3D:B2:27:78
keydata set hardware HW00000011C3000R -f
MAC存储位置/data/.mac
ps -ef | egrep start-app.sh | grep -v grep | awk '{print $2}' | xargs kill -9 2 > /dev/null
ps -ef | egrep dk_uart_id_reader | grep -v grep | awk '{print $2}' | xargs kill -9 2 > /dev/null
killall start-app.sh && killall GateFace
killall dk_uart_id_reader
tail -f /sdcard/logs/b020.log
mount -o remount rw /system/ && mv /system/bin/start-app.sh /system/bin/start-app.sh.bak
mount -o remount rw /system/ && mv /system/bin/start-app.sh.bak /system/bin/start-app.sh
echo 1 > /dev/watchdog
dk_uart_id_reader
keydata set hardware HW00000011C3000U -f
keydata get hardware
/etc/init.d/S97_lunch_init
```
`script/start-app.sh`有个`write_mac()`函数生成`/data/.mac`文件。
## 隐藏页面参数设置
```
http://192.168.8.120/otherPage.php?cmd=get_other_page_params
http://192.168.8.120/otherPage.php?cmd=set_other_page_params&distanceType=1&distance=1&dynamicFeatSimTh=70&dynamicFeatImgQualityTh=90&fast_temp_sw=true&save_reg_img_sw=true&audio_out_enabled=true
```
```json
{
"cmd": "set_other_page_params",
"distanceType": 1,
"save_reg_img_sw": true,
"fast_temp_sw": true,
"dynamicFeatSimTh": 70,
"dynamicFeatImgQualityTh": 90,
"audio_out_enabled": true
}
{
"ret": 0,
"code": 200,
"message": "OK",
"data": {
"distanceType": 1,
"distance": 100,
"dynamicFeatSimTh": 70,
"dynamicFeatImgQualityTh": 90,
"fast_temp_sw": true,
"save_reg_img_sw": true,
"audio_out_enabled": true
}
}
```
## FacePass平台交互
### 连接不成功UI上图标不对
```c++
void statusbarUi::updatePlatformConnectionStatus(const int status)
{
QPixmap pm;
switch(status)
{
case UiInterfaceForBackstage::PLATFORM_CONNECTION_STATUS_DISCONNECTED:
pm.load(":/res/image/disconnect.png");
break;
case UiInterfaceForBackstage::PLATFORM_CONNECTION_STATUS_CONNECTED:
pm.load(":/res/image/display.png");
break;
case UiInterfaceForBackstage::PLATFORM_CONNECTION_STATUS_LOGGED:
pm.load(":/res/image/display.png");
break;
default:
break;
}
m_label_platform->setPixmap(pm.scaled(20, 20, Qt::KeepAspectRatio));
}
```
## 测试/开发帐号
设备业务服务器地址统一都为9002。
- FacePass开发地址http://172.16.7.16/
- 账号luocai
- 密码:.Luo19961030
- 管理员账号admin
- 管理员密码Reconova_123456
- 可视对讲阳江博物馆项目https://172.16.100.22/
- 账号admin
- 密码Reconova_123456
## 人脸识别函数调用
相关模块初始化:
```c++
GoThread::taskProc(); // 初始化摄像头
FaceGate::preLoad(); // 等待摄像头初始化完成
FaceGate::taskProc(); // 初始化算法
AntiSpoof4Rv1109::init();
AttrDetector4Rv1109::init()
DetectorImpl4Rv1109::init()
LandmarkDetectorRk::init()
```
```mermaid
classDiagram
RwRecoResult
GRecoID --|> GObject
GRecoID --* RecoIDInfo
detector
attr_detector
landmark_detector
anti_spoof
GTrackerMng *-- AntiSpoof
GTrackerMng *-- LandmarkDetector
GDetectorHeadAttr *-- AttrDetector
AntiSpoof4Rv1109 ..|> AntiSpoof
LandmarkDetectorRk ..|> LandmarkDetector
AttrDetector4Rv1109 ..|> AttrDetector
GObject <|-- GTrackerLock
GDetectorTracker *-- Detector
RecoAlgorithm *-- Detector
RecoAlgorithm *-- LandmarkDetector
ParamManage --* GoThread
UdpServer --* GoThread
GCamera --* GoThread
GDetectorTracker --* GoThread
GTrackerMng --* GoThread
GTrackerLock --* GoThread
GDetectorHeadAttr --* GoThread
GReco1vsN --* GoThread
GReco1vs1 --* GoThread
GRecoID --* GoThread
GPeInput --* GoThread
```
逻辑实现都在`src/workflow/output/decision_actuator/decision_actuator.h`
```mermaid
flowchart TB
A["ADMsg::showDisplayMsg()"]
B["View::showRecoSuccess()"]
C["GDecisionActuator::showRecoResult()"]
D["GDecisionCenter::maskProc()"]
D-->C-->B-->A
```
## 人证核验逻辑
```mermaid
flowchart TB
A-->B-->C-->D-->E-->F-->G
F-->H-->I-->J
A["UDPIDCardReader::detect()"]
B["IdReader::isNewCardAvailable()"]
C["IdReader::polling()"]
D["Peripheral::idPolling()"]
E["ReaderThread::taskProc()"]
F["ReaderThread::readerInputAvailNoti()"]
G["GPeInput::readerInputAvailCallback()"]
H["GPeInput::idReaderCallback()"]
I["GDecisionCenter::idCardReaded()"]
J["GDecisionCenter::_idCardProc()"]
```
recoUi::slotShowSceneResult()
recoUiRecognize::slotsDrawScanner()
mainUi::notifyFaceInfo()
`recoUi::slotTimer()`负责将结果页面切回待机页面
### 人证核验限制
```
http://192.168.8.127/deviceAction.php?mask_check_sw=false&no_mask_no_entry=true&mask_no_entry=false&temp_check_sw=true&temp_anomaly_no_entry=true&min=35&max=37.3&sw=false&temp_unit=0&temp_type=1&temp_audio_sw=false&temp_show_sw=true&sim_th=0&reco_distance_type=3&face_sw=true&reco_from=1&fast_access_sw=false&ic_card_sw=false&face_and_id_sw=true&yuejuma=false&succ_interval=3&fail_interval=1&helmet_sw=false&dynamic_feature=false&face_frame_sw=false&dev_local_pwd_type=1&dev_local_pwd=&health_code_sw=false&health_code_allow_stranger_sw=false&health_code_allow_access_color=1&health_code_allow_access_c19t=4&health_code_allow_access_trip=0&health_code_allow_access_abt=0&travel_card_sw=false&disable_face_sw=false&health_code_needed_tip_type=0&health_trip_fail_times=3&health_trip_need_id_sw=false&health_ui_display_time=3&access_condition=[0,1]&light_and_background=[1,1,0,0,2]&health_check_phone_num_sw=false&health_ok_display_time=3&health_white_list_free_sw=false&health_code_c19t_hours_limit=0&health_trip_show_tip_sw=false&disable_dev_setting_sw=false&temp_sensitivity=0.75&cmd=set_device&face_id_card_verify_rule={"age_limit":{"enabled":true,"precision":2,"range":[{"from":40,"to":60},{"from":30,"to":-1},{"from":-1,"to":70}]},"zone_limit":{"enabled":true,"range":["14512","78945","31103"]}}
```
## 第三方票务平台注册
```
GDecisionCenter::ReconfirmReq
RWProtocol::sendRequestOpenDoorReconfirm()
UdpParse::voucher_verify_result_proc()
RWProtocol::voucherVerifyProc()
## 读取到身份证之后
GDecisionCenter::idCardReaded()
GRecoID::onIDCard() 保存图标
ReaderInfo 保存了nv21的图像编码
GDecisionCenterm_idInfo 保存了nv21的图像编码
```
## 闸机
### 故障上报
| 功能列表 | 类别 | |
| -------------------- | ------ | -------------- |
| 闸机主机电机故障 | 故障类 | 0x21+100=133 |
| 闸机副机电机故障 | 故障类 | 0x22+100=134 |
| 闸机主机离合器故障 | 故障类 | 2003+100= 2103 |
| 闸机副机离合器故障 | 故障类 | 2004+100=2104 |
| 闸机持续开闸信号故障 | 故障类 | 0x5A+100=190 |
| 闸机红外故障 | 故障类 | 0x5B+100=191 |
| 闸机遇阻停机故障 | 故障类 | 0x0A+100=110 |
| 闸机自检失败故障 | 故障类 | 0x23+100=135 |
| 闸机固件升级失败 | 故障类 | 1001+100=1104 |
| 闸机消防告警 | 告警类 | 0x04+100=104 |
| 闸机门长久未关告警 | 告警类 | 0x5C+100=192 |
| 人员强闯告警 | 告警类 | 0x60+100=196 |
| 人员非法推杆告警 | 告警类 | 2001+100=2101 |
| 人员逆行告警 | 告警类 | 0x61+100=197 |
| 人员尾随告警 | 告警类 | 0x62+100=198 |
| 人员逗留告警 | 告警类 | 0x5F+100=195 |
### 通行记录
```protobuf
//index=593 设备上报人员通过闸机事件
message PersonAccessedReport{
Common base=1;
string alarmId=2; //消息id
int64 recordId=3; //记录id
string timestamp=4;//时间戳,格式:"yyyy-MM-dd HH:mm:ss" 举例 "2023-11-30 11:32:45"
int32 direction=5;//方向12
}
//index=594 平台应答人员通过闸机事件
message ReplyPersonAccessedReport {
Common base=1;
string alarmId=2; //消息id
int64 recordId=3; //记录id
}
```
参考人脸通行记录
```
createAccessRecord
setAccessRecordsUploadStaByRecordIdRang
deleteAccessRecordByRecordId
getAccessRecordsNumByUploadSta
GPeInput::rs485DataProc 处理闸机进出
createGateAccessRecord
# upload thread
bool checkIfSendAccessInfoData(long long curSysSec);
int pushAccessInfoListToSrv(long long curSysSec);
int uploadAccessInfo(long long curSysSec);
```
## netconfig网络管理
```mermaid
classDiagram
NetConfigThread --> NetConfig
NetConfig --> Linker
EthLinker ..|> Linker
WlanLinker ..|> Linker
SIMLinker ..|> Linker
```
wifi_connect 连接wifi耗时过长
## UI组织
```mermaid
---
title: FaceGate UI
---
classDiagram
View *-- Backstage
View *-- mainUi
mainUi ..|> UiInterfaceForBackstage
mainUi *-- SetupUi
mainUi *-- settingUi
mainUi *-- recoUi
recoUi *-- recoUiRecognize
recoUi *-- recoUiRecognizeTypeColor
recoUi *-- recoUiRecognizeTypeAd
recoUi *-- recoUiScreensaver
recoUi *-- recoUiPassword
recoUi *-- recoUiHealthCode
recoUi *-- recoUiSceneResult
class View {
viewInitBackstage();
viewCreateUi();
}
```
### SetupUi
仅当`/data/config/need_setup_wizard`文件存在时显示,流程完成时再删除此文件。
### settingUi
```mermaid
classDiagram
SettingUiPage --|> MyWidgetWithMainStyleColor
settingUiDevMngNetWifi --|> SettingUiPage
settingUiDevMngNetWifiAccPoint --|> SettingUiPage
SettingUiPage *-- QListWidget
myListWidget --|> QWidget
```
### recoUi
```mermaid
classDiagram
SceneMsgWidget --|> QWidget
MsgWidget --|> QWidget
recoUiSceneResult *-- SceneMsgWidget
recoUi *-- recoUiSceneResult
recoUiRecognize --|> PageAcceptMouseAndTouch
PageAcceptMouseAndTouch --|> WidgetWithBackstageInterface
recoUiRecognize *-- PersonWidget
recoUiRecognizeTypeBase *-- MsgWidget
recoUiRecognizeTypeBase --|> PageAcceptMouseAndTouch
recoUiRecognizeTypeColor --|> recoUiRecognizeTypeBase
recoUiRecognizeTypeAd --|> recoUiRecognizeTypeBase
```
## 硬件、固件版本说明
硬件版本说明: http://wiki.reconova.cn/pages/viewpage.action?pageId=36798802
### B045 CI构建包存放地址
```
\\172.16.2.222\瑞为版本\Test\shop\B045
```
### 测试机信息记录
扫码枪:
```
/dev/hidraw0
```
万睿面板机
```json
// MAC 6C:5C:3D:B2:27:81
{
"mt": 98,
    "ct": "HWA0310722C1110W",
    "mac": "6C5C3DB22781",
    "id": "412d00003263",
    "key": "412d9f3500c79fb3",
    "sct": "b42f6f643aedaf00"
}
```
B045 V05带屏幕
```json
{"mt": 98,"ct": "HWA0310722C1110U","mac": "6C5C3DB229A0"}
keydata set hardware HWA0310722C1110W -f
```
B033 V05裸板
```json
// MAC 6C:5C:3D:B2:27:82
{
"mt": 98,
    "ct": "HW00000011C3000U",
    "mac": "6C5C3DB22782",
    "id": "6c5c3db22782",
    "key": "6d711a5543353b5a",
    "sct": "06b619feadfae838"
}
```
B026啪啪运动裸板
```json
// keydata set hardware HW00000011C3000R -f
// keydata set mac 6C:5C:3D:B2:27:83 -f
{
"mt": 98,
    "ct": "HW00000011C3000U",
    "mac": "6C5C3DB22783"
}
// 带屏幕
{
"mt": 98,
    "ct": "HWA0310511C1000R",
    "mac": "6C5C3DB22783"
}
```

81
Record/CMakeLists.txt Normal file
View File

@ -0,0 +1,81 @@
add_executable(Record main.cpp
RkAudio.h RkAudio.cpp
OpusCodec.h OpusCodec.cpp
FFmpegResample.h FFmpegResample.cpp
RkRecorder.cpp
)
target_include_directories(Record
PRIVATE ${ALSA_INCLUDE_DIR}
PRIVATE ${MPP_INCLUDE_DIR}
PRIVATE ${MPP_INCLUDE_DIR}/rkmedia
PRIVATE /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/opus-1.4/include
PRIVATE ${FFMPEG_INCLUDE_DIR}
)
target_link_directories(Record
PRIVATE ${ALSA_LIBRARY_DIRS}
PRIVATE ${MPP_LIBRARY_DIRS}
PRIVATE ${3rdparty_ROOT}/rkap_3a/lib
PRIVATE ${FFMPEG_LIBRARY_DIRS}
PRIVATE /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/opus-1.4/lib
)
target_link_libraries(Record
PRIVATE asound
PRIVATE easymedia
PRIVATE drm
PRIVATE rkaiq
PRIVATE rockchip_mpp
PRIVATE v4l2
PRIVATE v4lconvert
PRIVATE jpeg
PRIVATE png16
PRIVATE fontconfig
PRIVATE freetype
PRIVATE expat
PRIVATE rga
PRIVATE glib-2.0
PRIVATE pcre
PRIVATE opus
PRIVATE Universal
PRIVATE stdc++fs
PRIVATE RKAP_ANR
PRIVATE RKAP_Common
PRIVATE uuid
PRIVATE dl
PRIVATE z
PRIVATE ${FFMPEG_LIBRARY}
)
add_executable(rkmedia_audio_test rkmedia_audio_test.c)
target_include_directories(rkmedia_audio_test
PRIVATE ${MPP_INCLUDE_DIR}/rkmedia
)
target_link_directories(rkmedia_audio_test
PRIVATE ${MPP_LIBRARY_DIRS}
PRIVATE ${3rdparty_ROOT}/rkap_3a/lib
PRIVATE ${ALSA_LIBRARY_DIRS}
)
target_link_libraries(rkmedia_audio_test
PRIVATE asound
PRIVATE easymedia
PRIVATE drm
PRIVATE rkaiq
PRIVATE rockchip_mpp
PRIVATE v4l2
PRIVATE v4lconvert
PRIVATE jpeg
PRIVATE rga
PRIVATE glib-2.0
PRIVATE pcre
# PRIVATE opus
# PRIVATE Universal
# PRIVATE stdc++fs
PRIVATE RKAP_ANR
PRIVATE RKAP_Common
PRIVATE dl
)

61
Record/FFmpegResample.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "FFmpegResample.h"
#include "BoostLog.h"
#include "FFmpegResample.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
}
FFmpegResample::~FFmpegResample() {
if (m_buffer != nullptr) {
delete[] m_buffer;
}
}
void FFmpegResample::initialize(int32_t sampleRateIn, int32_t channelIn, int32_t sampleRateOut, int32_t channelOut,
int32_t period) {
m_sampleRateOut = sampleRateOut;
m_channelOut = channelOut;
m_sampleRateIn = sampleRateIn;
m_channelIn = channelIn;
int64_t outChLayout = channelOut == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
int64_t inChLayout = channelIn == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
m_swrContext = swr_alloc_set_opts(nullptr, outChLayout, AV_SAMPLE_FMT_S16, sampleRateOut, inChLayout, AV_SAMPLE_FMT_S16,
sampleRateIn, 0, nullptr);
if (m_swrContext == nullptr) {
LOG(error) << "swr_alloc_set_opts() failed.";
}
m_buffer = new uint8_t[sampleRateOut / 1000 * period * channelOut * sizeof(int16_t)];
int status = swr_init(m_swrContext);
if (status < 0) {
LOG(error) << "swr_init() failed.";
}
}
FFmpegResample::Frame FFmpegResample::resample(const uint8_t *pcm, int32_t size) {
auto begin = std::chrono::system_clock::now();
FFmpegResample::Frame ret;
// 1. 输入进来的是 1channel 16khz 16bit pcm
// 2. 重采样为 2channel 48khz 16bit pcm
// 3. 编码为 opus
int32_t inSamples = size / m_channelIn / sizeof(int16_t);
int32_t outSamples = inSamples * m_sampleRateOut / m_sampleRateIn;
uint8_t *outBuffer = buffer.data();
int samples = swr_convert(m_swrContext, &outBuffer, outSamples, &pcm, inSamples);
if (samples < 0) {
char buffer[512] = {0};
LOG(error) << "avcodec_receive_frame() failed, error: " << av_make_error_string(buffer, sizeof(buffer), samples);
return ret;
}
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - begin);
ret.data = outBuffer;
ret.byteSize = samples * m_channelOut * sizeof(int16_t);
// LOG(info) << "inSamples: " << inSamples << ", samples: " << samples << ", elapsed: " << elapsed.count();
return ret;
}

32
Record/FFmpegResample.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef __FFMPEGRESAMPLE_H__
#define __FFMPEGRESAMPLE_H__
#include <array>
#include <cstdint>
#include <fstream>
struct SwrContext;
class FFmpegResample {
public:
class Frame {
public:
uint8_t *data = nullptr;
int32_t byteSize = 0;
};
~FFmpegResample();
void initialize(int32_t sampleRateIn, int32_t channelIn, int32_t sampleRateOut, int32_t channelOut,int32_t period);
Frame resample(const uint8_t *pcm, int32_t size);
private:
SwrContext *m_swrContext = nullptr;
uint8_t *m_buffer;
std::array<uint8_t, 48 * 20 * 2 * 2> buffer;
int32_t m_sampleRateOut = 48000;
int32_t m_channelOut = 2;
int32_t m_sampleRateIn = 16000;
int32_t m_channelIn = 1;
int32_t m_period = 20; // ms
};
#endif // __FFMPEGRESAMPLE_H__

68
Record/OpusCodec.cpp Normal file
View File

@ -0,0 +1,68 @@
#include "OpusCodec.h"
#include "BoostLog.h"
namespace Opus {
bool Encoder::open(int32_t samplerate, int32_t channels, uint32_t sampleSize) {
int error = 0;
uint32_t maxFrameSize = samplerate / 1000 * 60 * sampleSize * channels; // opus最大60ms一帧编码
m_buffer.resize(maxFrameSize);
m_encoder = opus_encoder_create(samplerate, channels, OPUS_APPLICATION_AUDIO, &error);
if (error != OPUS_OK || m_encoder == nullptr) {
LOG(error) << "opus_encoder_create() failed, status: " << error;
return false;
}
opus_encoder_ctl(m_encoder, OPUS_SET_VBR(0)); // 0:CBR, 1:VBR
opus_encoder_ctl(m_encoder, OPUS_SET_VBR_CONSTRAINT(true));
opus_encoder_ctl(m_encoder, OPUS_SET_BITRATE(96000));
opus_encoder_ctl(m_encoder, OPUS_SET_COMPLEXITY(8)); // 8 0~10
opus_encoder_ctl(m_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
opus_encoder_ctl(m_encoder, OPUS_SET_LSB_DEPTH(16)); // 每个采样16个bit2个byte
opus_encoder_ctl(m_encoder, OPUS_SET_DTX(0));
opus_encoder_ctl(m_encoder, OPUS_SET_INBAND_FEC(0));
return true;
}
void Encoder::close() {
if (m_encoder != nullptr) {
opus_encoder_destroy(m_encoder);
m_encoder = nullptr;
}
}
Encoder::~Encoder() {
close();
}
const Opus::Packet Encoder::encode(const int16_t *pcm, int32_t framesize) {
Packet ret;
if (m_encoder == nullptr) return ret;
ret.byteSize = opus_encode(m_encoder, pcm, framesize, m_buffer.data(), m_buffer.size());
ret.data = m_buffer.data();
LOG(info) << "framesize: " << framesize << ", record size: " << ret.byteSize;
return ret;
}
bool Decoder::open(int32_t samplerate, int32_t channels) {
int error = 0;
m_decoder = opus_decoder_create(samplerate, channels, &error);
if (error != OPUS_OK || m_decoder == NULL) {
LOG(error) << "opus_decoder_create() failed, status: " << error;
return false;
}
opus_decoder_ctl(m_decoder, OPUS_SET_LSB_DEPTH(16));
return true;
}
int32_t Decoder::decode(const uint8_t *data, int32_t dataSize, int16_t *pcm, int32_t pcmBuffer) {
int32_t decodedSize = opus_decode(m_decoder, data, dataSize, pcm, pcmBuffer, 0);
LOG(info) << "dataSize: " << dataSize << ", decodes frame size: " << decodedSize;
return decodedSize;
}
} // namespace Opus

39
Record/OpusCodec.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef __OPUSENCODER_H__
#define __OPUSENCODER_H__
#include "opus/opus.h"
#include <string>
#include <vector>
namespace Opus {
class Packet {
public:
uint8_t *data = nullptr;
uint32_t byteSize = 0;
};
class Encoder {
public:
~Encoder();
bool open(int32_t samplerate, int32_t channels, uint32_t sampleSize);
void close();
const Packet encode(const int16_t *pcm, int32_t framesize);
private:
OpusEncoder *m_encoder = nullptr;
std::vector<uint8_t> m_buffer;
};
class Decoder {
public:
bool open(int32_t samplerate, int32_t channels);
int32_t decode(const uint8_t *data, int32_t dataSize, int16_t *pcm, int32_t pcmBuffer);
private:
OpusDecoder *m_decoder = nullptr;
};
} // namespace Opus
#endif // __OPUSENCODER_H__

187
Record/RkAudio.cpp Normal file
View File

@ -0,0 +1,187 @@
#include "RkAudio.h"
#include "BoostLog.h"
#include <cstring>
#include <rkmedia/rkmedia_api.h>
namespace RkAudio {
static SAMPLE_FORMAT_E rkAiFormat(Format::SampleType sampleType) {
SAMPLE_FORMAT_E ret = RK_SAMPLE_FMT_NONE;
switch (sampleType) {
case Format::SampleType::Unknown:
ret = RK_SAMPLE_FMT_NONE;
break;
case Format::SampleType::SignedInt16:
ret = RK_SAMPLE_FMT_S16;
break;
case Format::SampleType::SignedInt:
ret = RK_SAMPLE_FMT_S32;
break;
case Format::SampleType::Float:
ret = RK_SAMPLE_FMT_FLT;
break;
default:
LOG(error) << "unkonwn sample type: " << static_cast<int>(sampleType);
ret = RK_SAMPLE_FMT_NONE;
break;
}
return ret;
}
Input::Input() {
}
Input::~Input() {
if (m_channel >= 0) {
stop();
}
}
bool Input::open(const Format &format) {
bool ret = false;
// RK_MPI_SYS_DumpChn(RK_ID_AI);
m_channel = 0;
AI_CHN_ATTR_S parameter = {0};
parameter.pcAudioNode = "default";
parameter.enAiLayout = AI_LAYOUT_MIC_REF; // remove ref channel, and output mic mono
parameter.enSampleFormat = rkAiFormat(format.sampleType);
parameter.u32Channels = format.channels;
parameter.u32SampleRate = format.sampleRate;
parameter.u32NbSamples = format.sampleRate / 1000 * format.period;
int status = RK_MPI_AI_SetChnAttr(m_channel, &parameter);
if (status) {
LOG(error) << "RK_MPI_AI_SetChnAttr() failed, status: " << status;
return ret;
}
status = RK_MPI_AI_EnableChn(m_channel);
if (status) {
LOG(error) << "RK_MPI_AI_EnableChn() failed, status: " << status;
return ret;
}
AI_TALKVQE_CONFIG_S config = {0};
status = RK_MPI_AI_GetTalkVqeAttr(m_channel, &config);
if (status) {
LOG(error) << "RK_MPI_AI_GetTalkVqeAttr() failed, status: " << status;
return ret;
}
// LOG(info) << "param file: " << config.aParamFilePath;
config.s32WorkSampleRate = format.sampleRate;
config.s32FrameSample = format.sampleRate / 1000 * format.period;
config.u32OpenMask = AI_TALKVQE_MASK_AEC | AI_TALKVQE_MASK_ANR | AI_TALKVQE_MASK_AGC;
strncpy(config.aParamFilePath, ParamFilePath, sizeof(config.aParamFilePath));
RK_MPI_AI_SetTalkVqeAttr(m_channel, &config);
fprintf(stderr, "end\n");
if (status) {
LOG(error) << "RK_MPI_AI_SetTalkVqeAttr() failed, status: " << status;
return ret;
}
status = RK_MPI_AI_EnableVqe(m_channel);
if (status) {
LOG(error) << "RK_MPI_AI_EnableVqe() failed, status: " << status;
return ret;
}
status = RK_MPI_AI_StartStream(0);
if (status) {
LOG(info) << "start AI failed, status: " << status;
return ret;
}
m_exit = false;
m_thread = std::thread(&Input::run, this);
ret = true;
return ret;
}
void Input::stop() {
m_exit = true;
if (m_thread.joinable()) m_thread.join();
if (m_channel >= 0) {
RK_MPI_AI_DisableVqe(m_channel);
RK_MPI_AI_DisableChn(m_channel);
m_channel = -1;
}
}
void Input::setDataCallback(const ReadCallback &callback) {
m_callback = callback;
}
void Input::run() {
while (!m_exit) {
auto mediaBuffer = RK_MPI_SYS_GetMediaBuffer(RK_ID_AI, 0, -1);
if (!mediaBuffer) {
LOG(error) << "RK_MPI_SYS_GetMediaBuffer() failed.";
continue;
}
if (m_callback) {
Frame frame;
frame.data = reinterpret_cast<uint8_t *>(RK_MPI_MB_GetPtr(mediaBuffer));
frame.byteSize = RK_MPI_MB_GetSize(mediaBuffer);
frame.frameSize = frame.byteSize / m_format.channels / sizeof(uint16_t);
frame.timestamp = std::chrono::system_clock::now();
m_callback(frame);
}
RK_MPI_MB_ReleaseBuffer(mediaBuffer);
}
}
Output::Output() {
}
Output::~Output() {
close();
}
bool Output::open(uint32_t sampleSize, uint32_t sampleRate, uint32_t channels) {
m_channel = 0;
AO_CHN_ATTR_S parameter = {0};
parameter.pcAudioNode = "default";
parameter.enSampleFormat = RK_SAMPLE_FMT_S16;
parameter.u32NbSamples = sampleRate / 1000 * 20;
parameter.u32SampleRate = sampleRate;
parameter.u32Channels = channels;
RK_MPI_AO_SetChnAttr(m_channel, &parameter);
RK_MPI_AO_EnableChn(m_channel);
AO_VQE_CONFIG_S config = {0};
config.s32WorkSampleRate = sampleRate;
config.s32FrameSample = parameter.u32NbSamples;
config.u32OpenMask = AO_VQE_MASK_ANR | AO_VQE_MASK_AGC;
strncpy(config.aParamFilePath, ParamFilePath, sizeof(config.aParamFilePath));
RK_MPI_AO_SetVqeAttr(m_channel, &config);
RK_MPI_AO_EnableVqe(m_channel);
return true;
}
void Output::close() {
if (m_channel >= 0) {
RK_MPI_AO_DisableVqe(m_channel);
RK_MPI_AO_DisableChn(m_channel);
m_channel = -1;
}
}
void Output::write(const uint8_t *data, uint32_t byteSize) {
if (m_channel < 0) return;
auto buffer = RK_MPI_MB_CreateAudioBuffer(byteSize, RK_FALSE);
if (buffer != nullptr) {
memcpy(RK_MPI_MB_GetPtr(buffer), data, byteSize);
RK_MPI_MB_SetSize(buffer, byteSize);
RK_MPI_SYS_SendMediaBuffer(RK_ID_AO, m_channel, buffer);
RK_MPI_MB_ReleaseBuffer(buffer);
} else {
LOG(error) << "RK_MPI_MB_CreateAudioBuffer() failed.";
}
}
} // namespace RkAudio

73
Record/RkAudio.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef __RKAUDIO_H__
#define __RKAUDIO_H__
#include <functional>
#include <thread>
namespace RkAudio {
// constexpr auto ParamFilePath="/data/sdcard/rw_3a.bin";
constexpr auto ParamFilePath = "/data/sdcard/RKAP_3A_Para.bin";
class Format {
public:
enum Endian {
BigEndian,
LittleEndian,
};
enum SampleType {
Unknown,
SignedInt16,
SignedInt,
Float,
};
SampleType sampleType = SignedInt16;
Endian byteOrder = LittleEndian;
uint32_t sampleRate = 48000;
uint32_t channels = 2;
uint32_t period = 60;
};
class Frame {
public:
uint8_t *data = nullptr;
int32_t byteSize = 0;
int32_t frameSize = 0;
std::chrono::system_clock::time_point timestamp;
};
class Input {
public:
using ReadCallback = std::function<void(const Frame &)>;
Input();
~Input();
void setDataCallback(const ReadCallback &callback);
bool open(const Format &format);
void stop();
protected:
void run();
private:
int32_t m_channel = -1;
bool m_exit = false;
std::thread m_thread;
ReadCallback m_callback;
Format m_format;
};
class Output {
public:
Output();
~Output();
bool open(uint32_t sampleSize, uint32_t sampleRate, uint32_t channels);
void close();
void write(const uint8_t *data, uint32_t byteSize);
private:
int32_t m_channel = -1;
};
} // namespace RkAudio
#endif // __RKAUDIO_H__

226
Record/RkRecorder.cpp Normal file
View File

@ -0,0 +1,226 @@
#include "BoostLog.h"
#include <fstream>
#include <rkmedia/rkmedia_api.h>
#include <signal.h>
#include <thread>
#define VQEFILE "/data/sdcard/RKAP_3A_Para.bin"
#define ALSA_PATH "default" // get from "arecord -L"
static bool quit = false;
static void sigterm_handler(int sig) {
fprintf(stderr, "signal %d\n", sig);
quit = true;
}
std::shared_ptr<std::ofstream> ofs;
void run() {
ofs = std::make_shared<std::ofstream>("/data/sdcard/test.pcm", std::ofstream::binary);
while (!quit) {
auto mediaBuffer = RK_MPI_SYS_GetMediaBuffer(RK_ID_AI, 0, -1);
if (!mediaBuffer) {
LOG(error) << "RK_MPI_SYS_GetMediaBuffer() failed.";
continue;
}
LOG(info) << "get frame, timestamp: " << RK_MPI_MB_GetTimestamp(mediaBuffer)
<< ", size: " << RK_MPI_MB_GetSize(mediaBuffer);
ofs->write((const char *)RK_MPI_MB_GetPtr(mediaBuffer), RK_MPI_MB_GetSize(mediaBuffer));
RK_MPI_MB_ReleaseBuffer(mediaBuffer);
}
ofs.reset();
}
void rkDemo() {
AI_CHN_ATTR_S ai_attr;
ai_attr.pcAudioNode = "default";
ai_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ai_attr.u32NbSamples = 16 * 20;
ai_attr.u32SampleRate = 16000;
ai_attr.u32Channels = 2;
ai_attr.enAiLayout = AI_LAYOUT_REF_MIC;
int status = RK_MPI_AI_SetChnAttr(0, &ai_attr);
status |= RK_MPI_AI_EnableChn(0);
if (status) {
LOG(error) << "enable AI[0] failed, status = " << status;
return;
}
AI_TALKVQE_CONFIG_S config = {0};
strcpy(config.aParamFilePath, VQEFILE);
config.s32WorkSampleRate = 16000;
config.s32FrameSample = 16 * 20;
config.u32OpenMask = AI_TALKVQE_MASK_AEC | AI_TALKVQE_MASK_ANR | AI_TALKVQE_MASK_AGC;
status = RK_MPI_AI_SetTalkVqeAttr(0, &config);
if (status) {
LOG(error) << "RK_MPI_AI_SetTalkVqeAttr() failed, status: " << status;
return;
}
status = RK_MPI_AI_EnableVqe(0);
if (status) {
LOG(error) << "RK_MPI_AI_EnableVqe() failed, status: " << status;
return;
}
std::thread thread(&run);
status = RK_MPI_AI_StartStream(0);
if (status) {
LOG(info) << "start AI failed, status: " << status;
return;
}
signal(SIGINT, sigterm_handler);
while (!quit) {
usleep(500000);
}
if (thread.joinable()) {
thread.join();
}
RK_MPI_AI_DisableChn(0);
}
static RK_U32 g_enWorkSampleRate = 8000;
static RK_U32 g_s32VqeFrameSample = 320; // 20ms;
// #define VQEFILE "/data/sdcard/3a.bin"
int AI_VqeProcess_AO() {
AI_TALKVQE_CONFIG_S stAiVqeTalkAttr;
AI_RECORDVQE_CONFIG_S stAiVqeRecordAttr;
AO_VQE_CONFIG_S stAoVqeAttr;
MPP_CHN_S mpp_chn_ai, mpp_chn_ao;
memset(&stAiVqeTalkAttr, 0, sizeof(AI_TALKVQE_CONFIG_S));
stAiVqeTalkAttr.s32WorkSampleRate = g_enWorkSampleRate;
stAiVqeTalkAttr.s32FrameSample = g_s32VqeFrameSample;
strcpy(stAiVqeTalkAttr.aParamFilePath, VQEFILE);
stAiVqeTalkAttr.u32OpenMask = AI_TALKVQE_MASK_AEC | AI_TALKVQE_MASK_ANR | AI_TALKVQE_MASK_AGC;
// stAiVqeTalkAttr.u32OpenMask = AI_TALKVQE_MASK_AEC ;
memset(&stAoVqeAttr, 0, sizeof(AO_VQE_CONFIG_S));
stAoVqeAttr.s32WorkSampleRate = g_enWorkSampleRate;
stAoVqeAttr.s32FrameSample = g_s32VqeFrameSample;
strcpy(stAoVqeAttr.aParamFilePath, VQEFILE);
stAoVqeAttr.u32OpenMask = AO_VQE_MASK_ANR | AO_VQE_MASK_AGC;
mpp_chn_ai.enModId = RK_ID_AI;
mpp_chn_ai.s32ChnId = 0;
mpp_chn_ao.enModId = RK_ID_AO;
mpp_chn_ao.s32ChnId = 0;
AI_CHN_ATTR_S ai_attr;
ai_attr.pcAudioNode = "default";
ai_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ai_attr.u32NbSamples = 320;
ai_attr.u32SampleRate = g_enWorkSampleRate;
ai_attr.u32Channels = 1;
ai_attr.enAiLayout = AI_LAYOUT_MIC_REF; // remove ref channel, and output mic mono
AO_CHN_ATTR_S ao_attr;
ao_attr.pcAudioNode = "default";
ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ao_attr.u32NbSamples = 320;
ao_attr.u32SampleRate = g_enWorkSampleRate;
ao_attr.u32Channels = 1;
// 1. create AI
RK_MPI_AI_SetChnAttr(mpp_chn_ai.s32ChnId, &ai_attr);
RK_MPI_AI_EnableChn(mpp_chn_ai.s32ChnId);
RK_MPI_AI_SetTalkVqeAttr(mpp_chn_ai.s32ChnId, &stAiVqeTalkAttr);
RK_MPI_AI_EnableVqe(mpp_chn_ai.s32ChnId);
// 2. create AO
RK_MPI_AO_SetChnAttr(mpp_chn_ao.s32ChnId, &ao_attr);
RK_MPI_AO_EnableChn(mpp_chn_ao.s32ChnId);
RK_MPI_AO_SetVqeAttr(mpp_chn_ao.s32ChnId, &stAoVqeAttr);
RK_MPI_AO_EnableVqe(mpp_chn_ao.s32ChnId);
// 3. bind AI-AO
RK_MPI_SYS_Bind(&mpp_chn_ai, &mpp_chn_ao);
printf("%s initial finish\n", __func__);
signal(SIGINT, sigterm_handler);
while (!quit) {
usleep(500000);
}
printf("%s exit!\n", __func__);
RK_MPI_SYS_UnBind(&mpp_chn_ai, &mpp_chn_ao);
RK_MPI_AI_DisableChn(mpp_chn_ai.s32ChnId);
RK_MPI_AO_DisableChn(mpp_chn_ao.s32ChnId);
return RK_SUCCESS;
}
int AI_VqeProcess_AO1() {
AI_TALKVQE_CONFIG_S stAiVqeTalkAttr;
AI_RECORDVQE_CONFIG_S stAiVqeRecordAttr;
AO_VQE_CONFIG_S stAoVqeAttr;
MPP_CHN_S mpp_chn_ai, mpp_chn_ao;
memset(&stAiVqeTalkAttr, 0, sizeof(AI_TALKVQE_CONFIG_S));
stAiVqeTalkAttr.s32WorkSampleRate = g_enWorkSampleRate;
stAiVqeTalkAttr.s32FrameSample = g_s32VqeFrameSample;
strcpy(stAiVqeTalkAttr.aParamFilePath, VQEFILE);
stAiVqeTalkAttr.u32OpenMask = AI_TALKVQE_MASK_AEC | AI_TALKVQE_MASK_ANR | AI_TALKVQE_MASK_AGC;
memset(&stAoVqeAttr, 0, sizeof(AO_VQE_CONFIG_S));
stAoVqeAttr.s32WorkSampleRate = g_enWorkSampleRate;
stAoVqeAttr.s32FrameSample = g_s32VqeFrameSample;
strcpy(stAoVqeAttr.aParamFilePath, VQEFILE);
stAoVqeAttr.u32OpenMask = AO_VQE_MASK_ANR | AO_VQE_MASK_AGC;
RK_MPI_SYS_Init();
mpp_chn_ai.enModId = RK_ID_AI;
mpp_chn_ai.s32ChnId = 0;
mpp_chn_ao.enModId = RK_ID_AO;
mpp_chn_ao.s32ChnId = 0;
AI_CHN_ATTR_S ai_attr;
ai_attr.pcAudioNode = ALSA_PATH;
ai_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ai_attr.u32NbSamples = 640;
ai_attr.u32SampleRate = g_enWorkSampleRate;
ai_attr.u32Channels = 1;
ai_attr.enAiLayout = AI_LAYOUT_MIC_REF; // remove ref channel, and output mic mono
AO_CHN_ATTR_S ao_attr;
ao_attr.pcAudioNode = ALSA_PATH;
ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ao_attr.u32NbSamples = 640;
ao_attr.u32SampleRate = g_enWorkSampleRate;
ao_attr.u32Channels = 1;
// 1. create AI
RK_MPI_AI_SetChnAttr(mpp_chn_ai.s32ChnId, &ai_attr);
RK_MPI_AI_EnableChn(mpp_chn_ai.s32ChnId);
RK_MPI_AI_SetTalkVqeAttr(mpp_chn_ai.s32ChnId, &stAiVqeTalkAttr);
RK_MPI_AI_EnableVqe(mpp_chn_ai.s32ChnId);
// 2. create AO
RK_MPI_AO_SetChnAttr(mpp_chn_ao.s32ChnId, &ao_attr);
RK_MPI_AO_EnableChn(mpp_chn_ao.s32ChnId);
RK_MPI_AO_SetVqeAttr(mpp_chn_ao.s32ChnId, &stAoVqeAttr);
RK_MPI_AO_EnableVqe(mpp_chn_ao.s32ChnId);
// 3. bind AI-AO
RK_MPI_SYS_Bind(&mpp_chn_ai, &mpp_chn_ao);
printf("%s initial finish\n", __func__);
signal(SIGINT, sigterm_handler);
while (!quit) {
usleep(500000);
}
printf("%s exit!\n", __func__);
RK_MPI_SYS_UnBind(&mpp_chn_ai, &mpp_chn_ao);
RK_MPI_AI_DisableChn(mpp_chn_ai.s32ChnId);
RK_MPI_AO_DisableChn(mpp_chn_ao.s32ChnId);
return RK_SUCCESS;
}

61
Record/main.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "FFmpegResample.h"
#include "OpusCodec.h"
#include <fstream>
#include <rkmedia/rkmedia_api.h>
extern int recorder_demo();
extern void rkDemo();
extern int AI_VqeProcess_AO();
extern int AI_VqeProcess_AO1();
extern void AecTest();
extern int opus_test();
int main(int argc, char **argv) {
RK_MPI_SYS_Init();
// std::ifstream ifs("/data/sdcard/test2.pcm", std::ifstream::binary);
// AlsaPcmPlayer player;
// player.open(2, 48000, 2);
// char buffer[2 * 2 * 48 * 60];
// while (ifs.read(buffer, sizeof(buffer))) {
// int size = ifs.gcount();
// player.write((const uint8_t *)buffer, size);
// }
// recorder_demo();
// rkDemo();
// AI_VqeProcess_AO();
// AI_VqeProcess_AO1();
// AecTest();
{
FFmpegResample resample;
resample.initialize(16000, 1, 48000, 2, 20);
std::ifstream ifs("/sdcard/input.pcm", std::ifstream::binary);
std::ofstream ofs("/sdcard/my_48kz.pcm", std::ifstream::binary);
char buffer[16 * 20 * 2];
while (ifs.read(buffer, sizeof(buffer))) {
auto frame = resample.resample((uint8_t *)buffer, sizeof(buffer));
if (frame.data != nullptr) {
ofs.write((char *)frame.data, frame.byteSize);
}
}
}
{
FFmpegResample resample1;
resample1.initialize(48000, 2, 16000, 1, 20);
std::ifstream ifs1("/sdcard/my_48kz.pcm", std::ifstream::binary);
std::ofstream ofs1("/sdcard/my_16kz.pcm", std::ifstream::binary);
char buffer1[48 * 20 * 2 * 2];
while (ifs1.read(buffer1, sizeof(buffer1))) {
auto frame = resample1.resample((uint8_t *)buffer1, sizeof(buffer1));
if (frame.data != nullptr) {
ofs1.write((char *)frame.data, frame.byteSize);
}
}
}
return 0;
}

411
Record/rkmedia_audio_test.c Normal file
View File

@ -0,0 +1,411 @@
// Copyright 2020 Fuzhou Rockchip Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <assert.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <rkmedia_api.h>
#define MP3_NB_SAMPLES 1024
#define MP2_NB_SAMPLES 1152
//#define ALSA_PATH "default:CARD=rockchiprk809co" // get from "arecord -L"
#define ALSA_PATH "hw:0,0" // get from "arecord -L"
#define VQEFILE "/sdcard/RKAP_3A_Para.bin"
static bool quit = false;
static void sigterm_handler(int sig) {
fprintf(stderr, "signal %d\n", sig);
quit = true;
}
FILE *fp = NULL;
static RK_U32 g_enWorkSampleRate = 16000;
static RK_U32 g_s32VqeFrameSample = 256; // 20ms;
static RK_U32 g_s32AiLayout = AI_LAYOUT_MIC_REF;
static void audio_packet_cb(MEDIA_BUFFER mb) {
printf("Get Audio Encoded packet:ptr:%p, fd:%d, size:%zu, mode:%d\n",
RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetFD(mb), RK_MPI_MB_GetSize(mb),
RK_MPI_MB_GetModeID(mb));
fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), fp);
RK_MPI_MB_ReleaseBuffer(mb);
}
static RK_VOID AI_AO() {
RK_MPI_SYS_Init();
MPP_CHN_S mpp_chn_ai, mpp_chn_ao;
mpp_chn_ai.enModId = RK_ID_AI;
mpp_chn_ai.s32ChnId = 0;
mpp_chn_ao.enModId = RK_ID_AO;
mpp_chn_ao.s32ChnId = 0;
AI_CHN_ATTR_S ai_attr;
ai_attr.pcAudioNode = ALSA_PATH;
ai_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ai_attr.u32NbSamples = 1152;
ai_attr.u32SampleRate = g_enWorkSampleRate;
ai_attr.u32Channels = 1;
ai_attr.enAiLayout = g_s32AiLayout; // chanel layout: [ref:mic]; remove
// ref, output mic mono
AO_CHN_ATTR_S ao_attr;
ao_attr.pcAudioNode = ALSA_PATH;
ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ao_attr.u32NbSamples = 1152;
ao_attr.u32SampleRate = g_enWorkSampleRate;
ao_attr.u32Channels = 1;
// 1. create AI
RK_MPI_AI_SetChnAttr(mpp_chn_ai.s32ChnId, &ai_attr);
RK_MPI_AI_EnableChn(mpp_chn_ai.s32ChnId);
RK_MPI_AI_SetVolume(mpp_chn_ai.s32ChnId, 100);
// 2. create AO
RK_MPI_AO_SetChnAttr(mpp_chn_ao.s32ChnId, &ao_attr);
RK_MPI_AO_EnableChn(mpp_chn_ao.s32ChnId);
RK_MPI_AO_SetVolume(mpp_chn_ao.s32ChnId, 100);
// 3. bind AI-AO
RK_MPI_SYS_Bind(&mpp_chn_ai, &mpp_chn_ao);
printf("%s initial finish\n", __func__);
signal(SIGINT, sigterm_handler);
while (!quit) {
usleep(500000);
}
printf("%s exit!\n", __func__);
RK_MPI_SYS_UnBind(&mpp_chn_ai, &mpp_chn_ao);
RK_MPI_AI_DisableChn(mpp_chn_ai.s32ChnId);
RK_MPI_AO_DisableChn(mpp_chn_ao.s32ChnId);
}
static RK_VOID AI_AENC_FILE(char *file_path) {
fp = fopen(file_path, "w+");
RK_MPI_SYS_Init();
MPP_CHN_S mpp_chn_ai, mpp_chn_aenc;
mpp_chn_ai.enModId = RK_ID_AI;
mpp_chn_ai.s32ChnId = 0;
mpp_chn_aenc.enModId = RK_ID_AENC;
mpp_chn_aenc.s32ChnId = 0;
AI_CHN_ATTR_S ai_attr;
ai_attr.pcAudioNode = ALSA_PATH;
ai_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ai_attr.u32NbSamples = MP3_NB_SAMPLES;
ai_attr.u32SampleRate = g_enWorkSampleRate;
ai_attr.u32Channels = 1;
ai_attr.enAiLayout = g_s32AiLayout; // chanel layout: [ref:mic]; remove
// ref, output mic mono
AENC_CHN_ATTR_S aenc_attr;
aenc_attr.enCodecType = RK_CODEC_TYPE_MP3;
aenc_attr.u32Bitrate = 64000;
aenc_attr.u32Quality = 1;
aenc_attr.stAencMP3.u32Channels = 1;
aenc_attr.stAencMP3.u32SampleRate = g_enWorkSampleRate;
// 1. create AI
RK_MPI_AI_SetChnAttr(mpp_chn_ai.s32ChnId, &ai_attr);
RK_MPI_AI_EnableChn(mpp_chn_ai.s32ChnId);
// 2. create AENC
RK_MPI_AENC_CreateChn(mpp_chn_aenc.s32ChnId, &aenc_attr);
RK_U32 ret = RK_MPI_SYS_RegisterOutCb(&mpp_chn_aenc, audio_packet_cb);
printf("ret = %d.\n", ret);
// 3. bind AI-AENC
RK_MPI_SYS_Bind(&mpp_chn_ai, &mpp_chn_aenc);
printf("%s initial finish\n", __func__);
signal(SIGINT, sigterm_handler);
while (!quit) {
usleep(500000);
}
RK_MPI_SYS_UnBind(&mpp_chn_ai, &mpp_chn_aenc);
RK_MPI_AI_DisableChn(mpp_chn_ai.s32ChnId);
RK_MPI_AENC_DestroyChn(mpp_chn_aenc.s32ChnId);
fclose(fp);
}
static RK_VOID FILE_ADEC_AO(char *file_path) {
CODEC_TYPE_E codec_type = RK_CODEC_TYPE_MP3;
RK_U32 channels = 2;
RK_U32 sample_rate = g_enWorkSampleRate;
ADEC_CHN_ATTR_S stAdecAttr;
AO_CHN_ATTR_S stAoAttr;
stAdecAttr.enCodecType = codec_type;
MPP_CHN_S mpp_chn_ao, mpp_chn_adec;
mpp_chn_ao.enModId = RK_ID_AO;
mpp_chn_ao.s32ChnId = 0;
mpp_chn_adec.enModId = RK_ID_ADEC;
mpp_chn_adec.s32ChnId = 0;
stAoAttr.u32Channels = channels;
stAoAttr.u32SampleRate = sample_rate;
stAoAttr.u32NbSamples = 1024;
stAoAttr.pcAudioNode = ALSA_PATH;
switch (codec_type) {
case RK_CODEC_TYPE_MP3:
stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16;
stAoAttr.u32NbSamples = 1024;
break;
case RK_CODEC_TYPE_MP2:
stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16;
stAoAttr.u32NbSamples = 1152;
break;
case RK_CODEC_TYPE_G711A:
stAdecAttr.stAdecG711A.u32Channels = channels;
stAdecAttr.stAdecG711A.u32SampleRate = sample_rate;
stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16;
break;
case RK_CODEC_TYPE_G711U:
stAdecAttr.stAdecG711U.u32Channels = channels;
stAdecAttr.stAdecG711U.u32SampleRate = sample_rate;
stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16;
break;
case RK_CODEC_TYPE_G726:
stAoAttr.enSampleFormat = RK_SAMPLE_FMT_S16;
break;
default:
printf("audio codec type error.\n");
return;
}
// init MPI
RK_MPI_SYS_Init();
// create ADEC
RK_MPI_ADEC_CreateChn(mpp_chn_adec.s32ChnId, &stAdecAttr);
// create AO
RK_MPI_AO_SetChnAttr(mpp_chn_ao.s32ChnId, &stAoAttr);
RK_MPI_AO_EnableChn(mpp_chn_ao.s32ChnId);
RK_MPI_SYS_Bind(&mpp_chn_adec, &mpp_chn_ao);
RK_S32 buffer_size = 20480;
FILE *read_file = fopen(file_path, "r");
if (!read_file) {
printf("ERROR: open %s failed!\n", file_path);
exit(0);
}
quit = true;
while (quit) {
MEDIA_BUFFER mb = RK_MPI_MB_CreateAudioBuffer(buffer_size, RK_FALSE);
if (!mb) {
printf("ERROR: no space left!\n");
break;
}
RK_S32 s32ReadSize = fread(RK_MPI_MB_GetPtr(mb), 1, buffer_size, read_file);
RK_MPI_MB_SetSize(mb, s32ReadSize);
RK_MPI_SYS_SendMediaBuffer(RK_ID_ADEC, mpp_chn_adec.s32ChnId, mb);
RK_MPI_MB_ReleaseBuffer(mb);
if (s32ReadSize != buffer_size) {
printf("Get end of file!\n");
break;
}
}
sleep(2);
{
// flush decoder
printf("start flush decoder.\n");
MEDIA_BUFFER mb = RK_MPI_MB_CreateAudioBuffer(buffer_size, RK_FALSE);
RK_MPI_MB_SetSize(mb, 0);
RK_MPI_SYS_SendMediaBuffer(RK_ID_ADEC, mpp_chn_adec.s32ChnId, mb);
RK_MPI_MB_ReleaseBuffer(mb);
printf("end flush decoder.\n");
}
sleep(10);
}
/* 0: close, 1: talk, 2: record */
static RK_U32 u32AiVqeType = 1;
/* 0: close, 1: open */
static RK_U32 u32AoVqeType = 1;
/******************************************************************************
* function : Ai ->VqeProcess-> Ao
******************************************************************************/
RK_S32 AI_VqeProcess_AO(RK_VOID) {
AI_TALKVQE_CONFIG_S stAiVqeTalkAttr;
AI_RECORDVQE_CONFIG_S stAiVqeRecordAttr;
AO_VQE_CONFIG_S stAoVqeAttr;
MPP_CHN_S mpp_chn_ai, mpp_chn_ao;
if (1 == u32AiVqeType) {
memset(&stAiVqeTalkAttr, 0, sizeof(AI_TALKVQE_CONFIG_S));
stAiVqeTalkAttr.s32WorkSampleRate = g_enWorkSampleRate;
stAiVqeTalkAttr.s32FrameSample = g_s32VqeFrameSample;
strcpy(stAiVqeTalkAttr.aParamFilePath, VQEFILE);
stAiVqeTalkAttr.u32OpenMask =
AI_TALKVQE_MASK_AEC | AI_TALKVQE_MASK_ANR | AI_TALKVQE_MASK_AGC;
} else if (2 == u32AiVqeType) {
memset(&stAiVqeRecordAttr, 0, sizeof(AI_RECORDVQE_CONFIG_S));
stAiVqeRecordAttr.s32WorkSampleRate = g_enWorkSampleRate;
stAiVqeRecordAttr.s32FrameSample = g_s32VqeFrameSample;
stAiVqeRecordAttr.stAnrConfig.fPostAddGain = 0;
stAiVqeRecordAttr.stAnrConfig.fGmin = -30;
stAiVqeRecordAttr.stAnrConfig.fNoiseFactor = 0.98;
stAiVqeRecordAttr.u32OpenMask = AI_RECORDVQE_MASK_ANR;
}
if (1 == u32AoVqeType) {
memset(&stAoVqeAttr, 0, sizeof(AO_VQE_CONFIG_S));
stAoVqeAttr.s32WorkSampleRate = g_enWorkSampleRate;
stAoVqeAttr.s32FrameSample = g_s32VqeFrameSample;
strcpy(stAoVqeAttr.aParamFilePath, VQEFILE);
stAoVqeAttr.u32OpenMask = AO_VQE_MASK_ANR | AO_VQE_MASK_AGC;
}
RK_MPI_SYS_Init();
mpp_chn_ai.enModId = RK_ID_AI;
mpp_chn_ai.s32ChnId = 0;
mpp_chn_ao.enModId = RK_ID_AO;
mpp_chn_ao.s32ChnId = 0;
AI_CHN_ATTR_S ai_attr;
ai_attr.pcAudioNode = ALSA_PATH;
ai_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ai_attr.u32NbSamples = 1024;
ai_attr.u32SampleRate = g_enWorkSampleRate;
ai_attr.u32Channels = 2;
ai_attr.enAiLayout = g_s32AiLayout; // remove ref channel, and output mic mono
AO_CHN_ATTR_S ao_attr;
ao_attr.pcAudioNode = ALSA_PATH;
ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
ao_attr.u32NbSamples = 1024;
ao_attr.u32SampleRate = g_enWorkSampleRate;
ao_attr.u32Channels = 2;
// 1. create AI
RK_MPI_AI_SetChnAttr(mpp_chn_ai.s32ChnId, &ai_attr);
RK_MPI_AI_EnableChn(mpp_chn_ai.s32ChnId);
//RK_MPI_AI_SetVolume(mpp_chn_ai.s32ChnId, 100);
if (1 == u32AiVqeType) {
RK_MPI_AI_SetTalkVqeAttr(mpp_chn_ai.s32ChnId, &stAiVqeTalkAttr);
RK_MPI_AI_EnableVqe(mpp_chn_ai.s32ChnId);
} else if (2 == u32AiVqeType) {
RK_MPI_AI_SetRecordVqeAttr(mpp_chn_ai.s32ChnId, &stAiVqeRecordAttr);
RK_MPI_AI_EnableVqe(mpp_chn_ai.s32ChnId);
}
// 2. create AO
RK_MPI_AO_SetChnAttr(mpp_chn_ao.s32ChnId, &ao_attr);
RK_MPI_AO_EnableChn(mpp_chn_ao.s32ChnId);
//RK_MPI_AO_SetVolume(mpp_chn_ao.s32ChnId, 100);
if (1 == u32AoVqeType) {
RK_MPI_AO_SetVqeAttr(mpp_chn_ao.s32ChnId, &stAoVqeAttr);
RK_MPI_AO_EnableVqe(mpp_chn_ao.s32ChnId);
}
// 3. bind AI-AO
RK_MPI_SYS_Bind(&mpp_chn_ai, &mpp_chn_ao);
printf("%s initial finish\n", __func__);
signal(SIGINT, sigterm_handler);
while (!quit) {
usleep(500000);
}
printf("%s exit!\n", __func__);
RK_MPI_SYS_UnBind(&mpp_chn_ai, &mpp_chn_ao);
RK_MPI_AI_DisableChn(mpp_chn_ai.s32ChnId);
RK_MPI_AO_DisableChn(mpp_chn_ao.s32ChnId);
return RK_SUCCESS;
}
static RK_VOID RKMEDIA_AUDIO_Usage() {
printf("\n\n/Usage:./rkmdia_audio <index> <sampleRate> [filePath]/ "
"[nbsamples] [ailayout]\n");
printf("\tindex and its function list below\n");
printf("\t0: start AI to AO loop\n");
printf("\t1: send audio frame to AENC channel from AI, save them\n");
printf("\t2: read audio stream from file, decode and send AO\n");
printf("\t3: start AI(VQE process), then send to AO\n");
// printf("\t4: start AI to Extern Resampler\n");
printf("\n");
printf("\tsampleRate list:\n");
printf("\t0 16000 22050 24000 32000 44100 48000\n");
printf("\n");
printf("\tfilePath represents the path of audio file to be decoded, only for "
"sample 2.\n");
printf("\tdefault filePath: /userdata/out.mp2\n");
printf("\n");
printf("\tnbsamples, for example: 160 is 10ms at 16kHz\n");
printf("\n");
printf("\tailayout:\n");
printf("\t0: AI_LAYOUT_NORMAL\n");
printf("\t1: AI_LAYOUT_MIC_REF\n");
printf("\t2: AI_LAYOUT_REF_MIC\n");
printf("\t3: AI_LAYOUT_2MIC_REF_NONE\n");
printf("\t4: AI_LAYOUT_2MIC_NONE_REF\n");
printf("\t5: AI_LAYOUT_2MIC_2REF\n");
printf("\t6: AI_LAYOUT_BUTT\n");
printf("\n");
printf("\texample: ./rkmdia_audio 0 48000 480 1 /tmp/out_aiao.mp2\n");
}
int main(int argc, char *argv[]) {
RK_U32 u32Index;
RK_CHAR *pFilePath = RK_NULL;
if (!(argc >= 3 && argc <= 6)) {
RKMEDIA_AUDIO_Usage();
return -1;
}
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-?") == 0) {
RKMEDIA_AUDIO_Usage();
return -1;
}
u32Index = atoi(argv[1]);
g_enWorkSampleRate = atoi(argv[2]);
switch (argc) {
case 6:
pFilePath = argv[5];
g_s32AiLayout = atoi(argv[4]);
g_s32VqeFrameSample = atoi(argv[3]);
break;
case 5:
g_s32AiLayout = atoi(argv[4]);
g_s32VqeFrameSample = atoi(argv[3]);
break;
case 4:
g_s32VqeFrameSample = atoi(argv[3]);
break;
default:
pFilePath = (char *)"/tmp/out.mp2";
break;
}
switch (u32Index) {
case 0:
AI_AO();
break;
case 1:
AI_AENC_FILE(pFilePath);
break;
case 2:
FILE_ADEC_AO(pFilePath);
break;
case 3:
AI_VqeProcess_AO();
default:
break;
}
return 0;
}

View File

@ -0,0 +1,26 @@
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Boost REQUIRED COMPONENTS container url json)
add_executable(VoucherVerifyServer
main.cpp
HttpSession.h HttpSession.cpp
Listener.h Listener.cpp
ResponseUtility.h ResponseUtility.cpp
ServiceLogic.h ServiceLogic.cpp
SharedState.h SharedState.cpp
WebsocketSession.h WebsocketSession.cpp
)
target_link_directories(VoucherVerifyServer
PRIVATE ${OPENSSL_LIBRARY_DIRS}
)
target_link_libraries(VoucherVerifyServer
PRIVATE Universal
PRIVATE HttpProxy
PRIVATE ${Boost_LIBRARIES}
PRIVATE ${OPENSSL_LIBRARY}
PRIVATE dl
)

View File

@ -0,0 +1,107 @@
#include "HttpSession.h"
#include "WebsocketSession.h"
#include <boost/config.hpp>
#include <boost/url/parse_path.hpp>
#include <boost/url/url_view.hpp>
#include <iostream>
#include <limits>
HttpSession::HttpSession(boost::asio::ip::tcp::socket &&socket, const std::shared_ptr<SharedState> &state)
: m_stream(std::move(socket)), m_state(state) {
// m_buffer.reserve(1000 * 1000 * 1000);
}
void HttpSession::run() {
doRead();
}
void HttpSession::errorReply(const Request &request, boost::beast::http::status status,
boost::beast::string_view message) {
using namespace boost::beast;
// invalid route
http::response<http::string_body> res{status, request.version()};
res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(http::field::content_type, "text/html");
res.keep_alive(request.keep_alive());
res.body() = message;
res.prepare_payload();
reply(std::move(res));
}
void HttpSession::doRead() {
// Construct a new parser for each message
m_parser.emplace();
// Apply a reasonable limit to the allowed size
// of the body in bytes to prevent abuse.
m_parser->body_limit(std::numeric_limits<std::uint64_t>::max());
m_parser->header_limit(std::numeric_limits<std::uint32_t>::max());
m_buffer.clear();
// Set the timeout.
m_stream.expires_after(std::chrono::seconds(30));
boost::beast::http::async_read(
m_stream, m_buffer, *m_parser,
[self{shared_from_this()}](const boost::system::error_code &ec, std::size_t bytes_transferred) {
self->onRead(ec, bytes_transferred);
});
}
void HttpSession::onRead(boost::beast::error_code ec, std::size_t) {
using namespace boost::beast;
// This means they closed the connection
if (ec == http::error::end_of_stream) {
m_stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
return;
}
if (ec) {
if (ec == boost::asio::error::operation_aborted) return;
LOG(info) << ec << " : " << ec.message();
return;
}
auto &request = m_parser->get();
// See if it is a WebSocket Upgrade
if (websocket::is_upgrade(request)) {
// Create a websocket session, transferring ownership
// of both the socket and the HTTP request.
auto session = std::make_shared<WebSocketSession>(m_stream.release_socket(), m_state);
session->run(m_parser->release());
return;
}
auto path = boost::urls::parse_path(request.target());
if (!path) {
LOG(error) << request.target() << "failed, error: " << path.error().message();
errorReply(request, http::status::bad_request, "Illegal request-target");
return;
}
boost::urls::matches matches;
auto handler = m_state->find(*path, matches);
if (handler) {
(*handler)(*this, request, matches);
} else {
std::ostringstream oss;
oss << "The resource '" << request.target() << "' was not found.";
auto message = oss.str();
errorReply(request, http::status::not_found, message);
LOG(error) << message;
}
}
void HttpSession::onWrite(boost::beast::error_code ec, std::size_t, bool close) {
if (ec) {
if (ec == boost::asio::error::operation_aborted) return;
std::cerr << "write: " << ec.message() << "\n";
}
if (close) {
// This means we should close the connection, usually because
// the response indicated the "Connection: close" semantic.
m_stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
return;
}
// Read another request
doRead();
}

View File

@ -0,0 +1,42 @@
#ifndef HTTPSESSION_H
#define HTTPSESSION_H
#include "SharedState.h"
#include "boost/beast.hpp"
#include <cstdlib>
#include <memory>
#include <optional>
/** Represents an established HTTP connection
*/
class HttpSession : public std::enable_shared_from_this<HttpSession> {
void doRead();
void onRead(boost::beast::error_code ec, std::size_t);
void onWrite(boost::beast::error_code ec, std::size_t, bool close);
// void sendResponse(boost::beast::http::response<boost::beast::http::string_body> &&response);
public:
using Request = boost::beast::http::request<boost::beast::http::string_body>;
HttpSession(boost::asio::ip::tcp::socket &&socket, std::shared_ptr<SharedState> const &state);
template <typename Response>
void reply(Response &&response) {
using ResponseType = typename std::decay_t<decltype(response)>;
auto sp = std::make_shared<ResponseType>(std::forward<decltype(response)>(response));
boost::beast::http::async_write(
m_stream, *sp, [self = shared_from_this(), sp](boost::beast::error_code ec, std::size_t bytes) {
self->onWrite(ec, bytes, sp->need_eof());
});
}
void errorReply(const Request &request, boost::beast::http::status status, boost::beast::string_view message);
void run();
private:
boost::beast::tcp_stream m_stream;
boost::beast::flat_buffer m_buffer{std::numeric_limits<std::uint32_t>::max()};
SharedStatePtr m_state;
std::optional<boost::beast::http::request_parser<boost::beast::http::string_body>> m_parser;
};
#endif // HTTPSESSION_H

View File

@ -0,0 +1,61 @@
#include "Listener.h"
#include "BoostLog.h"
#include "HttpSession.h"
#include "SharedState.h"
#include <boost/asio/strand.hpp>
#include <boost/beast/core/error.hpp>
Listener::Listener(boost::asio::io_context &ioContext, const boost::asio::ip::tcp::endpoint &endpoint,
const std::shared_ptr<SharedState> &state)
: m_ioContext(ioContext), m_acceptor(ioContext), m_state(state) {
boost::beast::error_code error;
// Open the acceptor
m_acceptor.open(endpoint.protocol(), error);
if (error) {
LOG(error) << error.message();
return;
}
// Allow address reuse
m_acceptor.set_option(boost::asio::socket_base::reuse_address(true), error);
if (error) {
LOG(error) << error.message();
return;
}
// Bind to the server address
m_acceptor.bind(endpoint, error);
if (error) {
LOG(error) << error.message();
return;
}
// Start listening for connections
m_acceptor.listen(boost::asio::socket_base::max_listen_connections, error);
if (error) {
LOG(error) << error.message();
return;
}
}
void Listener::startAccept() {
auto client = std::make_shared<boost::asio::ip::tcp::socket>(boost::asio::make_strand(m_ioContext));
m_acceptor.async_accept(*client, [self{shared_from_this()}, client](const boost::system::error_code &ec) {
self->onAccept(ec, client);
});
}
void Listener::onAccept(boost::beast::error_code errorCode, std::shared_ptr<boost::asio::ip::tcp::socket> socket) {
if (errorCode) {
if (errorCode == boost::asio::error::operation_aborted) return;
LOG(error) << errorCode.message();
} else { // Launch a new session for this connection
if (!m_state.expired()) {
auto state = m_state.lock();
auto session = std::make_shared<HttpSession>(std::move(*socket), state);
session->run();
}
}
startAccept();
}

View File

@ -0,0 +1,26 @@
#ifndef __LISTENER_H__
#define __LISTENER_H__
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast/core/error.hpp>
#include <memory>
class SharedState;
class Listener : public std::enable_shared_from_this<Listener> {
public:
Listener(boost::asio::io_context &ioContext, const boost::asio::ip::tcp::endpoint &endpoint,
const std::shared_ptr<SharedState> &state);
void startAccept();
protected:
void onAccept(boost::beast::error_code errorCode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
private:
boost::asio::io_context &m_ioContext;
boost::asio::ip::tcp::acceptor m_acceptor;
std::weak_ptr<SharedState> m_state;
};
#endif // __LISTENER_H__

View File

@ -0,0 +1,51 @@
#include "ResponseUtility.h"
#include "boost/beast.hpp"
namespace ResponseUtility {
std::string_view mimeType(std::string_view path) {
using boost::beast::iequals;
auto const ext = [&path] {
auto const pos = path.rfind(".");
if (pos == std::string_view::npos) return std::string_view{};
return path.substr(pos);
}();
if (iequals(ext, ".pdf")) return "Application/pdf";
if (iequals(ext, ".htm")) return "text/html";
if (iequals(ext, ".html")) return "text/html";
if (iequals(ext, ".php")) return "text/html";
if (iequals(ext, ".css")) return "text/css";
if (iequals(ext, ".txt")) return "text/plain";
if (iequals(ext, ".js")) return "application/javascript";
if (iequals(ext, ".json")) return "application/json";
if (iequals(ext, ".xml")) return "application/xml";
if (iequals(ext, ".swf")) return "application/x-shockwave-flash";
if (iequals(ext, ".flv")) return "video/x-flv";
if (iequals(ext, ".png")) return "image/png";
if (iequals(ext, ".jpe")) return "image/jpeg";
if (iequals(ext, ".jpeg")) return "image/jpeg";
if (iequals(ext, ".jpg")) return "image/jpeg";
if (iequals(ext, ".gif")) return "image/gif";
if (iequals(ext, ".bmp")) return "image/bmp";
if (iequals(ext, ".ico")) return "image/vnd.microsoft.icon";
if (iequals(ext, ".tiff")) return "image/tiff";
if (iequals(ext, ".tif")) return "image/tiff";
if (iequals(ext, ".svg")) return "image/svg+xml";
if (iequals(ext, ".svgz")) return "image/svg+xml";
return "application/text";
}
std::string pathCat(std::string_view base, std::string_view path) {
if (base.empty()) return std::string(path);
std::string result(base);
char constexpr path_separator = '/';
if (result.back() == path_separator && path.front() == path_separator) {
result.resize(result.size() - 1);
} else if (result.back() != path_separator && path.front() != path_separator) {
result.append("/");
}
result.append(path.data(), path.size());
return result;
}
} // namespace ResponseUtility

View File

@ -0,0 +1,19 @@
#ifndef RESPONSEUTILITY_H
#define RESPONSEUTILITY_H
#include <string_view>
namespace ResponseUtility {
/**
* @brief Return a reasonable mime type based on the extension of a file.
*/
std::string_view mimeType(std::string_view path);
/**
* @brief Append an HTTP rel-path to a local filesystem path.The returned path is normalized for the
* platform.
*/
std::string pathCat(std::string_view base, std::string_view path);
} // namespace ResponseUtility
#endif // RESPONSEUTILITY_H

View File

@ -0,0 +1,34 @@
#include "ServiceLogic.h"
#include <sstream>
namespace ServiceLogic {
boost::beast::http::response<boost::beast::http::string_body>
notFound(const boost::beast::http::request<boost::beast::http::string_body> &request) {
using namespace boost::beast;
http::response<http::string_body> res{http::status::not_found, request.version()};
res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(http::field::content_type, "text/html");
res.keep_alive(request.keep_alive());
std::ostringstream oss;
oss << "The resource '" << request.target() << "' was not found.";
res.body() = oss.str();
res.prepare_payload();
return res;
}
boost::beast::http::response<boost::beast::http::string_body>
serverError(const boost::beast::http::request<boost::beast::http::string_body> &request,
std::string_view errorMessage) {
using namespace boost::beast;
http::response<http::string_body> res{http::status::internal_server_error, request.version()};
res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(http::field::content_type, "text/html");
res.keep_alive(request.keep_alive());
std::ostringstream oss;
oss << "An error occurred: '" << errorMessage << "'";
res.body() = oss.str();
res.prepare_payload();
return res;
}
} // namespace ServiceLogic

View File

@ -0,0 +1,42 @@
#ifndef SERVICELOGIC_H
#define SERVICELOGIC_H
#include "ResponseUtility.h"
#include "SharedState.h"
#include "StringUtility.h"
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/http/vector_body.hpp>
#include <boost/beast/version.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <fstream>
using StringRequest = boost::beast::http::request<boost::beast::http::string_body>;
namespace ServiceLogic {
// Returns a not found response
boost::beast::http::response<boost::beast::http::string_body>
notFound(const boost::beast::http::request<boost::beast::http::string_body> &request);
// Returns a server error response
boost::beast::http::response<boost::beast::http::string_body>
serverError(const boost::beast::http::request<boost::beast::http::string_body> &request, std::string_view errorMessage);
template <class ResponseBody, class RequestBody>
boost::beast::http::response<ResponseBody> make_200(const boost::beast::http::request<RequestBody> &request,
typename ResponseBody::value_type body,
boost::beast::string_view content) {
boost::beast::http::response<ResponseBody> response{boost::beast::http::status::ok, request.version()};
response.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
response.set(boost::beast::http::field::content_type, content);
response.body() = body;
response.prepare_payload();
response.keep_alive(request.keep_alive());
return response;
}
}; // namespace ServiceLogic
#endif // SERVICELOGIC_H

View File

@ -0,0 +1,87 @@
#include "SharedState.h"
#include "HttpSession.h"
#include "ServiceLogic.h"
#include "WebsocketSession.h"
#include <boost/json/object.hpp>
#include <boost/json/serialize.hpp>
#include <boost/json/parse.hpp>
SharedState::SharedState(boost::asio::io_context &ioContext)
: m_ioContext(ioContext), m_router{std::make_shared<boost::urls::router<Handler>>()} {
m_router->insert("/", [](HttpSession &session, const Request &request, const boost::urls::matches &matches) {
// Send content message to client and wait to receive next request
session.reply(ServiceLogic::make_200<boost::beast::http::string_body>(request, "Main page\n", "text/html"));
});
m_router->insert("/device/access/valid",[](HttpSession &session, const Request &request, const boost::urls::matches &matches) {
LOG(info) << "request body: " << request.body();
auto requestValue = boost::json::parse(request.body());
auto &requestObject = requestValue.as_object();
boost::json::object root;
root["code"] = 0;
boost::json::object data;
data["sid"]=requestObject.at("sid").as_string();
data["vid"]=requestObject.at("sid").as_string();
data["pass"]=1;
data["code"]=0;
data["voucherPerson"]="amass";
data["voucherMsg"]="测试验票通过";
data["register"]=1;
data["effectTime"]="2024-01-15 00:30:35";
data["expireTime"]="2024-01-20 19:30:35";
root["data"] = std::move(data);
using namespace boost::beast;
http::response<http::string_body> res{http::status::ok, request.version()};
res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(http::field::content_type, "application/json");
res.keep_alive(request.keep_alive());
res.body() = boost::json::serialize(root);
res.prepare_payload();
session.reply(std::move(res));
});
m_router->insert(
"/device/access/report", [](HttpSession &session, const Request &request, const boost::urls::matches &matches) {
// Send content message to client and wait to receive next request
session.reply(ServiceLogic::make_200<boost::beast::http::string_body>(request, "Main page\n", "text/html"));
});
}
const SharedState::Handler *SharedState::find(boost::urls::segments_encoded_view path,
boost::urls::matches_base &matches) const noexcept {
return m_router->find(path, matches);
}
void SharedState::join(WebSocketSession *session) {
std::lock_guard<std::mutex> lock(mutex_);
sessions_.insert(session);
}
void SharedState::leave(WebSocketSession *session) {
std::lock_guard<std::mutex> lock(mutex_);
sessions_.erase(session);
}
void SharedState::send(std::string message) {
// Put the message in a shared pointer so we can re-use it for each client
auto const ss = std::make_shared<std::string const>(std::move(message));
// Make a local list of all the weak pointers representing
// the sessions, so we can do the actual sending without
// holding the mutex:
std::vector<std::weak_ptr<WebSocketSession>> v;
{
std::lock_guard<std::mutex> lock(mutex_);
v.reserve(sessions_.size());
for (auto p : sessions_) v.emplace_back(p->weak_from_this());
}
// For each session in our local list, try to acquire a strong
// pointer. If successful, then send the message on that session.
for (auto const &wp : v)
if (auto sp = wp.lock()) sp->send(ss);
}

View File

@ -0,0 +1,50 @@
#ifndef SHAREDSTATE_H
#define SHAREDSTATE_H
#include "router.hpp"
#include <boost/asio/io_context.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/smart_ptr.hpp>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_set>
class HttpSession;
class WebSocketSession;
// Represents the shared server state
class SharedState : public std::enable_shared_from_this<SharedState> {
// This mutex synchronizes all access to sessions_
std::mutex mutex_;
// Keep a list of all the connected clients
std::unordered_set<WebSocketSession *> sessions_;
public:
using Request = boost::beast::http::request<boost::beast::http::string_body>;
using Handler = std::function<void(HttpSession &, const Request &, const boost::urls::matches &)>;
SharedState(boost::asio::io_context &ioContext);
const Handler *find(boost::urls::segments_encoded_view path, boost::urls::matches_base &matches) const noexcept;
void join(WebSocketSession *session);
void leave(WebSocketSession *session);
/**
* @brief Broadcast a message to all websocket client sessions
*/
void send(std::string message);
private:
boost::asio::io_context &m_ioContext;
std::shared_ptr<boost::urls::router<Handler>> m_router;
std::string m_docRoot;
std::string m_galleryRoot = "/root/photos";
std::string m_fileRoot;
};
using SharedStatePtr = std::shared_ptr<SharedState>;
#endif // SHAREDSTATE_H

View File

@ -0,0 +1,83 @@
#include "WebsocketSession.h"
#include <iostream>
WebSocketSession::WebSocketSession(boost::asio::ip::tcp::socket &&socket, std::shared_ptr<SharedState> const &state)
: m_ws(std::move(socket)), m_state(state) {}
WebSocketSession::~WebSocketSession() {
// Remove this session from the list of active sessions
m_state->leave(this);
}
void WebSocketSession::onAccept(boost::beast::error_code ec) {
// Handle the error, if any
if (ec) {
if (ec == boost::asio::error::operation_aborted || ec == boost::beast::websocket::error::closed) return;
std::cerr << "accept: " << ec.message() << "\n";
return;
}
// Add this session to the list of active sessions
m_state->join(this);
// Read a message
m_ws.async_read(m_buffer, boost::beast::bind_front_handler(&WebSocketSession::on_read, shared_from_this()));
}
void WebSocketSession::on_read(boost::beast::error_code ec, std::size_t) {
// Handle the error, if any
if (ec) {
// Don't report these
if (ec == boost::asio::error::operation_aborted || ec == boost::beast::websocket::error::closed) return;
LOG(error) << "read: " << ec.message();
return;
}
LOG(info) << boost::beast::buffers_to_string(m_buffer.data());
// Send to all connections
m_state->send(boost::beast::buffers_to_string(m_buffer.data()));
// Clear the buffer
m_buffer.consume(m_buffer.size());
// Read another message
m_ws.async_read(m_buffer, boost::beast::bind_front_handler(&WebSocketSession::on_read, shared_from_this()));
}
void WebSocketSession::send(std::shared_ptr<std::string const> const &ss) {
// Post our work to the strand, this ensures
// that the members of `this` will not be
// accessed concurrently.
m_ws.text();
boost::asio::post(m_ws.get_executor(),
boost::beast::bind_front_handler(&WebSocketSession::onSend, shared_from_this(), ss));
}
void WebSocketSession::onSend(std::shared_ptr<std::string const> const &ss) {
// Always add to queue
m_queue.push_back(ss);
// Are we already writing?
if (m_queue.size() > 1) return;
// We are not currently writing, so send this immediately
m_ws.async_write(boost::asio::buffer(*m_queue.front()),
boost::beast::bind_front_handler(&WebSocketSession::on_write, shared_from_this()));
}
void WebSocketSession::on_write(boost::beast::error_code ec, std::size_t) {
// Handle the error, if any
if (ec) {
// Don't report these
if (ec == boost::asio::error::operation_aborted || ec == boost::beast::websocket::error::closed) return;
std::cerr << "write: " << ec.message() << "\n";
return;
}
// Remove the string from the queue
m_queue.erase(m_queue.begin());
// Send the next message if any
if (!m_queue.empty())
m_ws.async_write(boost::asio::buffer(*m_queue.front()),
boost::beast::bind_front_handler(&WebSocketSession::on_write, shared_from_this()));
}

View File

@ -0,0 +1,56 @@
#ifndef WEBSOCKETSESSION_H
#define WEBSOCKETSESSION_H
#include "BoostLog.h"
#include "SharedState.h"
#include <boost/beast.hpp>
#include <cstdlib>
#include <memory>
#include <string>
#include <vector>
class SharedState;
/**
* @brief Represents an active WebSocket connection to the server
*/
class WebSocketSession : public std::enable_shared_from_this<WebSocketSession> {
public:
WebSocketSession(boost::asio::ip::tcp::socket &&socket, std::shared_ptr<SharedState> const &state);
~WebSocketSession();
template <class Body, class Allocator>
void run(boost::beast::http::request<Body, boost::beast::http::basic_fields<Allocator>> request) {
using namespace boost::beast::http;
using namespace boost::beast::websocket;
// Set suggested timeout settings for the websocket
m_ws.set_option(stream_base::timeout::suggested(boost::beast::role_type::server));
// Set a decorator to change the Server of the handshake
m_ws.set_option(stream_base::decorator([](response_type &response) {
response.set(field::server, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-chat-multi");
}));
// LOG(info) << request.base().target(); //get path
// Accept the websocket handshake
m_ws.async_accept(request, [self{shared_from_this()}](boost::beast::error_code ec) { self->onAccept(ec); });
}
// Send a message
void send(std::shared_ptr<std::string const> const &ss);
protected:
void onAccept(boost::beast::error_code ec);
void on_read(boost::beast::error_code ec, std::size_t bytes_transferred);
void on_write(boost::beast::error_code ec, std::size_t bytes_transferred);
void onSend(std::shared_ptr<std::string const> const &ss);
private:
boost::beast::flat_buffer m_buffer;
boost::beast::websocket::stream<boost::beast::tcp_stream> m_ws;
std::shared_ptr<SharedState> m_state;
std::vector<std::shared_ptr<std::string const>> m_queue;
};
#endif // WEBSOCKETSESSION_H

View File

@ -0,0 +1,17 @@
#include "BoostLog.h"
#include "IoContext.h"
#include "Listener.h"
#include "SharedState.h"
int main(int argc, char const *argv[])
{
using namespace boost::asio::ip;
boost::log::initialize("/data/sdcard/logs/VoucherVerifyServer", "/data/sdcard/logs");
auto ioContext = Amass::Singleton<IoContext>::instance<Amass::Construct>(std::thread::hardware_concurrency());
auto sharedState = Amass::Singleton<SharedState>::instance<Amass::Construct>(*ioContext->ioContext());
auto listener =
std::make_shared<Listener>(*ioContext->ioContext(), tcp::endpoint{tcp::v4(), 3392}, sharedState);
listener->startAccept();
ioContext->run<IoContext::Mode::Synchronous>();
return 0;
}

230
resources/build.sh Executable file
View File

@ -0,0 +1,230 @@
#!/bin/bash
cross_compile=true
build_hisi=false
debug_deploy=true
TARGET_IP="172.16.103.79"
TARGET_PATH="/system/bin"
base_path=$(pwd)
libraries_root="/opt/Libraries"
if [ $base_path==/home/* ]; then
build_path=${base_path}/build
else
build_path=/tmp/build
fi
echo "build directory: $build_path"
function cmake_scan() {
if [ $cross_compile = true ]; then
toolchain_file=-DCMAKE_TOOLCHAIN_FILE=resources/cmake/toolchain.cmake
else
toolchain_file="-DCROSS_BUILD=OFF"
fi
if [ ! -d ${build_path} ]; then
mkdir ${build_path}
fi
if [ $debug_deploy = true ]; then
build_debug=-DCMAKE_BUILD_TYPE=Debug
else
build_debug=""
fi
cmake \
-G Ninja \
-S ${base_path} \
-B ${build_path} \
$build_debug \
$toolchain_file
}
function qtmoc(){
/opt/Qt/5.9.4/gcc_64/bin/moc src/qt/mainUi/mainUi.h -o src/qt/mainUi/moc_mainUi.cpp
/opt/Qt/5.9.4/gcc_64/bin/moc src/qt/utility/UiTools.h -o src/qt/utility/moc_UiTools.cpp
/opt/Qt/5.9.4/gcc_64/bin/moc src/qt/videoChatUi/CallWaittingPage.h -o src/qt/videoChatUi/moc_CallWaittingPage.cpp
/opt/Qt/5.9.4/gcc_64/bin/moc src/qt/videoChatUi/DialPadPage.h -o src/qt/videoChatUi/moc_DialPadPage.cpp
/opt/Qt/5.9.4/gcc_64/bin/moc src/qt/videoChatUi/VideoChatPage.h -o src/qt/videoChatUi/moc_VideoChatPage.cpp
/opt/Qt/5.9.4/gcc_64/bin/moc src/qt/recoUi/recoUi.h -o src/qt/recoUi/moc_recoUi.cpp
/opt/Qt/5.9.4/gcc_64/bin/moc src/qt/recoUi/recoUiRecognize.h -o src/qt/recoUi/moc_recoUiRecognize.cpp
/opt/Qt/5.9.4/gcc_64/bin/moc src/qt/utility/DndModeCountDownItem.h -o src/qt/utility/moc_DndModeCountDownItem.cpp
}
function build() {
if [ ! -f "${build_path}/CMakeCache.txt" ]; then
cmake_scan
fi
if [ $? -ne 0 ]; then
exit 1
fi
cmake \
--build ${build_path} \
--target all
if [ $? -ne 0 ]; then
exit 1
fi
if [ $cross_compile = true ]; then
deploy
fi
}
function deploy() {
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/system/lib
if [ -n "$1" ]; then
TARGET_IP=$1
fi
if [ $debug_deploy = true ]; then
TARGET_PATH="/data/sdcard"
fi
echo "deploy to target $TARGET_IP, path: ${TARGET_PATH} ..."
ssh -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} "mount -o remount rw /system/"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "killall start-app.sh; pgrep -f GateFace | xargs kill -s 9"
ssh -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} "pgrep -f VoucherVerifyServer | xargs kill -s 9"
ssh -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} "pgrep -f Record | xargs kill -s 9"
scp -i ~/Projects/ssh_host_rsa_key_ok ${build_path}/src/gate_face/GateFace root@${TARGET_IP}:${TARGET_PATH}
# scp -i ~/Projects/ssh_host_rsa_key_ok ${build_path}/ThirdParty/librwSrvProtocol.so root@${TARGET_IP}:/system/lib/
scp -i resources/ssh_host_rsa_key_ok ${build_path}/Tools/Record/Record root@${TARGET_IP}:/sdcard/
scp -i resources/ssh_host_rsa_key_ok ${build_path}/Tools/Record/rkmedia_audio_test root@${TARGET_IP}:/sdcard/
scp -i resources/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/mpp/rk-libs/libeasymedia.so.1.0.1 root@${TARGET_IP}:/system/lib/
ssh -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} "sync"
if [ $debug_deploy != true ]; then
echo "reboot remote device."
ssh -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} "reboot"
fi
}
function clean() {
if [ -d ${build_path} ]; then
rm -fr ${build_path}
fi
}
function copy_ssh() {
if [ -n "$1" ]; then
TARGET_IP=$1
fi
SSH_KEY=$(cat ~/.ssh/id_rsa.pub)
echo "ssh copy id to ${TARGET_IP} ..."
# chmod 600 ./resources/ssh_host_rsa_key_ok
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "mount -o remount rw /oem/;mount -o remount rw /system/; mount -o remount rw /"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "if [ ! -f /usr/bin/scp ]; then cp /oem/bin/scp /usr/bin/; else echo 'scp exist'; fi"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "echo ${SSH_KEY} >> /oem/.ssh/authorized_keys"
scp -i ~/Projects/ssh_host_rsa_key_ok /mnt/e/Documents/gdb-rk root@${TARGET_IP}:/sdcard/gdb
scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/mpp/rk-libs/libeasymedia.so.1.0.1 root@${TARGET_IP}:/usr/lib/
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/toolchains/linux-x86/arm/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/bin/gdbserver root@${TARGET_IP}:/sdcard
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_url* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_log* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_program_options* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_date_time* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_filesystem* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_thread* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_regex* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_chrono* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_atomic* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_container* root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_84_0/lib/libboost_json* root@${TARGET_IP}:/system/lib
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "sync"
}
function deploy_old(){
if [ -n "$1" ]; then
TARGET_IP=$1
fi
if [ $debug_deploy = true ]; then
TARGET_PATH="/data/sdcard"
fi
# qtmoc
# if [ $? -ne 0 ]; then
# exit 1
# fi
if [ $build_hisi = true ]; then
docker run --rm -v /opt:/opt -v .:$(pwd) -w $(pwd) b020_dev make server_protocol
docker run --rm -v /opt:/opt -v .:$(pwd) -w $(pwd) b020_dev make
else
# docker run --rm -v .:$(pwd) -w $(pwd) b020_dev protoc --nanopb_out=./ 3rdparty/rwSrvProtocol/PacketModel_all.proto
# make PLATFORM=rv1109 server_protocol
# if [ $? -ne 0 ]; then
# exit 1
# fi
make PLATFORM=rv1109 -j4
fi
if [ $? -ne 0 ]; then
exit 1
fi
echo "deply to $TARGET_IP, path $TARGET_PATH"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "mount -o remount rw /; mount -o remount rw /system/"
if [ $build_hisi = true ]; then
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "killall start-app.sh; killall GateFace; sleep 1"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "killall start-app.sh; killall GateFace"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "killall start-app.sh; killall GateFace"
else
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "killall start-app.sh; killall GateFace; killall netconfig"
fi
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/mpp/rk-libs/libeasymedia.so.1.0.1 root@${TARGET_IP}:/usr/lib/
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/rkap_3a/lib/libRKAP_3A.so root@${TARGET_IP}:/system/lib/
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/rkap_3a/lib/libRKAP_Common.so root@${TARGET_IP}:/system/lib/
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/rkap_3a/lib/libRKAP_ANR.so root@${TARGET_IP}:/system/lib/
# scp -r -i ~/Projects/ssh_host_rsa_key_ok src/web/php/*.php root@${TARGET_IP}:/system/www/web/
scp -i ~/Projects/ssh_host_rsa_key_ok ./build/GateFace root@${TARGET_IP}:$TARGET_PATH
# scp -i ~/Projects/ssh_host_rsa_key_ok ./build/netconfig root@${TARGET_IP}:$TARGET_PATH
# scp -i ~/Projects/ssh_host_rsa_key_ok ./src/netlink/libRwNetlink.so root@${TARGET_IP}:/system/lib/
if [ $build_hisi = true ]; then
echo "."
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "reboot"
else
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/librwhscheckpw/lib/librwhscheckpw.so root@${TARGET_IP}:/system/lib/
scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/rwStageProtocol/lib/librwSrvProtocol.so root@${TARGET_IP}:/system/lib/
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/ffmepg/lib/libavdevice.so.58 root@${TARGET_IP}:/system/lib/
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/ffmepg/lib/libavfilter.so.7 root@${TARGET_IP}:/system/lib/
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/ffmepg/lib/libavformat.so.58 root@${TARGET_IP}:/system/lib/
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/ffmepg/lib/libavutil.so.56 root@${TARGET_IP}:/system/lib/
# scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/ffmepg/lib/libswresample.so.3 root@${TARGET_IP}:/system/lib/
fi
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "sync"
if [ $debug_deploy = false ]; then
if [ $build_hisi = false ]; then
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "echo 1 > /dev/watchdog"
fi
fi
}
function main() {
local cmd=$1
shift 1
case $cmd in
build)
build
;;
scan)
cmake_scan
;;
clean)
clean
;;
old)
deploy_old $@
;;
ssh)
copy_ssh $@
;;
*)
build
;;
esac
}
main $@

View File

@ -0,0 +1,41 @@
add_library(Qt5::Core SHARED IMPORTED)
set_target_properties(Qt5::Core PROPERTIES
IMPORTED_LOCATION ${QT5_ROOT}/lib/libQt5Core.so
INTERFACE_INCLUDE_DIRECTORIES ${QT5_ROOT}/include/QtCore
)
target_include_directories(Qt5::Core
INTERFACE ${QT5_ROOT}/include
)
target_link_libraries(Qt5::Core
INTERFACE rga
INTERFACE drm
INTERFACE z
INTERFACE png16
INTERFACE pcre
INTERFACE pcre2-16
INTERFACE gthread-2.0
INTERFACE glib-2.0
)
add_library(Qt5::Gui SHARED IMPORTED)
set_target_properties(Qt5::Gui PROPERTIES
IMPORTED_LOCATION ${QT5_ROOT}/lib/libQt5Gui.so
INTERFACE_INCLUDE_DIRECTORIES ${QT5_ROOT}/include/QtGui
)
add_library(Qt5::Widgets SHARED IMPORTED)
set_target_properties(Qt5::Widgets PROPERTIES
IMPORTED_LOCATION ${QT5_ROOT}/lib/libQt5Widgets.so
INTERFACE_INCLUDE_DIRECTORIES ${QT5_ROOT}/include/QtWidgets
)
target_include_directories(Qt5::Widgets
INTERFACE ${QT5_ROOT}/include
)
add_library(Qt5::Network SHARED IMPORTED)
set_target_properties(Qt5::Network PROPERTIES
IMPORTED_LOCATION ${QT5_ROOT}/lib/libQt5Network.so
INTERFACE_INCLUDE_DIRECTORIES ${QT5_ROOT}/include/QtNetwork
)

View File

@ -0,0 +1,25 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
# which compilers to use for C and C++
set(CMAKE_C_COMPILER arm-himix200-linux-gcc)
set(CMAKE_CXX_COMPILER arm-himix200-linux-g++)
# where is the target environment located
# set(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc
# /home/alex/mingw-install)
# adjust the default behavior of the FIND_XXX() commands:
# search programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# search headers and libraries in the target environment
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_C_COMPILER_FORCED ON)
set(CMAKE_CXX_COMPILER_FORCED ON)
string(APPEND CMAKE_CXX_FLAGS " -mfloat-abi=softfp -mfpu=neon")
set(BOOST_ROOT /opt/toolchains/Libraries/boost_1_83_0)

View File

@ -0,0 +1,22 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
# which compilers to use for C and C++
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# where is the target environment located
# set(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc
# /home/alex/mingw-install)
# adjust the default behavior of the FIND_XXX() commands:
# search programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# search headers and libraries in the target environment
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
string(APPEND CMAKE_CXX_FLAGS " -mfloat-abi=hard -mfpu=neon")
set(BOOST_ROOT /opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/lib/boost_1_85_0)

77
resources/deploy.sh Normal file
View File

@ -0,0 +1,77 @@
#!/bin/bash
#
TARGET_IP="192.168.8.108"
function build() {
if [ -n "$1" ]; then
TARGET_IP=$1
fi
make PLATFORM=rv1109 server_protocol
make PLATFORM=rv1109
if [ $? -ne 0 ]; then
exit 1
fi
echo "deply to $TARGET_IP"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "mount -o remount rw /system/"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "killall start-app.sh; pkill -f GateFace"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "pgrep -f netconfig | xargs kill -s 9"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "pgrep -f voucher_verify | xargs kill -s 9"
scp -r -i ~/Projects/ssh_host_rsa_key_ok src/web/php/*.php root@${TARGET_IP}:/system/www/web/
scp -i ~/Projects/ssh_host_rsa_key_ok ./build/GateFace root@${TARGET_IP}:/system/bin
scp -i ~/Projects/ssh_host_rsa_key_ok ./build/voucher_verify root@${TARGET_IP}:/system/bin
scp -i ~/Projects/ssh_host_rsa_key_ok ./src/netlink/libRwNetlink.so root@${TARGET_IP}:/system/lib
scp -i ~/Projects/ssh_host_rsa_key_ok ./build/netconfig root@${TARGET_IP}:/system/bin
scp -i ~/Projects/ssh_host_rsa_key_ok ./3rdparty/arm-linux-gnueabihf/rwStageProtocol/lib/librwSrvProtocol.so root@${TARGET_IP}:/system/lib/
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "sync"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "echo 1 > /dev/watchdog"
}
function build_debug() {
make PLATFORM=rv1109 server_protocol
scp -r -i ~/Projects/ssh_host_rsa_key_ok 3rdparty/arm-linux-gnueabihf/rwStageProtocol/lib/librwSrvProtocol.so root@${TARGET_IP}:/system/lib/
make PLATFORM=rv1109
echo "deply to /sdcard"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "mount -o remount rw /system/"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "pkill -f start-app.sh & pkill -f GateFace & pkill -f dk_uart_id_reader"
scp -r -i ~/Projects/ssh_host_rsa_key_ok src/web/php/*.php root@${TARGET_IP}:/system/www/web/
scp -i ~/Projects/ssh_host_rsa_key_ok ./build/GateFace root@${TARGET_IP}:/sdcard
scp -i ~/Projects/ssh_host_rsa_key_ok ./build/ryxconnector root@${TARGET_IP}:/sdcard
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "sync"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "amixer sset 'Master' 80%"
}
function copy_ssh() {
TARGET_IP=$1
SSH_KEY=$(cat ~/.ssh/id_rsa.pub)
echo "ssh copy id to ${TARGET_IP} ..."
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "mount -o remount rw /oem/; mount -o remount rw /"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "if [ ! -f /usr/bin/scp ]; then cp /oem/bin/scp /usr/bin/; else echo 'scp exist'; fi"
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "echo ${SSH_KEY} >> /oem/.ssh/authorized_keys"
scp -i ~/Projects/ssh_host_rsa_key_ok /mnt/e/Documents/gdb-rk root@${TARGET_IP}:/sdcard
scp -i ~/Projects/ssh_host_rsa_key_ok /opt/toolchains/linux-x86/arm/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/bin/gdbserver root@${TARGET_IP}:/sdcard
ssh -i ~/Projects/ssh_host_rsa_key_ok root@${TARGET_IP} "sync"
}
function main() {
local cmd=$1
shift 1
case $cmd in
build)
build $@
;;
debug)
build_debug
;;
ssh)
copy_ssh $@
;;
*)
build
;;
esac
}
main $@

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAnqnYt7KJAQ5bhO/MgyWUg6QV5ICWbQX/cqzxpKKPyQQuJbUz
ML2lKPz5ogsv+pn7Hgh+SvCSN6iF/9Rtr5fD5I8COZxLlWbC3fz6J+2hPtvjCvdI
sMe0PvKxUa7vsujnUzkwpBjRcHG/gBF0P6UWvZBVbtn6jwP9ufYcAI7jYMI3YBk5
PNOowdcAoRiwTe2KnJzQNj2ztUE6VFgo3U5gyoGKfxNDi8P2aMWW3xARLJHh3hbR
Ztmwz8eDWD9L2c6fn61t9yqpyCRepE33+yC7m1Jdgxx+FWQBBfExwJaSBbWXyT1f
13v4ElSJXk4zWkeB1ddv76MZqDM9kRLJB/1WcQIDAQABAoIBAArexBRBzRUfcLG4
5CAQEQ67zSwsiyHJCWlH4/5NjOBOwwKeWXV7aLdYLZomfhEDP6sdFdn4hWv+xb9z
RFiFY0xjZ9melacUtUEUNedKZoOx+OolavuBkx3E7tUT0SRGxKJ1BpoXgTHc+SvD
Bl3d56LxIolHsdzefyGgdOas43Mbf6RHbAnXA65VyYf/k7fY4GkrO8/hKTXos32R
fNV0OD8qq8+KTwgnYXBKrjbie6N5XmOS9IcLFNC8F+0PC5NO+xzOk1McnmMux7t9
EwUj8/VXAYZPFRkEZdhmdzMgs9dpT9n+L13XppJLAAGEvFySFOGjEz2HWT7Hf5qB
z/ct9ukCgYEAzjV7V82ueeUTqMM8Hm6RV8MwpJxVwUABOQ934DuBO/p8oMqy9qlA
V02oJVnA5gMhCKKSr3dZa4+JG3BubrOh9tGEcw4pXIYEAAB6qWxsyHhNPcTrjYNS
mF5TFKgfY9uJ4p2b+YKYAuwyucdQf7kNQTEz/eYHOkardfGF00dlAo8CgYEAxPlo
nCUxaWW+rPI1wiP5F0BMhxrR4H592BajQQ1i/3IBUny43rRO2Sqd0E4xQzmTaGbi
qJtBGvS0DGMHOHfJ/5ha6xPiUFk1TJuRtb5P/uwdtJe6YZHeYz/yEDu07hKdUySs
J7oXlxORxcDphmYiVlM5ARy7h3SlLZEaGocglv8CgYAJWE8gqYeQqpr7eO2Oi4A2
s/fOXe9c9KOZjGPoW4n9x9pCBy2ZFA6AZlqKZsjhI58pnwR6wzPgNf8GqU+34Jgk
cVZJSIkDUmd4AI2OhAViCGGnvPbX0O27TfsB4qSZh+d1x6K76fktmLqrxKaXQzGg
lLRAe140e+NlUu63pnKjbQKBgB6A1S9hHx7IT9fuhl6zPW7ZWUCO6bOPQyPElbGM
Rily2TuR7vsmBxPgYqIQidZ0Qxym2jDsIg/vlzZX25VmD5USXfoLkT+KIRPk/5Ka
jz7WB9+go49ajIroKy9SX7mCjnSCuFpKmj6eHDP4pPFYPbcKmkhOz8exS6cb0mQL
SwO3AoGAYhzb7EHOTDfhtJQ0d49/8jUXprrGdExs2u88Gv8WjLsLaMm9hmNzY13M
i2wkM1ZOZag1XwvznVdLoM7lt62evtnocnEIysiiNaryoPFw/NCndNNG6mealVut
1Xr3rUQS9HOYeIYW5IFUfCv7aMFnEqd6AWdvWJ69uMIt7Wgp5yo=
-----END RSA PRIVATE KEY-----