Follow us Follow us Signalogic on LinkedIn

Source code example for real-time VoIp packet processing

Source Code Home

' Edited / streamlined VB source code example for real-time VoIP processing
' using SigC54xx systems
' Streamlined for Technical Support Purposes:  28 Jun 2001, JHB
' Copyright (C) Signalogic 1999-2001


' variables and definitions

' operating mode

Global Const REALTIME = 1
Global Const SIMULATION = 2
 
Public OpMode As Integer  ' set to one of above values
 

' MELP functional mode

Global Const ANA_SYN = 1
Global Const ANALYSIS = 2
Global Const SYNTHESIS = 4

Public MelpMode As Integer  ' set to one of above values


' System output mode

Global Const ASCII = 1
Global Const TIM = 2
Global Const SERIAL_PORT = 4
Global Const WAV = 8
Global Const ANALOG = &H10

Public InMode As Integer   ' set to one or combination of above values
Public OutMode As Integer  '    ""


' Audio Loopback operation

Global Const LOOPBACK_ENABLED = 1
Global Const LOOPBACK_DISABLED = 0

Public AudioLoopback As Integer  ' set to one of above values


' physical addresses of DSP properties (see DSGetSymbolAddr function references)

Public getframe_addr As Long
Public sendframe_addr As Long
Public getcoeff_addr As Long
Public sendcoeff_addr As Long

Public speech_in_addr As Long
Public speech_out_addr As Long
Public chbuf_addr As Long

Public bzyflg_addr As Long
Public melpflg_addr As Long
Public melp_mode_addr As Long
Public audio_loopback_addr As Long

Public op_mode_addr As Long

Public flag_addr As Long


'misc

Public gNewSound() As Integer

' define memory buffer pointers

Public inbufk As Long
Public outbufk As Long
Public coeff_inbufk As Long
Public coeff_outbufk As Long
 


' host code and SigC54xx board initialization

Function Initialize() As Boolean

Dim hWnd As Long
Dim szBoard As String * 150
Dim rc As Long
Dim wBoardClass As Integer
Dim initflag As Boolean
Dim w As Integer
Dim wProcList As Integer
Dim i, nIndex As Integer
Dim HwEntry As HWLISTENTRY
   


   hBoard = 0
   hEngine = 0
   RunState = 0
   nCurBuf = 0
    
   initflag = True
    
  ' rc = DSInitToolLib()  ' only necessary if Toollib objects are being used;
                          ' not the case for most VB and MFC programs

   DSShowEngMgrStatusWindow  ' show Engine Manager status message window

   Call DSAddEngMgrStatusLine(ByVal "Starting Algorithm IDE")  ' add a "here we
                                                               ' are" line to
                                                               ' status window

 ' display Hardware Manager driver-selection dialog
   
   hWnd = DSShowHardwareSelectorDlg(0, szBoard)
    
   If (hWnd = IDCANCEL) Then
      Initialize = False
      Exit Function
   End If


 ' open driver or Engine Manager; try Hypersignal-Macro first
    
   hEngine = DSEngineOpen(ByVal DS_EO_HSM, ByVal 0&, NUL)
  
   If (hEngine = NUL) Then
   
      initflag = False
      GoTo Abort
   End If


 ' assign board handle
    
   hBoard = DSAssignBoard(hEngine, ByVal szBoard, 0, 0, 0)
   
   If (hBoard = NUL) Then
      initflag = False
      GoTo Abort
   End If

    
 ' set module site #1 on board as active  (assumes SigC54xx processor
 ' module is inserted into module site #1)
 
   rc = DSWriteBoardReg(hBoard, &HB, 1)


 ' deal with number of processors
   
   nIndex = DSGetHWMgrEntryIndex(szBoard) ' get index of entry matching szBoard

   rc = DSGetHWMgrEntry(nIndex, HwEntry) ' read entry into HWLISTENTRY structure
   
   wProcList = 0
   
   For i = 0 To HwEntry.NumProcessors - 1
      wProcList = wProcList * 2 Or 1
   Next
   

 ' init processor(s)
 '
 ' note:  for algorithm IDE, if module is 3-processor module, then init
 '        processors 1 and 2 also,
 '        to take them in/out of reset leave them idling with no PLL multiplier
 '        and reduce power consumption

   rc = DSInitProcessor(hBoard, wProcList)
   
   If rc <= 0 Then
      initflag = False
      GoTo Abort
   End If
   
   wBoardClass = DSGetBoardClass(hBoard)
    
   rc = DSGetMemArch(hBoard)
   If rc <= 0 Then initflag = False


 ' load DSP program file specified in DSP/Analog Hardware Manager dialog box
 ' to one or more processors
    
   rc = DSLoadFileProcessor(hBoard, ByVal 0&, &H1)
   
   If rc <= 0 Then
      
      MsgBox "DSP code file was not loaded"
      initflag = False
      GoTo Abort
   End If
    
   rc = DSGetMemSize(hBoard, &H1)      ' not needed; example only
   If rc <= 0 Then initflag = False
    
   rc = DSSetProcessorList(hBoard, &H1)  ' this was already set by last
                                         ' DSLoadFileProcessor, DSInitProcessor,
   If rc <= 0 Then initflag = False      ' DSResetProcessor call, but can do it
                                         ' any time using DSSetProcessorList
                                         ' function

 ' set the message blaster (MSGBLAST.VBX) to capture buffer ready messages
 ' from the DSP engine

   WndProc.hWndTarget = frmConfig.hWnd
   WndProc.MsgList(0) = WM_DSPENGINE_BUFRDY
 
 ' register handle of graph window with engine, to receive "buffer ready"
 ' messages
   
   rc = DSRegisterEngineMsgWnd(hEngine, DS_REMW_SETDSPDATARDYMSG, _         
frmConfig.hWnd)  ' register callback window for buffer ready messages


