EasyDarwin开源流媒体云平台之语音对讲功能设计与实现

来源:互联网 发布:sql笔试题及答案 编辑:程序博客网 时间:2024/05/23 12:04

EasyDarwin云平台一直在稳步的升级迭代中,近日,EasyDarwin云平台实现了语音对讲的功能。对讲功能的加入,标志着EasyDarwin云平台进一步的完善。

  • 流程设计

    1. 客户端使用POST的方式在body中携带协议报文向云平台发送开始对讲命令;

    2. 云平台组织协议报文向指定的设备发送;

    3. 设备执行开始对讲命令后向云平台返回相应报文;

    4. 云平台将响应报文返回给客户端;

    5. 客户端请求开始对讲成功后,开始向云平台发送采集的音频数据;

    6. 云平台将音频数据转发给设备;

    7. 设备将音频数据播放出来;

    8. 客户端需要停止对讲时,向云平台发送停止对讲命令;

    9. 云平台转发给设备;

    10. 设备执行停止对讲后返回执行结果给云平台;

    11. 云平台将结果返回给客户端。

tb

  • 协议设计
//客户端向云平台发送对讲报文{   "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 execNetMsgCSTalkbackControlReqQTSS_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 ControlTalkbackQTSS_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.org

WEB:www.EasyDarwin.org

QQ交流群:288214068

Copyright © EasyDarwin.org 2012-2016

EasyDarwin

0 0