feat: ios插件功能

This commit is contained in:
fanpeng 2025-06-30 09:43:16 +08:00
parent 4a2d418526
commit a01ac4a237
19 changed files with 468 additions and 62 deletions

View File

@ -50,7 +50,7 @@
></image>
<cover-view
v-if="isApp || buttonInfo"
v-if="(isApp || buttonInfo) && isVideoLoaded"
:style="{
top: isApp ? '60px' : buttonInfo.bottom + 15 + 'px'
}"
@ -189,9 +189,9 @@
// #ifdef APP-PLUS
import {
startServiceFunction,
stopService,
runSendService,
stopSendService,
stopServiceFunction,
runSendServiceFunction,
stopSendServiceFunction,
dataSend
} from '@/uni_modules/xhj-tencent-xp2p'
import { initAudio, onStartRecord, stopRecord, releaseRecord } from '@/uni_modules/xhj-record'
@ -224,7 +224,9 @@
const isVideoLoaded = ref(false)
const urlPrefix = computed(() => {
return url.value + `ipc.flv?action=live&channel=0&quality=${range.value[index.value].value}`
const data =
url.value + `ipc.flv?action=live&channel=0&quality=${range.value[index.value].value}`
return data
})
onMounted(async () => {
@ -277,13 +279,13 @@
params.deviceName,
params.xp2pInfo
)
console.log(1111, result)
console.log('初始化SDK结果', result)
if (result?.code === 0) {
url.value = result.data.url
runSendService(
runSendServiceFunction(
`${deviceInfo.value.productId}/${deviceInfo.value.deviceName}`,
'channel=0',
false
true
)
handlePlaySuccess()
} else {
@ -299,10 +301,8 @@
// #ifdef APP-PLUS
//
releaseRecord()
stopSendService(`${deviceInfo.value.productId}/${deviceInfo.value.deviceName}`)
stopService({
id: `${deviceInfo.value.productId}/${deviceInfo.value.deviceName}`
})
stopSendServiceFunction(`${deviceInfo.value.productId}/${deviceInfo.value.deviceName}`)
stopServiceFunction(`${deviceInfo.value.productId}/${deviceInfo.value.deviceName}`)
// #endif
// #ifdef MP-WEIXIN
const page = getCurrentPages().pop()

View File

@ -4,7 +4,7 @@
import { UTSAndroid } from 'io.dcloud.uts'
import { XP2PAppConfig, XP2P, XP2PCallback } from 'com.tencent.xnet'
import { Result, IdParams } from '../interface.uts'
import { Result } from '../interface.uts'
class XP2PCallbackImpl extends XP2PCallback {
private eventNotifyCallback?: (id: string | null, msg: string | null, event: Int) => void
@ -101,9 +101,9 @@ export const startServiceFunction = async function (
}
}
export const stopService = async function (params: IdParams): Promise<Result> {
export const stopServiceFunction = async function (id: string): Promise<Result> {
try {
await XP2P.stopService(params.id)
await XP2P.stopService(id)
return {
code: 0,
data: {},
@ -118,7 +118,7 @@ export const stopService = async function (params: IdParams): Promise<Result> {
}
}
export const runSendService = async function (
export const runSendServiceFunction = async function (
id: string,
cmd: string,
crypto: boolean
@ -140,7 +140,7 @@ export const runSendService = async function (
}
}
export const stopSendService = async function (id: string): Promise<Result> {
export const stopSendServiceFunction = async function (id: string): Promise<Result> {
try {
const result = await XP2P.stopSendService(id, null)
console.log('停止发送服务', result)

View File

@ -0,0 +1,333 @@
#ifndef __APPWRAPPER_H_
#define __APPWRAPPER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef WINDOWS
#ifdef IPCLIBRARY_EXPORTS
# define IPCLIBRARY_API __declspec(dllexport)
#else
# define IPCLIBRARY_API __declspec(dllimport)
#endif
#else
# define IPCLIBRARY_API
#endif
#define MAX_SIZE_OF_PARAMS 3000
static const char * VIDEOSDKVERSION = "2.4.x+git.2a469eda";
typedef enum
{
XP2P_PROTOCOL_AUTO = 0, //auto模式udp不通自动切换tcp
XP2P_PROTOCOL_UDP = 1, //udp传输
XP2P_PROTOCOL_TCP = 2, //tcp传输
} XP2PProtocolType;
typedef enum
{
XP2PTypeClose = 1000, //数据传输完成
XP2PTypeLog = 1001, //日志输出
XP2PTypeCmd = 1002, // command json
XP2PTypeDisconnect = 1003, // p2p链路断开
XP2PTypeDetectReady = 1004, // p2p链路初始化成功
XP2PTypeDetectError = 1005, // p2p链路初始化失败
XP2PTypeDeviceMsgArrived = 1006, // 设备端向App发消息
XP2PTypeCmdNOReturn = 1007, // 设备未返回app自定义信令
XP2PTypeStreamEnd = 1008, // 设备停止推流,或者由于达到设备最大连接数,拒绝推流
XP2PTypeDownloadEnd = 1009, // 设备停止推流,下载结束
XP2PTypeStreamRefush = 1010, // 设备拒绝推流请求的devicename不一致
XP2PTypeSaveFileOn = 8000, //获取保存音视频流开关状态
XP2PTypeSaveFileUrl = 8001 //获取音视频流保存路径
} XP2PType;
typedef enum
{
XP2PVoiceServiceClose = 2000, //语音对讲服务关闭
XP2PStreamServiceClose = 2001 //音视频流接收服务关闭
} XP2PCloseSubType;
typedef enum
{
XP2P_ERR_NONE = 0, //成功
XP2P_ERR_INIT_PRM = -1000, //入参为空
XP2P_ERR_GET_XP2PINFO = -1001, // SDK内部请求xp2p info失败
XP2P_ERR_PROXY_INIT = -1002, //本地p2p代理初始化失败
XP2P_ERR_UNINIT = -1003, //数据接收/发送服务未初始化
XP2P_ERR_ENCRYPT = -1004, //数据加密失败
XP2P_ERR_TIMEOUT = -1005, //请求超时
XP2P_ERR_REQUEST_FAIL = -1006, //请求错误
XP2P_ERR_VERSION = -1007, //设备版本过低,请升级设备固件
XP2P_ERR_APPLICATION = -1008, // application初始化失败
XP2P_ERR_REQUEST = -1009, // request初始化失败
XP2P_ERR_DETECT_NOTREADY = -1010, // p2p探测未完成
XP2P_ERR_P2P_ININED = -1011, //当前id对应的p2p已完成初始化
XP2P_ERR_P2P_UNININ = -1012, //当前id对应的p2p未初始化
XP2P_ERR_NEW_MEMERY = -1013, //内存申请失败
XP2P_ERR_XP2PINFO_RULE = -1014, //获取到的xp2p info格式错误
XP2P_ERR_XP2PINFO_DECRYPT = -1015, //获取到的xp2p info解码失败
XP2P_ERR_PROXY_LISTEN = -1016, //本地代理监听端口失败
XP2P_ERR_CLOUD_EMPTY = -1017, //云端返回空数据
XP2P_ERR_JSON_PARSE = -1018, // json解析失败
XP2P_ERR_SERVICE_NOTRUN = -1019, //当前id对应的服务(语音、直播等服务)没有在运行
XP2P_ERR_CLIENT_NULL = -1020 //从map中取出的client为空
} XP2PErrCode;
typedef struct data_report_t {
unsigned char* report_buf;
size_t report_size;
uint64_t live_size;
// uint64_t voice_size;
const char *data_action;
const char *status;
const char *uniqueId;
const char *appPeerName;
const char *deviceP2PInfo;
uint64_t appUpByte;
uint64_t appDownByte;
const char *appConnectIp;
int errorcode;
} data_report_t;
typedef struct app_config_t {
const char *server;
const char *ip;
uint64_t port;
XP2PProtocolType type;
bool cross;
} app_config_t;
typedef const char *(*msg_handle_t)(const char *id, XP2PType type, const char *msg);
typedef void (*av_recv_handle_t)(const char *id, uint8_t *recv_buf, size_t recv_len);
typedef char *(*device_data_recv_handle_t)(const char *id, uint8_t *recv_buf, size_t recv_len);
typedef void (*av_log_handle_t)(const char *id, data_report_t data_buf);
/**
* @brief
*
* @param recv_handle:
* @param msg_handle:
* @param device_data_handle: App发送消息的回调
* @return
*/
IPCLIBRARY_API void setUserCallbackToXp2p(av_recv_handle_t recv_handle, msg_handle_t msg_handle, device_data_recv_handle_t device_data_handle);
/**
* @brief camera设备并等待回复
*
* @param id: camera在app端的唯一标识符
* @param command:
* cmd_len提供16KB以内
* @param cmd_len: command长度
* @param recv_buf:
* camera回复的数据recv_len获取
* @param recv_len: camera回复的数据长度
* @param timeout_us: 0(7500ms左右)
* @return 0
*/
IPCLIBRARY_API int postCommandRequestSync(const char *id, const unsigned char *command, size_t cmd_len,
unsigned char **recv_buf, size_t *recv_len, uint64_t timeout_us);
/**
* @brief camera设备camera回复的数据由注册的回调函数返回
*
* @param id: camera在app端的唯一标识符
* @param command:
* cmd_len提供16KB以内
* @param cmd_len: command长度
* @return 0
*/
IPCLIBRARY_API int postCommandRequestWithAsync(const char *id, const unsigned char *command, size_t cmd_len);
/**
* @brief camera设备请求媒体流
*
* @param id: camera在app端的唯一标识符
* @param params: (`action=live`)(`action=playback`)
* @param crypto: (crypto=false)
* @return
*/
IPCLIBRARY_API void *startAvRecvService(const char *id, const char *params, bool crypto);
/**
* @brief
*
* @param id: camera在app端的唯一标识符
* @param req: `startAvRecvService`null
* @return 0
*/
IPCLIBRARY_API int stopAvRecvService(const char *id, void *req);
/**
* @brief xp2p服务
*
* @param id: camera在app端的唯一标识符
* @param product_id: ID
* @param device_name:
* @param sensor_timeout: tcp的超时时间
* @return 0
*/
IPCLIBRARY_API int startService(const char *id, const char *product_id, const char *device_name, app_config_t config);
/**
* @brief xp2p服务
*
* @param id: camera在app端的唯一标识符
* @param product_id: ID
* @param device_name:
* @param remote_host: ip
* @param remote_port:
* @return 0
*/
IPCLIBRARY_API int startLanService(const char *id, const char *product_id, const char *device_name,
const char *remote_host, const char *remote_port);
/**
* xp2pinfo,start时间
*/
IPCLIBRARY_API int setDeviceXp2pInfo(const char *id, const char *xp2p_info);
/**
* @brief url
*
* @param id: camera在app端的唯一标识符
* @return url
*/
IPCLIBRARY_API const char *delegateHttpFlv(const char *id);
/**
* @brief url
*
* @param id: camera在app端的唯一标识符
* @return url
*/
IPCLIBRARY_API const char *getLanUrl(const char *id);
/**
* @brief url
*
* @param id: camera在app端的唯一标识符
* @return
*/
IPCLIBRARY_API int getLanProxyPort(const char *id);
/**
* @brief camera设备发送语音或自定义数据服务
*
* @param id: camera在app端的唯一标识符
* @param params: key1=value&key2=value2
* key不允许以下划线_开头key和value中间不能包含&/+=
* @param crypto: (crypto=false)
* @return
*/
IPCLIBRARY_API void *runSendService(const char *id, const char *params, bool crypto);
/**
* @brief
*
* @param id: camera在app端的唯一标识符
* @param req: `runSendService`null
* @return
*/
IPCLIBRARY_API int stopSendService(const char *id, void *req);
/**
* @brief api信息sdk获取xp2p信息
*
* @param sec_id: API secrct_id
* @param sec_key: API secrct_key
* @return 0
*/
IPCLIBRARY_API int setQcloudApiCred(const char *sec_id, const char *sec_key);
/**
* @brief camera设备发送语音或自定义数据
*
* @param id: camera在app端的唯一标识符
* @param data:
* @param len:
* @return 0
*/
IPCLIBRARY_API int dataSend(const char *id, uint8_t *data, size_t len);
/**
* @brief xp2p服务
*
* @param id: camera在app端的唯一标识符
* @return 0
*/
IPCLIBRARY_API void stopService(const char *id);
/**
* @brief
*
* @param console:
* @param file:
*/
IPCLIBRARY_API void setLogEnable(bool console, bool file);
/*================================废弃接口=======================================*/
/**
* @brief camera设备并等待回复
*
* @param id: camera在app端的唯一标识符
* @param command:
* @param buf: camera回复的数据len获取
* @param len: camera回复的数据长度
* @param timeout_us: 0(7500ms左右)
* @return 0
*/
IPCLIBRARY_API int getCommandRequestWithSync(const char *id, const char *command, char **buf, size_t *len,
uint64_t timeout_us);
/**
* @brief camera设备camera回复的数据由注册的回调函数返回
*
* @param id:camera在app端的唯一标识符
* @param command:
* @return 0
*/
IPCLIBRARY_API int getCommandRequestWithAsync(const char *id, const char *command);
/**
* @brief 0 62 63
*
* @param id:camera在app端的唯一标识符
* @param command:
* @return 0
*/
IPCLIBRARY_API int getStreamLinkMode(const char *id);
/**
* @brief 便httpflv时
* @param id:camera在app端的唯一标识符
*/
IPCLIBRARY_API void startRecordPlayerStream(const char *id);
/**
* @brief p2p的水线超过一定值时I帧
* @param id:camera在app端的唯一标识符
*/
IPCLIBRARY_API size_t getStreamBufSize(const char *id);
IPCLIBRARY_API void setStunServerToXp2p(const char *server, uint16_t port);
IPCLIBRARY_API void setContentDetail(const char *content, const char *detail, av_log_handle_t reportdata_handle);
IPCLIBRARY_API const char* getUserID();
/**
* @brief
*/
IPCLIBRARY_API void setCrossStunTurn(bool enable);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,27 +1,4 @@
{
"deploymentTarget": "9",
"frameworks": [
"AVFoundation.framework",
"CoreMedia.framework",
"VideoToolbox.framework",
"AudioToolbox.framework"
],
"dependencies-pods": [
{
"name": "TIoTLinkVideo",
"version": "2.4.48"
},
{
"name": "TIoTLinkKit_XP2P",
"version": "2.4.53"
},
{
"name": "TIoTLinkKit_GVoiceSE",
"version": "1.0.9"
},
{
"name": "TIoTLinkKit_IJKPlayer",
"version": "2.0.15"
}
]
"frameworks": ["libc++.tbd", "libsqlite3.tbd", "libz.tbd"]
}

View File

@ -0,0 +1,13 @@
import Foundation
@objc
public class P2PConversionHelper: NSObject {
@objc
public static func cStringToString(_ cString: UnsafePointer<CChar>?) -> String? {
guard let pointer = cString else {
return nil
}
// Use explicit UTF-8 encoding for safety, especially with URLs.
return String(cString: pointer, encoding: .utf8)
}
}

View File

@ -3,9 +3,6 @@
// @ts-ignore-start
import { Result } from '../interface.uts'
// import 'TIoTCoreXP2PBridge.h'
// import 'TIoTCoreAudioConfig.h'
// import 'TIoTCoreVideoConfig.h'
export const startServiceFunction = async function (
appKey: string,
@ -14,18 +11,116 @@ export const startServiceFunction = async function (
deviceName: string,
xp2pInfo: string
): Promise<Result> {
return new Promise<Result>((resolve, reject) => {
try {
const config = app_config_t()
config.server = UnsafePointer(strdup('')!)
config.ip = UnsafePointer(strdup('')!)
config.port = 20002
config.type = XP2P_PROTOCOL_AUTO
config.cross = false
const result = startService(`${productId}/${deviceName}`, productId, deviceName, config)
if (NSNumber(0) === result) {
const setP2PInfoResult = setDeviceXp2pInfo(`${productId}/${deviceName}`, xp2pInfo)
if (NSNumber(0) === setP2PInfoResult) {
let attempts = 0
const maxAttempts = 20
const interval: Int = 100
function pollForUrl() {
if (attempts >= maxAttempts) {
resolve({ code: -1, data: {}, message: '获取播放URL超时' })
return
}
attempts++
const urlResult = delegateHttpFlv(`${productId}/${deviceName}`)
if (urlResult != null) {
const urlString = P2PConversionHelper.cStringToString(urlResult)
if (urlString != null && urlString != '') {
resolve({
code: 0,
data: { url: urlString },
message: '成功'
})
return
}
}
setTimeout(pollForUrl, interval)
}
pollForUrl()
} else {
resolve({ code: -1, data: {}, message: 'setDeviceXp2pInfo 调用失败' })
}
} else {
resolve({ code: -1, data: {}, message: 'startService 调用失败' })
}
} catch (error) {
console.log('startServiceFunction 报错', error)
resolve({
code: -1,
data: {},
message: error.toString()
})
}
})
}
export const stopServiceFunction = async function (id: string): Promise<Result> {
try {
console.log(1111, appKey, appSecret, productId, deviceName, xp2pInfo)
// console.log(1111, TIoTCoreXP2PBridge)
// const config = TIoTP2PAPPConfig()
// console.log(1111, config)
await stopService(id)
return {
code: 0,
data: {},
message: '成功'
}
} catch (error) {
return {
code: -1,
data: {},
message: '1'
message: error.toString()
}
}
}
export const runSendServiceFunction = async function (
id: string,
cmd: string,
crypto: boolean
): Promise<Result> {
try {
// const result = await runSendService(id, cmd, crypto)
// console.log('开始发送服务', result)
return {
code: 0,
data: {},
message: '成功'
}
} catch (error) {
return {
code: -1,
data: {},
message: error.toString()
}
}
}
export const stopSendServiceFunction = async function (id: string): Promise<Result> {
try {
// const nullPointer = P2PPointerHelper.createNullPointer()
// const result = await stopSendService(id, nullPointer)
// console.log('停止发送服务', result)
return {
code: 0,
data: {},
message: '成功'
}
} catch (error) {
console.log('startServiceFunction报错', error)
return {
code: -1,
data: {},

View File

@ -3,15 +3,3 @@ export type Result = {
data: object
message: string
}
export type InitParams = {
appKey: string
appSecret: string
productId: string
deviceName: string
xp2pInfo: string
}
export type IdParams = {
id: string
}