更新时间:2019-11-20
描述
会议中,主讲人和与会者可以进行屏幕共享。
前提条件:
业务流程
主讲人共享屏幕
SDK并未对接口tsdk_app_share_set_owner的调用者进行与角色限制,但实际应用场景中,UI应该仅对主讲人才提供主动“共享屏幕”入口。
//oc code - (BOOL)inviteDataShareWithNumber:(NSString *)number { TSDK_RESULT result = tsdk_app_share_set_owner(_confHandle, (TSDK_CHAR*)[number UTF8String], TSDK_E_CONF_AS_ACTION_ADD); return result; }
TSDK_E_CONF_EVT_AS_OWNER_CHANGE通知中携带的共享类型为TSDK_E_CONF_AS_ACTION_ADD,并且共享者ID为自己,调起系统屏幕录制界面,并选择当前程序然后点击“开始录制”。
//oc code - (void)startReplayKitBroadcast { dispatch_async(dispatch_get_main_queue(), ^{ DDLogInfo(@"enter startReplayKitBroadcast "); if (@available(iOS 12, *)) { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; BOOL isNeedSetpreferredExtension = [userDefaults boolForKey:@"ScreenShareFlag"]; NSString *mainBundleId = [[NSBundle mainBundle]bundleIdentifier]; NSString *extensionId = [mainBundleId stringByAppendingString:@".ScreenShareExtension"]; if (isNeedSetpreferredExtension) { self.broadcastPickerView.preferredExtension = extensionId; } self.broadcastPickerView.showsMicrophoneButton = NO; for (UIView *view in self.broadcastPickerView.subviews) { if ([view isKindOfClass:[UIButton class]]) { [(UIButton *)view sendActionsForControlEvents:UIControlEventTouchDown]; } } } }); }
1、在一个全局的对象的初始化方法中,调用initScreenShareManager初始化screenSharemanage对象;
2、当点击“开始录制”后,会上报系统录屏状态,当状态state == 1时,且自己已经加入数据会议中,开始调用设置虚拟显示器信息接口tsdk_app_share_set_virtual_view_info(),如果不在数据会议中,则通知系统关闭屏幕录制功能。
3、录制开始后,系统会不停的上报屏幕数据上来,调用processImage()方法,将图片数据的相关信息转换后传给服务器。
//oc code - (void)initScreenShareManager { DDLogInfo(@"enter initScreenShareManager "); NSString *appGroup = @"group.eSpaceMclientV2"; self.screenShareManager = [[ScreenShareManager alloc]initWithAppGroupIdentifier:appGroup]; [self.screenShareManager listenForMessageWithIdentifier:@"screenshare" listener:^(id messageObject) { NSDictionary *dir = [messageObject valueForKey:@"screendata"]; [self processImage:dir]; }]; [self.screenShareManager listenForMessageWithIdentifier:@"screenShareStateChange" listener:^(id messageObject) { long state = [[messageObject valueForKey:@"state"] longValue]; if (state == 1) { if (self.isJoinDataConfSuccess) { self.mIsScreenSharing = YES; [self startDataConfAsPre]; [self startDataShare]; } else { NSError *error = [[NSError alloc] initWithDomain:@"ScreenShare" code:-1 userInfo:@{NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"the meeting is unavailable", nil)}]; [self.screenShareManager passMessageObject:@{@"result" : error} identifier:@"StopBroadcast"]; } } else if (state == 0) { [self confStopReplayKitBroadcast]; } }]; } - (void) startDataConfAsPre { DDLogInfo(@"enter startDataConfAsPre _mIsScreenSharing: %d _mWidthPixels: %d _mHeightPixels: %d " , self.mIsScreenSharing, self.mWidthPixels , self.mHeightPixels); self.mIsStartScreenShareDelayed = NO; if (self.mWidthPixels == 0 || self.mHeightPixels == 0) { self.mIsStartScreenShareDelayed = YES; return; } TSDK_S_CONF_AS_VIRTUAL_VIEW_INFO virtual_view_info; memset(&virtual_view_info, 0, sizeof(TSDK_S_CONF_AS_VIRTUAL_VIEW_INFO)); virtual_view_info.width = _mWidthPixels; virtual_view_info.height = _mHeightPixels; virtual_view_info.bit_count = 32; tsdk_app_share_set_virtual_view_info(_confHandle, &virtual_view_info); } -(void)processImage:(NSDictionary *)dictionary { unsigned int width = [[dictionary objectForKey:@"width"] unsignedIntValue]; unsigned int height = [[dictionary objectForKey:@"height"] unsignedIntValue]; long orientation = [[dictionary objectForKey:@"orientation"] longValue]; if (!self.mIsScreenSharing) { if (orientation == UIImageOrientationLeft || orientation == UIImageOrientationRight || orientation == UIImageOrientationLeftMirrored || orientation == UIImageOrientationRightMirrored) { self.mWidthPixels = height; self.mHeightPixels = width; } else { self.mWidthPixels = width; self.mHeightPixels = height; } if (self.mIsStartScreenShareDelayed) { [self startDataConfAsPre]; } return; } unsigned int yPitch = [[dictionary objectForKey:@"yPitch"] unsignedIntValue]; unsigned int cbCrPitch = [[dictionary objectForKey:@"yPitch"] unsignedIntValue]; NSData *yData = [dictionary objectForKey:@"yData"]; NSData *uvData = [dictionary objectForKey:@"uvData"]; uint8_t *yBuffer = (unsigned char *)[yData bytes]; uint8_t *cbCrBuffer = (unsigned char *)[uvData bytes]; TSDK_S_CONF_AS_VIEW_DATA_INFO asViewUpdataData; memset(&asViewUpdataData, 0, sizeof(TSDK_S_CONF_AS_VIEW_DATA_INFO)); asViewUpdataData.y_data = yBuffer; asViewUpdataData.cb_cr_data = cbCrBuffer; asViewUpdataData.y_data_size = yPitch; asViewUpdataData.cb_cr_data_size = cbCrPitch; asViewUpdataData.width = width; asViewUpdataData.height = height; asViewUpdataData.orientation = (TSDK_E_IMAGE_ORIENTATION)orientation; tsdk_app_share_update_view_data(_confHandle, &asViewUpdataData); }
//oc code - (void)startDataShare { TSDK_RESULT result = tsdk_app_share_start(_confHandle, TSDK_E_CONF_APP_SHARE_DESKTOP); }
//oc code case TSDK_E_CONF_EVT_AS_SCREEN_DATA_UPDATE: { DDLogInfo(@"TSDK_E_CONF_EVT_AS_SCREEN_DATA_UPDATE"); [self handleScreenShareDataConfhandle:notify.param1]; } break;
//oc code -(void)handleScreenShareDataConfhandle:(TSDK_UINT32 )confHandle { if (!_isStartScreenSharing) { DDLogInfo(@"[Meeting] COMPT_MSG_AS_ON_SCREEN_DATA:current share type is not screen share!"); return; } if (_currentDataShareTypeId != 0x0002 && _currentDataShareTypeId != 0 && _currentDataShareTypeId != -1) { return; } TSDK_S_CONF_AS_SCREEN_DATA screenData; memset((void *)(&screenData), 0, sizeof(screenData)); // 获取数据 TSDK_RESULT dataRet = tsdk_app_share_get_screen_data(confHandle, &screenData); if (dataRet != TSDK_SUCCESS) { DDLogInfo(@"tsdk_app_share_get_screen_data failed:%d",dataRet); return; } DDLogInfo(@"tsdk_app_share_get_screen_data :%d",dataRet); char *data = (char *)screenData.data; if (data == NULL) { return; } TSDK_UINT32 ssize = *((TSDK_UINT32 *)((char *)data + sizeof(TSDK_UINT16))); NSData *imageData = [NSData dataWithBytes:data length:ssize]; if (imageData == nil) { DDLogInfo(@"share imageData from data fail!"); return; } __weak typeof(self) weakSelf = self; dispatch_async(espace_dataconf_datashare_queue, ^{ [weakSelf receiveSharedData:imageData]; }); }
主讲人邀请其他与会者共享屏幕
SDK并未对接口tup_conf_as_set_owner的调用者进行与角色限制,但实际应用场景中,UI应该仅对主讲人才提供“邀请其他与会者共享”入口;成功调用该接口后,原来拥有共享权限的用户的共享权限会自动取消,正在进行的共享会停止。
//oc code - (BOOL)inviteDataShareWithNumber:(NSString *)number { TSDK_RESULT result = tsdk_app_share_set_owner(_confHandle, (TSDK_CHAR*)[number UTF8String], TSDK_E_CONF_AS_ACTION_ADD); return result; }
TSDK_E_CONF_EVT_AS_OWNER_CHANGE通知中携带的共享类型为TSDK_E_CONF_AS_ACTION_REQUEST,并且共享者ID为自己,UI应提示用户收到共享邀请,并提供“同意共享”和“拒绝共享”入口,“同意共享”则调起系统屏幕录制界面,并选择当前程序然后点击开始共享,“拒绝共享”则调用tsdk_app_share_set_owner()接口,释放owner
//oc code case TSDK_E_CONF_EVT_AS_OWNER_CHANGE: { TSDK_E_CONF_AS_ACTION_TYPE actionType = (TSDK_E_CONF_AS_ACTION_TYPE)notify.param2; TSDK_S_ATTENDEE *owner = (TSDK_S_ATTENDEE *)notify.data; TSDK_BOOL isSelf = owner->status_info.is_self; if (isSelf) { if (actionType == TSDK_E_CONF_AS_ACTION_ADD) { dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:APP_START_SYSTEM_SHARE_VIEW object:nil]; }); }else if (actionType == TSDK_E_CONF_AS_ACTION_DELETE){ self.mIsScreenSharing = NO; [self confStopReplay]; [self respondsECConferenceDelegateWithType:SELF_DATACONF_AS_SCREEN_SHARE_STOP result:nil]; }else if (actionType == TSDK_E_CONF_AS_ACTION_REQUEST){ dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:CONF_SHARE_REQUEST_ACTION object:nil]; }); } } } break; - (BOOL)cancelDataShareWithNumber:(NSString *)number { TSDK_RESULT result = tsdk_app_share_set_owner(_confHandle, (TSDK_CHAR*)[number UTF8String], TSDK_E_CONF_AS_ACTION_DELETE); return result; }
共享者主动结束共享
//oc code - (void)confStopReplayKitBroadcast { if (self.mIsScreenSharing) { TSDK_RESULT result = tsdk_app_share_stop(_confHandle); } [self confStopReplay]; } - (void)confStopReplay { NSError *error = [[NSError alloc] initWithDomain:@"ScreenShare" code:-1 userInfo:@{NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"stop_screen_share", nil)}]; [self.screenShareManager passMessageObject:@{@"result" : error} identifier:@"StopBroadcast"]; _mWidthPixels = 0; _mHeightPixels = 0; self.mIsScreenSharing = NO; _mIsStartScreenShareDelayed = NO; }
主讲人结束共享者共享
TSDK_E_CONF_EVT_AS_OWNER_CHANGE通知中携带的共享类型为TSDK_E_CONF_AS_ACTION_DELETE
,并且共享者ID为自己,则表示自己的共享权限被取消,停止自己共享
//oc code case TSDK_E_CONF_EVT_AS_OWNER_CHANGE: { TSDK_E_CONF_AS_ACTION_TYPE actionType = (TSDK_E_CONF_AS_ACTION_TYPE)notify.param2; TSDK_S_ATTENDEE *owner = (TSDK_S_ATTENDEE *)notify.data; TSDK_BOOL isSelf = owner->status_info.is_self; if (isSelf) { if (actionType == TSDK_E_CONF_AS_ACTION_ADD) { dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:APP_START_SYSTEM_SHARE_VIEW object:nil]; }); }else if (actionType == TSDK_E_CONF_AS_ACTION_DELETE){ self.mIsScreenSharing = NO; [self confStopReplay]; [self respondsECConferenceDelegateWithType:SELF_DATACONF_AS_SCREEN_SHARE_STOP result:nil]; }else if (actionType == TSDK_E_CONF_AS_ACTION_REQUEST){ dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:CONF_SHARE_REQUEST_ACTION object:nil]; }); } } } break;
1、调用tsdk_app_share_stop接口前,先结束本地系统界面录制。
//oc code - (void)confStopReplayKitBroadcast { if (self.mIsScreenSharing) { TSDK_RESULT result = tsdk_app_share_stop(_confHandle); } [self confStopReplay]; } - (void)confStopReplay { NSError *error = [[NSError alloc] initWithDomain:@"ScreenShare" code:-1 userInfo:@{NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"stop_screen_share", nil)}]; [self.screenShareManager passMessageObject:@{@"result" : error} identifier:@"StopBroadcast"]; _mWidthPixels = 0; _mHeightPixels = 0; self.mIsScreenSharing = NO; _mIsStartScreenShareDelayed = NO; }
注意事项
无。
描述
在其他终端中,与会者间可以通过标注功能在共享界面进行远程交流。
1、在屏幕共享时,当别人发起标注,移动端iOS支持进行标注,不支持主动发起标注功能。
业务流程
设置画笔和画刷
//oc code case TSDK_E_CONF_EVT_AS_STATE_CHANGE: { DDLogInfo(@"TSDK_E_CONF_EVT_AS_STATE_CHANGE"); TSDK_S_CONF_AS_STATE_INFO *shareState = (TSDK_S_CONF_AS_STATE_INFO *)notify.data; BOOL isStopSharing = NO; TSDK_E_CONF_SHARE_STATE state = shareState->state; switch (state) { case TSDK_E_CONF_AS_STATE_NULL: { _isStartScreenSharing = NO; isStopSharing = YES; } break; case TSDK_E_CONF_AS_STATE_START: case TSDK_E_CONF_AS_STATE_VIEW: { TSDK_S_CONF_AS_STATE_INFO *as_state_info = (TSDK_S_CONF_AS_STATE_INFO *)notify.data; TSDK_UINT32 Annotation = as_state_info->sub_state; [self beginAnnotation:(Annotation == 512)]; _isStartScreenSharing = YES; _currentDataShareTypeId = TSDK_E_COMPONENT_AS; [self handleScreenShareDataConfhandle:notify.param1]; } break; default: break; } if (isStopSharing) { __weak typeof(self) weakSelf = self; dispatch_async(espace_dataconf_datashare_queue, ^{ [weakSelf stopSharedData]; _isStartScreenSharing = NO; }); } } break; |
//oc code - (void)annotationSetPenAndAnnotationColor:(unsigned int)color lineWidth:(int)lineWidth { TSDK_S_ANNOTATION_PEN_INFO newPenInfo; memset(&newPenInfo, 0, sizeof(TSDK_S_ANNOTATION_PEN_INFO)); newPenInfo.style = TSDK_E_ANNOTATION_PEN_STYLE_SOLID; newPenInfo.color = color; newPenInfo.width = lineWidth; TSDK_S_ANNOTATION_PEN_INFO oldPenInfo; memset(&oldPenInfo, 0, sizeof(TSDK_S_ANNOTATION_PEN_INFO)); TSDK_RESULT result = tsdk_annotation_set_pen(_confHandle, (TSDK_E_COMPONENT_ID)_currentDataShareTypeId, TSDK_E_ANNOTATION_PEN_NORMAL, &newPenInfo, &oldPenInfo); DDLogInfo(@"Annotation tsdk_annotation_set_pen: %d", result); TSDK_S_ANNOTATION_BRUSH_INFO newBrushInfo; memset(&newBrushInfo, 0, sizeof(TSDK_S_ANNOTATION_BRUSH_INFO)); newBrushInfo.style = TSDK_E_ANNOTATION_BRUSH_SOLID; newBrushInfo.color = color; TSDK_S_ANNOTATION_BRUSH_INFO oldBrushInfo; memset(&oldBrushInfo, 0, sizeof(TSDK_S_ANNOTATION_BRUSH_INFO)); TSDK_RESULT brushResult = tsdk_annotation_set_brush(_confHandle, (TSDK_E_COMPONENT_ID)_currentDataShareTypeId, &newBrushInfo, &oldBrushInfo); DDLogInfo(@"Annotation tsdk_annotation_set_brush: %d", brushResult); } |
创建几何标注
//oc code -(void)conferenceCreateAnnotationWithStartPointx:(long)pointx Pointy:(long)pointy { CGFloat hScale = [self heightScale]; CGFloat wScale = [self widthScale]; TSDK_S_POINT tsdkPoint; memset(&tsdkPoint, 0, sizeof(TSDK_S_POINT)); tsdkPoint.x = (TSDK_INT32)pointx * wScale; tsdkPoint.y = (TSDK_INT32)pointy * hScale; tsdk_annotation_create_start(_confHandle, (TSDK_E_COMPONENT_ID)_currentDataShareTypeId, TSDK_NULL_PTR, TSDK_E_ANNOTATION_DRAWING, 1, &tsdkPoint); } |
//oc code - (void)conferenceUpdateAnnotationWithPointx:(long)pointx Pointy:(long)pointy { CGFloat hScale = [self heightScale]; CGFloat wScale = [self widthScale]; TSDK_S_ANNOTATION_DRAWING_DATA data; memset(&data, 0, sizeof(TSDK_S_ANNOTATION_DRAWING_DATA)); data.point.x = (TSDK_INT32)pointx * wScale; data.point.y = (TSDK_INT32)pointy * hScale; tsdk_annotation_create_update(_confHandle, (TSDK_E_COMPONENT_ID)_currentDataShareTypeId, TSDK_E_ANNOTATION_DRAWING, &data); } |
若完成标注创建,则此接口的第三个参数应设置为0,否则设置为1。
//oc code - (void)conferenceFinishAnnotation { TSDK_UINT32 annotation_id = 0; tsdk_annotation_create_done(_confHandle, (TSDK_E_COMPONENT_ID)_currentDataShareTypeId, 0, &annotation_id); } |
实际上,在标注创建过程中,每次数据更新之后都会收到相应的数据更新通知,当前因流程图限制,仅呈现在标注创建完成后收到数据更新通知消息。
注意事项
无。
删除标注
此接口可以对选中的多个标注同时开始删除,应用程序也可以实现对标注ID的记录管理,给用户提供删除“自己创建的标注”、“其他人创建的标注”和“所有标注”功能入口。
擦除可以擦除线,擦除所有两种擦除场景。
//oc code - (void)conferenceEraseAnnotationsIntersectedBySegmentWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint { TSDK_S_ANNOTATION_HIT_TEST_LINE_INFO hit_test_line_info; memset(&hit_test_line_info, 0, sizeof(TSDK_S_ANNOTATION_HIT_TEST_LINE_INFO)); hit_test_line_info.doc_page_info.component_id = (TSDK_E_COMPONENT_ID)_currentDataShareTypeId; hit_test_line_info.doc_page_info.document_id = 0; hit_test_line_info.doc_page_info.page_count = 0; hit_test_line_info.doc_page_info.page_index = 0; hit_test_line_info.component_id = (TSDK_E_COMPONENT_ID)_currentDataShareTypeId; CGFloat hScale = [self heightScale]; CGFloat wScale = [self widthScale]; hit_test_line_info.start_point.x = (TSDK_INT32)startPoint.x * wScale; hit_test_line_info.start_point.y = (TSDK_INT32)startPoint.y * hScale; hit_test_line_info.end_point.x = (TSDK_INT32)endPoint.x * wScale; hit_test_line_info.end_point.y = (TSDK_INT32)endPoint.y * hScale; hit_test_line_info.hit_test_mode = TSDK_E_ANNOTATION_HIT_TEST_SOMEONE; strcpy(hit_test_line_info.user_number, [self.selfJoinNumber UTF8String]); TSDK_UINT32 *selectedIds = NULL; TSDK_UINT32 idsCount = 0; TSDK_RESULT result = tsdk_annotation_hit_test_line(_confHandle, &hit_test_line_info, &selectedIds, &idsCount); DDLogInfo(@"tsdk_annotation_hit_test_line: %d", result); if (selectedIds && idsCount > 0) { TSDK_S_ANNOTATION_DELETE_INFO delete_info; delete_info.annotation_id_list = selectedIds; delete_info.count = idsCount; delete_info.doc_page_info.component_id = (TSDK_E_COMPONENT_ID)_currentDataShareTypeId; delete_info.doc_page_info.document_id = 0; delete_info.doc_page_info.page_count = 0; delete_info.doc_page_info.page_index = 0; delete_info.component_id = (TSDK_E_COMPONENT_ID)_currentDataShareTypeId; result = tsdk_annotation_delete_annotation(_confHandle, &delete_info); DDLogInfo(@"Annotation tsdk_annotation_delete_annotation: %d", result); } } - (void)conferenceEraseAllAnnotations { TSDK_S_RECTANGULAR rect = { .left = 0, .top = 0, .right = (TSDK_INT32)INT_MAX, .bottom = (TSDK_INT32)INT_MAX }; [self conferenceEraseAnnotationsInRect:rect]; } - (void)conferenceEraseAnnotationsInRect:(TSDK_S_RECTANGULAR)rect { TSDK_UINT32 *selectedIds = NULL; TSDK_UINT32 idsCount = 0; TSDK_S_ANNOTATION_HIT_TEST_RECT_INFO hit_test_rect_info; hit_test_rect_info.doc_page_info.component_id = (TSDK_E_COMPONENT_ID)_currentDataShareTypeId; if (_currentDataShareTypeId == TSDK_E_COMPONENT_AS) { hit_test_rect_info.doc_page_info.document_id = 0; hit_test_rect_info.doc_page_info.page_count = 0; hit_test_rect_info.doc_page_info.page_index = 0; } hit_test_rect_info.hit_test_mode = TSDK_E_ANNOTATION_HIT_TEST_SOMEONE; hit_test_rect_info.rectangle_area.bottom = rect.bottom; hit_test_rect_info.rectangle_area.left = rect.left; hit_test_rect_info.rectangle_area.right = rect.right; hit_test_rect_info.rectangle_area.top = rect.top; strcpy(hit_test_rect_info.user_number, [self.selfJoinNumber UTF8String]); hit_test_rect_info.component_id = (TSDK_E_COMPONENT_ID)_currentDataShareTypeId; TSDK_RESULT result = tsdk_annotation_hit_test_rect(_confHandle, &hit_test_rect_info, &selectedIds, &idsCount); DDLogInfo(@"Annotation eraseAnnotationsInRect: tup_conf_annotation_hittest_rect returns: %d", result); if (selectedIds && idsCount > 0) { TSDK_S_ANNOTATION_DELETE_INFO delete_info; delete_info.annotation_id_list = selectedIds; delete_info.count = idsCount; delete_info.doc_page_info.component_id = (TSDK_E_COMPONENT_ID)_currentDataShareTypeId; delete_info.doc_page_info.document_id = 0; delete_info.doc_page_info.page_count = 0; delete_info.doc_page_info.page_index = 0; delete_info.component_id = (TSDK_E_COMPONENT_ID)_currentDataShareTypeId; result = tsdk_annotation_delete_annotation(_confHandle, &delete_info); DDLogInfo(@"Annotation eraseAnnotationsInRect: tup_conf_annotation_delete returns: %d", result); } } |
注意事项
无。
描述
会议中,移动与会者观看屏幕或程序共享。
前提条件
业务流程
一、开始观看屏幕或程序共享
case TSDK_E_CONF_EVT_AS_STATE_CHANGE: { DDLogInfo(@"TSDK_E_CONF_EVT_AS_STATE_CHANGE"); TSDK_S_CONF_AS_STATE_INFO *shareState = (TSDK_S_CONF_AS_STATE_INFO *)notify.data; TSDK_E_CONF_SHARE_STATE state = shareState->state; if (state == TSDK_E_CONF_AS_STATE_NULL) { [self respondsECConferenceDelegateWithType:DATACONF_SHARE_SCREEN_DATA_STOP result:nil]; } } break;
case TSDK_E_CONF_EVT_AS_SCREEN_DATA_UPDATE: { DDLogInfo(@"TSDK_E_CONF_EVT_AS_SCREEN_DATA_UPDATE"); [self handleScreenShareDataConfhandle:notify.param1]; } break;
屏幕共享数据通过接口同步返回,转换成图片格式在UI显示。
-(void)handleScreenShareDataConfhandle:(TSDK_UINT32 )confHandle { TSDK_S_CONF_AS_SCREEN_DATA screenData; memset((void *)(&screenData), 0, sizeof(screenData)); // get data info TSDK_RESULT dataRet = tsdk_app_share_get_screen_data(confHandle, &screenData); if (dataRet != TSDK_SUCCESS) { DDLogInfo(@"tsdk_app_share_get_screen_data failed:%d",dataRet); return; } DDLogInfo(@"tsdk_app_share_get_screen_data :%d",dataRet); char *data = (char *)screenData.data; TSDK_UINT32 ssize = *((TSDK_UINT32 *)((char *)data + sizeof(TSDK_UINT16))); NSData *imageData = [NSData dataWithBytes:data length:ssize]; UIImage *image = [[UIImage alloc] initWithData:imageData]; if (image == nil) { DDLogInfo(@"share image from data fail!"); return; } NSDictionary *shareDataInfo = @{ DATACONF_SHARE_DATA_KEY:image }; [self respondsECConferenceDelegateWithType:DATA_CONF_AS_ON_SCREEN_DATA result:shareDataInfo]; }
二、屏幕或程序共享结束处理
当前图示为共享者主动停止共享,若主讲人结束共享者共享,则对于观看侧,相应的消息顺序相反。
注意事项
无。
描述
会议中,所有人可以收到其他与会者发送的聊天消息内容。
前提条件是加入数据会议成功。
业务流程
TSDK_RESULT ret; ret = tsdk_send_chat_msg_in_conference(confHandle, chatMsgInfo); if (TSDK_SUCCESS != ret) { LOG_D_CALL_ERROR("send chat msg failed. result=%#x", ret); return -1; } return TSDK_SUCCESS;
case TSDK_E_CONF_EVT_RECV_CHAT_MSG: { /*Notify UI*/ }
注意事项
无。
描述
会议中,移动与会者观看文档共享。
移动应用程序暂不具备共享文档的能力,文档的共享者为PC应用程序。
前提条件
业务流程
一、开始观看文档共享
case TSDK_E_CONF_EVT_DS_DOC_CURRENT_PAGE_IND: { TSDK_S_DOC_PAGE_BASE_INFO *pageInfo = (TSDK_S_DOC_PAGE_BASE_INFO *)notify.data; [self handleDsDocCurrentPageInfoWithConfHandle:notify.param1 andPageInfo:pageInfo]; } break;
代码示例:
- (void)handleDsDocCurrentPageInfoWithConfHandle:(TSDK_INT32)confHandle andPageInfo:(TSDK_S_DOC_PAGE_BASE_INFO *)pageInfo { tsdk_doc_share_set_current_page(confHandle, pageInfo, NO); TSDK_S_DOC_PAGE_DETAIL_INFO detailInfo; memset(&detailInfo, 0, sizeof(TSDK_S_DOC_PAGE_DETAIL_INFO)); TSDK_RESULT result = tsdk_doc_share_get_syn_document_info(confHandle, pageInfo->component_id, &detailInfo); if (result == TSDK_SUCCESS && (detailInfo.height > 0 && detailInfo.width > 0)) { TSDK_S_SIZE size; memset(&size, 0, sizeof(TSDK_S_DOC_PAGE_BASE_INFO)); size.width = detailInfo.width; size.high = detailInfo.height; tsdk_doc_share_set_canvas_size(confHandle, pageInfo->component_id, &size, YES); }}
case TSDK_E_CONF_EVT_DS_DOC_DRAW_DATA_NOTIFY: { [self handleDsDocShareDataConfHandle:notify.param1]; } break;
文档共享数据通过接口同步返回,转换成图片格式在UI显示。
- (void)handleDsDocShareDataConfHandle:(TSDK_UINT32)confHandle { __weak typeof(self) weakSelf = self; dispatch_async(espace_dataconf_datashare_queue, ^{ @autoreleasepool { TSDK_UINT32 iWidth = 0; TSDK_UINT32 iHeight = 0; TSDK_VOID *pData = tsdk_doc_share_get_surface_bmp(confHandle, TSDK_E_COMPONENT_DS, &iWidth, &iHeight); if (NULL == pData) { DDLogInfo(@"[Meeting] Data is null."); return; } char *pBmpData = (char *)pData; TSDK_UINT32 wSize = *(TSDK_UINT32 *)((char *)pBmpData + sizeof(TSDK_UINT16)); NSData *imgData = [NSData dataWithBytes:(void*)pBmpData length:wSize]; if (nil == imgData) { DDLogInfo(@"[Meeting] Make image from data failed."); return; } [weakSelf receiveSharedData:imgData]; } }); }
二、文档共享结束处理
当前图示为共享者主动停止共享,若主讲人结束共享者共享,则对于观看侧,相应的消息顺序相反。
注意事项
无。
描述
会议中,移动与会者观看白板共享。
移动应用程序暂不具备共享白板的能力,白板的共享者为PC应用程序。
前提条件:
业务流程
一、开始观看白板共享
case TSDK_E_CONF_EVT_WB_DOC_CURRENT_PAGE_IND: { TSDK_S_DOC_PAGE_BASE_INFO *pageInfo = (TSDK_S_DOC_PAGE_BASE_INFO *)notify.data; [self handleDsDocCurrentPageInfoWithConfHandle:notify.param1 andPageInfo:pageInfo]; } break;
代码示例:
- (void)handleDsDocCurrentPageInfoWithConfHandle:(TSDK_INT32)confHandle andPageInfo:(TSDK_S_DOC_PAGE_BASE_INFO *)pageInfo { tsdk_doc_share_set_current_page(confHandle, pageInfo, NO); TSDK_S_DOC_PAGE_DETAIL_INFO detailInfo; memset(&detailInfo, 0, sizeof(TSDK_S_DOC_PAGE_DETAIL_INFO)); TSDK_RESULT result = tsdk_doc_share_get_syn_document_info(confHandle, pageInfo->component_id, &detailInfo); if (result == TSDK_SUCCESS && (detailInfo.height > 0 && detailInfo.width > 0)) { TSDK_S_SIZE size; memset(&size, 0, sizeof(TSDK_S_DOC_PAGE_BASE_INFO)); size.width = detailInfo.width; size.high = detailInfo.height; tsdk_doc_share_set_canvas_size(confHandle, pageInfo->component_id, &size, YES); }}
case TSDK_E_CONF_EVT_WB_DOC_DRAW_DATA_NOTIFY: { [self handleWbDocShareDataConfHandle:notify:notify.param1]; } break;
白板共享数据通过接口同步返回,转换成图片格式在UI显示。
- (void)handleWbDocShareDataConfHandle:(TSDK_UINT32)confHandle { __weak typeof(self) weakSelf = self; dispatch_async(espace_dataconf_datashare_queue, ^{ @autoreleasepool { TSDK_UINT32 iWidth = 0; TSDK_UINT32 iHeight = 0; TSDK_VOID *pData = tsdk_doc_share_get_surface_bmp(confHandle, TSDK_E_COMPONENT_DS, &iWidth, &iHeight); if (NULL == pData) { DDLogInfo(@"[Meeting] Data is null."); return; } char *pBmpData = (char *)pData; TSDK_UINT32 wSize = *(TSDK_UINT32 *)((char *)pBmpData + sizeof(TSDK_UINT16)); NSData *imgData = [NSData dataWithBytes:(void*)pBmpData length:wSize]; if (nil == imgData) { DDLogInfo(@"[Meeting] Make image from data failed."); return; } [weakSelf receiveSharedData:imgData]; } }); }
二、白板共享结束处理
当前图示为共享者主动停止共享,若主讲人结束共享者共享,则对于观看侧,相应的消息顺序相反。
注意事项
无。