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 125 126 127 128 129 130 131 132 133 134
|
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# pySFML - Python bindings for SFML
# Copyright 2012-2013, Jonathan De Wachter <dewachter.jonathan@gmail.com>
#
# This software is released under the LGPLv3 license.
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import threading
from time import sleep
import sfml as 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))
|