1. 说明
云存储采用的的取流方式,类似于实时观看,设备端在需要云端存储的时候,调用接口,通知云服务器来设备端取流,协议使用的是TUTK的AVAPIs协议。
设备端只需要有对接TUTK公版的实时音视频协议即可。
对SDK的版本要求:3.3以及以上版本。
编码格式要求:
图像:H264/H265
- 声音:pcm, aac,g711等
2. 初始化
//read vsaas info file and enable vsaas char *vsaas_info = NULL; FILE *vsaas_info_file_ptr = NULL; vsaas_info_file_ptr = fopen(gVsaasInfoFilePath, "r");//此处的gVsaasInfoFilePath为云存储url和token存放信息的本地文件。 //没有配置过云存储信息 if (vsaas_info_file_ptr == NULL) { printf("Enable VSaaS without preload data!\n"); printf("Device should get vsaas info from client,\n"); printf("and save the vsaas info received from VsaasConfigChangedHandle\n"); ret = avEnableVSaaS(device_ctx, NULL, VsaasConfigChangedHandle, VSaaSUpdateContractInfoHandle); } //已经配置过云存储信息 else { long file_size = 0; fseek(vsaas_info_file_ptr, 0, SEEK_END); file_size = ftell(vsaas_info_file_ptr); rewind(vsaas_info_file_ptr); vsaas_info = (char*)malloc(sizeof(char)*file_size); if(vsaas_info == NULL) { printf("memory alloc fail!\n"); return -1; } fread(vsaas_info, 1, file_size, vsaas_info_file_ptr); printf("Enable VSaaS with preload data!\n"); //云存储模块初始化 ret = avEnableVSaaS(device_ctx, vsaas_info, VsaasConfigChangedHandle, VSaaSUpdateContractInfoHandle); fclose(vsaas_info_file_ptr); free(vsaas_info); gVsaasConfigExist = true; } if (ret != AV_ER_NoERROR) { printf("avEnableVSaaS error [%d]\n", ret); return -1; }
3. 通知服务器取流
/* *starttime:时间戳,毫秒 *event_id:目前只定义了VSAAS_EVENT_GENERAL *event_file:本地录像的文件,当starttime填入时间戳时,表示以playback的方式取流,此时需要使用此字段标记时要取哪个本地文件,starttime为live时,表示以liveview的方式取流。 *media_type:0为h264,1为h265,2为jpeg。 *如以playback的方式,则参数需要带playback用的iotc channel id,不然设备端avServStartEx将超时。 */ if(isLiveView) sprintf(att_json_str, "{\"starttime\":\"live\",\"protocol\":\"tutk\",\"event_id\":\"%d\",\"media_type\":\"%d\"}", VSAAS_EVENT_GENERAL,h264?0:1); else sprintf(att_json_str, "{\"starttime\":\"%lu\",\"protocol\":\"tutk\",\"event_id\":\"%d\",\"event_file\":\"%s\",\"media_type\":\"%d\",\"channel\":\"%d\"}", current_time_sec, VSAAS_EVENT_GENERAL, gRecordFile,h264?0:1,iotc_channel_id_for_playback); printf("avServNotifyCloudRecordStream\n"); Nebula_Json_Obj_Create_From_String(att_json_str, &attr_obj); ret = avServNotifyCloudRecordStream(attr_obj, 3000, NULL); printf("avServNotifyCloudRecordStream ret[%d]\n", ret); if (ret != AV_ER_NoERROR) { //错误处理 } //通知服务器成功后,如果设备UDID有购买方案,云服务器会发起IOTC连线,然后通过P2P协议来设备端取流。 //此时,设备端会看到有IOTC连线建立,以及client(云服务器)发起拉流的指令(0x1ff,0x351) //服务器会进行取流的前提是用户购买了云存储的方案。否则,此API将会有报错产生,比如-20043等 设备端如何获取初始化推流的url和token信息,具体是在avEnableVSaaSByNebula的回调函数里面处理: //app会把相关的url和token信息,以json的方式发给设备,设备在此回调里面可以拿到和保存到本地。 static void VsaasConfigChangedHandle(const char *vsaas_config) { printf("Enter %s\n", __func__); printf("Get VSaaS info:\n%s\n", vsaas_config); //save VSaaSconfig for avEnableVSaaS() FILE *vsaas_info_file_ptr = fopen(gVsaasInfoFilePath, "w+"); if (vsaas_info_file_ptr == NULL) { printf("%s fopen %s error!!\n", __func__, gVsaasInfoFilePath); } else { fwrite(vsaas_config, 1, strlen(vsaas_config), vsaas_info_file_ptr); fclose(vsaas_info_file_ptr); gVsaasConfigExist = true; } } //方案变更 static void VSaaSUpdateContractInfoHandle(const VSaaSContractInfo *contract_info) { printf("Enter %s\n", __func__); printf("contract_type=%u\n", contract_info->contract_type); printf("event_recording_max_sec=%d\n", contract_info->event_recording_max_sec); printf("video_max_fps=%d\n", contract_info->video_max_fps); printf("recording_max_kbps=%d\n", contract_info->recording_max_kbps); printf("video_max_high=%d\n", contract_info->video_max_high); printf("video_max_width=%d\n", contract_info->video_max_width); gVsaasContractInfo.contract_type = contract_info->contract_type; gVsaasContractInfo.event_recording_max_sec = contract_info->event_recording_max_sec; gVsaasContractInfo.video_max_fps = contract_info->video_max_fps; gVsaasContractInfo.recording_max_kbps = contract_info->recording_max_kbps; gVsaasContractInfo.video_max_high = contract_info->video_max_high; gVsaasContractInfo.video_max_width = contract_info->video_max_width; //User should adopt the bit rate or resolution of record file according to the vsaas contract infomation. }
4. 注意事项
- 如果使用的APP是公版kalay app,需要修改设备端的密码验证机制,增加对account为"vsaas"的支持:
int ExPasswordAuthCallBackFn(const char *account, char *pwd, unsigned int pwd_buf_size) { if (strcmp(account, gAvAccount) != 0 || strcmp(account, "vsaas") != 0) return -1; if (pwd_buf_size <= strlen(gAvPassword)) return -1; strcpy(pwd, gAvPassword); return 0; }
5.优化策略
如果设备端使用live的方式进行云存推流,默认云端是拉取30s的流,不过开发者仍可以根据自身的一些算法(比如说人形识别,宠物行为识别),来调整云存的时长。例如:设备在10:00:00开始侦测到人形,并开始推流,在10:00:10的时候人形侦测结束,则直接断开连接,所以录制的云存时长为10s。设备需要做的事情:
识别对应的连接是云存储服务器发起的,并标记对应的avIndex。在检测到需要提前结束云存的时候,需要停止往对应的avIndex送流,并等待该avIndex中的流都送出后,再关闭连接。
更多代码和使用实际,请参考SDK sample code: AV_VSaaS_Server.c