For anyone interested in implementing voice chat into their game, below is a simple program to illustrate how to incorporate it using DarkNet's input system with DBPro's memblock and sound systems. It's also posted in the codebase.
` VoiceChat via DarkNet and Memblocks
` Version 1.0, July 17th, 2010
` Written by Shawn 'Vice' of StarWraith 3D Games LLC
` This sample code illustrates a technique to implement voice chat into DBPro games
` using DarkNet for recording input and memblocks for sound playback.
` When I was developing this system, I ran into playback compatibility issues with various
` 5.1 surround sound setups using DN exclusively, but found that by breaking up the
` sound samples into memblocks, the highly efficient recording of DN could be
` combined with DBPro's sound playback system quite nicely.
` This is an earlier and simplified version of the system I use in Evochron Mercenary,
` but should work well on most systems and is highly customizable. I'm sure others will
` likely improve on this and spot areas that can be tuned and tweaked for better results.
` But the code below should work well under most conditions on most system configurations
` to help you get started designing a system for your own game.
` If you run into performance issues, try adjusting the input smoothing value to shorten
` input sample lengths.
` Terms:
` I am releasing this code under free and open terms, you are welcome to use this
` code for your own projects, both commercial and non-commercial. Credit is not
` required, but I appreciate any listing you want to include in the credits for your game.
print "VoiceChat via DarkNet and Memblocks"
` you can specify a callsign for this player if you like here
input "Enter a name for this player: ",pilot$
` or you can rem out the line above and use the variable below
` pilot$="PlayerA"
` prompt for IP address
input "Enter IP address to use: ",add$
` or you can rem out the line above and use the variable below
` add$="192.168.0.2"
sync on
sync rate 0
` select client or server
repeat
cls 0:text 10,10,"Press 1 for server or 2 for client"
sync
until keystate(2)=1 or keystate(3)=1
` set up DarkNet and initial values
SendPacket = mn create packet()
RecvPacket = mn create packet()
SoundInput = mn create packet()
mn Start 1,0
mn Disable Message Boxes:mn Disable Debug
maxplayers=35
` you can use a value like this to specify whether voice chat is on or off in your game
voice$="On"
` setup for host
if keystate(2)=1
mn Set Local 0,add$,3788,add$,3789
mn Set Buffer Sizes 0, 20000, 20000, 1
sss = mn Start Server(0,maxplayers,1,4)
host=1
endif
` setup for client
if keystate(3)=1
mn Set Buffer Sizes 0, 20000, 20000, 2
sss = mn Connect(0,add$,3788,add$,3789,4,1)
if sss<1 then end
eee = mn Get Max Clients(0)
` you can retrieve some details about your connection here if you like
s$ = mn Get Local IP TCP(0)
eee = mn Get Local Port TCP(0)
s$ = mn Get Local IP UDP(0)
eee = mn Get Local Port UDP(0)
eee = mn Get Client Id(0)
host=0
endif
` set up the DarkNet sound system
mn start sound 1,0
` you can adjust the smoothing value of 350 to something else to experiment with different sample lengths
mn Set Input Smooth Values 0,2,350
` for this example, we'll use a fairly low sample rate of 8000 and 8-bit with one channel
mn Set Input Format 0,1,8000,8
` this starts the recording system
mn Start Input 0,-1
` Main Loop
waitl:
cls
if host=1
ssss = mn Client Joined(0)
if ssss>0
` you can retrieve some client details here at a join event if you like
s$ = mn Get Client IP TCP(0, ssss)
s = mn Get Client Port TCP(0, ssss)
s$ = mn Get Client IP UDP(0, ssss)
s = mn Get Client Port UDP(0, ssss)
endif
ssss = mn Client Left(0)
endif
` Here we control the DarkNet input system with the spacekey
if spacekey()=0
if mn Get Input Paused(0) = 0
mn Pause Input 0
endif
endif
if spacekey()>0
if mn Get Input Unpaused(0) = 0
mn Unpause Input 0
endif
endif
` Input data check and transmit routine
iResult = mn Get Input Data(0,SoundInput)
if iResult > 0
` Send data to server after recording cycle finishes
` it's a good idea to store some values for markers to help
` identify voice samples (good for muting control, proximity gauging, location data, etc)
` for this example, I'll include a 'VOI' marker to tell our multiplayer system that this is
` a voice chat packet with sound data
mn Add String SendPacket,"VOI",0,1
` next, we can include the name of the player sending the sound data
mn Add String SendPacket,pilot$,0,1
` here we include the raw sound data
mn Add Packet SendPacket,SoundInput
` and for this example, we'll send out the packet to everyone
if host=1 then mn Send UDP All 0,SendPacket,0,0,0
if host=0 then mn Send UDP 0,SendPacket,0,0,1
endif
` Receive routine
` lets start with ClientID 1 and check for messages from all connected players
` for the host, this could be up to the value in maxplayers
ClientID=1
KeepChecking:
sss = mn Recv UDP(0,RecvPacket,ClientID,0)
` if no message, skip the processing routine
if sss=0 then goto nomessages
` who the message is from
ooo = ClientID
pc$=mn Get String(RecvPacket,0,1)
if left$(pc$,3)="VOI"
` and we can retrieve the name of the player who sent the sound sample here
s$=mn Get String(RecvPacket,0,1):playername$=s$
` if we're the host, we need to rebroadcast this message to the other connected players
` for now, we'll just bounce the packet back out to everyone, then selectively play it
` back or not based on the pilot$ value on the client-side
` selective delivery/broadcasting can help performance later on, for now
` we'll keep things simple to illustrate
if host=1
mn Equal Packet SendPacket,RecvPacket
if host=1 then mn Send UDP All 0,SendPacket,0,0,0
endif
` remove used data from current packet before sending to the sound playback routine
mn Erase RecvPacket,0,mn Get Cursor(RecvPacket)
` if you want to remove excess bytes or edit that data, you can optionally do that here
` for example, you could remove the last 16 bytes of the data like this:
` eee=mn Get Used Size(RecvPacket):mn Erase RecvPacket,eee-16,eee
` now we'll transfer the raw sound data from RecvPacket to SoundInput
mn Equal Packet SoundInput,RecvPacket
` Play data
` create a memblock of the required size for the sound sample
eee=mn Get Used Size(SoundInput)
make memblock 2, eee+28
` find the memblock in memory
memblockPtr = get memblock ptr(2)
` now set up the memblock for use as a sound file,
` including the 8000, 8-bit, one channel format we set up for recording
write memblock dword 2,0,1
write memblock dword 2,4,1
write memblock dword 2,8,8000
write memblock dword 2,12,8000
write memblock dword 2,16,1
write memblock dword 2,20,8
write memblock dword 2,24,0
` now transfer the sound data from SoundInput to the memblock, be sure to skip the
` first 28 bytes which is used for the format data we entered above
mn get memblock SoundInput, memblockPtr+28,eee,0
` find the next available sound
s=0:ss=0
repeat
if sound exist(1+s)=1
if sound playing(1+s)=0
delete sound 1+s:ss=1
else
s=s+1
endif
else
ss=1
endif
until ss>0 or s>50
if s<51 and playername$<>pilot$
make sound from memblock 1+s,2
if voice$="On" then play sound 1+s
endif
delete memblock 2
` in case there are other values to check for, include a goto to skip them
goto nomessages
endif
` you can check for other message values here if desired
` now that we've finished checking for messages, loop through the rest of the client ID's
nomessages:
ClientID=ClientID+1:if ClientID<maxplayers then goto KeepChecking
ink rgb(255,255,255),0
text 10,20,"VoiceChat Ready..."
text 10,30,"Press and hold the spacebar to talk..."
if spacekey()>0
text 10,40,"Recording/streaming audio..."
else
text 10,40,"Waiting..."
endif
text 10,50,"Sound Slots: "+str$(s)
sync
goto waitl