Abort:

   If initflag = False Then
      MsgBox ("Board Initialization Failed")
      HardwareCleanup
      Initialize = False
      Exit Function
   End If


 ' get physical addresses from the DSP program COFF file (symbol table area);
 ' this avoids modifying host-side code when DSP code changes
   
   speech_out_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_spee_out")
   speech_in_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_speech_in")

   chbuf_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_chbuf")

   bzyflg_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_bzyflg")
   melpflg_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_melpflg")
   
   flag_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "BZYADD")
   melp_mode_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_melpmode")
   op_mode_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_opmode")
   audio_loopback_addr = DSGetSymbolAddress(hBoard, ByVal NUL, _                
                             "_audio_loopback")
   
   getframe_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_getframeaddr")
   sendframe_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_sendframeaddr")
   getcoeff_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_getcoeffaddr")
   sendcoeff_addr = DSGetSymbolAddress(hBoard, ByVal NUL, "_sendcoeffaddr")

   
   Initialize = True
    
End Function


Sub RunMode()

   Dim bzyflgval As Integer
   Dim flagval As Integer
   Dim w As Integer
   
   Dim i, j, k, rc, ret As Long
   Dim FRAMESIZE As Long
   Dim FsDesired, FsActual as Single
   Dim dwFsMode As Long, dwFsActual As Long
   Dim ChanList(MAXCHANNELS) As Integer
   Dim szChanList, szChan, szChar As String
   Dim chan As Integer
   Dim fRange As Boolean

   
   If (RunState = 0) Then
  
    ' initialize channel list to default
    
      For j = 0 To (MAXCHANNELS - 1)
         ChanList(j) = j
      Next
      
      
    ' initialize algorithm data

      If OpMode = REALTIME Then
         
         Fs = CSng(frmConfig.txtSampFreqRT)
         BufferSize = CLng(frmConfig.txtBufferSize)
         
         szChanList = frmConfig.txtChanListRT
         szChan = ""
         fRange = False
         k = 0
         
         For j = 1 To Len(szChanList)
          
            szChar = Mid(szChanList, j, 1)
            
            If (szChar >= "0") And (szChar <= "9") Then
               
               szChan = szChan + szChar
               
               If j = Len(szChanList) Then GoTo ChanCheck
               
            ElseIf Len(szChan) > 0 Then
               
