1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
import threading
from time import sleep
from sfml import sf
from struct import unpack
# python 2.* compatability
try: input = raw_input
except NameError: pass
AUDIO_DATA, END_OF_STREAM = list(range(1, 3))
class NetworkAudioStream(sf.SoundStream):
def __init__(self):
sf.SoundStream.__init__(self)
self.offset = 0
self.has_finished = False
self.listener = sf.TcpListener()
self.samples = sf.Chunk()
# set the sound parameters
self.initialize(1, 44100)
def start(self, port):
if not self.has_finished:
try:
# listen to the given port for incoming connections
self.listener.listen(port)
print("Server is listening to port {0}, waiting for connections... ".format(port))
# wait for a connection
self.client = self.listener.accept()
print("Client connected: {0}".format(self.client.remote_address))
except sf.SocketException: return
# start playback
self.play()
# start receiving audio data
self.receive_loop()
else:
# start playback
self.play()
def on_get_data(self, chunk):
# we have reached the end of the buffer and all audio data have been played : we can stop playback
if self.offset >= len(self.samples) and self.has_finished:
return False
# no new data has arrived since last update : wait until we get some
while self.offset >= len(self.samples) and not self.has_finished:
sf.sleep(sf.milliseconds(10))
# don't forget to lock as we run in two separate threads
lock = threading.Lock()
lock.acquire()
# fill audio data to pass to the stream
chunk.data = self.samples.data[self.offset*2:]
# update the playing offset
self.offset += len(chunk)
lock.release()
return True
def on_seek(self, time_offset):
self.offset = time_offset.milliseconds * self.sample_rate * self.channel_count // 1000
def receive_loop(self):
lock = threading.RLock()
while not self.has_finished:
# get waiting audio data from the network
data = self.client.receive(1)
# extract the id message
id = unpack("B", data)[0]
if id == AUDIO_DATA:
# extract audio samples from the packet, and append it to our samples buffer
data = self.client.receive(4)
sample_count = unpack("I", data)[0]
samples = self.client.receive(sample_count)
# don't forget the other thread can access the sample array at any time
lock.acquire()
self.samples.data += samples
lock.release()
elif id == END_OF_STREAM:
# end of stream reached : we stop receiving audio data
print("Audio data has been 100% received!")
self.has_finished = True
else:
# something's wrong...
print("Invalid data received...")
self.has_finished = True
def do_server(port):
# build an audio stream to play sound data as it is received through the network
audio_stream = NetworkAudioStream()
audio_stream.start(port)
# loop until the sound playback is finished
while audio_stream.status != sf.SoundStream.STOPPED:
# leave some CPU time for other threads
sf.sleep(sf.milliseconds(100))
# wait until the user presses 'enter' key
input("Press enter to replay the sound...")
# replay the sound (just to make sure replaying the received data is OK)
audio_stream.play();
# loop until the sound playback is finished
while audio_stream.status != sf.SoundStream.STOPPED:
sf.sleep(sf.milliseconds(100))
|