diff --git a/src/channel.cpp b/src/channel.cpp index d01d1d52..5f6c4a98 100755 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -112,44 +112,50 @@ bool CChannelSet::PutData ( const CVector& vecbyRecBuf, const int iNumBytesRead, const CHostAddress& HostAdr ) { + bool bChanOK = true; + Mutex.lock (); - - /* get channel ID ------------------------------------------------------- */ - bool bChanOK = true; - - /* check address */ - int iCurChanID = CheckAddr ( HostAdr ); - - if ( iCurChanID == INVALID_CHANNEL_ID ) { - /* a new client is calling, look for free channel */ - iCurChanID = GetFreeChan (); + /* get channel ID --------------------------------------------------- */ + /* check address */ + int iCurChanID = CheckAddr ( HostAdr ); - if ( iCurChanID != INVALID_CHANNEL_ID ) + if ( iCurChanID == INVALID_CHANNEL_ID ) { - vecChannels[iCurChanID].SetAddress ( HostAdr ); + /* a new client is calling, look for free channel */ + iCurChanID = GetFreeChan (); + + if ( iCurChanID != INVALID_CHANNEL_ID ) + { + vecChannels[iCurChanID].SetAddress ( HostAdr ); + } + else + { + bChanOK = false; /* no free channel available */ + } } - else + + + /* put received data in jitter buffer ------------------------------- */ + if ( bChanOK ) { - bChanOK = false; /* no free channel available */ + /* put packet in socket buffer */ + switch ( vecChannels[iCurChanID].PutData ( vecbyRecBuf, iNumBytesRead ) ) + { + case PS_AUDIO_OK: + PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_GREEN, iCurChanID ); + break; + + case PS_AUDIO_ERR: + PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_RED, iCurChanID ); + break; + + case PS_PROT_ERR: + PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_YELLOW, iCurChanID ); + break; + } } } - - - /* put received data in jitter buffer ----------------------------------- */ - if ( bChanOK ) - { - /* put packet in socket buffer */ - if ( vecChannels[iCurChanID].PutData ( vecbyRecBuf, iNumBytesRead ) ) - { - PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_GREEN, iCurChanID ); - } - else - { - PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_RED, iCurChanID ); - } - } - Mutex.unlock (); return !bChanOK; /* return 1 if error */ @@ -167,36 +173,36 @@ void CChannelSet::GetBlockAllConC ( CVector& vecChanID, /* make put and get calls thread safe. Do not forget to unlock mutex afterwards! */ Mutex.lock (); - - /* Check all possible channels */ - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) { - /* read out all input buffers to decrease timeout counter on - disconnected channels */ - const bool bGetOK = vecChannels[i].GetData ( vecdData ); - - if ( vecChannels[i].IsConnected () ) + /* Check all possible channels */ + for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) { - /* add ID and data */ - vecChanID.Add ( i ); + /* read out all input buffers to decrease timeout counter on + disconnected channels */ + const bool bGetOK = vecChannels[i].GetData ( vecdData ); - const int iOldSize = vecvecdData.Size (); - vecvecdData.Enlarge ( 1 ); - vecvecdData[iOldSize].Init ( vecdData.Size () ); - vecvecdData[iOldSize] = vecdData; + if ( vecChannels[i].IsConnected () ) + { + /* add ID and data */ + vecChanID.Add ( i ); - /* send message for get status (for GUI) */ - if ( bGetOK ) - { - PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_GREEN, i ); - } - else - { - PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_RED, i ); + const int iOldSize = vecvecdData.Size (); + vecvecdData.Enlarge ( 1 ); + vecvecdData[iOldSize].Init ( vecdData.Size () ); + vecvecdData[iOldSize] = vecdData; + + /* send message for get status (for GUI) */ + if ( bGetOK ) + { + PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_GREEN, i ); + } + else + { + PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_RED, i ); + } } } } - Mutex.unlock (); /* release mutex */ } @@ -221,20 +227,6 @@ void CChannelSet::GetConCliParam ( CVector& vecHostAddresses, } } -void CChannelSet::SetSockBufSize ( const int iNewBlockSize, const int iNumBlocks ) -{ - /* this opperation must be done with mutex */ - Mutex.lock (); - -/* as a test we adjust the buffers of all channels to the new value. Maybe later - do change only for some channels -> take care to set value back to default if - channel is disconnected, afterwards! */ -for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) - vecChannels[i].SetSockBufSize ( iNewBlockSize, iNumBlocks ); - - Mutex.unlock (); -} - /******************************************************************************\ * CChannel * @@ -286,9 +278,9 @@ void CChannel::SetSockBufSize ( const int iNewBlockSize, const int iNumBlocks ) { /* this opperation must be done with mutex */ Mutex.lock (); - - SockBuf.Init ( iNewBlockSize, iNumBlocks ); - + { + SockBuf.Init ( iNewBlockSize, iNumBlocks ); + } Mutex.unlock (); } @@ -314,10 +306,10 @@ bool CChannel::GetAddress(CHostAddress& RetAddr) } } -bool CChannel::PutData ( const CVector& vecbyData, - int iNumBytes ) +EPutDataStat CChannel::PutData ( const CVector& vecbyData, + int iNumBytes ) { - bool bRet = true; + EPutDataStat eRet = PS_GEN_ERROR; /* only process if packet has correct size */ if ( iNumBytes == iAudComprSize ) @@ -342,41 +334,61 @@ for (int i = 0; i < BLOCK_SIZE_SAMPLES; i++) Mutex.lock (); /* put mutex lock */ - - bRet = SockBuf.Put ( vecdResOutData ); - + { + if ( SockBuf.Put ( vecdResOutData ) ) + { + eRet = PS_AUDIO_OK; + } + else + { + eRet = PS_AUDIO_ERR; + } + } Mutex.unlock (); /* put mutex unlock */ - /* reset time-out counter */ + // if channel was not connected, emit signal to inform that new connection + // was established + if ( iConTimeOut == 0 ) + { + emit NewConnection(); + } + + // reset time-out counter iConTimeOut = CON_TIME_OUT_CNT_MAX; } else { // this seems not to be an audio block, parse the message - -// TODO: different return code for protocol - - bRet = Protocol.ParseMessage ( vecbyData, iNumBytes ); + if ( Protocol.ParseMessage ( vecbyData, iNumBytes ) ) + { + eRet = PS_PROT_OK; + } + else + { + eRet = PS_PROT_ERR; + } } - return bRet; + return eRet; } bool CChannel::GetData ( CVector& vecdData ) -{ - Mutex.lock (); /* get mutex lock */ +{ + bool bGetOK = false; - const bool bGetOK = SockBuf.Get ( vecdData ); - - if ( !bGetOK ) + Mutex.lock (); /* get mutex lock */ { - /* decrease time-out counter */ - if ( iConTimeOut > 0 ) + bGetOK = SockBuf.Get ( vecdData ); + + if ( !bGetOK ) { - iConTimeOut--; + /* decrease time-out counter */ + if ( iConTimeOut > 0 ) + { + iConTimeOut--; + } } } - Mutex.unlock (); /* get mutex unlock */ return bGetOK; diff --git a/src/channel.h b/src/channel.h index e16b5eaf..719843fe 100755 --- a/src/channel.h +++ b/src/channel.h @@ -46,55 +46,44 @@ #define MAX_NUM_CHANNELS 10 /* max number channels for server */ /* no valid channel number */ -#define INVALID_CHANNEL_ID (MAX_NUM_CHANNELS + 1) - - -/* Classes ********************************************************************/ -class CSampleOffsetEst -{ -public: - CSampleOffsetEst() {Init();} - virtual ~CSampleOffsetEst() {} - - void Init(); - void AddTimeStampIdx(const int iTimeStampIdx); - double GetSamRate() {return dSamRateEst;} - -protected: - QTime RefTime; - int iAccTiStVal; - double dSamRateEst; - CVector veciTimeElapsed; - CVector veciTiStIdx; - int iInitCnt; +#define INVALID_CHANNEL_ID (MAX_NUM_CHANNELS + 1) + +enum EPutDataStat +{ + PS_GEN_ERROR, + PS_AUDIO_OK, + PS_AUDIO_ERR, + PS_PROT_OK, + PS_PROT_ERR }; +/* Classes ********************************************************************/ /* CChannel ----------------------------------------------------------------- */ class CChannel : public QObject { Q_OBJECT public: - CChannel (); - virtual ~CChannel () {} + CChannel(); + virtual ~CChannel() {} - bool PutData ( const CVector& vecbyData, - int iNumBytes ); + EPutDataStat PutData ( const CVector& vecbyData, + int iNumBytes ); bool GetData ( CVector& vecdData ); CVector PrepSendPacket ( const CVector& vecsNPacket ); - bool IsConnected () const { return iConTimeOut > 0; } + bool IsConnected() const { return iConTimeOut > 0; } - int GetComprAudSize () { return iAudComprSize; } + int GetComprAudSize() { return iAudComprSize; } void SetAddress ( const CHostAddress NAddr ) { InetAddr = NAddr; } bool GetAddress ( CHostAddress& RetAddr ); CHostAddress GetAddress () { return InetAddr; } void SetSockBufSize ( const int iNewBlockSize, const int iNumBlocks ); - int GetSockBufSize () { return SockBuf.GetSize(); } + int GetSockBufSize() { return SockBuf.GetSize(); } // network protocol interface void CreateJitBufMes ( const int iJitBufSize ) @@ -139,6 +128,7 @@ public slots: signals: void MessReadyForSending ( CVector vecMessage ); + void NewConnection(); }; @@ -151,28 +141,29 @@ public: CChannelSet(); virtual ~CChannelSet() {} - bool PutData(const CVector& vecbyRecBuf, - const int iNumBytesRead, const CHostAddress& HostAdr); + bool PutData ( const CVector& vecbyRecBuf, + const int iNumBytesRead, const CHostAddress& HostAdr ); - int GetFreeChan(); - int CheckAddr(const CHostAddress& Addr); + int GetFreeChan(); - void GetBlockAllConC(CVector& vecChanID, - CVector >& vecvecdData); - void GetConCliParam(CVector& vecHostAddresses, - CVector& veciJitBufSize); + int CheckAddr ( const CHostAddress& Addr ); + + void GetBlockAllConC ( CVector& vecChanID, + CVector >& vecvecdData ); + + void GetConCliParam( CVector& vecHostAddresses, + CVector& veciJitBufSize ); /* access functions for actual channels */ - bool IsConnected(const int iChanNum) - {return vecChannels[iChanNum].IsConnected();} - CVector PrepSendPacket(const int iChanNum, - const CVector& vecsNPacket) - {return vecChannels[iChanNum].PrepSendPacket(vecsNPacket);} - CHostAddress GetAddress(const int iChanNum) - {return vecChannels[iChanNum].GetAddress();} + bool IsConnected ( const int iChanNum ) + { return vecChannels[iChanNum].IsConnected(); } - void SetSockBufSize ( const int iNewBlockSize, const int iNumBlocks); - int GetSockBufSize() {return vecChannels[0].GetSockBufSize();} + CVector PrepSendPacket ( const int iChanNum, + const CVector& vecsNPacket ) + { return vecChannels[iChanNum].PrepSendPacket ( vecsNPacket ); } + + CHostAddress GetAddress ( const int iChanNum ) + { return vecChannels[iChanNum].GetAddress(); } protected: /* do not use the vector class since CChannel does not have appropriate @@ -200,6 +191,27 @@ void OnSendProtMessCh9(CVector mess) {emit MessReadyForSending(9,mess); signals: void MessReadyForSending ( int iChID, CVector vecMessage ); }; + + +/* Sample rate offset estimation -------------------------------------------- */ +class CSampleOffsetEst +{ +public: + CSampleOffsetEst() { Init(); } + virtual ~CSampleOffsetEst() {} + + void Init(); + void AddTimeStampIdx ( const int iTimeStampIdx ); + double GetSamRate() { return dSamRateEst; } + +protected: + QTime RefTime; + int iAccTiStVal; + double dSamRateEst; + CVector veciTimeElapsed; + CVector veciTiStIdx; + int iInitCnt; +}; #endif /* !defined(CHANNEL_HOIH9345KJH98_3_4344_BB23945IUHF1912__INCLUDED_) */ diff --git a/src/llconserverdlg.cpp b/src/llconserverdlg.cpp index 502b4c23..38799e3f 100755 --- a/src/llconserverdlg.cpp +++ b/src/llconserverdlg.cpp @@ -69,12 +69,6 @@ CLlconServerDlg::CLlconServerDlg ( CServer* pNServP, QWidget* parent, #endif } - /* Init slider control */ - SliderNetBuf->setRange(1, MAX_NET_BUF_SIZE_NUM_BL); - const int iCurNumNetBuf = pServer->GetChannelSet()->GetSockBufSize(); - SliderNetBuf->setValue(iCurNumNetBuf); - TextNetBuf->setText("Size: " + QString().setNum(iCurNumNetBuf)); - /* Init timing jitter text label */ TextLabelResponseTime->setText(""); @@ -93,11 +87,7 @@ CLlconServerDlg::CLlconServerDlg ( CServer* pNServP, QWidget* parent, /* timers */ QObject::connect(&Timer, SIGNAL(timeout()), this, SLOT(OnTimer())); - /* sliders */ - QObject::connect(SliderNetBuf, SIGNAL(valueChanged(int)), - this, SLOT(OnSliderNetBuf(int))); - - + /* timers --------------------------------------------------------------- */ /* start timer for GUI controls */ Timer.start(GUI_CONTRL_UPDATE_TIME); @@ -158,12 +148,6 @@ void CLlconServerDlg::OnTimer() } } -void CLlconServerDlg::OnSliderNetBuf(int value) -{ - pServer->GetChannelSet()->SetSockBufSize( MIN_BLOCK_SIZE_SAMPLES, value ); - TextNetBuf->setText("Size: " + QString().setNum(value)); -} - void CLlconServerDlg::customEvent(QCustomEvent* Event) { if (Event->type() == QEvent::User + 11) diff --git a/src/llconserverdlg.h b/src/llconserverdlg.h index 210dd762..e2bcbc11 100755 --- a/src/llconserverdlg.h +++ b/src/llconserverdlg.h @@ -74,5 +74,4 @@ protected: public slots: void OnTimer(); - void OnSliderNetBuf(int value); }; diff --git a/src/llconserverdlgbase.ui b/src/llconserverdlgbase.ui index 3f373e24..9631f4bb 100755 --- a/src/llconserverdlgbase.ui +++ b/src/llconserverdlgbase.ui @@ -11,7 +11,7 @@ 0 0 - 633 + 629 240 @@ -37,110 +37,35 @@ 6 - QLayoutWidget + QListView + + + text + Column 1 + + + clickable + true + + + resizeable + true + + + + + text + New Item + + + pixmap + + + name - Layout4 + ListViewClients - - - margin - 0 - - - spacing - 6 - - - QListView - - - text - Column 1 - - - clickable - true - - - resizeable - true - - - - - text - New Item - - - pixmap - - - - - name - ListViewClients - - - - QGroupBox - - name - GroupBox3 - - - title - Jitter Buffer - - - - margin - 11 - - - spacing - 6 - - - QLabel - - name - TextNetBuf - - - text - Size - - - alignment - AlignCenter - - - hAlign - - - - QSlider - - name - SliderNetBuf - - - pageStep - 1 - - - orientation - Vertical - - - tickmarks - Both - - - - - QLayoutWidget diff --git a/src/protocol.cpp b/src/protocol.cpp index 594e7321..2f9bdec3 100755 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -72,14 +72,6 @@ MESSAGES /* Implementation *************************************************************/ - - - -// TODO take care of mutexing ressources!!!!!! - - - - CProtocol::CProtocol() : iCounter ( 0 ), iOldRecID ( PROTMESSID_ILLEGAL ), iOldRecCnt ( 0 ) { @@ -132,98 +124,6 @@ void CProtocol::SendMessage() } } -void CProtocol::DeleteSendMessQueue() -{ - // delete complete "send message queue" - SendMessQueue.clear(); -} - -bool CProtocol::ParseMessage ( const CVector& vecbyData, - const int iNumBytes ) -{ -/* - return code: true -> ok; false -> error -*/ - int iRecCounter, iRecID, iData; - unsigned int iPos; - CVector vecData; - - -// convert unsigned char in uint8_t, TODO convert all buffers in uint8_t -CVector vecbyDataConv ( iNumBytes ); -for ( int i = 0; i < iNumBytes; i++ ) { - vecbyDataConv[i] = static_cast ( vecbyData[i] ); -} - - -// important: vecbyDataConv must have iNumBytes to get it work!!! - if ( ParseMessageFrame ( vecbyDataConv, iRecCounter, iRecID, vecData ) ) - { - // In case we received a message and returned an answer but our answer - // did not make it to the receiver, he will resend his message. We check - // here if the message is the same as the old one, and if this is the - // case, just resend our old answer again - if ( ( iOldRecID == iRecID ) && ( iOldRecCnt == iRecCounter ) ) - { - // acknowledgments are not acknowledged - if ( iRecID != PROTMESSID_ACKN ) - { - // re-send acknowledgement - CreateAndSendAcknMess ( iRecID, iRecCounter ); - } - } - else - { - // check which type of message we received and do action - switch ( iRecID ) - { - case PROTMESSID_ACKN: - - // extract data from stream and emit signal for received value - iPos = 0; - iData = static_cast ( GetValFromStream ( vecData, iPos, 2 ) ); - - // check if this is the correct acknowledgment - if ( ( SendMessQueue.front().iCnt == iRecCounter ) && - ( SendMessQueue.front().iID == iData ) ) - { - // message acknowledged, remove from queue - SendMessQueue.pop_front(); - - // send next message in queue - SendMessage(); - } - - break; - - case PROTMESSID_JITT_BUF_SIZE: - - // extract data from stream and emit signal for received value - iPos = 0; - iData = static_cast ( GetValFromStream ( vecData, iPos, 2 ) ); - - // invoke message action - emit ChangeJittBufSize ( iData ); - - // send acknowledge message - CreateAndSendAcknMess ( iRecID, iRecCounter ); - - break; - } - } - - // save current message ID and counter to find out if message was re-sent - iOldRecID = iRecID; - iOldRecCnt = iRecCounter; - - return true; // everything was ok - } - else - { - return false; // return error code - } -} - void CProtocol::CreateAndSendAcknMess ( const int& iID, const int& iCnt ) { CVector vecAcknMessage; @@ -240,46 +140,145 @@ void CProtocol::CreateAndSendAcknMess ( const int& iID, const int& iCnt ) emit MessReadyForSending ( vecAcknMessage ); } -void CProtocol::CreateJitBufMes ( const int iJitBufSize ) + +/* + The following functions are access functions from different threads. These + functions have to be secured by a mutex to avoid data corruption +*/ +void CProtocol::DeleteSendMessQueue() { - CVector vecNewMessage; - CVector vecData ( 2 ); // 2 bytes of data - unsigned int iPos = 0; // init position pointer + Mutex.lock(); + { + // delete complete "send message queue" + SendMessQueue.clear(); + } + Mutex.unlock(); +} - // store current counter value - const int iCurCounter = iCounter; +void CProtocol::OnTimerSendMess() +{ + Mutex.lock(); + { + SendMessage(); + } + Mutex.unlock(); +} -// increase counter (wraps around automatically) -// TODO: make it thread safe!!!!!!!!!!!! -iCounter++; +bool CProtocol::ParseMessage ( const CVector& vecbyData, + const int iNumBytes ) +{ +/* + return code: true -> ok; false -> error +*/ + Mutex.lock(); + { + int iRecCounter, iRecID, iData; + unsigned int iPos; + CVector vecData; - // build data vector - PutValOnStream ( vecData, iPos, static_cast ( iJitBufSize ), 2 ); - // build complete message - GenMessageFrame ( vecNewMessage, iCurCounter, PROTMESSID_JITT_BUF_SIZE, vecData ); - - // enqueue message - EnqueueMessage ( vecNewMessage, iCurCounter, PROTMESSID_JITT_BUF_SIZE ); +// convert unsigned char in uint8_t, TODO convert all buffers in uint8_t +CVector vecbyDataConv ( iNumBytes ); +for ( int i = 0; i < iNumBytes; i++ ) { + vecbyDataConv[i] = static_cast ( vecbyData[i] ); } +// important: vecbyDataConv must have iNumBytes to get it work!!! + if ( ParseMessageFrame ( vecbyDataConv, iRecCounter, iRecID, vecData ) ) + { + // In case we received a message and returned an answer but our answer + // did not make it to the receiver, he will resend his message. We check + // here if the message is the same as the old one, and if this is the + // case, just resend our old answer again + if ( ( iOldRecID == iRecID ) && ( iOldRecCnt == iRecCounter ) ) + { + // acknowledgments are not acknowledged + if ( iRecID != PROTMESSID_ACKN ) + { + // re-send acknowledgement + CreateAndSendAcknMess ( iRecID, iRecCounter ); + } + } + else + { + // check which type of message we received and do action + switch ( iRecID ) + { + case PROTMESSID_ACKN: + // extract data from stream and emit signal for received value + iPos = 0; + iData = static_cast ( GetValFromStream ( vecData, iPos, 2 ) ); + // check if this is the correct acknowledgment + if ( ( SendMessQueue.front().iCnt == iRecCounter ) && + ( SendMessQueue.front().iID == iData ) ) + { + // message acknowledged, remove from queue + SendMessQueue.pop_front(); + // send next message in queue + SendMessage(); + } + break; + case PROTMESSID_JITT_BUF_SIZE: + // extract data from stream and emit signal for received value + iPos = 0; + iData = static_cast ( GetValFromStream ( vecData, iPos, 2 ) ); + // invoke message action + emit ChangeJittBufSize ( iData ); + // send acknowledge message + CreateAndSendAcknMess ( iRecID, iRecCounter ); + break; + } + } + // save current message ID and counter to find out if message was re-sent + iOldRecID = iRecID; + iOldRecCnt = iRecCounter; + return true; // everything was ok + } + else + { + return false; // return error code + } + } + Mutex.unlock(); +} +void CProtocol::CreateJitBufMes ( const int iJitBufSize ) +{ + Mutex.lock(); + { + CVector vecNewMessage; + CVector vecData ( 2 ); // 2 bytes of data + unsigned int iPos = 0; // init position pointer + // store current counter value + const int iCurCounter = iCounter; + // increase counter (wraps around automatically) + iCounter++; + // build data vector + PutValOnStream ( vecData, iPos, static_cast ( iJitBufSize ), 2 ); + // build complete message + GenMessageFrame ( vecNewMessage, iCurCounter, PROTMESSID_JITT_BUF_SIZE, vecData ); + + // enqueue message + EnqueueMessage ( vecNewMessage, iCurCounter, PROTMESSID_JITT_BUF_SIZE ); + } + Mutex.unlock(); +} /******************************************************************************\ diff --git a/src/protocol.h b/src/protocol.h index d8991691..e583543a 100755 --- a/src/protocol.h +++ b/src/protocol.h @@ -118,11 +118,12 @@ protected: uint8_t iCounter; int iOldRecID, iOldRecCnt; std::list SendMessQueue; + QTimer TimerSendMess; QMutex Mutex; public slots: - void OnTimerSendMess() { SendMessage(); } + void OnTimerSendMess(); signals: // transmitting diff --git a/src/socket.cpp b/src/socket.cpp index f48c78c9..f4e4aabe 100755 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -105,14 +105,21 @@ void CSocket::OnDataReceived () return; } - if ( pChannel->PutData( vecbyRecBuf, iNumBytesRead ) ) - { + switch ( pChannel->PutData( vecbyRecBuf, iNumBytesRead ) ) + { + case PS_AUDIO_OK: PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_GREEN ); - } - else - { + break; + + case PS_AUDIO_ERR: + case PS_GEN_ERROR: PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_RED ); - } + break; + + case PS_PROT_ERR: + PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_YELLOW ); + break; + } } else {