Добавь в мою пародию на дискорд поддержку создания и подключения к каналам. Когда создается новый канал его начинают видеть все. Люди в разных каналах не могут слышать друг друга, а в одинаковых - могут. Если не выбран ни один канал - нельзя ни слышать ни говорить. Код клиента: import sys
import socket
import pyaudio
import threading
from PyQt5 import QtWidgets, QtCore

# Настройки
HOST = '26.189.118.250'  # Замените на IP-адрес сервера
PORT = 12345        # Тот же порт, что и на сервере

# Настройки аудио
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100

class VoiceChatClient(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Голосовой чат с каналами")
        self.setGeometry(100, 100, 400, 300)
        self.init_ui()
        self.client_socket = None
        self.audio = pyaudio.PyAudio()
        self.stream = None
        self.receive_thread = None
        self.send_thread = None
        self.listen_thread = None
        self.is_connected = False
        self.channels = []
        self.current_channel = None

    def init_ui(self):
        # Кнопки подключения/отключения
        self.connect_btn = QtWidgets.QPushButton("Подключиться", self)
        self.connect_btn.setGeometry(50, 20, 300, 40)
        self.connect_btn.clicked.connect(self.connect_to_server)

        self.disconnect_btn = QtWidgets.QPushButton("Отключиться", self)
        self.disconnect_btn.setGeometry(50, 70, 300, 40)
        self.disconnect_btn.clicked.connect(self.disconnect_from_server)
        self.disconnect_btn.setEnabled(False)

        # Список каналов
        self.channel_list = QtWidgets.QListWidget(self)
        self.channel_list.setGeometry(50, 120, 200, 100)
        self.channel_list.itemDoubleClicked.connect(self.join_channel)

        # Кнопка создания канала
        self.create_channel_btn = QtWidgets.QPushButton("Создать канал", self)
        self.create_channel_btn.setGeometry(260, 120, 90, 30)
        self.create_channel_btn.clicked.connect(self.create_channel)
        self.create_channel_btn.setEnabled(False)

        # Метка статуса
        self.status_label = QtWidgets.QLabel("Статус: Отключен", self)
        self.status_label.setGeometry(50, 230, 300, 20)
        self.status_label.setAlignment(QtCore.Qt.AlignCenter)

        # Стили
        self.setStyleSheet("""
            QMainWindow {
                background-color: #2c3e50;
            }
            QPushButton {
                background-color: #1abc9c;
                color: white;
                font-size: 16px;
                border-radius: 5px;
            }
            QPushButton:pressed {
                background-color: #16a085;
            }
            QLabel {
                color: white;
                font-size: 14px;
            }
            QListWidget {
                background-color: #ecf0f1;
                font-size: 14px;
            }
        """)

    def connect_to_server(self):
        if not self.is_connected:
            self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                self.client_socket.connect((HOST, PORT))
                self.is_connected = True
                self.status_label.setText("Статус: Подключен")
                self.connect_btn.setEnabled(False)
                self.disconnect_btn.setEnabled(True)
                self.create_channel_btn.setEnabled(True)
                # Запуск потока для прослушивания сообщений сервера
                self.listen_thread = threading.Thread(target=self.listen_to_server)
                self.listen_thread.start()
                # Запросить список каналов
                self.request_channels()
            except Exception as e:
                QtWidgets.QMessageBox.warning(self, "Ошибка", f"Не удалось подключиться к серверу:\n{e}")

    def disconnect_from_server(self):
        if self.is_connected:
            self.is_connected = False
            if self.current_channel:
                self.leave_channel()
            self.client_socket.close()
            self.status_label.setText("Статус: Отключен")
            self.connect_btn.setEnabled(True)
            self.disconnect_btn.setEnabled(False)
            self.create_channel_btn.setEnabled(False)
            self.channel_list.clear()
            self.channels = []

    def listen_to_server(self):
        try:
            while self.is_connected:
                data = self.client_socket.recv(1024).decode('utf-8')
                if data:
                    cmd, *args = data.split()
                    if cmd == "CHANNELS":
                        self.update_channel_list(args)
                    elif cmd == "NEW_CHANNEL":
                        channel_name = args[0]
                        self.add_channel(channel_name)
                    elif cmd == "AUDIO":
                        audio_data = self.client_socket.recv(CHUNK)
                        if self.stream:
                            self.stream.write(audio_data)
        except Exception as e:
            print(f"Ошибка при прослушивании сервера: {e}")

    def update_channel_list(self, channels):
        self.channels = channels
        self.channel_list.clear()
        self.channel_list.addItems(self.channels)

    def add_channel(self, channel_name):
        if channel_name not in self.channels:
            self.channels.append(channel_name)
            self.channel_list.addItem(channel_name)

    def request_channels(self):
        self.client_socket.sendall("GET_CHANNELS".encode('utf-8'))

    def create_channel(self):
        channel_name, ok = QtWidgets.QInputDialog.getText(self, "Создать канал", "Введите название канала:")
        if ok and channel_name:
            self.client_socket.sendall(f"CREATE_CHANNEL {channel_name}".encode('utf-8'))

    def join_channel(self, item):
        channel_name = item.text()
        if self.current_channel == channel_name:
            QtWidgets.QMessageBox.information(self, "Информация", f"Вы уже в канале {channel_name}")
            return
        if self.current_channel:
            self.leave_channel()
        self.client_socket.sendall(f"JOIN_CHANNEL {channel_name}".encode('utf-8'))
        self.current_channel = channel_name
        self.status_label.setText(f"Статус: В канале {channel_name}")
        # Запуск потоков для отправки и получения аудио
        self.receive_thread = threading.Thread(target=self.receive_audio)
        self.receive_thread.start()
        self.send_thread = threading.Thread(target=self.send_audio)
        self.send_thread.start()

    def leave_channel(self):
        self.client_socket.sendall(f"LEAVE_CHANNEL {self.current_channel}".encode('utf-8'))
        self.current_channel = None
        self.status_label.setText("Статус: Подключен")
        if self.stream:
            self.stream.stop_stream()
            self.stream.close()
            self.stream = None

    def receive_audio(self):
        self.stream = self.audio.open(format=FORMAT,
                                      channels=CHANNELS,
                                      rate=RATE,
                                      output=True,
                                      frames_per_buffer=CHUNK)
        try:
            while self.is_connected and self.current_channel:
                data = self.client_socket.recv(4096)
                if data:
                    self.stream.write(data)
        except Exception as e:
            print(f"Ошибка при получении аудио: {e}")
        finally:
            if self.stream:
                self.stream.stop_stream()
                self.stream.close()
                self.stream = None

    def send_audio(self):
        stream = self.audio.open(format=FORMAT,
                                 channels=CHANNELS,
                                 rate=RATE,
                                 input=True,
                                 frames_per_buffer=CHUNK)
        try:
            while self.is_connected and self.current_channel:
                data = stream.read(CHUNK, exception_on_overflow=False)
                self.client_socket.sendall(data)
        except Exception as e:
            print(f"Ошибка при отправке аудио: {e}")
        finally:
            stream.stop_stream()
            stream.close()

    def closeEvent(self, event):
        self.disconnect_from_server()
        self.audio.terminate()
        event.accept()

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = VoiceChatClient()
    window.show()
    sys.exit(app.exec_())

Код сервера:
import socket
import threading

HOST = '26.189.118.250'
PORT = 12345

clients = []
channels = {}

def client_handler(conn, addr):
    print(f"Подключен {addr}")
    current_channel = None
    while True:
        try:
            data = conn.recv(1024).decode('utf-8')
            if not data:
                break
            command, *args = data.strip().split()
            if command == "GET_CHANNELS":
                send_channels(conn)
            elif command == "CREATE_CHANNEL":
                channel_name = args[0]
                if channel_name not in channels:
                    channels[channel_name] = []
                    broadcast_channel_list(channel_name)
            elif command == "JOIN_CHANNEL":
                channel_name = args[0]
                if channel_name in channels:
                    if current_channel:
                        channels[current_channel].remove(conn)
                    channels[channel_name].append(conn)
                    current_channel = channel_name
            elif command == "LEAVE_CHANNEL":
                channel_name = args[0]
                if channel_name in channels and conn in channels[channel_name]:
                    channels[channel_name].remove(conn)
                    current_channel = None
            else:
                # Предполагаем, что это аудио данные
                audio_data = data.encode('utf-8') + conn.recv(4096)
                broadcast_audio(audio_data, current_channel, conn)
        except Exception as e:
            print(f"Ошибка с клиентом {addr}: {e}")
            break
    if current_channel and conn in channels.get(current_channel, []):
        channels[current_channel].remove(conn)
    clients.remove(conn)
    conn.close()
    print(f"Отключен {addr}")

def send_channels(conn):
    channel_list = " ".join(channels.keys())
    conn.sendall(f"CHANNELS {channel_list}".encode('utf-8'))

def broadcast_channel_list(new_channel):
    for client in clients:
        try:
            client.sendall(f"NEW_CHANNEL {new_channel}".encode('utf-8'))
        except:
            pass

def broadcast_audio(data, channel, sender_conn):
    if channel:
        for client in channels.get(channel, []):
            if client != sender_conn:
                try:
                    client.sendall(data)
                except:
                    pass

def main():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((HOST, PORT))
    server_socket.listen()
    print("Сервер запущен и ждет подключений...")
    while True:
        conn, addr = server_socket.accept()
        clients.append(conn)
        threading.Thread(target=client_handler, args=(conn, addr)).start()

if __name__ == "__main__":
    main()