EasyDarwin開源流媒體雲平臺之語音對講功能設計與實現
阿新 • • 發佈:2019-01-22
EasyDarwin雲平臺一直在穩步的升級迭代中,近日,EasyDarwin雲平臺實現了語音對講的功能。對講功能的加入,標誌著EasyDarwin雲平臺進一步的完善。
流程設計
客戶端使用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;
}
獲取更多資訊
QQ交流群:288214068
Copyright © EasyDarwin.org 2012-2016