-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathclient.py
More file actions
154 lines (130 loc) · 4.87 KB
/
client.py
File metadata and controls
154 lines (130 loc) · 4.87 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import socket
import threading
import pyaudio
import signal
import sys
from termcolor import colored
import time
import argparse
class VoiceClient:
# Audio parameters
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
def __init__(self, host, port):
self.host = host
self.port = port
self.running = True
self.name = ''
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.audio = pyaudio.PyAudio()
# Set up audio streams
self.input_stream = self.audio.open(
format=self.FORMAT,
channels=self.CHANNELS,
rate=self.RATE,
input=True,
frames_per_buffer=self.CHUNK
)
self.output_stream = self.audio.open(
format=self.FORMAT,
channels=self.CHANNELS,
rate=self.RATE,
output=True,
frames_per_buffer=self.CHUNK
)
# Connect to server
print(colored(f"Connecting to voice server at {host}:{port}...", "yellow"))
try:
self.sock.connect((host, port))
except ConnectionRefusedError:
print(colored("Connection refused. Make sure the server is running.", "red"))
self.cleanup()
sys.exit(1)
print(colored("Connected to voice server.", "green"))
def start(self):
"""Start the voice client"""
# Set up signal handler
signal.signal(signal.SIGINT, self.handle_signal)
# Get user's name
while not self.name:
self.name = input(colored("Enter your name: ", "blue")).strip()
# Send name to server
self.sock.send(f"NAME:{self.name}".encode())
# Start audio threads
receive_thread = threading.Thread(target=self.receive_audio)
send_thread = threading.Thread(target=self.send_audio)
receive_thread.daemon = True
send_thread.daemon = True
receive_thread.start()
send_thread.start()
print(colored("Voice chat started! Press Ctrl+C to exit.", "yellow"))
# Keep main thread alive (cross-platform)
try:
while self.running:
time.sleep(0.1) # Sleep briefly to prevent high CPU usage
except KeyboardInterrupt:
self.handle_signal(None, None)
def send_audio(self):
"""Capture and send audio to server"""
while self.running:
try:
data = self.input_stream.read(self.CHUNK, exception_on_overflow=False)
if self.running:
self.sock.send(data)
except Exception as e:
if self.running:
print(colored(f"Error sending audio: {e}", "red"))
break
def receive_audio(self):
"""Receive and play audio from server"""
while self.running:
try:
data = self.sock.recv(self.CHUNK * 2)
if not data:
break
# Check for control messages
if data.startswith(b"CONTROL:"):
message = data[8:].decode()
print(colored(message, "cyan"))
continue
# Check for server full message
if data == b"SERVER_FULL":
print(colored("Server is full. Try again later.", "red"))
self.running = False
break
# Play audio data
self.output_stream.write(data)
except Exception as e:
if self.running:
print(colored(f"Error receiving audio: {e}", "red"))
break
def handle_signal(self, signum, frame):
"""Handle Ctrl+C"""
print(colored("\nExiting voice chat...", "yellow"))
self.running = False
self.cleanup()
sys.exit(0)
def cleanup(self):
"""Cleanup resources"""
self.running = False
if hasattr(self, 'input_stream'):
self.input_stream.stop_stream()
self.input_stream.close()
if hasattr(self, 'output_stream'):
self.output_stream.stop_stream()
self.output_stream.close()
if hasattr(self, 'audio'):
self.audio.terminate()
if hasattr(self, 'sock'):
self.sock.close()
def main():
parser = argparse.ArgumentParser(description='Voice Chat Client')
parser.add_argument('host', help='server address')
parser.add_argument('port', type=int, help='server port')
args = parser.parse_args()
client = VoiceClient(args.host, args.port)
client.start()
if __name__ == "__main__":
main()