How to send audio from a client computer to a server over the wifi | PyShine

How to send audio from a client computer to a server over the wifi

 · 9 mins read

Hi friends! In a previous tutorial we used opencv to obtain video frames of webcam and send them over wifi to server/client. Below is the video about basics of socket programming.



Today, we will move one step further, instead of transmitting video frames over wifi from one computer to another, we will use pyshine to send audio frames. The default audio frame will be of 1024 data samples for each audio channel from the microphone device of a computer. The mechanism is almost similar to that of video transmitting and receiving. So without any delay, let’s install the essentials.

Install pyshine version 0.0.6 in Windows OS as:

pip3 install pyshine==0.0.6

Both server and client computers should be on the same wifi router. The required IP address will be for Wifi LAN (inet)

Windows OS users

From the cmd window run this command:

ipconfig

Mac OS users

ifconfig en0

The required IP address will be shown against IPv4 Address, or inet in MAC OS

Here is the server side code. First, please change the IP address: ‘192.168.1.104’ to yours, otherwise your server will not start.

server.py


import socket,pickle,struct,time
import pyshine as ps
import threading
mode =  'get'
name = 'SERVER RECEIVING AUDIO'
audio,context= ps.audioCapture(mode=mode)
#ps.showPlot(context,name)

# Socket Create
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host_ip = '192.168.1.104'
port = 4982
backlog = 5
socket_address = (host_ip,port)
print('STARTING SERVER AT',socket_address,'...')
server_socket.bind(socket_address)
server_socket.listen(backlog)


def listen_client(addr,client_socket):
	try:
		print('CLIENT {} CONNECTED!'.format(addr))
		if client_socket: # if a client socket exists
			data = b""
			payload_size = struct.calcsize("Q")
			while True:
				while len(data) < payload_size:
					packet = client_socket.recv(4*1024) # 4K
					if not packet: break
					data+=packet
				packed_msg_size = data[:payload_size]
				data = data[payload_size:]
				msg_size = struct.unpack("Q",packed_msg_size)[0]
				
				while len(data) < msg_size:
					data += client_socket.recv(4*1024)
				frame_data = data[:msg_size]
				data  = data[msg_size:]
				frame = pickle.loads(frame_data)
				audio.put(frame)
				
			client_socket.close()
	except Exception as e:
		print(f"CLINET {addr} DISCONNECTED")
		pass
		
while True:
	client_socket,addr = server_socket.accept()
	thread = threading.Thread(target=listen_client, args=(addr,client_socket))
	thread.start()
	print("TOTAL CLIENTS ",threading.activeCount() - 1)

client.py

import socket, pickle,struct
import pyshine as ps

mode =  'send'
name = 'CLIENT SENDING AUDIO'
audio,context = ps.audioCapture(mode=mode)
# ps.showPlot(context,name)

# create socket
client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host_ip = '192.168.1.104'
port = 4982

socket_address = (host_ip,port)
client_socket.connect(socket_address) 
print("CLIENT CONNECTED TO",socket_address)

if client_socket: 
	while (True):
		try:
			frame = audio.get()
			a = pickle.dumps(frame)
			message = struct.pack("Q",len(a))+a
			client_socket.sendall(message)
			
		except:
			print('AUDIO FINISHED!')
			break

client_socket.close()



To run the code, please run the server.py first at the server computer and make sure that its speakers are not mute.

python server.py

On the client computer the Microphone should be working and run this code:

python client.py

Once successfully connected the server computer will play back the client audio.

Some friends have asked about the possibility of recording the received audio data at the server side. Although this is bit experimental but we can try to record the incoming data at the server side. We will use soundfile library to record the audio data at the server side. First install the soundfile as:

pip3 install soundfile

Then instead of above server.py use this one:

server_with_record.py


import socket,pickle,struct,time
import pyshine as ps
import threading
import tempfile
import soundfile as sf
filename = tempfile.mktemp(prefix='output',suffix='.wav',dir='')

mode =  'get'
name = 'SERVER RECEIVING AUDIO'
audio,context= ps.audioCapture(mode=mode)
#ps.showPlot(context,name)

# Socket Create
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host_ip = '192.168.1.104'
port = 4982
backlog = 5
socket_address = (host_ip,port)
print('STARTING SERVER AT',socket_address,'...')
server_socket.bind(socket_address)
server_socket.listen(backlog)


def listen_client(addr,client_socket):
	try:
		print('CLIENT {} CONNECTED!'.format(addr))
		if client_socket: # if a client socket exists
			data = b""
			payload_size = struct.calcsize("Q")
			while True:
				while len(data) < payload_size:
					packet = client_socket.recv(4*1024) # 4K
					if not packet: break
					data+=packet
				packed_msg_size = data[:payload_size]
				data = data[payload_size:]
				msg_size = struct.unpack("Q",packed_msg_size)[0]
				
				while len(data) < msg_size:
					data += client_socket.recv(4*1024)
				frame_data = data[:msg_size]
				data  = data[msg_size:]
				frame = pickle.loads(frame_data)
				audio.put(frame)
				
			client_socket.close()
	except Exception as e:
		print(f"CLINET {addr} DISCONNECTED")
		pass
		
while True:
	client_socket,addr = server_socket.accept()
	thread = threading.Thread(target=listen_client, args=(addr,client_socket))
	thread.start()
	print("TOTAL CLIENTS ",threading.activeCount() - 1)
	with sf.SoundFile(filename, mode='x', samplerate=44100,channels=2) as file:
		while True:
			file.write(audio.get())


Once audio data is coming, the wav file will be generated in the same directory as this Python code for the server file. If you want to finish the recording press ctrl+c and then exit the terminal window at the server side. You can exit the loop by other means as well but you already have got the point. A wav file will be generated containing the received audio.