AnyChat SDK的使用及简易视频聊天软件的快速开发(QT5.3)
为了在linux平台下快速开发一款视频聊天软件,本文选取了AnyChat SDK作为核心开发,开发环境使用QT5.3,下面将讲解我的开发过程。
一、 开发环境的搭建
1. 首先,虚拟机安装linux系统,我选取的是最新的Ubuntu14.04-32bit ;
2. 然后,到QT官网http://qt-project.org/downloads,下载最新的linux版本QT5.3.2,如下所示:
3. 最后,到AnyChat官网http://www.anychat.cn/download.html,下载最新的linux版本的SDK,这里我们选取32bit,如下图所示:
二、 软件功能
在这里,我只需要如下几个功能即可:
1. 能够打开本地音视频;
2. 能够获取在线用户列表;
3. 能够请求在线用户音视频,实现视频聊天;
4. 能够发送文字聊天。
三、 真正的开始
需求确定之后,我们就开始创建我们的工程啦!
1. 现在我们打开QT5软件,创建一个新工程,首先就是布局我们的UI,如下图所示;
然后我们给我们的UI写上对象名字,如下所示:
2. 添加工程依赖性(包括anychat sdk依赖文件的添加)
QT软件配置头文件和库文件有两种方法:
2.1 可以手动在.pro为后缀的文件里面进行添加;
2.2 可以右键工程项目,然后添加相应的文件和库,此方法会自动修改.pro文件,如下左右两图所示(左图为手动添加,右图为添加后的pro文件,也可以按右图修改pro文件):
其中INCLUDEPATH为头文件包含路径,这里添加anychat sdk目录;LIBS为依赖库文件,这里添加anychatcore动态库;$$PWD表示pro文件当前目录;当然也可以使用绝对路径,直接填写路径和文件名即可,按左图方法添加绝对正确。
我的anychat sdk文件如下所示:
3. 接下来我们需要编写具体功能的实现;
3.1 初始化
因为我们要使用anychat sdk,因此我们在程序初始化的时候对sdk初始化;
SDK初始化参数设置,其中,对于视频,我们设置为BRAC_FUNC_VIDEO_CBDATA,为视频数据回调方式,后续需要我们实现视频数据的处理,这里主要是渲染显示;对于音频,我们设置为BRAC_FUNC_AUDIO_AUTOPLAY,使用SDK自动播放模式,我们不用做任何处理。
在BRAC_InitSDK函数之后我们又调用了四个API接口,分别设置视频回调、声音回调(这里实际不用设置,我们采用自动播放模式)、系统消息回调、文字信息回调(文字聊天);
至此初始化完毕!
3.2 编写登录服务器接口
这里为了方便,服务器地址、端口号、用户名、密码都写进来了;当我们登录成功之后,就可以继续往下啦。
3.3 进入相应的房间
RoomId_lineEdit就是我们的ui控件,我们在编辑控件填写相应的房号即可;
3.4 刷新在线用户列表
我单独写了一个接口,实现由用户进入房间和离开房间时会刷新列表;
3.5 打开本地音视频
当我们成功进入房间时,我们首先打开自己的音视频,这里用到了两个API,
BRAC_UserCameraControl()和BRAC_UserSpeakControl(),分别打开音视频;
这个函数有系统消息回调函数来调用,而系统消息回调函数我们在初始化的时候已经设置了,下面将我们的系统消息回调函数贴出来:
// 异步消息通知回调函数定义
void CALLBACK Widget::NotifyMessage_CallBack(DWORD dwNotifyMsg, DWORD wParam, DWORD lParam, LPVOID lpUserValue)
{
Widget* pAnyChatSDKProc = (Widget*)lpUserValue;
if(!pAnyChatSDKProc)
return;
switch(dwNotifyMsg)
{
case WM_GV_CONNECT: pAnyChatSDKProc->OnGVClientConnect(wParam,NULL);
break;
case WM_GV_LOGINSYSTEM: pAnyChatSDKProc->OnGVClientLogin(wParam,lParam);
break;
case WM_GV_ENTERROOM: pAnyChatSDKProc->OnGVClientEnterRoom(wParam,lParam);
break;
case WM_GV_MICSTATECHANGE: pAnyChatSDKProc->OnGVClientMicStateChange(wParam,lParam);
break;
case WM_GV_USERATROOM: pAnyChatSDKProc->OnGVClientUserAtRoom(wParam,lParam);
break;
case WM_GV_LINKCLOSE: pAnyChatSDKProc->OnGVClientLinkClose(wParam, lParam);
break;
case WM_GV_ONLINEUSER: pAnyChatSDKProc->OnGVClientOnlineUser(wParam,lParam);
break;
case WM_GV_CAMERASTATE: pAnyChatSDKProc->OnAnyChatCameraStateChgMessage(wParam,lParam); break;
case WM_GV_ACTIVESTATE: pAnyChatSDKProc->OnAnyChatActiveStateChgMessage(wParam,lParam);
break;
case WM_GV_P2PCONNECTSTATE: pAnyChatSDKProc->OnAnyChatP2PConnectStateMessage(wParam,lParam); break;
case WM_GV_SDKWARNING: pAnyChatSDKProc->OnAnyChatSDKWarningMessage(wParam,lParam); break;
default:
break;
}
pAnyChatSDKProc->OnAnyChatNotifyMessageCallBack(dwNotifyMsg,wParam,lParam);
};
3.6 请求在线用户视频
我们进入房间后,获取在线用户并更新列表,所谓的在线用户是指同一房间的在线用户。
然后我们双击列表中的用户,进行视频请求:
我的虚拟机中打不开本地视频,所以左下角没有视频,具体的实现如下:
其中g_sOpenedCamUserId为全局变量,用于保存被请求视频的用户名;
音视频成功啦,接下来我们继续扩展文字消息。
BRAC_UserCameraControl(g_sOpenedCamUserId,0); //视频控制
BRAC_UserSpeakControl(g_sOpenedCamUserId,0); //音频控制
以上两个函数说明,参数1为用户id值,这个不难理解,参数2为打开和关闭控制值,建议使用true或false;在我实际开发过程中,在音视频关闭的时候,参数2设置为-1的时候,结果没有关闭成功,因为理解有误,应该设置为0。
3.7 实现发送文字消息聊天
是的,使用BARC_SendTextMessage即可啦,参数一为用户id,至此,我们的功能基本完成;
3.8 有进必有出---离开房间
离开房间之后可以做什么?我们考虑实现离开房间后,要进入其他房间而不马上退出,因此这里我只使用了LeaveRoom!!!
当然我们离开后需要关闭视频和刷新列表,对于关闭视频调用关闭音视频接口,然后设置ui-->clear和text,对于列表,调用封装好的接口即可;
3.9 关键的视频渲染
因为我使用了回调方式获取视频数据,所以我得手动进行视频渲染首先定义视频缓冲和大小(我这里定义为类成员):
然后在回调函数中做视频渲染:
QT中我使用QImage来加载视频数据,然后调用label控件的setPixmap方法来绘制图像,当然这个渲染方法效率一般;
//视频数据显示
void Widget::DrawUserVideo(DWORD dwUserid, LPVOID lpBuf, DWORD dwLen,
BITMAPINFOHEADER bmiHeader,Widget *pWidget)
{
int width = bmiHeader.biWidth;
int height = bmiHeader.biHeight;
//判断用户id选择不同的显示区域
if(m_SelfId == dwUserid) //本地用户视频
{
char* p = m_lpLocalVideoFrame;
if( !p ||m_iLocalVideoSize < dwLen)
{
p = (char*)realloc(p, dwLen);
if(!p)
return;
m_iLocalVideoSize = dwLen;
}
memcpy(p, lpBuf, dwLen);
QImage img = QImage((uchar *)p,width,height,QImage::Format_RGB32);
pWidget->ui->RemoteUserlabel->setPixmap(QPixmap::fromImage(img));
}
else //远程用户视频
{
char* p = m_lpRemoteVideoFrame;
if( !p ||m_iRemoteVideoSize < dwLen)
{
p = (char*)realloc(p, dwLen);
if(!p)
return;
m_iRemoteVideoSize = dwLen;
}
memcpy(p, lpBuf, dwLen);
QImage img = QImage((uchar *)p,width,height,QImage::Format_RGB32);
pWidget->ui->RemoteUserlabel->setPixmap(QPixmap::fromImage(img));
}
}
3.10
最后,我没有添加关闭按钮,而是使用窗口的关闭按钮,所以我要重载CloseEvent,在关闭时调用断开连接和释放资源。
四、 总结
整个过程开发非常方便快捷,得益于AnyChat SDK接口的使用简洁,尤其是音视频打开和处理过程的简化,全面的回调功能函数接口。本设计采用服务器为anychat sdk提供的demo服务器,可以直接运行部署。