如何实现屏幕共享时的多人实时标注?

前言
随着实时通信技术的发展,在线教育、视频会议、在线金融等实时互动应用的使用量越来越多,通过线上共享文档和桌面进行教学、协作、产品演示也日益普遍。多样化的场景也催生了对实时互动技术更个性化的需求,其中就包括对屏幕共享内容进行实时标注。
拍乐云 Pano 推出业内首个支持基于实时视频、屏幕共享、文档内容流的实时标注产品,解决多个行业在线上复杂交互场景下的实时互动和实时标注痛点,更好地提升线上互动的效率和效果。
目前 Pano SDK 已上线实时标注 API,为开发者提供便捷的接入方式,可快速上线标注功能满足业务需求。本文以 Windows 端 C++ 接口为例,来看看如何快速接入 Pano SDK 的共享标注功能。
准备工作
拍乐云开发者账户(通过拍乐云官网注册)
Pano SDK v1.3.3+版本
接入拍乐云屏幕共享功能(https://developer.pano.video/features/rtc/screen/)
流程
共享标注 API 用于实现在共享窗口上标注并实现各端的标注内容同步。标注功能需要确保收到 onWhiteboardAvailable 事件通知。在开启共享后,开发者可指定需要标注的共享流。标注功能的接入分为标注发起方和接收方。
发起方
1)获取共享标注对象
2)设置标注工具格式等
3)开始标注 (startAnnotation)
4)修改标注工具格式、标注
5)结束标注 (stopAnnotation)
接收方
1)收到共享标注开始事件(onShareAnnotationStart)
2)获取共享标注对象
3)设置标注工具格式等
4)打开标注窗口(开始标注)(startAnnotation)
5)修改标注工具格式、标注
6)收到共享标注结束事件(onShareAnnotationStop)
7)获取共享标注对象
8)关闭标注窗口(结束标注)(stopAnnotation)

