import argparse import audioop import logging import sys import time from functools import partial import pymumble_py3 as pymumble from pymumble_py3.constants import PYMUMBLE_CLBK_TEXTMESSAGERECEIVED is_streaming = False silence_time = 0 def message_received(mumble, message): global is_streaming global silence_time command = message.message if command == "/start": is_streaming = True silence_time = 0 mumble.my_channel().send_text_message("Diretta iniziata") logging.info("Diretta iniziata") mumble.users.myself.recording() elif command == "/stop": is_streaming = False mumble.my_channel().send_text_message("Diretta terminata") logging.info("Diretta terminata") mumble.users.myself.unrecording() def get_parser(): parser = argparse.ArgumentParser(description="Regia pienamente automatizzata") parser.add_argument("--channel", help="Set channel", default="") parser.add_argument("--name", help="Set bot nickname", default="RadioRobbot") parser.add_argument("--server", help="Set server", default="mumble.esiliati.org") parser.add_argument("--port", help="Set port", type=int, default=64738) parser.add_argument( "--stream", action="store_true", help="Ignore commands in chat and stream everything", ) parser.add_argument( "--auto-suspend-stream", action="store_true", help="Ignore commands in chat and stream everything", ) parser.add_argument( "--max-silence-time", type=int, help="max silence time in seconds", default=30 ) return parser def main(): global is_streaming global silence_time args = get_parser().parse_args() logging.basicConfig(level=logging.DEBUG) pwd = "" # password server = args.server nick = args.name channel = args.channel port = args.port is_streaming = False stream_always = args.stream # Spin up a client and connect to mumble server mumble = pymumble.Mumble(server, nick, password=pwd, port=port) mumble.callbacks.set_callback( PYMUMBLE_CLBK_TEXTMESSAGERECEIVED, partial(message_received, mumble) ) mumble.set_receive_sound(1) # Enable receiving sound from mumble server mumble.start() mumble.is_ready() # Wait for client is ready mumble.channels.find_by_name(channel).move_in() mumble.users.myself.mute() if is_streaming: mumble.users.myself.recording() BUFFER = 0.1 BITRATE = 48000 RESOLUTION = 10 # in ms FLOAT_RESOLUTION = float(RESOLUTION) / 1000 MONO_CHUNK_SIZE = BITRATE * 2 * RESOLUTION / 1000 STEREO_CHUNK_SIZE = MONO_CHUNK_SIZE * 2 silent = b"\x00" * int(STEREO_CHUNK_SIZE) cursor_time = time.time() - BUFFER while mumble.is_alive(): if cursor_time < time.time() - BUFFER: base_sound = None try: for user in mumble.users.values(): # check the audio queue of each user if user.sound.is_sound(): # available sound is to be treated now and not later sound = user.sound.get_sound(FLOAT_RESOLUTION) stereo_pcm = audioop.tostereo(sound.pcm, 2, 1, 1) if base_sound is None: base_sound = stereo_pcm else: base_sound = audioop.add(base_sound, stereo_pcm, 2) except RuntimeError: print("ignored exception in stderr...", file=sys.stderr) if is_streaming or stream_always: if base_sound: silence_time = 0 sys.stdout.buffer.write(base_sound) else: silence_time += RESOLUTION sys.stdout.buffer.write(silent) if ( args.auto_suspend_stream and (silence_time >= args.max_silence_time * 1000) and is_streaming ): is_streaming = False logging.info("max-silence-time reached") mumble.my_channel().send_text_message( "Diretta terminata in automatico dopo %d secondi circa di silenzio" % args.max_silence_time ) mumble.users.myself.unrecording() cursor_time += FLOAT_RESOLUTION else: time.sleep(FLOAT_RESOLUTION) if __name__ == "__main__": main()