// PocketPJDlg.cpp : implementation file // #include "stdafx.h" #include "PocketPJ.h" #include "PocketPJDlg.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define TIMER_ID 101 static CPocketPJDlg *theDlg; ///////////////////////////////////////////////////////////////////////////// // CPocketPJDlg dialog CPocketPJDlg::CPocketPJDlg(CWnd* pParent /*=NULL*/) : CDialog(CPocketPJDlg::IDD, pParent), m_PopUp(NULL) { //{{AFX_DATA_INIT(CPocketPJDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); theDlg = this; m_PopUp = new CPopUpWnd(this); m_PopUp->Hide(); unsigned i; m_PopUpCount = 0; for (i=0; iIpAddress.String); cfg.nameserver_count = 1; cfg.nameserver[0] = pj_str(nameserver); } } char tmp_stun[80]; if (m_Cfg.m_UseStun) { pj_unicode_to_ansi((LPCTSTR)m_Cfg.m_StunSrv, m_Cfg.m_StunSrv.GetLength(), tmp_stun, sizeof(tmp_stun)); cfg.stun_host = pj_str(tmp_stun); } pjsua_logging_config_default(&log_cfg); log_cfg.msg_logging = PJ_TRUE; log_cfg.log_filename = pj_str("\\PocketPJ.TXT"); pjsua_media_config_default(&media_cfg); media_cfg.clock_rate = 8000; media_cfg.audio_frame_ptime = 40; media_cfg.ec_tail_len = 0; media_cfg.ilbc_mode = 30; media_cfg.max_media_ports = 8; // use default quality setting //media_cfg.quality = 5; media_cfg.thread_cnt = 1; media_cfg.enable_ice = m_Cfg.m_UseIce; media_cfg.no_vad = !m_Cfg.m_VAD; if (m_Cfg.m_EchoSuppress) { media_cfg.ec_options = PJMEDIA_ECHO_SIMPLE; media_cfg.ec_tail_len = m_Cfg.m_EcTail; } // Init PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Initializing.."); status = pjsua_init(&cfg, &log_cfg, &media_cfg); if (status != PJ_SUCCESS) { Error(_T("Error initializing library"), status); pjsua_destroy(); PopUp_Hide(POPUP_REGISTRATION); return FALSE; } // Create one UDP transport PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Adding UDP transport.."); pjsua_transport_id transport_id; pjsua_transport_config udp_cfg; pjsua_transport_config_default(&udp_cfg); udp_cfg.port = 0; status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &udp_cfg, &transport_id); if (status != PJ_SUCCESS) { Error(_T("Error creating UDP transport"), status); pjsua_destroy(); PopUp_Hide(POPUP_REGISTRATION); return FALSE; } // Always instantiate TCP to support auto-switching to TCP when // packet is larger than 1300 bytes. If TCP is disabled when // no auto-switching will occur if (1) { // Create one TCP transport PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Adding TCP transport.."); pjsua_transport_id transport_id; pjsua_transport_config tcp_cfg; pjsua_transport_config_default(&tcp_cfg); tcp_cfg.port = 0; status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, &tcp_cfg, &transport_id); if (status != PJ_SUCCESS) { Error(_T("Error creating TCP transport"), status); pjsua_destroy(); PopUp_Hide(POPUP_REGISTRATION); return FALSE; } } // Adjust codecs priority pj_str_t tmp; pjsua_codec_set_priority(pj_cstr(&tmp, "*"), 0); for (i=0; i<(unsigned)m_Cfg.m_Codecs.GetSize(); ++i) { CString codec = m_Cfg.m_Codecs.GetAt(i); char tmp_nam[80]; pj_unicode_to_ansi((LPCTSTR)codec, codec.GetLength(), tmp_nam, sizeof(tmp_nam)); pjsua_codec_set_priority(pj_cstr(&tmp, tmp_nam), (pj_uint8_t)(200-i)); } // Start! PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Starting.."); status = pjsua_start(); if (status != PJ_SUCCESS) { Error(_T("Error starting library"), status); pjsua_destroy(); PopUp_Hide(POPUP_REGISTRATION); return FALSE; } // Add account PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Adding account.."); char domain[80], username[80], passwd[80]; char id[80], reg_uri[80]; pjsua_acc_config acc_cfg; pj_unicode_to_ansi((LPCTSTR)m_Cfg.m_Domain, m_Cfg.m_Domain.GetLength(), domain, sizeof(domain)); pj_unicode_to_ansi((LPCTSTR)m_Cfg.m_User, m_Cfg.m_User.GetLength(), username, sizeof(username)); pj_unicode_to_ansi((LPCTSTR)m_Cfg.m_Password, m_Cfg.m_Password.GetLength(), passwd, sizeof(passwd)); snprintf(id, sizeof(id), "", username, domain); snprintf(reg_uri, sizeof(reg_uri), "sip:%s", domain); pjsua_acc_config_default(&acc_cfg); acc_cfg.id = pj_str(id); acc_cfg.reg_uri = pj_str(reg_uri); acc_cfg.cred_count = 1; acc_cfg.cred_info[0].scheme = pj_str("Digest"); acc_cfg.cred_info[0].realm = pj_str("*"); acc_cfg.cred_info[0].username = pj_str(username); acc_cfg.cred_info[0].data_type = 0; acc_cfg.cred_info[0].data = pj_str(passwd); #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) acc_cfg.use_srtp = (m_Cfg.m_UseSrtp ? PJMEDIA_SRTP_OPTIONAL : PJMEDIA_SRTP_DISABLED); acc_cfg.srtp_secure_signaling = 0; #endif acc_cfg.publish_enabled = m_Cfg.m_UsePublish; char route[80]; if (m_Cfg.m_TCP) { snprintf(route, sizeof(route), "", domain); acc_cfg.proxy[acc_cfg.proxy_cnt++] = pj_str(route); } else { snprintf(route, sizeof(route), "", domain); acc_cfg.proxy[acc_cfg.proxy_cnt++] = pj_str(route); } status = pjsua_acc_add(&acc_cfg, PJ_TRUE, &m_PjsuaAccId); if (status != PJ_SUCCESS) { Error(_T("Invalid account settings"), status); pjsua_destroy(); PopUp_Hide(POPUP_REGISTRATION); return FALSE; } CString acc_text = m_Cfg.m_User + _T("@") + m_Cfg.m_Domain; m_AccId.SetWindowText(acc_text); PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE1, acc_text); PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE2, "Registering.."); PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, ""); SetTimer(TIMER_ID, 100, NULL); return TRUE; } void CPocketPJDlg::PopUp_Show( PopUpType type, const CString& title1, const CString& title2, const CString& title3, const CString& btn1, const CString& btn2, unsigned userData) { PJ_UNUSED_ARG(userData); if (!m_PopUpState[type]) ++m_PopUpCount; m_PopUpState[type] = TRUE; m_PopUpContent[type].m_Title1 = title1; m_PopUpContent[type].m_Title2 = title2; m_PopUpContent[type].m_Title3 = title3; m_PopUpContent[type].m_Btn1 = btn1; m_PopUpContent[type].m_Btn2 = btn2; m_PopUp->SetContent(m_PopUpContent[type]); m_PopUp->Show(); } void CPocketPJDlg::PopUp_Modify(PopUpType type, PopUpElement el, const CString& text) { switch (el) { case POPUP_EL_TITLE1: m_PopUpContent[type].m_Title1 = text; break; case POPUP_EL_TITLE2: m_PopUpContent[type].m_Title2 = text; break; case POPUP_EL_TITLE3: m_PopUpContent[type].m_Title3 = text; break; case POPUP_EL_BUTTON1: m_PopUpContent[type].m_Btn1 = text; break; case POPUP_EL_BUTTON2: m_PopUpContent[type].m_Btn1 = text; break; } m_PopUp->SetContent(m_PopUpContent[type]); } void CPocketPJDlg::PopUp_Hide(PopUpType type) { if (m_PopUpState[type]) --m_PopUpCount; m_PopUpState[type] = FALSE; if (m_PopUpCount == 0) { m_PopUp->Hide(); UpdateWindow(); } else { for (int i=POPUP_MAX_TYPE-1; i>=0; --i) { if (m_PopUpState[i]) { m_PopUp->SetContent(m_PopUpContent[i]); break; } } } } void CPocketPJDlg::OnIncomingCall() { pjsua_call_info ci; pjsua_call_get_info(0, &ci); PopUp_Show(POPUP_CALL, "Incoming call..", ci.remote_info.ptr, "", "Answer", "Hangup", 0); pjsua_call_answer(0, 180, NULL, NULL); if (m_Cfg.m_AutoAnswer) OnPopUpButton(1); } void CPocketPJDlg::OnCallState() { pjsua_call_info ci; pjsua_call_get_info(0, &ci); switch (ci.state) { case PJSIP_INV_STATE_NULL: /**< Before INVITE is sent or received */ break; case PJSIP_INV_STATE_CALLING: /**< After INVITE is sent */ PopUp_Show(POPUP_CALL, "Calling..", ci.remote_info.ptr, "", "", "Hangup", 0); break; case PJSIP_INV_STATE_INCOMING: /**< After INVITE is received. */ OnIncomingCall(); break; case PJSIP_INV_STATE_EARLY: /**< After response with To tag. */ case PJSIP_INV_STATE_CONNECTING:/**< After 2xx is sent/received. */ case PJSIP_INV_STATE_CONFIRMED: /**< After ACK is sent/received. */ { CString stateText = ci.state_text.ptr; PopUp_Modify(POPUP_CALL, POPUP_EL_TITLE3, stateText); } break; case PJSIP_INV_STATE_DISCONNECTED:/**< Session is terminated. */ PopUp_Modify(POPUP_CALL, POPUP_EL_TITLE3, "Disconnected"); PopUp_Hide(POPUP_CALL); break; } } void CPocketPJDlg::on_call_state(pjsua_call_id call_id, pjsip_event *e) { PJ_UNUSED_ARG(e); PJ_UNUSED_ARG(call_id); theDlg->OnCallState(); } void CPocketPJDlg::on_call_media_state(pjsua_call_id call_id) { pjsua_call_info call_info; pjsua_call_get_info(call_id, &call_info); if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE) { pjsua_conf_connect(call_info.conf_slot, 0); pjsua_conf_connect(0, call_info.conf_slot); } } void CPocketPJDlg::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata) { PJ_UNUSED_ARG(acc_id); PJ_UNUSED_ARG(call_id); PJ_UNUSED_ARG(rdata); theDlg->OnIncomingCall(); } void CPocketPJDlg::OnRegState() { pjsua_acc_info ai; pjsua_acc_get_info(m_PjsuaAccId, &ai); CString acc_text = m_Cfg.m_User + _T("@") + m_Cfg.m_Domain; if (ai.expires>0 && ai.status/100==2) { /* Registration success */ HBITMAP old = m_BtnAcc.SetBitmap(::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_ONLINE)) ); PJ_UNUSED_ARG(old); acc_text += " (OK)"; m_AccId.SetWindowText(acc_text); } else if (ai.status/100 != 2) { acc_text += " (err)"; Error(_T("SIP registration error"), PJSIP_ERRNO_FROM_SIP_STATUS(ai.status)); m_AccId.SetWindowText(acc_text); } PopUp_Hide(POPUP_REGISTRATION); } void CPocketPJDlg::on_reg_state(pjsua_acc_id acc_id) { PJ_UNUSED_ARG(acc_id); theDlg->OnRegState(); } void CPocketPJDlg::on_buddy_state(pjsua_buddy_id buddy_id) { PJ_UNUSED_ARG(buddy_id); theDlg->RedrawBuddyList(); } void CPocketPJDlg::on_pager(pjsua_call_id call_id, const pj_str_t *from, const pj_str_t *to, const pj_str_t *contact, const pj_str_t *mime_type, const pj_str_t *text) { PJ_UNUSED_ARG(call_id); PJ_UNUSED_ARG(from); PJ_UNUSED_ARG(to); PJ_UNUSED_ARG(contact); PJ_UNUSED_ARG(mime_type); PJ_UNUSED_ARG(text); } ///////////////////////////////////////////////////////////////////////////// // CPocketPJDlg message handlers BOOL CPocketPJDlg::OnInitDialog() { CDialog::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon CenterWindow(GetDesktopWindow()); // center to the hpc screen // TODO: Add extra initialization here m_Cfg.LoadRegistry(); //ShowWindow(SW_SHOW); m_AccId.SetWindowText(m_Cfg.m_User); CImageList *il = new CImageList; VERIFY(il->Create(16, 16, ILC_COLOR|ILC_MASK, 2, 4)); CBitmap *bmp = new CBitmap; bmp->LoadBitmap(MAKEINTRESOURCE(IDB_BLANK)); il->Add(bmp, RGB(255,255,255)); bmp = new CBitmap; bmp->LoadBitmap(MAKEINTRESOURCE(IDB_ONLINE)); il->Add(bmp, RGB(255,255,255)); m_BuddyList.SetImageList(il, LVSIL_SMALL); if (m_Cfg.m_Domain.GetLength()==0 || Restart() == FALSE) { for (;;) { CSettingsDlg dlg(m_Cfg); if (dlg.DoModal() != IDOK) { EndDialog(IDOK); return TRUE; } m_Cfg.SaveRegistry(); if (Restart()) break; } } RedrawBuddyList(); return TRUE; // return TRUE unless you set the focus to a control } void CPocketPJDlg::OnBtnAcc() { CMenu menu; VERIFY(menu.LoadMenu(IDR_ACC_MENU)); CMenu* pPopup = menu.GetSubMenu(0); ASSERT(pPopup != NULL); RECT r; m_BtnAcc.GetWindowRect(&r); pPopup->TrackPopupMenu(TPM_LEFTALIGN, r.left+4, r.top+4, this); } void CPocketPJDlg::OnBtnAction() { CMenu menu; VERIFY(menu.LoadMenu(IDR_URI_MENU)); CMenu* pPopup = menu.GetSubMenu(0); ASSERT(pPopup != NULL); RECT r; this->m_BtnUrlAction.GetWindowRect(&r); pPopup->TrackPopupMenu(TPM_LEFTALIGN, r.left+4, r.top+4, this); } void CPocketPJDlg::OnSettings() { for (;;) { CSettingsDlg dlg(m_Cfg); if (dlg.DoModal() != IDOK) { return; } m_Cfg.SaveRegistry(); if (Restart()) break; } } void CPocketPJDlg::OnOK() { if (AfxMessageBox(_T("Quit PocketPJ?"), MB_YESNO)==IDYES) { KillTimer(TIMER_ID); PopUp_Show(POPUP_REGISTRATION, "", "Shutting down..", "", "", "", 0); pjsua_destroy(); CDialog::OnOK(); PopUp_Hide(POPUP_REGISTRATION); m_Cfg.SaveRegistry(); return; } } void CPocketPJDlg::OnTimer(UINT nIDEvent) { pjsua_handle_events(10); CDialog::OnTimer(nIDEvent); } int CPocketPJDlg::FindBuddyInPjsua(const CString &Uri) { char uri[80]; pjsua_buddy_id id[128]; unsigned i, count = PJ_ARRAY_SIZE(id); if (pjsua_enum_buddies(id, &count) != PJ_SUCCESS) return PJSUA_INVALID_ID; if (count==0) return PJSUA_INVALID_ID; pj_unicode_to_ansi((LPCTSTR)Uri, Uri.GetLength(), uri, sizeof(uri)); for (i=0; i