Assuming you get a network stream you could do something like the code below.
The Main()
sub gets a network stream and reads it until the end. It passed the bytes over to the PlayBuffer
class which appends the bytes to the end of a MemoryStream. When you use the Read()
method on the PlayBuffer
, it reads from the start and keeps a pointer to where you have read to. The locking is there so that you can write and read to the stream from separate threads. I have not provided code which uses Read(). It's just to give an idea. If you are getting continous bytes, then you could allocate a large buffer and once at the end, you start writing at the beginning again (ring-buffer).
[Edit - modified code to write and read at the same time]
I have not completely tested the code, but the PlayBuffer class inherits a stream and should be able to write and read at the same time, as long as one thread writes and the other just reads.
Friend Class PlayProgram
Public Sub Main()
Dim playBuffer As New PlayBuffer
Dim readData As New Thread(Function
Using client As TcpClient = New TcpClient("somehostname", 80)
Using networkStream As NetworkStream = client.GetStream
Dim readBytes As Integer
Dim buffer As Byte() = New Byte(&H1000 - 1) {}
Do While (readBytes = networkStream.Read(buffer, 0, buffer.Length) > 0)
playBuffer.Write(buffer, 0, readBytes)
playBuffer.Flush
Loop
End Using
End Using
End Function)
readData.Start
New SoundPlayer(playBuffer).Play
readData.Join
End Sub
End Class
Friend Class PlayBuffer
Inherits Stream
Public Sub AppendToBuffer(ByVal buffer As Byte(), ByVal bytesRead As Integer)
SyncLock PlayBuffer._lock
Me._buffer.Position = Me._buffer.Length
Me._buffer.Write(buffer, 0, bytesRead)
End SyncLock
End Sub
Public Overrides Sub Flush()
SyncLock PlayBuffer._lock
Me._buffer.Flush
End SyncLock
End Sub
Public Overrides Function Read(ByVal internalBuffer As Byte(), ByVal offset As Integer, ByVal count As Integer) As Integer
SyncLock PlayBuffer._lock
Me._buffer.Position = Me._readPosition
Dim bytesRead As Integer = Me._buffer.Read(internalBuffer, 0, internalBuffer.Length)
Me._readPosition = (Me._readPosition + bytesRead)
Return bytesRead
End SyncLock
End Function
Public Overrides Function Seek(ByVal offset As Long, ByVal origin As SeekOrigin) As Long
Throw New NotImplementedException
End Function
Public Overrides Sub SetLength(ByVal value As Long)
Throw New NotImplementedException
End Sub
Public Overrides Sub Write(ByVal buffer As Byte(), ByVal offset As Integer, ByVal count As Integer)
SyncLock PlayBuffer._lock
Me._buffer.Position = Me._buffer.Length
Me._buffer.Write(buffer, offset, count)
End SyncLock
End Sub
Public Overrides ReadOnly Property CanRead As Boolean
Get
Return True
End Get
End Property
Public Overrides ReadOnly Property CanSeek As Boolean
Get
Throw New NotImplementedException
End Get
End Property
Public Overrides ReadOnly Property CanWrite As Boolean
Get
Return True
End Get
End Property
Public Overrides ReadOnly Property Length As Long
Get
Return Me._buffer.Length
End Get
End Property
Public Overrides Property Position As Long
Get
Return Me._readPosition
End Get
Set(ByVal value As Long)
Throw New NotImplementedException
End Set
End Property
Private ReadOnly _buffer As MemoryStream = New MemoryStream
Private Shared ReadOnly _lock As Object = New Object
Private _readPosition As Long
End Class