#include "stdafx.h" #include "SpBase.h" #include "ListEntry.h" #include "VideoDesc.h" #include "AssistantChannel_server_g.h" #include "..\..\Other\libbizchan\bizchan.h" #include "rec_common.h" #include "chan_protocol.h" #include "..\include\EventCode.h" #include "..\mod_counterconnector\CallType.h" using namespace AssistantChannel; class CBizChannelEntity; 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) { if (eMobilePadType == eDevicetype) { return media_desc_encode( ACM_VIDEO_MODE_SQUARE, ACM_VIDEO_ENCODE_H264, ACM_VIDEO_FPS_MOBILE, ACM_VIDEO_MODE_QVGA, ACM_VIDEO_ENCODE_H264, ACM_VIDEO_FPS_MOBILEAGENT); } else if((ePadtype == eDevicetype)||(eDesk2SType == eDevicetype)) { return media_desc_encode( ACM_VIDEO_MODE_SQUARE, ACM_VIDEO_ENCODE_H264, ACM_VIDEO_FPS_MOBILE, ACM_VIDEO_MODE_QVGA, ACM_VIDEO_ENCODE_H264, ACM_VIDEO_FPS_MOBILE); } else { 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; } class ChannelServiceSession : public ChannelService_ServerSessionBase { public: ChannelServiceSession(CBizChannelEntity *pEntity, int id) : m_pEntity(pEntity), m_id(id) {} virtual void Handle_Connect(SpReqAnsContext::Pointer ctx); virtual void Handle_Close(SpReqAnsContext::Pointer ctx); virtual void Handle_GetState(SpReqAnsContext::Pointer ctx); virtual void Handle_BeginState(SpSubscribeContext::Pointer ctx); virtual void Handle_EndState(SpOnewayCallContext::Pointer ctx); virtual void Handle_Send(SpOnewayCallContext::Pointer ctx); virtual void Handle_BeginRecv(SpSubscribeContext::Pointer ctx); virtual void Handle_EndRecv(SpOnewayCallContext::Pointer ctx); virtual void OnClose(ErrorCodeEnum eErrorCode); private: int m_id; CBizChannelEntity *m_pEntity; }; class CBizChannelEntity : public CEntityBase { public: CBizChannelEntity() : m_id_seq(0) {} virtual ~CBizChannelEntity() {} virtual const char *GetEntityName() const { return "AssistantChannel"; } virtual bool IsService()const{return true;} virtual void OnPreStart(CAutoArray strArgs,CSmartPointer pTransactionContext) { ErrorCodeEnum Error = __OnStart(Error_Succeed); pTransactionContext->SendAnswer(Error); } virtual void OnPreClose(EntityCloseCauseEnum eCloseCause,CSmartPointer pTransactionContext) { ErrorCodeEnum Error = __OnClose(Error_Succeed); pTransactionContext->SendAnswer(Error); } ErrorCodeEnum __OnStart(ErrorCodeEnum preOperationError) { //MessageBoxA(0,0,0,0); bizchan_lib_init(); m_eState = eChannelState_Idle; m_pChan = NULL; m_eDeviceType = eStand2sType; //is Pad Version CSmartPointer spFunction = GetFunction(); CSystemStaticInfo stStaticinfo; spFunction->GetSystemStaticInfo(stStaticinfo); if (stricmp(stStaticinfo.strMachineType,"RVC.PAD")==0) { if (stricmp(stStaticinfo.strSite,"CMB.FLB")==0) { LOG_TRACE("the type is mobile pad"); m_eDeviceType = eMobilePadType; } else { LOG_TRACE("the type is pad"); m_eDeviceType = ePadtype; } } else if (stricmp(stStaticinfo.strMachineType,"RVC.Desk2S")==0) { LOG_TRACE("the type is Desk2S"); m_eDeviceType = eDesk2SType; } else if (stricmp(stStaticinfo.strMachineType,"RPM.Stand1S")==0) { LOG_TRACE("the type is RPM.Stand1S"); m_eDeviceType = eRpm1sType; } else { LOG_TRACE("the type is standard"); m_eDeviceType = eStand2sType; } ListEntry_InitHead(&m_stateList); ListEntry_InitHead(&m_rxpktList); return Error_Succeed; } ErrorCodeEnum __OnClose(ErrorCodeEnum preOperationError) { //..... bizchan_lib_term(); return Error_Succeed; } virtual CServerSessionBase *OnNewSession(const char* pszRemoteEntityName, const char * pszClass) { LOG_FUNCTION(); LOG_TRACE("%s connected class = %s!", pszRemoteEntityName, pszClass); return new ChannelServiceSession(this, m_id_seq++); } ErrorCodeEnum Connect(const char *ip, int port, const char *callno, CallingTypeEnum eType) { 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; if (MOBILETOPAD_CALLTYPE == eType || PADTOPAD_CALLTYPE == eType){ config.session_id = const_cast(callno); }else{ config.session_id = const_cast(((const char*)Info.strTerminalID)); } if (MOBILETOPAD_CALLTYPE == eType){ config.crypt_type = 1; } config.call_no = const_cast(callno); config.client_id = ""; 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; 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 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; } int GetState() { return m_eState; } ErrorCodeEnum 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 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; } } Dbg("RegisterRxPkt id = %d",id); pos = new rxpkt_entry(); pos->id = id; pos->ctx = ctx; ListEntry_AddTail(&m_rxpktList, &pos->entry); return Error_Succeed; } void 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 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)) { Dbg("UnregisterRxpkt id = %d",pos->id); ListEntry_DeleteNode(&pos->entry); delete pos; } } } ErrorCodeEnum 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)); Dbg("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; } } private: struct NotifyOnClose : public ITaskSp { CBizChannelEntity *m_pEntity; virtual void Process() { m_pEntity->on_close(); } }; struct NotifyOnRecvPkt : public ITaskSp { CBizChannelEntity *m_pEntity; int type; int sub_type; int id; CBlob data; virtual void Process() { m_pEntity->on_recv_pkt(type, sub_type, id, data); } }; struct NotifyOnConnect : public ITaskSp { CBizChannelEntity *m_pEntity; int error; CSimpleStringA remote_rtp_ip; int remote_video_port; int remote_video_desc; virtual void Process() { m_pEntity->on_connect(error, (LPCSTR)remote_rtp_ip, remote_video_port, remote_video_desc); } }; void ChangeState(int new_state, const char *param = NULL) { if (m_eState != new_state) { LOG_TRACE("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 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)); Dbg("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 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((LPCSTR)strValue, local_view_x, local_view_y, local_view_cx, local_view_cy, remote_view_x, remote_view_y, remote_view_cx, remote_view_cy); Dbg("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; if (eMobilePadType == m_eDeviceType) { param = BuildVideoDesc(remote_ip, remote_video_rtp, remote_video_width, remote_video_height, REC_COMMON_VIDEO_FPS_MOBILE_AGENT, local_view_x, local_view_y, local_view_cx, local_view_cy, remote_view_x, remote_view_y, remote_view_cx, remote_view_cy); } else if((ePadtype == m_eDeviceType)||(eDesk2SType == m_eDeviceType)) { param = BuildVideoDesc(remote_ip, remote_video_rtp, remote_video_width, remote_video_height, REC_COMMON_VIDEO_FPS_MOBILE, local_view_x, local_view_y, local_view_cx, local_view_cy, remote_view_x, remote_view_y, remote_view_cx, remote_view_cy); } else { 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, (LPCSTR)param); } else { Dbg("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 on_close() { if (m_pChan) { bizchan_close(m_pChan); bizchan_destroy(m_pChan); m_pChan = NULL; } ChangeState(eChannelState_Idle); } void _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 _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 _on_close() { NotifyOnClose *task = new NotifyOnClose(); task->m_pEntity = this; GetFunction()->PostEntityTaskFIFO(task); } 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) { } private: DeviceTypeEnum m_eDeviceType; int m_eState; bizchan_t *m_pChan; int m_id_seq; struct state_entry { LIST_ENTRY entry; int id; SpSubscribeContext::Pointer ctx; }; LIST_ENTRY m_stateList; struct rxpkt_entry { LIST_ENTRY entry; int id; SpSubscribeContext::Pointer ctx; }; LIST_ENTRY m_rxpktList; }; void ChannelServiceSession::Handle_Connect( SpReqAnsContext::Pointer ctx ) { LOG_TRACE("start connect, %s:%d [%s]", (LPCSTR)ctx->Req.ip, ctx->Req.port, (LPCSTR)ctx->Req.callno); ErrorCodeEnum Error = m_pEntity->Connect(ctx->Req.ip, ctx->Req.port, ctx->Req.callno, (CallingTypeEnum)ctx->Req.etype); LOG_TRACE("connect Error = %d", Error); ctx->Answer(Error); } void ChannelServiceSession::Handle_Close( SpReqAnsContext::Pointer ctx ) { LOG_TRACE("connect close!"); ErrorCodeEnum Error = m_pEntity->Close(); ctx->Answer(Error); } void ChannelServiceSession::Handle_GetState( SpReqAnsContext::Pointer ctx ) { 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 ) { m_pEntity->UnregisterState(m_id); } void ChannelServiceSession::Handle_Send( SpOnewayCallContext::Pointer ctx ) { 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 ) { 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()