/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "ChannelDlg.h" #include "VideoSize.h" #include "CaptureDevicePool.h" #include "ChannelPool.h" #include #include #include "assert.h" #include // threads. #if defined _WIN32 #define SLEEP_10_SEC ::Sleep(10000) #define GET_TIME_IN_MS timeGetTime #endif // Hack to convert char to TCHAR, using two buffers to be able to // call twice in the same statement TCHAR convertTemp1[256] = {0}; TCHAR convertTemp2[256] = {0}; bool convertBufferSwitch(false); TCHAR* CharToTchar(const char* str, int len) { #ifdef _UNICODE TCHAR* temp = convertBufferSwitch ? convertTemp1 : convertTemp2; convertBufferSwitch = !convertBufferSwitch; memset(temp, 0, sizeof(convertTemp1)); MultiByteToWideChar(CP_UTF8, 0, str, len, temp, 256); return temp; #else return str; #endif } // Hack to convert TCHAR to char char convertTemp3[256] = {0}; char* TcharToChar(TCHAR* str, int len) { #ifdef _UNICODE memset(convertTemp3, 0, sizeof(convertTemp3)); WideCharToMultiByte(CP_UTF8, 0, str, len, convertTemp3, 256, 0, 0); return convertTemp3; #else return str; #endif } ///////////////////////////////////////////////////////////////////////////// // CDXChannelDlg dialog CDXChannelDlg::CDXChannelDlg(VideoEngine* videoEngine, CaptureDevicePool& captureDevicePool, ChannelPool& channelPool, void* voiceEngine ,CWnd* pParent,CDXChannelDlgObserver* observer, int parentChannel/*=-1*/) : CDialog(CDXChannelDlg::IDD, pParent), _canAddLog(true), _dialogObserver(observer), _videoEngine(videoEngine), _captureDevicePool(captureDevicePool), _channelPool(channelPool), _parentChannel(parentChannel), #ifndef NO_VOICE_ENGINE _voiceEngine((VoiceEngine*) voiceEngine), #endif _callbackEvent(::CreateEvent( NULL, FALSE, FALSE, NULL)), _externalTransport(NULL) { strcpy(_logMsg,""); _channelId = -1; _audioChannel=-1; _captureId=-1; //_transport = NULL; //{{AFX_DATA_INIT(CDXChannelDlg) //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 InitializeCriticalSection(&_critCallback); unsigned int threadID; _callbackThread=(HANDLE)_beginthreadex(NULL,1024*1024,CallbackThread,(void*)this,0, &threadID); } void CDXChannelDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDXChannelDlg) DDX_Control(pDX, IDC_DEVICE, m_ctrlDevice); DDX_Control(pDX, IDC_CODEC_LIST, m_ctrlCodec); DDX_Control(pDX, IDC_CAPTURE, m_ctrlLiveRemoteVideo); DDX_Control(pDX, IDC_LIVEVIDEO, m_ctrlLiveVideo); DDX_Control(pDX, IDC_LOCAL_PORT1, m_localPort1); DDX_Control(pDX, IDC_REMOTE_PORT1, m_remotePort1); DDX_Control(pDX, IDC_IPADDRESS1, m_remoteIp1); DDX_Control(pDX, IDC_CODEC_SIZE, m_ctrlCodecSize); DDX_Control(pDX, IDC_RTCPMODE, m_ctrlRtcpMode); DDX_Control(pDX, IDC_PACKETBURST, m_ctrlPacketBurst); DDX_Control(pDX, IDC_BITRATE, m_ctrlBitrate); DDX_Control(pDX, IDC_MIN_FRAME_RATE, m_ctrlMinFrameRate); DDX_Control(pDX, IDC_TMMBR,m_cbTmmbr); DDX_Control(pDX, IDC_EXTTRANSPORT,m_cbExternalTransport); DDX_Control(pDX, IDC_PACKETLOSS,m_ctrlPacketLoss); DDX_Control(pDX, IDC_DELAY,m_ctrlDelay); DDX_Control(pDX, IDC_FREEZELOG,m_cbFreezeLog); DDX_Control(pDX,IDC_INFORMATION,m_ctrlInfo); //}}AFX_DATA_MAP } // ON_WM_SYSKEYDOWN ALT+key BEGIN_MESSAGE_MAP(CDXChannelDlg, CDialog) //{{AFX_MSG_MAP(CDXChannelDlg) ON_WM_SYSCOMMAND() ON_WM_RBUTTONUP() //ON_WM_DEVICECHANGE() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_STARTSEND, OnStartSend) ON_BN_CLICKED(IDC_STOPSend, OnStopSend) //ON_WM_TIMER() ON_WM_DESTROY() //}}AFX_MSG_MAP ON_CBN_SELCHANGE(IDC_CODEC_LIST, OnCbnSelchangeCodecList) ON_CBN_SELCHANGE(IDC_DEVICE, OnCbnSelchangeDevice) ON_CBN_SELCHANGE(IDC_CODEC_SIZE, OnCbnSelchangeSize) ON_CBN_SELCHANGE(IDC_BITRATE, OnCbnSelchangeBitrate) //ON_MESSAGE(WM_DISPLAYCHANGE, OnDisplayChange) ON_CBN_SELCHANGE(IDC_MIN_FRAME_RATE, OnCbnSelchangeMinFrameRate) ON_BN_CLICKED(IDC_STARTLISTEN, OnBnClickedStartlisten) ON_BN_CLICKED(IDC_STOPLISTEN, OnBnClickedStoplisten) ON_BN_CLICKED(IDC_TMMBR, &CDXChannelDlg::OnBnClickedTmmbr) ON_CBN_SELCHANGE(IDC_RTCPMODE, &CDXChannelDlg::OnCbnSelchangeRtcpmode) ON_BN_CLICKED(IDC_PROT_NACK, &CDXChannelDlg::OnBnClickedProtNack) ON_BN_CLICKED(IDC_PROT_NONE, &CDXChannelDlg::OnBnClickedProtNone) ON_BN_CLICKED(IDC_PROT_FEC, &CDXChannelDlg::OnBnClickedProtFec) ON_BN_CLICKED(IDC_FREEZELOG, &CDXChannelDlg::OnBnClickedFreezelog) ON_BN_CLICKED(IDC_CAMERACAP, &CDXChannelDlg::OnBnClickedCameracap) ON_BN_CLICKED(IDC_EXTTRANSPORT, &CDXChannelDlg::OnBnClickedExttransport) ON_CBN_SELCHANGE(IDC_PACKETLOSS, &CDXChannelDlg::OnCbnSelchangePacketloss) ON_CBN_SELCHANGE(IDC_DELAY, &CDXChannelDlg::OnCbnSelchangeDelay) ON_BN_CLICKED(IDC_BTN_RECORD_INCOMING, &CDXChannelDlg::OnBnClickedBtnRecordIncoming) ON_BN_CLICKED(IDC_BTN_RECORD_OUTGOING, &CDXChannelDlg::OnBnClickedBtnRecordOutgoing) ON_BN_CLICKED(IDC_BTN_CREATE_SLAVE, &CDXChannelDlg::OnBnClickedBtnCreateSlave) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CDXChannelDlg message handlers BOOL CDXChannelDlg::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 ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("5")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("6")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("7")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("8")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("9")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("10")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("11")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("12")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("13")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("14")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("15")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("16")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("17")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("18")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("19")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("20")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("21")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("22")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("23")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("24")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("25")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("26")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("27")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("28")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("29")); ::SendMessage(m_ctrlMinFrameRate.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("30")); m_ctrlMinFrameRate.SetCurSel(25); // Codec sizes for(VideoSize i=VideoSize::UNDEFINED;iSetVoiceEngine(_voiceEngine),-5); #endif int err = 0; char str[64]; bool found = false; int captureIdx = 0; while (-1 !=_vieCapture->GetCaptureDevice(captureIdx,str,sizeof(str),NULL,0)) { char* tmp = strstr(str,"(VFW)"); if (!tmp) { ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)CharToTchar(str,-1)); found = true; } captureIdx++; memset(str, 0, 64); } WIN32_FIND_DATA FindFileData; HANDLE hFind; //char fileSearch[256]; //strcpy(fileSearch,_T("*.avi")); hFind = FindFirstFile(_T("*.avi"), &FindFileData); if (hFind != INVALID_HANDLE_VALUE) { ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)(FindFileData.cFileName)); while(FindNextFile(hFind,&FindFileData)) { ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)(FindFileData.cFileName)); } FindClose(hFind); } ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("Conference")); ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)_T("None")); if (!found) { strncpy(str,"N/A",64); ::SendMessage(m_ctrlDevice.m_hWnd, CB_ADDSTRING, 0,(LPARAM)CharToTchar(str,-1)); } m_ctrlDevice.SetCurSel(0); //Codecs int numOfCodecs = _vieCodec->NumberOfCodecs(); for(int i=0; iGetCodec(i,codec)) { ::SendMessage(m_ctrlCodec.m_hWnd, CB_ADDSTRING, 0,(LPARAM)CharToTchar(codec.plName,-1)); } } m_ctrlCodec.SetCurSel(0); #ifndef NO_VOICE_ENGINE CodecInst voiceCodec; int numOfVeCodecs = _veCodec->NumOfCodecs(); for(int i=0; iGetCodec(i,voiceCodec)!=-1) { if(strncmp(voiceCodec.plname,"ISAC",4)==0) break; } } _audioChannel = _veBase->CreateChannel(); TEST_MUSTPASS(_veRTCP->SetRTCPStatus(_audioChannel, true),-5); TEST_MUSTPASS(_veCodec->SetSendCodec(_audioChannel, voiceCodec),-5); TEST_MUSTPASS(_veBase->StartPlayout(_audioChannel),-5); #endif //NO_VOICE_ENGINE if(_parentChannel==-1) { TEST_MUSTPASS(_vieBase->CreateChannel(_channelId),-5); } else // This is a slave channel { TEST_MUSTPASS(_vieBase->CreateChannel(_channelId,_parentChannel),-5); } #ifndef NO_VOICE_ENGINE TEST_MUSTPASS(_vieBase->ConnectAudioChannel(_channelId,_audioChannel),-5); #endif _channelPool.AddChannel(_channelId); //Set Receive codec { VideoCodec codec; int numOfCodecs = _vieCodec->NumberOfCodecs();; for(int i=0; iGetCodec(i,codec)) { if(codec.codecType == webrtc::kVideoCodecVP8) { codec.codecSpecific.VP8.feedbackModeOn = true; codec.codecSpecific.VP8.pictureLossIndicationOn = true; } TEST_MUSTPASS(_vieCodec->SetReceiveCodec(_channelId,codec),-5); } } } //TMMBR m_cbTmmbr.SetCheck(BST_CHECKED); OnBnClickedTmmbr(); //Packet Burst m_ctrlPacketBurst.SetCurSel(0); //Protection method none CButton *opProtection = (CButton *) GetDlgItem(IDC_PROT_NONE); opProtection->SetCheck(BST_CHECKED); OnBnClickedProtNone(); // Configure the renderer ConfigureRender(); TEST_MUSTPASS(_vieCodec->RegisterEncoderObserver(_channelId,*this),kViECodecObserverAlreadyRegistered); TEST_MUSTPASS(_vieCodec->RegisterDecoderObserver(_channelId,*this),-5); TEST_MUSTPASS(_vieBase->RegisterObserver(*this),kViEBaseObserverAlreadyRegistered); //Set captions based on channel id m_remoteIp1.SetAddress(127,0,0,1); CString port; port.AppendFormat(_T("%d"),11111+_channelId*4); m_remotePort1.SetWindowText(port); m_localPort1.SetWindowText(port); CString title; this->GetWindowText(title); if(_parentChannel==-1) { title.AppendFormat(_T("%s - channel %d"),title,_channelId); } else { title.AppendFormat(_T("%s - slave channel %d - parent %d"),title,_channelId,_parentChannel); } this->SetWindowText(title); if(_parentChannel!=-1) m_ctrlDevice.EnableWindow(FALSE); //Prevent from changing capture device return TRUE; // return TRUE unless you set the focus to a control } void CDXChannelDlg::OnTimer(UINT nIDEvent) { CDialog::OnTimer(nIDEvent); } void CDXChannelDlg::SetSendCodec() { // Get the codec stucture int codecSel= m_ctrlCodec.GetCurSel(); VideoCodec codec; TEST_MUSTPASS(_vieCodec->GetCodec(codecSel,codec),-5); // Set Codec Size VideoSize sizeSel=VideoSize(m_ctrlCodecSize.GetCurSel()); int width, height; GetWidthHeight(sizeSel, width, height); codec.width=width; codec.height=height; //Set the codec bitrate CString bitrateStr; m_ctrlBitrate.GetLBText(m_ctrlBitrate.GetCurSel(), bitrateStr); int bitrate = _ttoi(bitrateStr.GetBuffer(0)); if(codec.codecType!=kVideoCodecI420) { codec.startBitrate=bitrate; codec.maxBitrate=bitrate*4; } //Set the codec frame rate codec.maxFramerate = m_ctrlMinFrameRate.GetCurSel() +5; if(strncmp(codec.plName, "VP8", 5) == 0) { codec.codecSpecific.VP8.feedbackModeOn = true; codec.codecSpecific.VP8.pictureLossIndicationOn = true; TEST_MUSTPASS(_vieRTPRTCP->SetKeyFrameRequestMethod(_channelId, kViEKeyFrameRequestPliRtcp),-5); }else { TEST_MUSTPASS(_vieRTPRTCP->SetKeyFrameRequestMethod(_channelId, kViEKeyFrameRequestPliRtcp),-5); } TEST_MUSTPASS(_vieCodec->SetSendCodec(_channelId, codec),-5); if (codec.codecType == webrtc::kVideoCodecMPEG4) { unsigned char configParameterSize = 0; _vieCodec->GetCodecConfigParameters(_channelId, codec.codecSpecific.MPEG4.configParameters, configParameterSize); codec.codecSpecific.MPEG4.configParametersSize = configParameterSize; _vieCodec->SetReceiveCodec(_channelId, codec); } if (codec.codecType == webrtc::kVideoCodecI420) { // Need to set the receive codec size _vieCodec->SetReceiveCodec(_channelId, codec); } } void CDXChannelDlg::SetSendDestination() { if(_externalTransport) return; BYTE part1, part2, part3, part4; char sendIP1[16]; m_remoteIp1.GetAddress(part1, part2, part3, part4); sprintf(sendIP1,"%d.%d.%d.%d",part1,part2,part3,part4); CString strPort; m_remotePort1.GetWindowText(strPort); int remotePort1 = _ttoi(strPort.GetString()); #ifdef IPV6 char* recIP = "::0"; #else char* recIP = "0.0.0.0"; #endif //IPV6 TEST_MUSTPASS(_vieNetwork->SetSendDestination(_channelId,sendIP1,remotePort1),kViENetworkAlreadySending); #ifndef NO_VOICE_ENGINE m_localPort1.GetWindowText(strPort); int localPort1 = _ttoi(strPort.GetString()); int res=_veBase->SetLocalReceiver(_audioChannel,localPort1+2); TEST_MUSTPASS(_veBase->SetSendDestination(_audioChannel, remotePort1+2, sendIP1),-5) #endif } void CDXChannelDlg::SetLocalReceiver() { if(_externalTransport) return; CString strPort; m_localPort1.GetWindowText(strPort); int localPort1 = _ttoi(strPort.GetString()); // May fail because we are sending TEST_MUSTPASS(_vieNetwork->SetLocalReceiver(_channelId, localPort1),-5); #ifndef NO_VOICE_ENGINE int res=_veBase->SetLocalReceiver(_audioChannel,localPort1+2); #endif } void CDXChannelDlg::SetCaptureDevice() { if(_parentChannel!=-1) // don't accept changing input on slave channels. return; int camSel=-1; camSel=m_ctrlDevice.GetCurSel(); CString captureStr; //captureStr.Compare m_ctrlDevice.GetLBText(camSel, captureStr); if(captureStr!=_T("N/A") != 0) { TEST_MUSTPASS(_vieFile->StopPlayFile(_captureId),kViEFileNotPlaying); TEST_MUSTPASS(_vieCapture->DisconnectCaptureDevice(_channelId),kViECaptureDeviceNotConnected); TEST_MUSTPASS(_vieRender->RemoveRenderer(_captureId),kViERenderInvalidRenderId); if(_captureId>=0x1001 && _captureId<0x10FF)// ID is a capture device { TEST_MUSTPASS(_captureDevicePool.ReturnCaptureDevice(_captureId),-5); } if(captureStr!=_T("None")==0) { _captureId=-1; } else if(_tcsstr(captureStr,_T(".avi"))!=NULL ) // Selected an AVI file { TEST_MUSTPASS(_vieFile->StartPlayFile(TcharToChar(captureStr.GetBuffer(),-1),_captureId,false,webrtc::kFileFormatAviFile),-5); TEST_MUSTPASS(_vieRender->AddRenderer(_captureId,m_ctrlLiveVideo.m_hWnd, 0, 0.0f, 0.0f,1.0f,1.0f),-5); TEST_MUSTPASS(_vieRender->StartRender(_captureId),-5); TEST_MUSTPASS(_vieFile->SendFileOnChannel(_captureId,_channelId),-5); TEST_MUSTPASS(_vieFile->StartPlayFileAsMicrophone(_captureId,_channelId,true),-5); //TEST_MUSTPASS(_vieFile->StartPlayAudioLocally(_captureId,_channelId),-5); } else { char captureName[256]; char uniqueCaptureName[256]; TEST_MUSTPASS(_vieCapture->GetCaptureDevice(camSel,captureName,256,uniqueCaptureName,256),-5); TEST_MUSTPASS(_captureDevicePool.GetCaptureDevice(_captureId,uniqueCaptureName),-5); TEST_MUSTPASS(_vieCapture->StartCapture(_captureId),kViECaptureDeviceAlreadyStarted); TEST_MUSTPASS(_vieCapture->RegisterObserver(_captureId,*this),kViECaptureObserverAlreadyRegistered); TEST_MUSTPASS(_vieRender->AddRenderer(_captureId,m_ctrlLiveVideo.m_hWnd, 0, 0.0f, 0.0f,1.0f,1.0f),-5); TEST_MUSTPASS(_vieCapture->ConnectCaptureDevice(_captureId,_channelId),-5); TEST_MUSTPASS(_vieRender->StartRender(_captureId),-5); } } } void CDXChannelDlg::OnBnClickedStartlisten() { // Configure the local ports SetLocalReceiver(); //Configure the remote destination- needed in order to be able to respond to RTCP messages SetSendDestination(); #ifndef NO_VOICE_ENGINE TEST_MUSTPASS(_veBase->StartReceive(_audioChannel),-5); #endif TEST_MUSTPASS(_vieBase->StartReceive(_channelId),-5); } void CDXChannelDlg::OnStartSend() { // Set the send destination SetSendDestination(); // Configure the local ports (Needed to be able to receive RTCP //SetLocalReceiver(); // Set the send codec SetSendCodec(); if(_captureId==-1) // If no capture device has been set. SetCaptureDevice(); //Set the capture device //TEST_MUSTPASS(_vieRTPRTCP->SetStartSequenceNumber(_channelId,1),-5); // Start sending TEST_MUSTPASS(_vieBase->StartSend(_channelId),-5); #ifndef NO_VOICE_ENGINE TEST_MUSTPASS(_veBase->StartSend(_audioChannel),-5); #endif } void CDXChannelDlg::ConfigureRender() { TEST_MUSTPASS(_vieRender->AddRenderer(_channelId,m_ctrlLiveRemoteVideo.m_hWnd, 0, 0.0f, 0.0f,1.0f,1.0f),-5); TEST_MUSTPASS(_vieFile->SetRenderStartImage(_channelId,"renderStartImage.jpg"),-5); TEST_MUSTPASS(_vieRender->StartRender(_channelId),-5); TEST_MUSTPASS(_vieFile->SetRenderTimeoutImage(_channelId,"renderTimeoutImage.jpg"),-5); } void CDXChannelDlg::OnStopSend() { #ifndef NO_VOICE_ENGINE TEST_MUSTPASS(_veBase->StopSend(_audioChannel),-5); #endif TEST_MUSTPASS(_vieBase->StopSend(_channelId),kViEBaseNotSending); // Accept error Not sending } void CDXChannelDlg::OnBnClickedStoplisten() { #ifndef NO_VOICE_ENGINE TEST_MUSTPASS(_veBase->StopReceive(_audioChannel),-5); #endif TEST_MUSTPASS(_vieBase->StopReceive(_channelId),-5); } void CDXChannelDlg::OnDestroy() { OnStopSend(); OnBnClickedStoplisten(); if(_vieCapture && _parentChannel==-1) { _vieCapture->DisconnectCaptureDevice(_channelId); _captureDevicePool.ReturnCaptureDevice(_captureId); } if(_vieFile && _parentChannel!=-1) { TEST_MUSTPASS(_vieFile->StopPlayFile(_captureId),kViEFileNotPlaying); } if(_videoEngine) { if(_parentChannel==-1) { _vieCodec->DeregisterEncoderObserver(_channelId); } _vieBase->DeleteChannel(_channelId); _channelPool.RemoveChannel(_channelId); } _videoEngine = NULL; #ifndef NO_VOICE_ENGINE if (_voiceEngine) { _veBase->DeleteChannel(_audioChannel); _veBase->Release(); _veNetwork->Release(); _veCodec->Release(); _veRTCP->Release(); } #endif strcpy(_logMsg,""); SetEvent(_callbackEvent); MSG msg; // Wait until the callback thread exits. Need to handle messages since the callback thread can call SendMessage when updating UI while(WaitForSingleObject(_callbackThread,10)==WAIT_TIMEOUT) { DWORD ret = PeekMessage( &msg, NULL, 0, 0,PM_REMOVE ); if (ret >0) { TranslateMessage(&msg); DispatchMessage(&msg); } } CloseHandle(_callbackThread); CloseHandle(_callbackEvent); DeleteCriticalSection(&_critCallback); TEST_MUSTPASS(_vieCapture->Release()<0,-5); TEST_MUSTPASS(_vieRTPRTCP->Release()<0,-5); TEST_MUSTPASS(_vieRender->Release()<0,-5); TEST_MUSTPASS(_vieCodec->Release()<0,-5); TEST_MUSTPASS(_vieNetwork->Release()<0,-5); TEST_MUSTPASS(_vieFile->Release()<0,-5); TEST_MUSTPASS(_vieBase->Release()<0,-5); #ifdef TEST_EXTERNAL_TRANSPORT if(_transport) delete _transport; _transport = NULL; #endif delete _externalTransport; CDialog::OnDestroy(); if(_dialogObserver) { _dialogObserver->ChannelDialogEnded(this); } } void CDXChannelDlg::OnCancel() { DestroyWindow(); } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CDXChannelDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } BOOL CDXChannelDlg::OnDeviceChange( UINT nID, DWORD lParam) { if(nID == DBT_DEVNODES_CHANGED) { // SetCaptureDevice(); } return CDialog::OnDeviceChange(nID, lParam); } void CDXChannelDlg::OnSysCommand(UINT nID, LPARAM lParam) { if(SC_MAXIMIZE == nID) {} CDialog::OnSysCommand(nID, lParam); } static bool fullScreen = false; void CDXChannelDlg::OnRButtonUp( UINT nFlags, CPoint point) { CDialog::OnRButtonUp( nFlags, point); } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CDXChannelDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CDXChannelDlg::OnCbnSelchangeCodecList() { SetSendCodec(); } void CDXChannelDlg::OnCbnSelchangeSize() { SetSendCodec(); } void CDXChannelDlg::OnCbnSelchangeDevice() { SetCaptureDevice(); } void CDXChannelDlg::OnCbnSelchangeBitrate() { SetSendCodec(); } void CDXChannelDlg::OnCbnSelchangeMinFrameRate() { SetSendCodec(); } void CDXChannelDlg::OnBnClickedTmmbr() { TEST_MUSTPASS(_vieRTPRTCP->SetTMMBRStatus(_channelId,m_cbTmmbr.GetCheck()==BST_CHECKED),-5); } void CDXChannelDlg::OnCbnSelchangeRtcpmode() { /* kRtcpNone = 0, kRtcpCompound_RFC4585 = 1, kRtcpNonCompound_RFC5506 = 2 */ ViERTCPMode mode=ViERTCPMode(m_ctrlRtcpMode.GetCurSel()); TEST_MUSTPASS(_vieRTPRTCP->SetRTCPStatus(_channelId,mode),-5); } void CDXChannelDlg::OnBnClickedFreezelog() { _canAddLog=m_cbFreezeLog.GetCheck()!=BST_CHECKED; } void CDXChannelDlg::OnBnClickedProtNack() { TEST_MUSTPASS(_vieRTPRTCP->SetNACKStatus(_channelId,true),-5); } void CDXChannelDlg::OnBnClickedProtNone() { TEST_MUSTPASS(_vieRTPRTCP->SetNACKStatus(_channelId,false),-5); TEST_MUSTPASS(_vieRTPRTCP->SetFECStatus(_channelId,false,0,0),-5); } void CDXChannelDlg::OnBnClickedProtFec() { int noCodec=_vieCodec->NumberOfCodecs(); int redPayloadType=0; int fecPayloadType=0; for(unsigned char i=0;iGetCodec(i,codec); if(codec.codecType==webrtc::kVideoCodecRED) { redPayloadType=codec.plType; } if(codec.codecType==webrtc::kVideoCodecULPFEC) { fecPayloadType=codec.plType; } } TEST_MUSTPASS(_vieRTPRTCP->SetFECStatus(_channelId,true,redPayloadType,fecPayloadType),-5); } void CDXChannelDlg::OnBnClickedCameracap() { char version[1024]; _vieBase->GetVersion(version); MessageBox(CharToTchar(version,-1)); int p=strlen(version); #ifndef NO_VOICE_ENGINE _veBase->GetVersion(version); MessageBox(CharToTchar(version,-1)); #endif } unsigned int WINAPI CDXChannelDlg::CallbackThread(LPVOID lpParameter) { static_cast(lpParameter)->CallbackThreadProcess(); return 0; } void CDXChannelDlg::CallbackThreadProcess() { while(1) { if(WAIT_OBJECT_0==WaitForSingleObject(_callbackEvent,INFINITE)) { char smsg[512]; EnterCriticalSection(&_critCallback); strncpy(smsg,_logMsg,strlen(_logMsg)+1); strcpy(_logMsg,""); LeaveCriticalSection(&_critCallback); if(strstr(smsg,"Send")!=NULL) { unsigned short fractionLost=0; unsigned int cumulativeLost=0; unsigned int extendedMax=0; unsigned int jitter=0; int rttMs=0; _vieRTPRTCP->GetReceivedRTCPStatistics(_channelId, fractionLost, cumulativeLost, extendedMax, jitter, rttMs); //int bw=0; //if(_vieCodec->GetAvailableBandwidth(_channelId,bw)==0) //{ // sprintf(smsg,"%s, rtt %d, loss %d,bw %d", smsg,rttMs,fractionLost,bw); //} //else //{ // _vieBase->LastError(); // Reset last error. //} } if(strlen(smsg)) { m_ctrlInfo.InsertString(0,(LPCTSTR) CharToTchar(smsg,-1)); while(m_ctrlInfo.GetCount()==151) m_ctrlInfo.DeleteString(150); } else { break; // End the callback thread } } } } void CDXChannelDlg::AddToInfo(const char* msg) { if(!_canAddLog) return; EnterCriticalSection(&_critCallback); SYSTEMTIME systemTime; GetSystemTime(&systemTime); if(strlen(_logMsg)==0) { SetEvent(_callbackEvent); // Notify of new } sprintf (_logMsg, "(%2u:%2u:%2u:%3u) %s", systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds, msg ); LeaveCriticalSection(&_critCallback); } void CDXChannelDlg::IncomingRate(const int videoChannel, unsigned int framerate, unsigned int bitrate) { char str[64]; sprintf(str,"Incoming Fr:%d br %d\n", framerate, bitrate); AddToInfo(str); } void CDXChannelDlg::RequestNewKeyFrame(int channel) { assert(!"(RequestNewKeyFrame why is it called"); } void CDXChannelDlg::PerformanceAlarm(unsigned int cpuLoad) { char str[64]; sprintf(str,"Performance alarm %d",cpuLoad); AddToInfo(str); } void CDXChannelDlg::OutgoingRate(const int videoChannel, unsigned int framerate, unsigned int bitrate) { char str[64]; sprintf(str,"Send Fr:%d br %d", framerate, bitrate); AddToInfo(str); } void CDXChannelDlg::IncomingCodecChanged(const int videoChannel, const VideoCodec& videoCodec) { char str[128]; sprintf(str,"Incoming codec channel:%d pltype:%d width:%d height:%d\n", videoChannel, videoCodec.plType, videoCodec.width,videoCodec.height); AddToInfo(str); } void CDXChannelDlg::BrightnessAlarm(const int captureId, const Brightness brightness) { switch(brightness) { case Normal: AddToInfo("BrightnessAlarm - image ok.\n"); break; case Bright: AddToInfo("BrightnessAlarm - light image.\n"); break; case Dark: AddToInfo("BrightnessAlarm - dark image.\n"); break; } } void CDXChannelDlg::CapturedFrameRate(const int captureId, const unsigned char frameRate) { char str[64]; sprintf(str,"Local Camera Frame rate:%d \n", frameRate); AddToInfo(str); } void CDXChannelDlg::NoPictureAlarm(const int captureId, const CaptureAlarm alarm) { char str[64]; sprintf(str,"No Picture alarm\n"); AddToInfo(str); } void CDXChannelDlg::OnBnClickedExttransport() { if(m_cbExternalTransport.GetCheck()==BST_CHECKED) { m_localPort1.EnableWindow(FALSE); m_remotePort1.EnableWindow(FALSE); m_remoteIp1.EnableWindow(FALSE); m_ctrlPacketLoss.EnableWindow(TRUE); m_ctrlDelay.EnableWindow(TRUE); _externalTransport= new tbExternalTransport(*_vieNetwork); _vieNetwork->RegisterSendTransport(_channelId,*_externalTransport); } else { _vieNetwork->DeregisterSendTransport(_channelId); delete _externalTransport; _externalTransport=NULL; m_localPort1.EnableWindow(TRUE); m_remotePort1.EnableWindow(TRUE); m_remoteIp1.EnableWindow(TRUE); m_ctrlPacketLoss.EnableWindow(FALSE); m_ctrlDelay.EnableWindow(FALSE); } } void CDXChannelDlg::OnCbnSelchangePacketloss() { if(_externalTransport) { _externalTransport->SetPacketLoss(m_ctrlPacketLoss.GetCurSel()*2); } } void CDXChannelDlg::OnCbnSelchangeDelay() { if(_externalTransport) { _externalTransport->SetNetworkDelay(m_ctrlDelay.GetCurSel()*30); } } void CDXChannelDlg::OnBnClickedBtnRecordIncoming() { CButton *recordBtn = (CButton *) GetDlgItem(IDC_BTN_RECORD_INCOMING); CString text; recordBtn->GetWindowText(text); if(text!=_T("Stop Rec Inc")!=0) { recordBtn->SetWindowText(_T("Stop Rec Inc")); SYSTEMTIME time; GetSystemTime(&time); sprintf(_fileName,"IncomingChannel%d_%4d%2d%2d%2d%2d.avi",_channelId,time.wYear,time.wMonth,time.wDay,time.wHour,time.wMinute); AudioSource audioSource=PLAYOUT; webrtc::CodecInst audioCodec; strcpy(audioCodec.plname,"L16"); audioCodec.rate = 256000; audioCodec.plfreq = 16000; audioCodec.pacsize = 160; webrtc::VideoCodec videoCodec; memset(&videoCodec,0,sizeof(videoCodec)); strcpy(videoCodec.plName,"VP8"); videoCodec.maxBitrate=1000; videoCodec.startBitrate=1000; videoCodec.width=352; videoCodec.height=288; videoCodec.codecType=webrtc::kVideoCodecVP8; videoCodec.maxFramerate=30; TEST_MUSTPASS(_vieFile->StartRecordIncomingVideo(_channelId,_fileName,audioSource,audioCodec, videoCodec),-5); } else { recordBtn->SetWindowText(_T("Record Incoming")); TEST_MUSTPASS(_vieFile->StopRecordIncomingVideo(_channelId),-5); CString msg; msg.AppendFormat(_T("Recorded file %s"),_fileName); MessageBox(msg); } } void CDXChannelDlg::OnBnClickedBtnRecordOutgoing() { CButton *recordBtn = (CButton *) GetDlgItem(IDC_BTN_RECORD_OUTGOING); CString text; recordBtn->GetWindowText(text); if(text!=_T("Stop Rec Out")) { recordBtn->SetWindowText(_T("Stop Rec Out")); SYSTEMTIME time; GetSystemTime(&time); sprintf(_fileName,"OutgoingChannel%d_%4d%2d%2d%2d%2d.avi",_channelId,time.wYear,time.wMonth,time.wDay,time.wHour,time.wMinute); AudioSource audioSource=MICROPHONE; webrtc::CodecInst audioCodec; strcpy(audioCodec.plname,"L16"); audioCodec.rate = 256000; audioCodec.plfreq = 16000; audioCodec.pacsize = 160; webrtc::VideoCodec videoCodec; memset(&videoCodec,0,sizeof(videoCodec)); strcpy(videoCodec.plName,"VP8"); videoCodec.maxBitrate=1000; videoCodec.startBitrate=1000; videoCodec.width=352; videoCodec.height=288; videoCodec.codecType=webrtc::kVideoCodecVP8; videoCodec.maxFramerate=30; TEST_MUSTPASS(_vieFile->StartRecordOutgoingVideo(_channelId,_fileName,audioSource,audioCodec,videoCodec),-5); } else { recordBtn->SetWindowText(_T("Record Outgoing")); TEST_MUSTPASS(_vieFile->StopRecordOutgoingVideo(_channelId),-5); CString msg; msg.AppendFormat(_T("Recorded file %s"),_fileName); MessageBox(msg); } } void CDXChannelDlg::OnBnClickedBtnCreateSlave() { CDXChannelDlg* newSlave =new CDXChannelDlg(_videoEngine,_captureDevicePool,_channelPool,_voiceEngine,NULL,_dialogObserver,_channelId); newSlave->Create(CDXChannelDlg::IDD,NULL); }