EasyDarwin开源流媒体云平台之语音对讲功能设计与实现
2016-07-23 22:21
507 查看
EasyDarwin云平台一直在稳步的升级迭代中,近日,EasyDarwin云平台实现了语音对讲的功能。对讲功能的加入,标志着EasyDarwin云平台进一步的完善。
流程设计
客户端使用POST的方式在body中携带协议报文向云平台发送开始对讲命令;
云平台组织协议报文向指定的设备发送;
设备执行开始对讲命令后向云平台返回相应报文;
云平台将响应报文返回给客户端;
客户端请求开始对讲成功后,开始向云平台发送采集的音频数据;
云平台将音频数据转发给设备;
设备将音频数据播放出来;
客户端需要停止对讲时,向云平台发送停止对讲命令;
云平台转发给设备;
设备执行停止对讲后返回执行结果给云平台;
云平台将结果返回给客户端。
协议设计
格式说明:
Serial:设备序列号;
Channel:摄像机通道号;
Protocol:指定预置位控制方式,ONVIF协议或者设备SDK;
Command:对讲控制命令,包括启动对讲、停止对讲、发送对讲数据(START/STOP/SENDDATA);
AudioType:音频数据类型,包括G711A/G726;
AudioData:音频数据,将音频数据通过Base64编码发送;
Pts:音频时间戳,开始为0,每20ms增加20;
Reserve:预留。
格式说明:
From: EasyCMS接收Client访问的SessionID;
To: EasyCMS向Device发送报文的SessionID;
Via: EasyCMS的ServiceID;
实现
WEB:www.EasyDarwin.org
QQ交流群:288214068
Copyright © EasyDarwin.org 2012-2016
流程设计
客户端使用POST的方式在body中携带协议报文向云平台发送开始对讲命令;
云平台组织协议报文向指定的设备发送;
设备执行开始对讲命令后向云平台返回相应报文;
云平台将响应报文返回给客户端;
客户端请求开始对讲成功后,开始向云平台发送采集的音频数据;
云平台将音频数据转发给设备;
设备将音频数据播放出来;
客户端需要停止对讲时,向云平台发送停止对讲命令;
云平台转发给设备;
设备执行停止对讲后返回执行结果给云平台;
云平台将结果返回给客户端。
协议设计
//客户端向云平台发送对讲报文 { "EasyDarwin": { "Body": { "Channel": "0", "Command": "START", "AudioType": "G711A", "Protocol": "ONVIF", "Reserve": "1", "Serial": "001001000058", "Preset": "3", "AudioData": "BASE64DATA", "Pts": "20" }, "Header": { "CSeq": "1", "MessageType": "MSG_CS_TALKBACK_CONTROL_REQ", "Version": "1.0" } } }
格式说明:
Serial:设备序列号;
Channel:摄像机通道号;
Protocol:指定预置位控制方式,ONVIF协议或者设备SDK;
Command:对讲控制命令,包括启动对讲、停止对讲、发送对讲数据(START/STOP/SENDDATA);
AudioType:音频数据类型,包括G711A/G726;
AudioData:音频数据,将音频数据通过Base64编码发送;
Pts:音频时间戳,开始为0,每20ms增加20;
Reserve:预留。
//云平台响应客户端请求 { "EasyDarwin": { "Body": { "Channel": "0", "Protocol": "ONVIF", "Reserve": "1", "Serial": "001001000058" }, "Header": { "CSeq": "1", "ErrorNum": "200", "ErrorString": "Success OK", "MessageType": "MSG_SC_TALKBACK_CONTROL_ACK", "Version": "1.0" } } }
//云平台向设备发送对讲命令 { "EasyDarwin": { "Body": { "Channel": "0", "Command": "SENDDATA", "AudioType": "G711A", "AudioData": "BASE64DATA", "Pts": "20", "From": "f6a221eec46b47dea8ae1a2bd11f8d02", "Protocol": "ONVIF", "Reserve": "1", "Serial": "001001000058", "To": "245d6ec33cd247b7b7524219552db4d8", "Via": "27823d2e8b6b4032b453d435a16b7be8" }, "Header": { "CSeq": "1", "MessageType": "MSG_SD_CONTROL_TALKBACK_REQ", "Version": "1.0" } } }
格式说明:
From: EasyCMS接收Client访问的SessionID;
To: EasyCMS向Device发送报文的SessionID;
Via: EasyCMS的ServiceID;
//设备向云平台响应对讲命令 { "EasyDarwin": { "Body": { "Channel": "0", "From": "245d6ec33cd247b7b7524219552db4d8", "Protocol": "ONVIF", "Reserve": "1", "Serial": "001001000058", "To": "f6a221eec46b47dea8ae1a2bd11f8d02", "Via": "27823d2e8b6b4032b453d435a16b7be8" }, "Header": { "CSeq": "1", "ErrorNum": "200", "ErrorString": "Success OK", "MessageType": "MSG_DS_CONTROL_TALKBACK_ACK", "Version": "1.0" } } }
实现
//EasyCMS HTTPSession.cpp execNetMsgCSTalkbackControlReq QTSS_Error HTTPSession::execNetMsgCSTalkbackControlReq(const char* json) { if (!fAuthenticated)//没有进行认证请求 return httpUnAuthorized; EasyProtocol req(json); string strDeviceSerial = req.GetBodyValue(EASY_TAG_SERIAL); string strChannel = req.GetBodyValue(EASY_TAG_CHANNEL); string strProtocol = req.GetBodyValue(EASY_TAG_PROTOCOL); string strReserve = req.GetBodyValue(EASY_TAG_RESERVE); string strCmd = req.GetBodyValue(EASY_TAG_CMD); string strAudioType = req.GetBodyValue(EASY_TAG_AUDIO_TYPE); string strAudioData = req.GetBodyValue(EASY_TAG_AUDIO_DATA); string strPts = req.GetBodyValue(EASY_TAG_PTS); string strCSeq = req.GetHeaderValue(EASY_TAG_CSEQ);//这个是关键字 if (strChannel.empty()) strChannel = "0"; if (strReserve.empty()) strReserve = "1"; OSRefTableEx* deviceMap = QTSServerInterface::GetServer()->GetDeviceSessionMap(); OSRefTableEx::OSRefEx* theDevRef = deviceMap->Resolve(strDeviceSerial); if (theDevRef == NULL)//找不到指定设备 return EASY_ERROR_DEVICE_NOT_FOUND; OSRefReleaserEx releaser(deviceMap, strDeviceSerial); //走到这说明存在指定设备 HTTPSession* pDevSession = static_cast<HTTPSession *>(theDevRef->GetObjectPtr());//获得当前设备回话 string errNo, errString; if (strCmd == "SENDDATA") { if (!pDevSession->GetTalkbackSession().empty() && pDevSession->GetTalkbackSession() == fSessionID) { EasyProtocolACK reqreq(MSG_SD_CONTROL_TALKBACK_REQ); EasyJsonValue headerheader, bodybody; char chTemp[16] = { 0 }; UInt32 uDevCseq = pDevSession->GetCSeq(); sprintf(chTemp, "%d", uDevCseq); headerheader[EASY_TAG_CSEQ] = string(chTemp);//注意这个地方不能直接将UINT32->int,因为会造成数据失真 headerheader[EASY_TAG_VERSION] = EASY_PROTOCOL_VERSION; bodybody[EASY_TAG_SERIAL] = strDeviceSerial; bodybody[EASY_TAG_CHANNEL] = strChannel; bodybody[EASY_TAG_PROTOCOL] = strProtocol; bodybody[EASY_TAG_RESERVE] = strReserve; bodybody[EASY_TAG_CMD] = strCmd; bodybody[EASY_TAG_AUDIO_TYPE] = strAudioType; bodybody[EASY_TAG_AUDIO_DATA] = strAudioData; bodybody[EASY_TAG_PTS] = strPts; bodybody[EASY_TAG_FROM] = fSessionID; bodybody[EASY_TAG_TO] = pDevSession->GetValue(EasyHTTPSessionID)->GetAsCString(); bodybody[EASY_TAG_VIA] = QTSServerInterface::GetServer()->GetCloudServiceNodeID(); reqreq.SetHead(headerheader); reqreq.SetBody(bodybody); string buffer = reqreq.GetMsg(); StrPtrLen theValue(const_cast<char*>(buffer.c_str()), buffer.size()); pDevSession->SendHTTPPacket(&theValue, false, false); errNo = EASY_ERROR_SUCCESS_OK; errString = EasyProtocol::GetErrorString(EASY_ERROR_SUCCESS_OK); } else { errNo = EASY_ERROR_CLIENT_BAD_REQUEST; errString = EasyProtocol::GetErrorString(EASY_ERROR_CLIENT_BAD_REQUEST); goto ACK; } } else { if (strCmd == "START") { if (pDevSession->GetTalkbackSession().empty()) { pDevSession->SetTalkbackSession(fSessionID); errNo = EASY_ERROR_SUCCESS_OK; errString = EasyProtocol::GetErrorString(EASY_ERROR_SUCCESS_OK); } else { errNo = EASY_ERROR_CLIENT_BAD_REQUEST; errString = EasyProtocol::GetErrorString(EASY_ERROR_CLIENT_BAD_REQUEST); goto ACK; } } else if (strCmd == "STOP") { if (pDevSession->GetTalkbackSession().empty() || pDevSession->GetTalkbackSession() != fSessionID) { errNo = EASY_ERROR_CLIENT_BAD_REQUEST; errString = EasyProtocol::GetErrorString(EASY_ERROR_CLIENT_BAD_REQUEST); goto ACK; } else { pDevSession->SetTalkbackSession(""); errNo = EASY_ERROR_SUCCESS_OK; errString = EasyProtocol::GetErrorString(EASY_ERROR_SUCCESS_OK); } } EasyProtocolACK reqreq(MSG_SD_CONTROL_TALKBACK_REQ); EasyJsonValue headerheader, bodybody; char chTemp[16] = { 0 }; UInt32 uDevCseq = pDevSession->GetCSeq(); sprintf(chTemp, "%d", uDevCseq); headerheader[EASY_TAG_CSEQ] = string(chTemp);//注意这个地方不能直接将UINT32->int,因为会造成数据失真 headerheader[EASY_TAG_VERSION] = EASY_PROTOCOL_VERSION; bodybody[EASY_TAG_SERIAL] = strDeviceSerial; bodybody[EASY_TAG_CHANNEL] = strChannel; bodybody[EASY_TAG_PROTOCOL] = strProtocol; bodybody[EASY_TAG_RESERVE] = strReserve; bodybody[EASY_TAG_CMD] = strCmd; bodybody[EASY_TAG_AUDIO_TYPE] = strAudioType; bodybody[EASY_TAG_AUDIO_DATA] = strAudioData; bodybody[EASY_TAG_PTS] = strPts; bodybody[EASY_TAG_FROM] = fSessionID; bodybody[EASY_TAG_TO] = pDevSession->GetValue(EasyHTTPSessionID)->GetAsCString(); bodybody[EASY_TAG_VIA] = QTSServerInterface::GetServer()->GetCloudServiceNodeID(); reqreq.SetHead(headerheader); reqreq.SetBody(bodybody); string buffer = reqreq.GetMsg(); StrPtrLen theValue(const_cast<char*>(buffer.c_str()), buffer.size()); pDevSession->SendHTTPPacket(&theValue, false, false); } ACK: char chTemp[16] = { 0 }; UInt32 uDevCseq = pDevSession->GetCSeq(); sprintf(chTemp, "%d", uDevCseq); EasyProtocolACK rsp(MSG_SC_TALKBACK_CONTROL_ACK); EasyJsonValue header, body; body[EASY_TAG_SERIAL] = strDeviceSerial; body[EASY_TAG_CHANNEL] = strChannel; body[EASY_TAG_PROTOCOL] = strProtocol; body[EASY_TAG_RESERVE] = strReserve; header[EASY_TAG_VERSION] = EASY_PROTOCOL_VERSION; header[EASY_TAG_CSEQ] = string(chTemp);; header[EASY_TAG_ERROR_NUM] = errNo; header[EASY_TAG_ERROR_STRING] = errString; rsp.SetHead(header); rsp.SetBody(body); string msg = rsp.GetMsg(); StrPtrLen theValueAck(const_cast<char*>(msg.c_str()), msg.size()); this->SendHTTPPacket(&theValueAck, false, false); return QTSS_NoErr; }
//EasyCamera EasyCameraSource.cpp ControlTalkback QTSS_Error EasyCameraSource::ControlTalkback(Easy_CameraTalkback_Params* params) { QTSS_Error result = QTSS_RequestFailed; if (cameraLogin()) { HI_S32 error = HI_SUCCESS; switch (params->inCommand) { case EASY_TALKBACK_CMD_TYPE_START: { int type = 1; if (params->inType == EASY_TALKBACK_AUDIO_TYPE_G711A) type = 1; else if (params->inType == EASY_TALKBACK_AUDIO_TYPE_G726) type = 4; error = HI_NET_DEV_StartVoice(m_u32Handle, type); } break; case EASY_TALKBACK_CMD_TYPE_SENDDATA: { if (params->inBuff == NULL || params->inBuffLen == 0) { result = QTSS_BadArgument; break; } int len = params->inBuffLen; int offset = 0; int pts = params->inPts; while (len >= BUFFLEN) { AddHead(fTalkbackBuff, (char*)params->inBuff + offset, BUFFLEN); error = HI_NET_DEV_SendVoiceData(m_u32Handle, fTalkbackBuff, HSBUFFLEN, pts); offset += BUFFLEN; len -= BUFFLEN; pts += PTSPER; } } break; case EASY_TALKBACK_CMD_TYPE_STOP: error = HI_NET_DEV_StopVoice(m_u32Handle); break; default: result = QTSS_RequestFailed; break; } if (error == HI_SUCCESS) { result = QTSS_NoErr; } else { result = QTSS_RequestFailed; } } return result; }
获取更多信息
邮件:support@easydarwin.orgWEB:www.EasyDarwin.org
QQ交流群:288214068
Copyright © EasyDarwin.org 2012-2016
相关文章推荐
- 这段时间云计算挺热门!
- 云计算-云山雾罩不计算
- 云计算安全概述
- Linux与云计算——第二阶段 第三章:SSH服务器架设(下)openssh 进阶
- Linux与云计算——第二阶段 第三章:SSH服务器架设(上)openssh 基础
- Linux与云计算——第二阶段 第一章:NTP服务器架设
- 云计算(世界的技术发展潮流和趋势)
- EasyDarwin开源流媒体云平台中boost Base64编解码后与源长度不匹配的bug
- EasyDarwin开源流媒体云平台中boost Base64编解码后与源长度不匹配的bug
- hadoop大数据与hadoop云计算
- 云计算的三种服务模式 (IaaS SaaS PaaS)
- EasyDarwin开源流媒体云平台中boost Base64编解码后与源长度不匹配的bug
- 盗版软件满天飞,禁不了但可止得住!
- 扬尘噪声智能监测云平台
- 扬尘防治实时在线监控云平台
- 第三讲:云计算的产生和特点
- 第一讲:云计算基础知识第一讲:云计算概念
- 云计算之--------高级虚拟化KVM
- 红帽&誉天OpenStack云计算技术沙龙(北京站)
- 云计算之--------基础概念篇