MBS: Trying an audio play thru based on the send/receive examples; having troubles

Hello,

My goal is to provide simple audio play thru (take audio from an input device and send it to an output device).
I was a little confused by the examples about PortAudio, because none seems to do exactly what I want. So I chose the 2 projects to send and receive audio over a network and am attempting to merge them.

My current code has two issues:
1: playback just gives a small noise at the beginning and then nothing.
2: after around 7 seconds, I’m getting an error with Buffer.AddFloatAudio; but the error number is 0 and the explanation is empty :thinking:
Overall, I don’t have much clue about what’s wrong.

So, this is a console application and here’s my code with the values used for this test (I made sure to select the correct default devices in the OS, which happens to be Windows 10 for this project):

Class CInput, for recording the microphone
2 properties:
Public Property mb As MemoryBlock
Public Property Recorder As PortAudioStreamRecorderMBS

2 methods:

Public Function InitAudio() As Boolean
  mb=newMemoryBlock(4*102400) // read maximum 102400 samples per timer loop
  
  Recorder=new PortAudioStreamRecorderMBS(1024*1024*16)
  
  dim e as integer=Recorder.OpenDefaultStream(1,8000.0)
  if e=0 then
    if Recorder.Start=0 then
      Print "Recording started."
      Return True //State is valid
    else
      Print "Failed to start audio recording."
    end if
  else
    Print "Audio Error: "+str(e)+" with host error: "+str(Recorder.HostError.ErrorCode)+" "+Recorder.HostError.ErrorText
  end if
End Function

Public Sub Destructor()
  if Recorder<>nil then
    call Recorder.Close
    Recorder=nil //Probably not necessary, but taken from example
  end if
End Sub

Class COutput, to send to the earphone
3 properties:
Public Property Buffer As PortAudioStreamBufferedMBS
Public Property LastTime As Double
Public Property pa As PortAudioMBS

3 methods:

Public Function InitAudio() As Boolean
  dim e as integer
  
  pa=new PortAudioMBS
  Buffer=new PortAudioStreamBufferedMBS
  Buffer.NoUnderflow=True
  
  e=Buffer.OpenDefaultStream(1,8000.0)
  
  if e=0 then
    Return True //State is valid
  else
    Print "Audio Error: "+str(e)+" with host error: "+str(Buffer.HostError)
  end if
End Function

Public Sub ProcessNext(Data As MemoryBlock)
  //Called manually to process the next frame
  if Buffer=nil then Return
  if Data=nil or Data.Size=0 then Return //Empty
  
  if not Buffer.AddFloatAudio(Data) then
    Print "Failed to play audio! "+Buffer.HostError.ErrorCode.ToString
  else
    if Buffer.IsStreamActive<>1 then
      var e as integer=Buffer.Start
      
      if e<>0 then. Print "Audio Error: "+str(e)
    end if
  end if
  
  dim n as double=Data.Size/4
  
  Print "Received "+str(n)+" frames. "+str(floor(n/((Microseconds-LastTime)/1000000.0)))+" frames/s"
  LastTime=Microseconds
End Sub

Public Sub Destructor()
  if Buffer<>nil then call Buffer.Close
End Sub

And finally, this is the app.Run event:

var PInput As CInput
var POutput As COutput

PInput=new CInput
if not PInput.InitAudio then
  Print "Input not inited."
  Return 1
end if

POutput=new COutput
if not POutput.InitAudio then
  Print "Output not inited."
  Return 2
end if

var StartTime As Integer=System.Ticks //Loop for some seconds only

do
  if System.Ticks-StartTime>1000 then exit //10 seconds for testing
  
  var l as integer
  
  // we ask for samples in the buffer
  l=PInput.Recorder.ReadFrames(PInput.mb,PInput.mb.Size)
  
  if l>0 then
    POutput.ProcessNext PInput.mb
    Print "Sending "+str(l)+" frames."
  end if
  app.DoEvents //I tried with or without it
loop
Print Input //Prevent the console window from automatically closing so I can see the printed strings

This is a new area for me so I’m puzzled. Is a console app not suitable for this or I’ve implemented it inappropriately?
Advices greatly appreciated.

Forum for Xojo Programming Language and IDE. Copyright © 2021 Xojo, Inc.