ChanCheck:     chan = CInt(szChan)

               If (fRange = True) Then
                   i = ChanList(k - 1) + 1
               Else
                   i = chan
               End If
                  
               Do While (i <= chan)
                  ChanList(k) = i
                  i = i + 1
                  k = k + 1
               Loop
                  
               If ((szChar = "-") Or (szChar = ".")) And (k > 0) Then
                  fRange = True
               Else
                  fRange = False
               End If
               
               szChan = ""
               
            End If
         Next
         
         NumChan = k
         
      End If
      
      
    ' write properties to DSP/data acquisition board

    ' main type in low byte
      rc = DSPutDSPProperty(hBoard, DSP_BOARDCLASS, wBoardClass And &HFF)
    
    ' subtype in high byte
      rc = DSPutDSPProperty(hBoard, DSP_BOARDSUBCLASS, wBoardClass \ 256)

    ' main operating mode = LBR codec mode
      rc = DSPutDSPProperty(hBoard, DSP_OPMODE, 9)

         
      FRAMESIZE = 180  ' default value for MELP
         
      rc = DSPutDSPProperty(hBoard, DSP_FRMSIZ, FRAMESIZE)

      rc = DSPutDSPProperty(hBoard, DSP_BUFLEN, BufferSize * NumChan)

      ret = DSPutDSPProperty(hBoard, DSP_NUMCHAN, NumChan)  ' number of channels

      w = 0
      For j = 0 To (NumChan - 1)
         w = w Or Shift(ChanList(j), 4 * j)
      Next

      ret = DSPutDSPProperty(hBoard, DSP_CHANLIST, w)       ' channel list
         
      rc = DSPutDSPProperty(hBoard, DSP_SCALEIN, Shift(1&, 8))
      
      ret = DSPutDSPProperty(hBoard, DSP_FILTTYPE1, 0)  ' disable trace 1
                                                        ' real-time filter

      ret = DSPutDSPProperty(hBoard, DSP_FILTTYPE2, 0)  ' disable trace 2
                                                        ' real-time filter

      ret = DSPutDSPProperty(hBoard, DSP_TRIGLEVEL, 0)  ' free-run triggering

      ret = DSPutDSPProperty(hBoard, DSP_TRIGCHANLIST, 0)

      ret = DSPutDSPProperty(hBoard, DSP_HOSTBUFNUM, 0) ' starting buffer
                                                        ' numbers

      ret = DSPutDSPProperty(hBoard, DSP_BUFNUM, 0)     ' set initial buffer
                                                        ' number to zero

      ret = DSPutDSPProperty(hBoard, DSP_GAINLIST, 0)   ' gain list


    ' determine sampling rate ctrl. reg. value, and actual rate (closest rate
    ' possible to desired)
    ' CalcSampFreq returns ctrl. reg. value directly, uses ptr to return actual 
    ' sampling frequency (in Hz)

      FsDesired = 8000  ' default value for MELP

      dwFsMode = DSCalcSampFreq(hBoard, FsDesired, NumChan, ChanList(0), _      
                           FsActual)

      ActualFs.Text = Str$(FsActual)

      ret = DSPutDSPProperty(hBoard, DSP_FSMODE, dwFsMode) ' sampling rate
                                                           ' control register
                                                           ' (mode value)
   
      dwFsActual = FsActual
      ret = DSPutDSPProperty(hBoard, DSP_FSVALUE, dwFsActual) ' actual sampling
                                                              ' rate (in Hz)
      
    ' init flag at DSP
       
      w = 1
      rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA_RT, flag_addr, DS_GM_SIZE16, w, 1)
      

    ' run the DSP(s)

      rc = DSRunProcessor(hBoard, &H1)
 
      CurFrame = 0
      nCurBuf = 0
      RunState = 1  ' initialization, waveform file stored
   
   End If


   frmConfig.List1.AddItem "Real-Time mode enabled"
       
   frmConfig.List1.TopIndex = Max(frmConfig.List1.ListCount - 1, 0)
   
   rc = DSGetMem(hBoard, DS_GM_LINEAR_DATA, flag_addr, DS_GM_SIZE16, flagval, 1)
         
   While (flagval = 1)
   
      frmConfig.List1.AddItem "Waiting for DSP to initialize"
      frmConfig.List1.TopIndex = Max(frmConfig.List1.ListCount - 1, 0)
      rc = DSGetMem(hBoard, DS_GM_LINEAR_DATA, flag_addr, DS_GM_SIZE16, _
                    flagval,  1)
      DoEvents
      
   Wend
    
    
 ' some things to set for MELP operation
         
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA_RT, getframe_addr, DS_GM_SIZE32, _
                 inbufk, 1)
         
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA_RT, sendframe_addr, DS_GM_SIZE32, _
                 outbufk, 1)
         
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA_RT, getcoeff_addr, DS_GM_SIZE32, _
                 coeff_inbufk, 1)
         
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA_RT, sendcoeff_addr, DS_GM_SIZE32, _
                 coeff_outbufk, 1)
         
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA_RT, melp_mode_addr, DS_GM_SIZE16, _
                 MelpMode, 1)
   
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA_RT, op_mode_addr, DS_GM_SIZE16, _
                 OpMode, 1)
 
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA_RT, audio_loopback_addr, _
                 DS_GM_SIZE16, AudioLoopback, 1)
 

   w = 0
   
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA, bzyflg_addr, DS_GM_SIZE16, w, 1)
 
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA, melpflg_addr, DS_GM_SIZE16, w, 1)
   
   
 ' Let DSP free run
 
   rc = DSPutMem(hBoard, DS_GM_LINEAR_DATA, flag_addr, DS_GM_SIZE16, w, 1)
                            
   rc = DSGetMem(hBoard, DS_GM_LINEAR_DATA, bzyflg_addr, DS_GM_SIZE16, _
                 bzyflgval, 1)

   if (bzyflgval <> 0) Then

      frmConfig.List1.AddItem "Sanity check failed; DSP may not be"
      frmConfig.List1.AddItem "  able to access external SRAM using"
      frmConfig.List1.AddItem "  zero-waite state timing"
      frmConfig.List1.TopIndex = Max(frmConfig.List1.ListCount - 1, 0)

   End If
  

 ' if real-time mode, initialize to waiting for WM_BUFREADY message
    
   If (fSerialCommMode or fNetworkMode) Then  ' see WndProc procedure for
                                              ' real-time processing

      ReDim gNewSound(0 To (MAX_PACKET_DELAY + 1) * (NUMCOEFFS + 2)) ' redim for
                                                                     ' max pkt
                                                                     ' delay

      RxJitterBufferOutPtr = MAX_PACKET_DELAY  ' initialize jitter buffer to
                                               ' maximum packet delay
      RxJitterBufferInPtr = 0

      TxPacketCounter = 0
      RxPacketCounter = 0
       
    ' start hardware buffer ready message stream
         
      rc = DSWaitForBuffer(hBoard, nCurBuf, 0&, DS_WFB_POLLED)
         
   End If
  