API 简介
1、获取共享标注对象
使用共享标注对象需要首先获取共享标注管理器对象 AnnotationManager。管理器对象可以从 PanoRtcEngine 中获得。之后从 AnnotationManager 中获取共享标注对象,接口中需要指定共享流对应的 userId。
RtcEngine
/**
* @~english
* @brief get annotation manager.
* @return
* - non-null: a pointer to annotation manager
* - others: Failure
* @note DO NOT delete this pointer, RtcEngine can handle its life cycle.
* @~chinese
* @brief 获取标注管理器
* @return
* - 非空指针: 指向标注管理器的指针。
* - 空指针: 失败
* @note 不要删除此指针, RtcEgine 会维护其生命周期。
*/
virtual AnnotationManager* getAnnotationManager() = 0;
AnnotationManager
/**
* @~english
* @brief get share annotation object.
* @param userId User ID
* @return
* - non-null: a pointer to the share annotation object
* - others: Failure
* @note DO NOT delete this pointer, AnnotationManager can handle its le cycle.
* @~chinese
* @brief 获取共享标注对象
* @param userId 用户 ID
* @return
* - 非空指针: 指向共享标注对象的指针。
* - 空指针: 失败
* @note 不要删除此指针, AnnotationManager 会维护其生命周期。
*/
virtual PanoAnnotation* getShareAnnotation(uint64_t userId) = 0;
2、开始、结束共享标注
在获得共享标注对象后,可以开始/结束标注,并通知各端共享标注开始/结束
a、开始标注调用 startAnnotation, 接口需要传入一个标注视图。结束标注调用 stopAnnotation,结束共享标注。
PanoAnnotation
/**
* @~english
* @brief Start annotation and set render window
* @param window Platform specified window object, it should HWND on Windows platform.
* @return
* - OK: Success
* - Others: Fail
* @note
* - Please make sure that whiteboard service is available before start annotation
* - For share annotation at presenter, pass NULL for window parameter
* @~chinese
* @brief 开启标注并且设置显示窗口
* @param window 平台相关的窗口对象, 在 windows 平台, 该参数必须是 HWND 对象。
* @return
* - OK: 成功
* - Others: 失败
* @note
* - 开启标注前需要保证白板服务是正常的。
* - 对共享标注的共享端,window 参数传 NULL
*/
virtual QResult startAnnotation(void *window) = 0;
/**
* @~english
* @brief Stop the annotation.
* @return
* - OK: Success
* - Others: Fail
* @~chinese
* @brief 停止标注
* @return
* - OK: 成功
* - Others: 失败
*/
virtual QResult stopAnnotation() = 0;
Windows 传入的 window 对象为 HWND 类型,与 SubscribeScreen 中指定的 window 对象相同。如果是共享端,传入 NULL。Pano 内部会自动创建一个与共享区域一致的透明窗口。
b、在标注管理器的回调中,有通知共享标注的开始和结束事件,app 在收到事件后可以加入到共享标注或关闭标注视图。收到 onShareAnnotationStart 后,可以通过回调中的 userId 获取对应的标注对象。之后调用 startAnnotation 加入标注。收到 onShareAnnotationStop 后,可以调用 stopAnnotation 关闭标注。
AnnotationManager::Callback
/*!
* @~english
* @brief Notification of share annotation start
* @param userId User ID
* @~chinese
* @brief 开始共享标注通知
* @param userId 用户 ID
*/
virtual void onShareAnnotationStart(uint64_t userId) {}
/*!
* @~english
* @brief Notification of share annotation stop
* @param userId User ID
* @~chinese
* @brief 终止共享标注通知
* @param userId 用户 ID
*/
virtual void onShareAnnotationStop(uint64_t userId) {}
3、设置标注工具,格式,操作等
标注提供了多种工具和操作。通过相应接口设置或调用。目前提供的功能包括,画笔,直线,矩形,椭圆,文字等。颜色,线宽,文字粗斜体,撤消/重做,清除等。不支持填充类型对象。支持用户角色设置(Admin, Attendee, Viewer);
清除全部标注内容,清除非本人标注内容需要 Admin 角色权限。Viewer 角色仅可观看,不可标注;
通过设置 Viewer 角色可以关闭某个用户的标注绘制功能。设置为 Attendee 或 Admin 可以重新开启标注绘制功能;
快照功能可以快速获得包含当前标注与共享内容的截图。
PanoAnnotation
/**
* @~english
* @brief Set annotation role type.
* @param type The annotation role type.
* @~chinese
* @brief 设置标注角色类型。
* @param type 标注角色。
*/
virtual QResult setRoleType(WBRoleType type) = 0;
/**
* @~english
* @brief set tool type
* @param type tool type
* @return
* - OK: Success
* - Others: Fail
* @~chinese
* @brief 设置工具类型
* @paran type 工具类型
* @return
* - OK: 成功
* - Others: 失败
*/
virtual QResult setToolType(WBToolType type) = 0;
/**
* @~english
* @brief set line width
* @param size line width. Valid value range [1, 20]
* @return
* - OK: Success
* - Others: Fail
* @~chinese
* @brief 设置线宽
* @paran size 线宽。 有效值范围 [1, 20]
* @return
* - OK: 成功
* - Others: 失败
*/
virtual QResult setLineWidth(int size) = 0;
/**
* @~english
* @brief Set color
* @param color Color
* @return
* - OK: Success
* - Others: Fail
* @~chinese
* @brief 设置颜色
* @paran color 颜色
* @return
* - OK: 成功
* - Others: 失败
*/
virtual QResult setColor(WBColor color) = 0;
/**
* @~english
* @brief Set font style
* @param style font style
* @return
* - OK: Success
* - Others: Fail
* @~chinese
* @brief 设置字体样式
* @paran style 字体样式
* @return
* - OK: 成功
* - Others: 失败
*/
virtual QResult setFontStyle(WBFontStyle style) = 0;
/**
* @~english
* @brief Set font size
* @param size font size
* @return
* - OK: Success
* - Others: Fail
* @~chinese
* @brief 设置字体大小
* @paran size 字体大小
* @return
* - OK: 成功
* - Others: 失败
*/
virtual QResult setFontSize(int size) = 0;
/**
* @~english
* @brief undo
* @return
* - OK: Success
* - Others: Fail
* @~chinese
* @brief 撤消上一次操作
* @return
* - OK: 成功
* - Others: 失败
*/
virtual QResult undo() = 0;
/**
* @~english
* @brief redo
* @return
* - OK: Success
* - Others: Fail
* @~chinese
* @brief 重做标注的上一次被撤销操作
* @return
* - OK: 成功
* - Others: 失败
*/
virtual QResult redo() = 0;
/**
* @~english
* @brief clear annotation content by specific user ID
* @param userId user ID
* @return
* - OK: Success
* - NO_PRIVILEGE: need ADMIN role to call this API
* - Others: Fail
* @note ADMIN role is required if the userId is not local user
* @~chinese
* @brief 清除指定用户标注内容
* @param userId 用户 ID
* @return
* - OK: 成功
* - NO_PRIVILEGE: 没有权限
* - Others: 失败
* @note 只有 ADMIN 角色才可以清除非本地用户的内容
*/
virtual QResult clearUserContents(uint64_t userId) = 0;
/**
* @~english
* @brief clear annotation content
* @return
* - OK: Success
* - NO_PRIVILEGE: need ADMIN role to call this API
* - Others: Fail
* @note this API need ADMIN role
* @~chinese
* @brief 清除标注内容,需要 ADMIN 角色才可调用成功
* @return
* - OK: 成功
* - NO_PRIVILEGE: 没有权限
* - Others: 失败
* @note 此接口只有 ADMIN 角色才可调用
*/
virtual QResult clearContents() = 0;
/**
* @~english
* @brief save annotation contents to image.
* @param outputDir output directory
* @return
* - OK: Success
* - Others: Fail
* @note snapshot result and image filename is returned in callback onSnapshotComplete
* @~chinese
* @brief 保存标注内容到图像。
* @param outputDir 输出路径
* @return
* - OK: 成功
* - Others: 失败
* @note 快照结果和图像文件名通过回调函数 onSnapshotComplete 返回
*/
virtual QResult snapshot(const char *outputDir) = 0;
4、回调事件
通过 setCallback 注册标注对象的回调事件目前的回调事件为标注角色变化和快照完成通知。
PanoAnnotation::Callback
/**
* @~english
* @brief Notification of annotation role type changed
* @param newRole The new role type.
* @~chinese
* @brief 标注角色类型变化通知
* @param newRole 新角色。
*/
virtual void onAnnoRoleChanged(WBRoleType newRole) {}
/**
* @~english
* @brief Notification of annotation snapshot complete
* @param result Snapshot result
* @param filename Snapshot image full path with name.
* @~chinese
* @brief 标注快照完成通知
* @param result 快照结果
* @param filename 快照文件名
*/
virtual void onSnapshotComplete(QResult result, const char *filename) {}
以上就是 Windows 端实时共享标注的详细教程,如需接入其他端,你也可以联系官网客服获取技术文档。关注我们,我们将为大家分享更多关于音视频技术的探索和实践,以及基于 Pano SDK 的详细开发教程。
关于拍乐云
拍乐云成立于 2019 年,是国内第一家视频会议背景的实时互动通信云服务提供商,汇聚了一大批专注于音频、视频、白板、网络、AI 等领域的资深技术专家。通过 Pano SDK,企业开发者即可在全球范围内快速实现互动小班、超级小班、双师大班、语音聊天室、视频社交、直播连麦、游戏语音、视频客服、远程医疗、办公协作等场景。
评论