def get_channel_list(server): mumble = Mumble(server, 'random_user', password='******', debug=False) mumble.start() mumble.is_ready() channels = [c['name'] for c in list(mumble.channels.values())[1:]] if mumble.is_alive(): mumble.connected = PYMUMBLE_CONN_STATE_NOT_CONNECTED mumble.control_socket.close() return channels
class MumbleClient: def __init__(self, config): debug = int(config['debug']) == 1 self.mumble = Mumble(config['host'], config['user'], debug=debug) self.mumble.start() self.mumble.is_ready() self.mumble.set_receive_sound(True) self.mumble.users.myself.unmute() self.mumble.channels.find_by_name(config['channel']).move_in() self.mumble.set_bandwidth(int(config['bandwith'])) self.mumble.callbacks.set_callback( constants.PYMUMBLE_CLBK_SOUNDRECEIVED, self.play_sound) self.output_device = alsaaudio.PCM( alsaaudio.PCM_PLAYBACK, alsaaudio.PCM_NONBLOCK, config['output']) self.output_device.setchannels(int(config['channels'])) self.output_device.setrate(int(config['bitrate'])) self.output_device.setformat(alsaaudio.PCM_FORMAT_S16_LE) self.output_device.setperiodsize(int(config['periodsize'])) self.input_device = alsaaudio.PCM( alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NONBLOCK, config['input']) self.input_device.setchannels(int(config['channels'])) self.input_device.setrate(int(config['bitrate'])) self.input_device.setformat(alsaaudio.PCM_FORMAT_S16_LE) self.input_device.setperiodsize(int(config['periodsize'])) def send_audio_chunk(self, audio_chunk): self.mumble.sound_output.add_sound(audio_chunk) def play_sound(self, info, sound_chunk): self.output_device.write(sound_chunk.pcm) def clear_input(self): self.input_device.read() def send_input_audio(self): length, data = self.input_device.read() if length: self.send_audio_chunk(data)
class MumbleListener: def __init__(self, server, nick, channel, debug=False): self.nick = nick.format(channel=channel) self.mumble = Mumble(server, self.nick, password='******', debug=debug) self.mumble.set_application_string( 'Audio Meter for Channel {}'.format(channel)) self.mumble.callbacks.set_callback(PYMUMBLE_CLBK_SOUNDRECEIVED, self.sound_received_handler) self.mumble.set_receive_sound(1) self.mumble.start() self.mumble.is_ready() if channel is not 'root': self.channel = self.mumble.channels.find_by_name(channel) self.channel.move_in() def sound_received_handler(self, user, sound): pass
class MumbleReceiver: def __init__(self, server, channel, file, nick='recv-{r}@{channel}', debug=False): r = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6)) self.channelname = channel self.nick = nick.format(r=r, channel=channel) self.mumble = Mumble(server, self.nick, password='******', debug=debug) self.mumble.set_application_string( 'Receiver for Channel {}'.format(channel)) if file: self.fd = open(file, "wb", 0o644) else: self.fd = os.fdopen(sys.stdout.fileno(), "wb", closefd=False) self.rate = 48000 self.interval = .02 # 20ms of samples self.mumble.set_receive_sound(1) self.mumble.start() self.mumble.is_ready() self.channel = self.mumble.channels.find_by_name(self.channelname) self.channel.move_in() self.thread = None self.start() def start(self): self.thread = threading.Thread(target=self.send, daemon=True) self.thread.start() def clip(self, val): return -32768 if val < -32768 else 32767 if val > 32767 else val def send(self): ts = time.time() - self.interval while True: start = time.time() buffer = array("h", [0] * int(self.interval * self.rate)) for user in self.channel.get_users(): samples = array("h") while len(samples) < len(buffer): sound = user.sound.get_sound(self.interval) if not sound: # print(f"not enough samples: {len(samples)} < {len(buffer)}", file=sys.stderr) break samples.frombytes(sound.pcm) if sys.byteorder == 'big': samples.byteswap() for i in range(0, len(samples)): buffer[i] = self.clip(buffer[i] + samples[i]) if sys.byteorder == 'big': buffer.byteswap() self.fd.write(buffer.tobytes()) wait = self.interval * 0.9 - (time.time() - start) if wait > 0: time.sleep(wait) while time.time() < ts: # spin until time is reached pass
global Sound stream_to_radio.write(sound.pcm) Sound = True #Callback for receiving audio from mumble mumble.callbacks.set_callback(constants.PYMUMBLE_CLBK_SOUNDRECEIVED, ProcessSound) #Set application name mumble.set_application_string("HamRadioLink") #Set codec profile mumble.set_codec_profile("audio") #Start mumble client mumble.start() #Wait to continue until we connect. mumble.is_ready() #Set bandwidth mumble.set_bandwidth(96000) #See if we actually connected. print("Connected: " + str(mumble.connected == constants.PYMUMBLE_CONN_STATE_CONNECTED)) #Enable callback if we are ready. mumble.set_receive_sound(ENABLE_TRANSMIT) stream_from_radio = PyAudio.open(48000, 1, pyaudio.paInt16, True, False, AUDIO_DEVICE_INDEX, None, 64, True, None, None, SendAudio) last_state = False #Used if transmitting.
class MumbleReceiver: def __init__(self, num, channel, config, mux): self.num = num self.muxer = mux server = config["address"] nick = config.get("nick", "mux-{r}") debug = config.get("debug", False) # def __init__(self, server, channel, nick='recv-{r}@{channel}', debug=False): r = "".join(random.choices(string.ascii_uppercase + string.digits, k=6)) self.channelname = channel self.nick = nick.format(r=r, channel=channel) print("connect mumble", server, self.nick) self.mumble = Mumble(server, self.nick, password="******", debug=debug) self.mumble.set_application_string( "Receiver for Channel {}".format(channel)) self.rate = 48000 self.interval = 0.02 # 20ms of samples self.mumble.set_receive_sound(1) self.mumble.start() self.mumble.is_ready() self.channel = self.mumble.channels.find_by_name(self.channelname) self.channel.move_in() self.thread = None self.start() def start(self): self.thread = threading.Thread(target=self.send, daemon=True) self.thread.start() def stop(self): self.thread.join() def clip(self, val): return -32768 if val < -32768 else 32767 if val > 32767 else val def send(self): ts = time.time() - self.interval while True: start = time.time() buffer = array("h", [0] * int(self.interval * self.rate)) for user in self.channel.get_users(): samples = array("h") while len(samples) < len(buffer): sound = user.sound.get_sound(self.interval) if not sound: # print(f"not enough samples: {len(samples)} < {len(buffer)}", file=sys.stderr) break samples.frombytes(sound.pcm) if sys.byteorder == "big": samples.byteswap() for i in range(0, len(samples)): buffer[i] = self.clip(buffer[i] + samples[i]) if sys.byteorder == "big": buffer.byteswap() self.muxer.push_audio(self.num, buffer) wait = self.interval * 1 - (time.time() - start) if wait > 0: time.sleep(wait)
class MumbleReceiver: def __init__(self, server, channel, dev, nick='recv-{r}@{channel}', use_cb=False, debug=False): r = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6)) self.channelname = channel self.nick = nick.format(r=r, channel=channel) self.mumble = Mumble(server, self.nick, password='******', debug=debug) self.mumble.set_application_string( 'Receiver for Channel {}'.format(channel)) audio = Audio() devinfo = audio.get_devinfo(dev, min_input_channels=0) if not devinfo: print(f"Unable to find output device \"{dev}\".", file=sys.stderr) print( f"use \"python -m c3lingo_mumble.audio\" to get a list of devices", file=sys.stderr) sys.exit(1) self.rate = 48000 self.interval = .02 # 20ms of samples self.mumble.set_receive_sound(1) self.mumble.start() self.mumble.is_ready() self.channel = self.mumble.channels.find_by_name(self.channelname) self.channel.move_in() self.thread = None if use_cb: callback = self.pyaudio_send else: callback = None self.stream = audio.pyaudio.open( format=audio.pyaudio.get_format_from_width(2), channels=1, rate=48000, output_device_index=devinfo['index'], output=True, stream_callback=callback) if use_cb: self.stream.start_stream() else: self.start() def start(self): self.thread = threading.Thread(target=self.send, daemon=True) self.thread.start() def clip(self, val): return -32768 if val < -32768 else 32767 if val > 32767 else val def get_audio(self): buffer = array("h", [0] * int(self.interval * self.rate)) for user in self.channel.get_users(): samples = array("h") while len(samples) < len(buffer): sound = user.sound.get_sound(self.interval) if not sound: break samples.frombytes(sound.pcm) if sys.byteorder == 'big': samples.byteswap() for i in range(0, len(samples)): buffer[i] = self.clip(buffer[i] + samples[i]) if sys.byteorder == 'big': samples.byteswap() for i in range(0, len(samples)): buffer[i] = self.clip(buffer[i] + samples[i]) if sys.byteorder == 'big': buffer.byteswap() return buffer.tobytes() def send(self): ts = time.time() - self.interval while True: start = time.time() self.stream.write(self.get_audio()) wait = self.interval * 0.9 - (time.time() - start) if wait > 0: time.sleep(wait) while time.time() < ts: # spin until time is reached pass def pyaudio_send(self, in_data, frame_count, time_info, status): data = self.get_audio() return (data, pyaudio.paContinue)