项目中用到实时视频技术,我们使用tokbox来解决这个问题 ,官方没有C++版本.我写了一个qt c++版本的用于获取sessionId和tonkenId来进行视频通话
开发人员:Jason‘s.Alex QQ:531401335
csdn博客:http://blog.csdn.net/RuShrooM
#ifndef TOKENSDK_H #define TOKENSDK_H #include <QObject> #include <QUrl> #include <QNetworkAccessManager> #include <QNetworkReply> //http访问 class TokboxSDK : public QObject { Q_OBJECT public: explicit TokboxSDK(QObject *parent = 0); ~TokboxSDK(); const QString &getSessionId()const{return sessionId;} const QString &getTokenId()const{return tokenId;} const QString &getKeyId()const{return keyId;} void createTokboxKeys(const QString &keyid, //创建一个密钥 const QString &secret, const QString &role="publisher", const long &expireTime=0, const QString &connectData="");//创建密钥 QString generateToken(const QString &sessionId,const QString &role="publisher", //生成token const long &expireTime=0,const QString &connectData=""); void loadRemoteXMLData(const QString &keyid,const QString &secret); //载入远程xml数据 signals: void error(const QString &s);//创建失败就返回错误信号 void createFinish();//创建完成信号 private slots: void downRemoteXml(QNetworkReply *reply); void downRemoteXmlError(QNetworkReply::NetworkError); private: QNetworkAccessManager *nkm; QNetworkReply *reply; QString repeatString(const QString &str,const int ×); private: QString sessionId; QString tokenId; QString keyId; QString secret; QString role; //角色 long expireTime;//有效时间 QString connectData;//连接的用户数据 }; #endif // HTTPACCESS_H
#include "TokenSDK.h" #include <QDebug> #include <QSslConfiguration> #include <QSsl> #include <QtXml/QDomDocument> #include <QDateTime> #include <QMessageAuthenticationCode> TokboxSDK::TokboxSDK(QObject *parent): QObject(parent) { reply=0; nkm=new QNetworkAccessManager(this); connect(nkm,&QNetworkAccessManager::finished,this,&TokboxSDK::downRemoteXml); } TokboxSDK::~TokboxSDK() { if(reply!=0) reply->deleteLater(); } void TokboxSDK::loadRemoteXMLData(const QString &keyid,const QString &secret) //载入远程xml数据 { if(reply!=0) reply->deleteLater(); QNetworkRequest reque(QUrl("https://api.opentok.com/hl/session/create")); reque.setRawHeader("X-TB-PARTNER-AUTH",QString("%1:%2").arg(keyid).arg(secret).toLatin1()); reque.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream"); // QByteArray byte="location=127.0.0.1&p2p.preference=disabled"; //reque.setHeader(QNetworkRequest::ContentLengthHeader,byte.length()); reply=nkm->post(reque,""); connect(reply,static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),this,&TokboxSDK::downRemoteXmlError); } void TokboxSDK::createTokboxKeys(const QString &keyid,const QString &secret,const QString &role, const long &expireTime,const QString &connectData)//创建一个密钥创建密钥 { this->keyId=keyid; this->secret=secret; this->role=role; this->expireTime=expireTime; this->connectData=connectData; this->loadRemoteXMLData(keyid,secret); //下载远程数据 } void TokboxSDK::downRemoteXml(QNetworkReply *) { if(reply->bytesAvailable()<20) { emit error("download remote xml none"); reply->deleteLater(); reply=0; return; } QDomDocument doc; QString msgErrorStr; int line; int col; if(!doc.setContent(reply->readAll(),&msgErrorStr,&line,&col)) //载入xml数据 { emit error(QString("parse tokbox session xml error:%1 line:%2 col:%3").arg(msgErrorStr).arg(line).arg(col)); reply->deleteLater(); reply=0; return; } QDomElement ele=doc.firstChildElement("sessions").firstChildElement("Session"); //解析session 字段 this->sessionId=ele.firstChildElement("session_id").text(); this->tokenId=generateToken(sessionId); //生成一个token reply->deleteLater(); reply=0; emit createFinish(); } QString TokboxSDK::generateToken(const QString &sessionId,const QString &role, //生成token const long &expireTime,const QString &connectData) { if(sessionId.isEmpty()) { emit error("Null or empty session ID are not valid"); return ""; } QString subSessionId=sessionId.mid(2);//从第二个字符串开始截取 QString decodeSessionId; //解码的sessionid for(int i=0;i<3;++i) { QString newSessionId=subSessionId+repeatString("=",i); decodeSessionId=QByteArray::fromBase64(newSessionId.replace(‘-‘,‘+‘).replace(‘_‘,‘/‘).toLatin1()); if(decodeSessionId.contains("~")) { if(decodeSessionId.split("~")[1]!=keyId) { emit error("An invalid session ID was passed"); return ""; } break; } } long createTime=QDateTime::currentMSecsSinceEpoch()/1000;//获取当前的系统时间 qsrand(QDateTime::currentMSecsSinceEpoch()); int nonce=qrand(); QString dataStringBuilder=QString("session_id=%1&create_time=%2&nonce=%3&role=%4") .arg(sessionId).arg(createTime).arg(nonce).arg(role); if("subscriber"!=role&&"publisher"!=role&&"moderator"!=role&&!role.isEmpty()) { emit error(role+" is not a recognized role"); return ""; } if(expireTime!=0) { if(expireTime<QDateTime::currentMSecsSinceEpoch()/1000-1) { emit error("Expire time must be in the future"); return ""; } if(expireTime>QDateTime::currentMSecsSinceEpoch()/1000+2592000) { emit error("Expire time must be in the next 30 days"); return ""; } dataStringBuilder.append("&expire_time="); dataStringBuilder.append(QString::number(expireTime)); } if(!connectData.isEmpty()) { if(connectData.length()>1000) { emit error("Connection data must be less than 1000 characters"); return ""; } dataStringBuilder.append("&connection_data="); dataStringBuilder.append(connectData); } QString tokenStringBuiler="T1=="; //添加hmac密钥 QString innerBuilder=QString("partner_id=%1&sig=%2:%3").arg(keyId) .arg(QString(QMessageAuthenticationCode::hash(dataStringBuilder.toLatin1(), secret.toLatin1(),QCryptographicHash::Sha1).toHex())) .arg(dataStringBuilder); return tokenStringBuiler.append(innerBuilder.toLatin1().toBase64()); } QString TokboxSDK::repeatString(const QString &str,const int ×) { QString ret; for(int i=0;i<times;++i) ret+=str; return ret; } void TokboxSDK::downRemoteXmlError(QNetworkReply::NetworkError ) { emit error(reply->errorString()); if(reply!=0) { reply->deleteLater(); reply=0; } }