主頁 > 服務(wù)與支持 > 開發(fā)平臺(tái) > 客戶端SDK參考 > iOS Native SDK > 會(huì)議 桌面協(xié)同與共享
更新時(shí)間:2019-11-20
iOS 屏幕共享要求操作系統(tǒng) iOS 12.0 及以上版本,使用功能時(shí),需要啟動(dòng)系統(tǒng)的屏幕錄制功能,因此需要配置相關(guān)工程,詳見會(huì)議中屏幕共享進(jìn)行配置。
描述
會(huì)議中,主講人和與會(huì)者可以進(jìn)行屏幕共享。
前提條件:
業(yè)務(wù)流程
主講人共享屏幕
SDK并未對接口tsdk_app_share_set_owner的調(diào)用者進(jìn)行與角色限制,但實(shí)際應(yīng)用場景中,UI應(yīng)該僅對主講人才提供主動(dòng)“共享屏幕”入口。
//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為自己,調(diào)起系統(tǒng)屏幕錄制界面,并選擇當(dāng)前程序然后點(diǎn)擊“開始錄制”。
//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、在一個(gè)全局的對象的初始化方法中,調(diào)用initScreenShareManager初始化screenSharemanage對象;
2、當(dāng)點(diǎn)擊“開始錄制”后,會(huì)上報(bào)系統(tǒng)錄屏狀態(tài),當(dāng)狀態(tài)state == 1時(shí),且自己已經(jīng)加入數(shù)據(jù)會(huì)議中,開始調(diào)用設(shè)置虛擬顯示器信息接口tsdk_app_share_set_virtual_view_info(),如果不在數(shù)據(jù)會(huì)議中,則通知系統(tǒng)關(guān)閉屏幕錄制功能。
3、錄制開始后,系統(tǒng)會(huì)不停的上報(bào)屏幕數(shù)據(jù)上來,調(diào)用processImage()方法,將圖片數(shù)據(jù)的相關(guān)信息轉(zhuǎn)換后傳給服務(wù)器。
//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)); // 獲取數(shù)據(jù) 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]; }); }
主講人邀請其他與會(huì)者共享屏幕
SDK并未對接口tup_conf_as_set_owner的調(diào)用者進(jìn)行與角色限制,但實(shí)際應(yīng)用場景中,UI應(yīng)該僅對主講人才提供“邀請其他與會(huì)者共享”入口;成功調(diào)用該接口后,原來擁有共享權(quán)限的用戶的共享權(quán)限會(huì)自動(dòng)取消,正在進(jìn)行的共享會(huì)停止。
//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應(yīng)提示用戶收到共享邀請,并提供“同意共享”和“拒絕共享”入口,“同意共享”則調(diào)起系統(tǒng)屏幕錄制界面,并選擇當(dāng)前程序然后點(diǎn)擊開始共享,“拒絕共享”則調(diào)用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; }
后繼步驟與“主講人共享屏幕”相同。
共享者主動(dòng)結(jié)束共享
//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; }
主講人結(jié)束共享者共享
TSDK_E_CONF_EVT_AS_OWNER_CHANGE通知中攜帶的共享類型為TSDK_E_CONF_AS_ACTION_DELETE
,并且共享者ID為自己,則表示自己的共享權(quán)限被取消,停止自己共享
//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、調(diào)用tsdk_app_share_stop接口前,先結(jié)束本地系統(tǒng)界面錄制。
//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; }
注意事項(xiàng)
無。
描述
在其他終端中,與會(huì)者間可以通過標(biāo)注功能在共享界面進(jìn)行遠(yuǎn)程交流。
1、在屏幕共享時(shí),當(dāng)別人發(fā)起標(biāo)注,移動(dòng)端iOS支持進(jìn)行標(biāo)注,不支持主動(dòng)發(fā)起標(biāo)注功能。
業(yè)務(wù)流程
設(shè)置畫筆和畫刷
//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); } |
創(chuàng)建幾何標(biāo)注
//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); } |
若完成標(biāo)注創(chuàng)建,則此接口的第三個(gè)參數(shù)應(yīng)設(shè)置為0,否則設(shè)置為1。
//oc code - (void)conferenceFinishAnnotation { TSDK_UINT32 annotation_id = 0; tsdk_annotation_create_done(_confHandle, (TSDK_E_COMPONENT_ID)_currentDataShareTypeId, 0, &annotation_id); } |
實(shí)際上,在標(biāo)注創(chuàng)建過程中,每次數(shù)據(jù)更新之后都會(huì)收到相應(yīng)的數(shù)據(jù)更新通知,當(dāng)前因流程圖限制,僅呈現(xiàn)在標(biāo)注創(chuàng)建完成后收到數(shù)據(jù)更新通知消息。
注意事項(xiàng)
無。
刪除標(biāo)注
此接口可以對選中的多個(gè)標(biāo)注同時(shí)開始刪除,應(yīng)用程序也可以實(shí)現(xiàn)對標(biāo)注ID的記錄管理,給用戶提供刪除“自己創(chuàng)建的標(biāo)注”、“其他人創(chuàng)建的標(biāo)注”和“所有標(biāo)注”功能入口。
擦除可以擦除線,擦除所有兩種擦除場景。
//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); } } |
注意事項(xiàng)
無。
描述
會(huì)議中,移動(dòng)與會(huì)者觀看屏幕或程序共享。
前提條件
業(yè)務(wù)流程
一、開始觀看屏幕或程序共享
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;
屏幕共享數(shù)據(jù)通過接口同步返回,轉(zhuǎn)換成圖片格式在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]; }
二、屏幕或程序共享結(jié)束處理
當(dāng)前圖示為共享者主動(dòng)停止共享,若主講人結(jié)束共享者共享,則對于觀看側(cè),相應(yīng)的消息順序相反。
注意事項(xiàng)
無。
描述
會(huì)議中,所有人可以收到其他與會(huì)者發(fā)送的聊天消息內(nèi)容。
前提條件是加入數(shù)據(jù)會(huì)議成功。
業(yè)務(wù)流程
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*/ }
注意事項(xiàng)
無。
描述
會(huì)議中,移動(dòng)與會(huì)者觀看文檔共享。
移動(dòng)應(yīng)用程序暫不具備共享文檔的能力,文檔的共享者為PC應(yīng)用程序。
前提條件
業(yè)務(wù)流程
一、開始觀看文檔共享
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;
文檔共享數(shù)據(jù)通過接口同步返回,轉(zhuǎn)換成圖片格式在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]; } }); }
二、文檔共享結(jié)束處理
當(dāng)前圖示為共享者主動(dòng)停止共享,若主講人結(jié)束共享者共享,則對于觀看側(cè),相應(yīng)的消息順序相反。
注意事項(xiàng)
無。
描述
會(huì)議中,移動(dòng)與會(huì)者觀看白板共享。
移動(dòng)應(yīng)用程序暫不具備共享白板的能力,白板的共享者為PC應(yīng)用程序。
前提條件:
業(yè)務(wù)流程
一、開始觀看白板共享
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;
白板共享數(shù)據(jù)通過接口同步返回,轉(zhuǎn)換成圖片格式在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]; } }); }
二、白板共享結(jié)束處理
當(dāng)前圖示為共享者主動(dòng)停止共享,若主講人結(jié)束共享者共享,則對于觀看側(cè),相應(yīng)的消息順序相反。
注意事項(xiàng)
無。