End Sub


' Hardware Message Processing

' Upload analysis coefficients from DSP and send over sync. serial link or IP
' network
'   and/or
' Download analysis coefficients received from sync. serial link or IP network
' to DSP

' Notes: 1) Message arrives every 22.5 msec, or Framesize/Fs, where Framesize =
' 180 pts, and Fs = 8000 Hz.
'
'        2) Each message indicates a packet is ready (analysis) or a packet can
'           be accepted (synthesis) in half-duplex mode, or both (full-duplex
'           mode).
'
'        3) For full-duplex operation, a packet should be read from DSP board
'           memory (DSGetMem function call, and a packet should be written to
'           DSP board memory (DSPutMem function call).
'
'        4) The DS_GM_DIRECTACCESS attribute used in the DSxxxMem calls is used
'           for faster driver operation.


Private Sub WndProc_Message(MsgVal As Integer, wParam As Integer, lParam As _
                            Long, ReturnVal As Long)

   Dim ret As Integer
   Dim fStatus As Boolean
   Dim Index As Integer

   
 ' process buffer ready messages from DirectDSP driver / engine
 
   If (MsgVal = WM_DSPENGINE_BUFRDY) Then
      
      If (fSerialCommMode or fNetWorkMode) Then  ' read one packet from DSP
                                                 ' board and transmit
      
       ' get compressed speech packet from DSP board
       
         If (RunState = 1) Then

            ret = DSGetMem(hBoard, DS_GM_LINEAR_PROGRAM Or DS_GM_DIRECTACCESS, _
                           chbuf_addr, DS_GM_SIZE16, gNewSound(0), NUMCOEFFS)
         End If
         
       ' Tx:  send over sync. serial output
     
