通过阅读本文,您可以快速了解 iOS 远程双录的相关功能及调用方法。
远程双录功能同时使用了 MPIDRSSDK AI 原子能力和音视频通话组件( Mobile Real-Time Communication,简称 MRTC)。在双录过程中 MPIDRSSDK 通过 MRTC 拿到音视频数据进行智能检测,MRTC 将 MPIDRSSDK 合成的音频数据推流到音视频通话房间内。
iOS 接入
创建项目工程
使用 xcode 创建一个新的项目。
环境配置
SDK 环境依赖
MPIDRSSDK 为动态库,支持 iOS 9.0 及以上系统。
进入 Targets > Build Phases,添加 MPIDRSSDK 及 ARTVC 依赖库,如下图所示。
参数配置
进入 Targets > Build Phases,添加 MPIDRSSDK、ARTVC 动态库,如下图所示。
添加 MPIDRSSDK.bundle 资源,如下图所示。
将 Other Linker Flags 设置为 -ObjC,如下图所示。
增加支持 HTTP 协议允许,如下图所示。
允许使用相机、麦克风权限。
使用示例
初始化 MPIDRSSDK
NSString * userId = [[DemoSetting sharedInstance] userId];
IDRSModelType type = [DemoSetting getSettingConfig];
// IDRSRecordRemote 远程双录模式
[MPIDRSSDK initWithRecordType:IDRSRecordRemote
userId:userId
appId:AppId
packageName:PackageName
AK:Ak
SK:Sk
model:type
addDelegate:self
success:^(id responseObject) {
self.idrs = responseObject;
self.idrs.nui_tts_delegate = self;
} failure:^(NSError *error)
[self showToastWith:@"sdk init error" duration:2];
NSLog(@"%@",error);
}];
语音播报
//通过代理能拿到语音合成数据、播报状态以及语音识别回调,详情见下面 IDRSNUITTSDelegate
self.idrsSDK.nui_tts_delegate = self;
NSString *ttsString = @"智能双录质检是蚂蚁集团移动开发平台团队与阿里巴巴达摩院共同研制的一款智能化的音视频内容录制、检测及审核产品";
// 设置语音播报速度
[self.idrsSDK setTTSParam:@"speed_level" value:@"1.5"];
// 开始播放
[self.idrsSDK startTTSWithText:ttsString];
// 结束TTS合成
[self.idrsSDK stopTTS];
// 暂停当前播放(与resume相反)
[self.idrsSDK pauseTTS];
// 重启当前播放(与pause相反)
[self.idrsSDK resumeTTS];
IDRSNUITTSDelegate
/// player播放完成
- (void)onPlayerDidFinish;
/// tts合成状态
/// @param event 状态
/// @param taskid 任务id
/// @param code code
- (void)onNuiTtsEventCallback:(ISDRTtsEvent)event taskId:(NSString *)taskid code:(int)code;
/// tts合成数据
/// @param info 文本信息
/// @param info_len 下角标
/// @param buffer 音频数据流
/// @param len 数据流长度
/// @param task_id 任务id
- (void)onNuiTtsUserdataCallback:(NSString *)info infoLen:(int)info_len buffer:(char*)buffer len:(int)len taskId:(NSString *)task_id;
/// 激活词识别结果
/// @param result 激活词识别的结果
- (void)onNuiKwsResultCallback:(NSString *)result;
语音识别
可识别的激活词请参见 MPIDRSSDK.bundle/mandarin/kws/keywords
。
// 开启激活词检测
[self.idrsSDK startDialog];
// 停止激活词检测
[self.idrsSDK stopDialog];
//如果检测非本地麦克风收集的声音,需使用:
/**
激活词外部输入数据
@param voiceFrame 音频数据(需要:pcm、单声道、16k采样率)
*/
- (void)feedAudioFrame:(NSData*)voiceFrame;
人脸检测
检测人脸特征。
//这里以IDRSFaceDetectInputTypePixelBuffer为例,更多支持类型见:IDRSFaceDetectParam CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); IDRSFaceDetectParam *detectParam = [[IDRSFaceDetectParam alloc]init]; detectParam.dataType = IDRSFaceDetectInputTypePixelBuffer; detectParam.buffer = pixelBuffer; detectParam.inputAngle = inAngle; detectParam.outputAngle = outAngle; // 输出人脸特征值结果 NSArray<FaceDetectionOutput *> *detectedFace = [_idrsSDK detectFace:detectParam];
进行人脸比对。
// 两个人脸特征值比对结果 float similarity = [self.idrsSDK faceRecognitionSimilarity:detectedFace1.feature feature2:detectedFace2.face1Feature];
人脸追踪。
//这里以IDRSFaceDetectInputTypePixelBuffer为例,更多支持类型见:IDRSFaceDetectParam CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); IDRSFaceDetectParam *detectParam = [[IDRSFaceDetectParam alloc]init]; detectParam.dataType = IDRSFaceDetectInputTypePixelBuffer; detectParam.buffer = pixelBuffer; detectParam.inputAngle = inAngle; detectParam.outputAngle = outAngle; detectParam.supportFaceLiveness = YES; // 回调人脸特征信息,包括人脸区域等。 [self.idrsSDK faceTrackFromVideo:detectParam faceDetectionCallback:^(NSError *error, NSArray<FaceDetectionOutput*> *faces) { }];
手势检测
动态手势检测,如手持手机签字。
CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); IDRSHandDetectParam *handParam = [[IDRSHandDetectParam alloc]init]; handParam.dataType = IDRSHandInputTypeBGRA; handParam.buffer = pixelBuffer; handParam.outAngle = 0; NSArray<HandDetectionOutput *> *handResults = [self.idrsSDK detectHandGesture:handParam];
静态手势检测。
CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); IDRSHandDetectParam *handParam = [[IDRSHandDetectParam alloc]init]; handParam.dataType = IDRSHandInputTypeBGRA; handParam.buffer = pixelBuffer; handParam.outAngle = 0; NSArray<HandDetectionOutput *> *handResults = [self.idrsSDK detectHandStaticGesture:handParam];
签名类型检测
UIImage * image = [self.idrs getImageFromRPVideo:newBuffer];
NSArray<NSNumber*> *kXMediaOptionsROIKey = @[@(0.2),@(0.2),@(0.6),@(0.6)];
//返回签名可信度结果
NSArray<IDRSSignConfidenceCheck *>*sings = [self.idrs checkSignClassifyWithImage:image AndROI:kXMediaOptionsROIKey];
身份证检测
// 这里只列举了imageBuffer的使用方式,其他方式参数详见 IDRSIDCardDetectParam
CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
IDRSIDCardDetectParam *detectParam = [[IDRSIDCardDetectParam alloc]init];
detectParam.buffer = pixelBuffer;
detectParam.dataType = IDRSIDCardInputTypePixelBuffer;
NSArray<NSNumber*> *kXMediaOptionsROIKey = @[@(0.2),@(0.2),@(0.6),@(0.6)];
// 身份证信息
IDCardDetectionOutput *ocrOutPut = [_idrsSDK detectIDCard:detectParam roiKey:kXMediaOptionsROIKey rotate:angleDic[@"outAngle"] isFrontCamera:NO isDetectFrontIDCard:isDetectFront];
释放
/// 释放资源
- (void)releaseResources;
常用功能
/// 获取SDK版本号
+ (NSString*)getVersion;
/// 将相机中获取的sampleBuffer保存到相册
/// @param sampleBuffer CMSampleBufferRef
- (void)saveSampleBufferFromCamera: (CMSampleBufferRef)sampleBuffer;
/// 将rtc视频流转成图片
/// @param imageBuffer CVPixelBufferRef、CVPixelBufferRef
- (UIImage *) getImageFromRPVideo: (CVImageBufferRef)imageBuffer;
使用 MRTC
下面仅列举了远程双录中可能用到的部分 MRTC 接口,关于 MRTC 接口的更多信息请参见 iOS 进阶功能。
初始化 MRTC 实例
MPIDRSSDK 可以用来初始化 MRTC 实例,您获取 MRTC 实例之后可以配置音视频通话逻辑,以下为 Demo 配置。
[MPIDRSSDK initRTCWithUserId:self.uid appId:AppId success:^(id _Nonnull responseObject) {
self.artvcEgnine = responseObject;
// 音视频通话相关状态回调delegate
self.artvcEgnine.delegate = self;
//设置视频编码分辨率,默认是 ARTVCVideoProfileType_640x360_15Fps。
self.artvcEgnine.videoProfileType = ARTVCVideoProfileType_1280x720_30Fps;
// 音视频通话 发布流配置
ARTVCPublishConfig *publishConfig = [[ARTVCPublishConfig alloc] init];
publishConfig.videoProfile = self.artvcEgnine.videoProfileType;
publishConfig.audioEnable = YES;
publishConfig.videoEnable = YES;
self.artvcEgnine.autoPublishConfig = publishConfig;
// 自动推流
self.artvcEgnine.autoPublish = YES;
// 音视频通话 订阅配置
ARTVCSubscribeOptions *subscribeOptions = [[ARTVCSubscribeOptions alloc] init];
subscribeOptions.receiveAudio = YES;
subscribeOptions.receiveVideo = YES;
self.artvcEgnine.autoSubscribeOptions = subscribeOptions;
// 自动拉流(订阅)
self.artvcEgnine.autoSubscribe = YES;
// 如果需要回调本地音频数据,设置YES
self.artvcEgnine.enableAudioBufferOutput = YES;
// 如果需要回调本地视频数据,设置YES
self.artvcEgnine.enableCameraRawSampleOutput = YES;
// 声音模式
self.artvcEgnine.expectedAudioPlayMode = ARTVCAudioPlayModeSpeaker;
// 带宽不足时保证分辨率优先(帧率下降)还是流畅度优先 (分辨率下降)
/*
ARTVCDegradationPreferenceMAINTAIN_FRAMERATE, //流畅度优先
ARTVCDegradationPreferenceMAINTAIN_RESOLUTION, //分辨率优先
ARTVCDegradationPreferenceBALANCED, //自动平衡
*/
self.artvcEgnine.degradationPreference = ARTVCDegradationPreferenceMAINTAIN_FRAMERATE;
// 启动相机预览,默认使用前置摄像头,如果设置为 YES 则使用后置摄像头
[self.artvcEgnine startCameraPreviewUsingBackCamera:NO];
// 没有房间时选择创建房间
[IDRSSDK createRoom];
// 或者加入已有房间
// [IDRSSDK joinRoom:self.roomId token:self.rtoken];
} failure:^(NSError * _Nonnull error) {
}];
MRTC 代理回调
下面仅列出了部分常用回调 API,更多 API 信息请参见 ARTVCEngineDelegate。
启动相机预览后,如果本地 feed 没有被回调过,则回调后返回一个 ARTVCFeed 对象,可用于关联后续返回的渲染 View。
- (void)didReceiveLocalFeed:(ARTVCFeed*)localFeed { switch(localFeed.feedType){ case ARTVCFeedTypeLocalFeedDefault: self.localFeed = localFeed; break; case ARTVCFeedTypeLocalFeedCustomVideo: self.customLocalFeed = localFeed; break; case ARTVCFeedTypeLocalFeedScreenCapture: self.screenLocalFeed = localFeed; break; default: break; } }
本地和远端 feed 相关的 renderView 回调。
重要此时不代表 renderView 已经渲染首帧。
- (void)didVideoRenderViewInitialized:(UIView*)renderView forFeed:(ARTVCFeed*)feed { //可触发 UI 布局,把 renderView add 到 view 层级中去 [self.viewLock lock]; [self.contentView addSubview:renderView]; [self.viewLock unlock]; }
本地和远端 feed 首帧渲染的回调。
//fist video frame has been rendered - (void)didFirstVideoFrameRendered:(UIView*)renderView forFeed:(ARTVCFeed*)feed { }
某个 feed 停止渲染的回调。
- (void)didVideoViewRenderStopped:(UIView*)renderView forFeed:(ARTVCFeed*)feed { }
创建房间成功,有房间信息回调。
-(void)didReceiveRoomInfo:(ARTVCRoomInfomation*)roomInfo { //拿到房间号、token // roomInfo.roomId // roomInfo.rtoken }
创建房间失败,有 Error 回调。
-(void)didEncounterError:(NSError *)error forFeed:(ARTVCFeed*)feed{ //error.code == ARTVCErrorCodeProtocolErrorCreateRoomFailed }
加入房间成功,会有加入房间成功的回调以及房间已有成员的回调。
-(void)didJoinroomSuccess{ } -(void)didParticepantsEntered:(NSArray<ARTVCParticipantInfo*>*)participants{ }
加入房间失败、推流失败等音视频通话中出现错误的回调。
-(void)didEncounterError:(NSError *)error forFeed:(ARTVCFeed*)feed{ //error.code == ARTVCErrorCodeProtocolErrorJoinRoomFailed }
成员离开房间后,房间其他成员会收到成员离开的回调。
-(void)didParticepant:(ARTVCParticipantInfo*)participant leaveRoomWithReason:(ARTVCParticipantLeaveRoomReasonType)reason { }
创建或者加入房间成功后开始推流与拉流,推流/拉流过程中,有如下相关状态回调。
-(void)didConnectionStatusChangedTo:(ARTVCConnectionStatus)status forFeed:(ARTVCFeed*)feed{ [self showToastWith:[NSString stringWithFormat:@"connection status:%d\nfeed:%@",status,feed] duration:1.0]; if((status == ARTVCConnectionStatusClosed) && [feed.uid isEqualToString:[self uid]]){ [self.artvcEgnine stopCameraPreview];//音视频通话下,停止摄像头预览。 [self.artvcEgnine leaveRoom]; } }
状态说明
推流成功后,其他房间成员会收到新 feed 的回调。
-(void)didNewFeedAdded:(ARTVCFeed*)feed { }
取消发布后,房间其他成员会收到取消发布的回调。
-(void)didFeedRemoved:(ARTVCFeed*)feed{ }
本地流音频数据回调。
- (void)didOutputAudioBuffer:(ARTVCAudioData*)audioData { if (audioData.audioBufferList->mBuffers[0].mData != NULL && audioData.audioBufferList->mBuffers[0].mDataByteSize > 0) { pcm_frame_t pcmModelInput; pcmModelInput.len = audioData.audioBufferList->mBuffers[0].mDataByteSize; pcmModelInput.buf = (uint8_t*)audioData.audioBufferList->mBuffers[0].mData; pcmModelInput.sample_rate = audioData.sampleRate; pcm_frame_t pcmModelOutput; pcm_resample_16k(&pcmModelInput, &pcmModelOutput); NSData *srcData = [NSData dataWithBytes:pcmModelOutput.buf length:pcmModelOutput.len]; //检测音频数据 [self.idrs feedAudioFrame:srcData]; } }
远端流音频数据回调。
可用来检测远端语音,下面示例代码以检测远端激活词为例。
- (void)didOutputRemoteMixedAudioBuffer:(ARTVCAudioData *)audioData { if (audioData.audioBufferList->mBuffers[0].mData != NULL && audioData.audioBufferList->mBuffers[0].mDataByteSize > 0) { pcm_frame_t pcmModelInput; pcmModelInput.len = audioData.audioBufferList->mBuffers[0].mDataByteSize; pcmModelInput.buf = (uint8_t*)audioData.audioBufferList->mBuffers[0].mData; pcmModelInput.sample_rate = audioData.sampleRate; pcm_frame_t pcmModelOutput; pcm_resample_16k(&pcmModelInput, &pcmModelOutput); NSData *srcData = [NSData dataWithBytes:pcmModelOutput.buf length:pcmModelOutput.len]; //检测音频数据 [self.idrs feedAudioFrame:srcData]; } }
本地相机流数据回调。
可用来检测人脸、手势、签名类型、身份证等,下方代码以检测人脸特征代码为例。
dispatch_queue_t testqueue = dispatch_queue_create("testQueue", NULL); - (void)didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer { dispatch_sync(testqueue, ^{ @autoreleasepool { CVPixelBufferRef newBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); UIImage * image = [self.idrs getImageFromRPVideo:newBuffer]; IDRSFaceDetectParam *detectParam = [[IDRSFaceDetectParam alloc]init]; detectParam.dataType = IDRSFaceDetectInputTypePixelBuffer; detectParam.buffer = newBuffer; detectParam.inputAngle = 0; detectParam.outputAngle = 0; detectParam.faceNetType = 0; detectParam.supportFaceRecognition = false; detectParam.supportFaceLiveness = false; //人脸追踪 [self.idrs faceTrackFromVideo:detectParam faceDetectionCallback:^(NSError *error, NSArray<FaceDetectionOutput *> *faces) { dispatch_async(dispatch_get_main_queue(), ^{ self.drawView.faceDetectView.detectResult = faces; }); }]; } }) }
自定义推音频数据流回调时,MRTC 会自动触发调用,此时则需要在下面这个方法中发送数据。
- (void)didCustomAudioDataNeeded { //[self.artvcEgnine sendCustomAudioData:data]; }
应用内投屏
以下为 MRTC 自带的应用内投屏代码示例,如果需要使用跨应用投屏请参见 iOS 跨应用投屏。
开始投屏
ARTVCCreateScreenCaputurerParams* screenParams = [[ARTVCCreateScreenCaputurerParams alloc] init];
screenParams.provideRenderView = YES;
[self.artvcEgnine startScreenCaptureWithParams:screenParams complete:^(NSError* error){
if(error){
[weakSelf showToastWith:[NSString stringWithFormat:@"Error:%@",error] duration:1.0];
}else {
ARTVCPublishConfig* config = [[ARTVCPublishConfig alloc] init];
config.videoSource = ARTVCVideoSourceType_Screen;
config.audioEnable = NO;
config.videoProfile = ARTVCVideoProfileType_ScreenRatio_1280_15Fps;
config.tag = @"MPIDRS_ShareScreen";
[weakSelf.artvcEgnine publish:config];
}
}];
停止投屏
- (void)stopScreenSharing {
[self.artvcEgnine stopScreenCapture];
ARTVCUnpublishConfig* config = [[ARTVCUnpublishConfig alloc] init];
config.feed = self.screenLocalFeed;
[self.artvcEgnine unpublish:config complete:^(){
}];
}
推送语音流到房间内
自定义推流(音频数据专用)。
// MRTC 发布自定义推流用于TTS音频文件 - (void)startCustomAudioCapture{ ARTVCCreateCustomVideoCaputurerParams* params = [[ARTVCCreateCustomVideoCaputurerParams alloc] init]; params.audioSourceType = ARTVCAudioSourceType_Custom; params.customAudioFrameFormat.sampleRate = 16000; params.customAudioFrameFormat.samplesPerChannel = 160; ARTVCPublishConfig* audioConfig = [[ARTVCPublishConfig alloc] init]; audioConfig.videoSource = ARTVCVideoSourceType_Custom; audioConfig.videoEnable = YES; audioConfig.audioSource = ARTVCAudioSourceType_Custom; audioConfig.tag = @"customAuidoFeed"; self.audioConfig = audioConfig; self.customAudioCapturer = [_artvcEgnine createCustomVideoCapturer:params]; _artvcEgnine.autoPublish = NO; [_artvcEgnine publish:self.audioConfig]; }
推荐在自定义推流发布成功后开始 TTS 合成播报。
- (void)didConnectionStatusChangedTo:(ARTVCConnectionStatus)status forFeed:(ARTVCFeed*)feed { if (status == ARTVCConnectionStatusConnected && [feed isEqual:self.customLocalFeed]) { NSString * string = @"盛先生您好,被保险人于本附加合同生效(或最后复效)之日起一百八十日内"; self.customAudioData = [[NSMutableData alloc] init]; self.customAudioDataIndex = 0; self.ttsPlaying = YES; [self.idrs setTTSParam:@"extend_font_name" value:@"xiaoyun"]; [self.idrs setTTSParam:@"speed_level" value:@"1"]; [self.idrs startTTSWithText:string]; [self.idrs getTTSParam:@"speed_level"]; } }
在 TTS 代理回调中获取合成进度。
- (void)onNuiTtsUserdataCallback:(NSString *)info infoLen:(int)info_len buffer:(char *)buffer len:(int)len taskId:(NSString *)task_id{ NSLog(@"remote :: onNuiTtsUserdataCallback:%@ -- %d",info,info_len); }
在 MRTC 代理回调中发送音频数据。
- (void)didCustomAudioDataNeeded { NSData * data = [[IDRSBufferTool sharedInstance] bufferTool_read:320]; if (data) { [self.artvcEgnine sendCustomAudioData:data]; } }
开启服务端录制
成功初始化 MPIDRSSDK 和 MRTC 实例后相关录制功能才生效。
开启远程录制。
每开启一次服务端录制任务,录制回调则返回一个录制 ID,录制 ID 可用来停止、变更对应的录制任务。
MPRemoteRecordInfo *recordInfo = [[MPRemoteRecordInfo alloc] init]; recordInfo.roomId = self.roomId; // 控制台水印id //recordInfo.waterMarkId = self.watermarkId; recordInfo.tagFilter = tagPrefix; recordInfo.userTag = self.uid; recordInfo.recordType = MPRemoteRecordTypeBegin; // 业务根据实际情况传入是单流还是合流(混流) recordInfo.fileSuffix = MPRemoteRecordFileSingle; // 如果录制时有流布局要求,可参考MPRemoteRecordInfo自定义 // recordInfo.tagPositions = tagModelArray; // 如果录制时有端上自定义水印要求,可参考MPRemoteRecordInfo自定义 //recordInfo.overlaps = customOverlaps; [MPIDRSSDK executeRemoteRecord:recordInfo waterMarkHandler:^(NSError * _Nonnull error) { }];
变更录制配置。
已经开启的录制任务,支持修改水印和流布局。
MPRemoteRecordInfo *recordInfo = [[MPRemoteRecordInfo alloc] init]; recordInfo.roomId = self.roomId; recordInfo.recordType = MPRemoteRecordTypeChange; // 1、录制任务id recordInfo.recordId = recordId; // 2、流布局 recordInfo.tagPositions = tagModelArray; // 3、水印 recordInfo.overlaps = customOverlaps; [MPIDRSSDK executeRemoteRecord:recordInfo waterMarkHandler:^(NSError * _Nonnull error) { }];
MRTC 录制回调。
说明开启录制成功后需要上报一次录制任务。
- (void)didReceiveCustomSignalingResponse:(NSDictionary *)dictionary { id opcmdObject = [dictionary objectForKey:@"opcmd"]; if ([opcmdObject isKindOfClass:[NSNumber class]]) { int opcmd = [opcmdObject intValue]; switch (opcmd) { case MPRemoteRecordTypeBeginResponse: { self.startTime = [NSDate date]; // 回调录制id self.recordId = [dictionary objectForKey:@"recordId"]; if ([[dictionary objectForKey:@"msg"] isEqualToString:@"SUCCESS"]) { NSLog(@"开启录制成功,上报录制任务"); [self uploadOpenRecordInfo]; }else { NSLog(@"开启录制失败,此时业务需重新开始录制或者提醒业务"); } } break; case MPRemoteRecordTypeChangeResponse: { if ([[dictionary valueForKey:@"msg"] isEqualToString:@"SUCCESS"]) { NSLog(@"修改录制配置成功"); }else { NSLog(@"修改录制配置失败"); } } break; case MPRemoteRecordTypeStopResponse: { if ([[dictionary valueForKey:@"msg"] isEqualToString:@"SUCCESS"]) { NSLog(@"结束录制成功,如果有result文件产生 则上报文件"); [self uploadRecordResult]; }else { NSLog(@"结束录制错误"); } } break; default: break; } } } - (void)uploadOpenRecordInfo { IDRSUploadManagerParam *param = [[IDRSUploadManagerParam alloc] init]; param.appId = AppId; param.ak = Ak; param.sk = Sk; param.type = IDRSRecordRemote; param.recordAt = self.startTime; param.roomId = self.roomId; param.rtcRecordId = dictionary[@"recordId"]; // 业务自定义角色,跟随视频流tag一致即可 param.role = @"customRole"; // 合流视频 / 单流视频 param.videoType = IDRSRemoteRecordMix; param.outerBusinessId = [DemoSetting sharedInstance].outBusinessId; IDRSUploadManager *update = [[IDRSUploadManager alloc] init]; [update uploadFileWithParam:param success:^(id _Nonnull responseObject) { if ([[responseObject objectForKey:@"Code"] isEqualToString:@"OK"]) { [self showToastWith:@"result文件上传成功" duration:2]; } } failure:^(NSError * _Nonnull error, IDRSUploadManagerParam * _Nonnull upLoadParam) { if (upLoadParam) { [self showToastWith:@"result文件上传失败,请储存上传信息、下次再次上传" duration:3]; } }]; }
停止指定的服务端录制任务。
[MPIDRSSDK stopRemoteRecord:@"录制id"];
结束录制最终上传录制信息。
说明如果没有 reslut 文件,则录制结束时无需再次上报。
开启多次录制时,需要上报多次。
- (void)uploadRecordResult { IDRSUploadFile * filesss = [[IDRSUploadFile alloc] init]; filesss.fileName = @"filename"; filesss.filePath = @"filepath"; IDRSUploadManagerParam *param = [[IDRSUploadManagerParam alloc] init]; param.files = [NSArray arrayWithObjects:filesss, nil]; param.appId = AppId; param.ak = Ak; param.sk = Sk; param.type = IDRSRecordRemote; param.recordAt = self.startTime; param.roomId = self.roomId; param.rtcRecordId = dictionary[@"recordId"]; // 业务自定义角色,跟随视频流tag一致即可 param.role = @"customRole"; // 合流视频 / 单流视频 param.videoType = IDRSRemoteRecordMix; param.outerBusinessId = [DemoSetting sharedInstance].outBusinessId; IDRSUploadManager *update = [[IDRSUploadManager alloc] init]; [update uploadFileWithParam:param success:^(id _Nonnull responseObject) { if ([[responseObject objectForKey:@"Code"] isEqualToString:@"OK"]) { [self showToastWith:@"result文件上传成功" duration:2]; } } failure:^(NSError * _Nonnull error, IDRSUploadManagerParam * _Nonnull upLoadParam) { if (upLoadParam) { [self showToastWith:@"result文件上传失败,请储存上传信息、下次再次上传" duration:3]; } }]; }