#include "stdafx.h" #include "mod_assistantchannel.h" #include "EventCode.h" #include static const char *__states[] = { "Idle", "Connecting", "Connected", "Closing" }; inline const char *state2str(int state) { return __states[state]; } static __inline unsigned int hash32_buf(const void *bf, size_t len, unsigned int hash) { const unsigned char *s = (const unsigned char*)bf; while (len-- != 0) /* "nemesi": k=257, r=r*257 */ hash = hash * 257 + *s++; return (hash * 257); } static int MakeDesc(DWORD eScreen,DeviceTypeEnum eDevicetype) { if (eScreen == 1) { return media_desc_encode( ACM_VIDEO_MODE_SQUARE, ACM_VIDEO_ENCODE_H264, ACM_VIDEO_FPS_BASELINE, ACM_VIDEO_MODE_QVGA, ACM_VIDEO_ENCODE_H264, ACM_VIDEO_FPS_BASELINE); } else if (eScreen == 2) { return media_desc_encode( ACM_VIDEO_MODE_SQUARE, ACM_VIDEO_ENCODE_H264, ACM_VIDEO_FPS_BASELINE, ACM_VIDEO_MODE_VGA, ACM_VIDEO_ENCODE_H264, ACM_VIDEO_FPS_BASELINE); } else { assert(0); } return 0; } static void __on_recv_pkt(bizchan_t *chan, int type, int sub_type, int id, const char *pkt, int pkt_size, void *user_data) { CBizChannelEntity *pThis = static_cast(user_data); pThis->_on_recv_pkt(type, sub_type, id, pkt, pkt_size); } static void __on_connect(bizchan_t *chan, int error, const char *remote_ip, int remote_video_rtp, int remote_video_desc, const char *remote_client_id, void *user_data) { CBizChannelEntity *pThis = static_cast(user_data); pThis->_on_connect(error, remote_ip, remote_video_rtp, remote_video_desc); } static void __on_close(bizchan_t *chan, void *user_data) { CBizChannelEntity *pThis = static_cast(user_data); pThis->_on_close(); } static void __on_destroy(bizchan_t *chan, void *user_data) { } static void __dbg(void *user_data, const char *fmt, va_list arg) { int n = _vscprintf(fmt, arg); if (n >= MAX_PATH) { char* buf = (char*)malloc((size_t)(n + 1)); vsnprintf(buf, n + 1, fmt, arg); DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("%s", buf); free(buf); } else { char strlog[MAX_PATH] = { 0 }; _vsnprintf(strlog, MAX_PATH, fmt, arg); DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("%s", strlog); } } void CBizChannelEntity::OnPreStart(CAutoArray strArgs,CSmartPointer pTransactionContext) { ErrorCodeEnum Error = __OnStart(Error_Succeed); pTransactionContext->SendAnswer(Error); } void CBizChannelEntity::OnPreClose(EntityCloseCauseEnum eCloseCause,CSmartPointer pTransactionContext) { ErrorCodeEnum Error = __OnClose(Error_Succeed); pTransactionContext->SendAnswer(Error); } ErrorCodeEnum CBizChannelEntity::__OnStart(ErrorCodeEnum preOperationError) { //MessageBoxA(0,0,0,0); bizchan_lib_init(); m_eState = eChannelState_Idle; m_pChan = NULL; m_eDeviceType = RvcGetDeviceType(); ListEntry_InitHead(&m_stateList); ListEntry_InitHead(&m_rxpktList); return Error_Succeed; } void CBizChannelEntity::OnStarted() { LogEvent(Severity_Middle, LOG_EVT_MOD_ASSISCHAN_STARTED_SUCCESS, "assistant channel started successfully."); } DeviceTypeEnum CBizChannelEntity::RvcGetDeviceType() { DeviceTypeEnum eType = eStand2sType; CSmartPointer spFunction = GetFunction(); CSystemStaticInfo stStaticinfo; spFunction->GetSystemStaticInfo(stStaticinfo); //TODO: recommand to use SpStr2MachineType in SpHelper.h [Gifur@202584] if (_stricmp(stStaticinfo.strMachineType, "RVC.Stand1SPlus") == 0) { eType = eStand1SPlusType; } else if (stricmp(stStaticinfo.strMachineType, "RVC.CardStore") == 0 || stricmp(stStaticinfo.strMachineType, "RVC.CardPrinter") == 0) { eType = eCardStore; } else{ eType = eStand2sType; } if (eType >= 0 && eType < sizeof(Device_Type_Table)/sizeof(char*)){ DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("device type is %s.", Device_Type_Table[eType]); } return eType; } ErrorCodeEnum CBizChannelEntity::__OnClose(ErrorCodeEnum preOperationError) { //..... bizchan_lib_term(); return Error_Succeed; } CServerSessionBase* CBizChannelEntity::OnNewSession(const char* pszRemoteEntityName, const char * pszClass) { return new ChannelServiceSession(this, m_id_seq++); } ErrorCodeEnum CBizChannelEntity::Connect(const char *ip, int port) { ErrorCodeEnum Error = Error_Succeed; if (m_eState == eChannelState_Idle) { CSystemStaticInfo Info; bizchan_config_t config = {0}; bizchan_callback_t cb = {0}; GetFunction()->GetSystemStaticInfo(Info); config.proxy_server = const_cast(ip); config.proxy_server_port = port; config.session_id = const_cast(((const char*)Info.strTerminalID)); config.client_id = ""; config.call_no = ""; config.video.desc = MakeDesc(Info.eScreen,m_eDeviceType); config.video.rtp_port = REC_COMMON_VIDEO_PORT; cb.user_data = this; cb.on_close = &__on_close; cb.on_connect = &__on_connect; cb.on_destroy = &__on_destroy; cb.on_recv_pkt = &__on_recv_pkt; cb.dbg = &__dbg; int rc = bizchan_create(&config, &cb, &m_pChan); if (rc == 0) { rc = bizchan_start_connect(m_pChan); } if (rc != 0) { Error = Error_Unexpect; } else { ChangeState(eChannelState_Connecting); } } else { Error = Error_InvalidState; } return Error; } ErrorCodeEnum CBizChannelEntity::Close() { ErrorCodeEnum Error = Error_Succeed; if (m_eState == eChannelState_Connecting || m_eState == eChannelState_Connected) { int rc = bizchan_start_close(m_pChan); if (rc == 0) { ChangeState(eChannelState_Closing); } else { Error = Error_Unexpect; } } else { Error = Error_InvalidState; } return Error_Succeed; } ErrorCodeEnum CBizChannelEntity::RegisterState(int id, SpSubscribeContext::Pointer ctx) { state_entry *pos; ListEntry_ForEach(pos, &m_stateList, state_entry, entry) { if (pos->id == id) { return Error_AlreadyExist; } } pos = new state_entry(); pos->ctx = ctx; pos->id = id; ListEntry_AddTail(&m_stateList, &pos->entry); return Error_Succeed; } ErrorCodeEnum CBizChannelEntity::RegisterRxPkt(int id, SpSubscribeContext::Pointer ctx) { rxpkt_entry *pos; ListEntry_ForEach(pos, &m_rxpktList, rxpkt_entry, entry) { if ((pos->id == id)&&(pos->ctx->Req.type == ctx->Req.type)) { return Error_AlreadyExist; } } pos = new rxpkt_entry(); pos->id = id; pos->ctx = ctx; ListEntry_AddTail(&m_rxpktList, &pos->entry); return Error_Succeed; } void CBizChannelEntity::UnregisterState(int id) { state_entry *pos,*n; ListEntry_ForEachSafe(pos,n, &m_stateList, state_entry, entry) { if (pos->id == id) { ListEntry_DeleteNode(&pos->entry); delete pos; } } } void CBizChannelEntity::UnregisterRxpkt(int id) { rxpkt_entry *pos,*n; //ListEntry_ForEach(pos, &m_rxpktList, rxpkt_entry, entry) ListEntry_ForEachSafe(pos, n, &m_rxpktList, rxpkt_entry, entry) { if((pos->id == id)) { ListEntry_DeleteNode(&pos->entry); delete pos; } } } ErrorCodeEnum CBizChannelEntity::Send(int type, bool compress, bool encrypt, int sub_type, int id, CBlob &data) { if (m_eState == eChannelState_Connected) { //LOG_TRACE("tx pkt, %d bytes, type = %d, compress = %d, encrypt = %d, sub_type = %d, id = %d, hash=%d", data.m_iLength, type, !!compress, !!encrypt, sub_type, id, hash32_buf(data.m_pData, data.m_iLength, 0)); //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("tx pkt, %d bytes, type = %d, compress = %d, encrypt = %d, sub_type = %d, id = %d, hash=%d", data.m_iLength, type, !!compress, !!encrypt, sub_type, id, hash32_buf(data.m_pData, data.m_iLength, 0)); int rc = bizchan_post_pkt(m_pChan, type, compress, encrypt, sub_type, id, (const char*)data.m_pData, data.m_iLength); return rc == 0 ? Error_Succeed : Error_NetBroken; } else { return Error_NetBroken; } } void CBizChannelEntity::ChangeState(int new_state, const char *param) { if (m_eState != new_state) { //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("change state from %s to %s", state2str(m_eState), state2str(new_state)); m_eState = new_state; state_entry *pos; ListEntry_ForEach(pos, &m_stateList, state_entry, entry) { ChannelService_State_Info State; State.state = new_state; State.status = state2str(new_state); if (param) { State.param = param; } pos->ctx->SendMessage(State); } } } //void on_recv_pkt(int type, int sub_type, const char *pkt, int pkt_size) void CBizChannelEntity::on_recv_pkt(int type, int sub_type, int id, CBlob &data) { //LOG_TRACE("rx pkt, %d bytes, type = %d, sub_type = %d, id = %d, hash = %d", data.m_iLength, type, sub_type, id, hash32_buf(data.m_pData, data.m_iLength, 0)); //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("rx pkt, %d bytes, type = %d, sub_type = %d, id = %d, hash = %d", data.m_iLength, type, sub_type, id, hash32_buf(data.m_pData, data.m_iLength, 0)); rxpkt_entry *pos; ListEntry_ForEach(pos, &m_rxpktList, rxpkt_entry, entry) { if (pos->ctx->Req.type == type) { ChannelService_Packet_Info pkt; pkt.type = type; pkt.sub_type = sub_type; pkt.id = id; //pkt.data.m_bManaged = true; pkt.data = data; //data.m_bManaged = false; pos->ctx->SendMessage(pkt); //break; } } } void CBizChannelEntity::on_connect(int error, const char *remote_ip, int remote_video_rtp, int remote_video_desc) { if (!error) { if (m_eState == eChannelState_Connecting) { CSimpleStringA strValue; ErrorCodeEnum Error = GetFunction()->GetSysVar("VideoWindowInitializeParam", strValue); if (Error == Error_Succeed) { int local_view_x; int local_view_y; int local_view_cx; int local_view_cy; int remote_view_x; int remote_view_y; int remote_view_cx; int remote_view_cy; int remote_video_width = 0; int remote_video_height = 0; { CSystemStaticInfo Info; GetFunction()->GetSystemStaticInfo(Info); if (Info.eScreen == 1) { remote_video_width = REC_COMMON_VIDEO_SSM_AGENT_WIDTH; remote_video_height = REC_COMMON_VIDEO_SSM_AGENT_HEIGHT; } else { remote_video_width = REC_COMMON_VIDEO_DSM_AGENT_WIDTH; remote_video_height = REC_COMMON_VIDEO_DSM_AGENT_HEIGHT; } } ParseVideoViewParam(strValue.GetData(), local_view_x, local_view_y, local_view_cx, local_view_cy, remote_view_x, remote_view_y, remote_view_cx, remote_view_cy); //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("Get Video Window Initialize Param:%d,%d,%d,%d %d,%d,%d,%d",local_view_x, local_view_y, local_view_cx, local_view_cy, //remote_view_x, remote_view_y, remote_view_cx, remote_view_cy); CSimpleStringA param; param = BuildVideoDesc(remote_ip, remote_video_rtp, remote_video_width, remote_video_height, REC_COMMON_VIDEO_FPS, local_view_x, local_view_y, local_view_cx, local_view_cy, remote_view_x, remote_view_y, remote_view_cx, remote_view_cy); ChangeState(eChannelState_Connected, param.GetData()); } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("get VideoWindowInitializeParam failed!"); bizchan_start_close(m_pChan); } } } else { if (m_pChan) { bizchan_close(m_pChan); bizchan_destroy(m_pChan); m_pChan = NULL; } ChangeState(eChannelState_Idle); } } void CBizChannelEntity::on_close() { if (m_pChan) { bizchan_close(m_pChan); bizchan_destroy(m_pChan); m_pChan = NULL; } ChangeState(eChannelState_Idle); } void CBizChannelEntity::_on_recv_pkt(int type, int sub_type, int id, const char *pkt, int pkt_size) { //LOG_TRACE("_on rx pkt, %d bytes, type = %d, sub_type = %d, id = %d, hash = %d", pkt_size, type, sub_type, id, hash32_buf(pkt, pkt_size, 0)); NotifyOnRecvPkt *task = new NotifyOnRecvPkt(); task->m_pEntity = this; task->type = type; task->sub_type = sub_type; task->id = id; task->data.m_bManaged = true; task->data.m_iLength = pkt_size; if (pkt_size) { task->data.m_pData = new char[pkt_size]; memcpy(task->data.m_pData, pkt, pkt_size); } else { task->data.m_pData = NULL; } GetFunction()->PostEntityTaskFIFO(task); } void CBizChannelEntity::_on_connect(int error, const char *remote_ip, int remote_video_rtp, int remote_video_desc) { NotifyOnConnect *task = new NotifyOnConnect(); task->m_pEntity = this; task->error = error; task->remote_rtp_ip = remote_ip; task->remote_video_port = remote_video_rtp; task->remote_video_desc = remote_video_desc; GetFunction()->PostEntityTaskFIFO(task); } void CBizChannelEntity::_on_close() { NotifyOnClose *task = new NotifyOnClose(); task->m_pEntity = this; GetFunction()->PostEntityTaskFIFO(task); } void ChannelServiceSession::Handle_Connect( SpReqAnsContext::Pointer ctx ) { DbgToBeidou(ctx->link, __FUNCTION__)(); DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("start connect, %s:%d", ctx->Req.ip.GetData(), ctx->Req.port); ErrorCodeEnum Error = m_pEntity->Connect(ctx->Req.ip, ctx->Req.port); DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("connect Error = %d", Error); ctx->Answer(Error); } void ChannelServiceSession::Handle_Close( SpReqAnsContext::Pointer ctx ) { DbgToBeidou(ctx->link, __FUNCTION__)(); ErrorCodeEnum Error = m_pEntity->Close(); ctx->Answer(Error); } void ChannelServiceSession::Handle_GetState( SpReqAnsContext::Pointer ctx ) { DbgToBeidou(ctx->link, __FUNCTION__)(); ctx->Ans.status = state2str(m_pEntity->GetState()); ctx->Answer(Error_Succeed); } void ChannelServiceSession::Handle_BeginState( SpSubscribeContext::Pointer ctx ) { m_pEntity->RegisterState(m_id, ctx); } void ChannelServiceSession::Handle_EndState( SpOnewayCallContext::Pointer ctx ) { DbgToBeidou(ctx->link, __FUNCTION__)(); m_pEntity->UnregisterState(m_id); } void ChannelServiceSession::Handle_Send( SpOnewayCallContext::Pointer ctx ) { DbgToBeidou(ctx->link, __FUNCTION__)(); m_pEntity->Send(ctx->Info.type, ctx->Info.compress, ctx->Info.encrypt, ctx->Info.sub_type, ctx->Info.id, ctx->Info.data); } void ChannelServiceSession::Handle_BeginRecv( SpSubscribeContext::Pointer ctx ) { m_pEntity->RegisterRxPkt(m_id, ctx); } void ChannelServiceSession::Handle_EndRecv( SpOnewayCallContext::Pointer ctx ) { DbgToBeidou(ctx->link, __FUNCTION__)(); m_pEntity->UnregisterRxpkt(m_id); } void ChannelServiceSession::OnClose( ErrorCodeEnum eErrorCode ) { m_pEntity->UnregisterRxpkt(m_id); m_pEntity->UnregisterState(m_id); } SP_BEGIN_ENTITY_MAP() SP_ENTITY(CBizChannelEntity) SP_END_ENTITY_MAP()