'         fStatus = SendSerial(1)
         fStatus = SendNetwork(1)
         
         If (fStatus) Then
      
            If ((TxPacketCounter Mod 100) = 0) Then
      
               frmConfig.List1.AddItem "Tx data frame " & CStr(TxPacketCounter)
               frmConfig.List1.TopIndex = Max(frmConfig.List1.ListCount - 1, 0)
            End If
      
          ' always increment packet counter
    
            TxPacketCounter = TxPacketCounter + 1
            
         End If
         
      End If
      
      If (fSerialCommMode or fNetworkMode) Then  ' get one packet from jitter
                                                 ' buffer and write to DSP board
       
       ' check for packet overrun
       
         If (RxJitterBufferOutPtr = RxJitterBufferInPtr) Then
    
            frmConfig.List1.AddItem "Rx jitter buffer overrun"
            frmConfig.List1.TopIndex = Max(frmConfig.List1.ListCount - 1, 0)
         End If
    
    
       ' Rx:  take next packet out of jitter buffer, write to DSP
       
         Index = (NUMCOEFFS + 2) * RxJitterBufferOutPtr
         
         If (RunState = 1) Then

            ret = DSPutMem(hBoard, DS_GM_LINEAR_PROGRAM Or DS_GM_DIRECTACCESS, _
                           chbuf_addr, DS_GM_SIZE16, gNewSound(Index), _
                           NUMCOEFFS)

         End If
         
       ' toggle output jitter buffer
       
         RxJitterBufferOutPtr = RxJitterBufferOutPtr + 1

         If (RxJitterBufferOutPtr > MAX_PACKET_DELAY) Then _
           RxJitterBufferOutPtr = 0
   
         Index = (NUMCOEFFS + 2) * RxJitterBufferInPtr
       
      End If

      
      If (RunState <> 0) Then
         
       ' instruct engine to wait for next buffer
   
         nCurBuf = nCurBuf Xor 1  ' toggle buffer number
      
         ret = DSWaitForBuffer(hBoard, nCurBuf, 0&, DS_WFB_POLLED)
      
      End If
      
   End If
    
End Sub


' Hardware Cleanup Code--should be done at program close or abort

Sub HardwareCleanup()
  
   Dim rc As Integer
  
   If (hFileInput <> NUL) Then
   
       DSCloseFile (hFileInput)
       hFileInput = NUL
   End If
   
   If (hBoard <> 0) Then
      
      If (RunState <> 0) Then
      
         rc = DSDisableBoard(hBoard)
         If rc = 0 Then ErrorHandler
         
         RunState = 0
      End If
        
      rc = DSFreeBoard(hBoard)
      If rc = 0 Then ErrorHandler
      
      hBoard = 0

   End If
  
   If (hEngine <> 0) Then
      If (DSEngineClose(hEngine) = 0) Then MsgBox ("error closing engine")
      hEngine = 0
   End If
      
End Sub


' error handler procedure that checks different types of DirectDSP error
' messages

Sub ErrorHandler()

Dim nErrorType As Integer
 
   DSShowEngMgrStatusWindow
   
   nErrorType = DSGetEngineErrorStatus(hEngine)
   If nErrorType = 0 Then nErrorType = DSGetEngMgrErrorStatus()
   If nErrorType = 0 Then nErrorType = DSGetHWLibErrorStatus()

End Sub