|
@@ -1,107 +1,136 @@
|
|
|
-import pymumble_py3 as pymumble
|
|
|
-from pymumble_py3.constants import *
|
|
|
-import subprocess as sp
|
|
|
-import time
|
|
|
-import sys
|
|
|
-import os
|
|
|
-import fcntl
|
|
|
-import audioop
|
|
|
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(message):
|
|
|
+def message_received(mumble, message):
|
|
|
global is_streaming
|
|
|
global silence_time
|
|
|
- command=message.message
|
|
|
+ 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()
|
|
|
-
|
|
|
-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)
|
|
|
-
|
|
|
-sys.argv.pop(0)
|
|
|
-args = parser.parse_args(sys.argv)
|
|
|
-
|
|
|
-
|
|
|
-pwd = "" # password
|
|
|
-server = args.server
|
|
|
-nick = args.name
|
|
|
-channel = args.channel
|
|
|
-port = args.port
|
|
|
-is_streaming=False
|
|
|
-stream_always= args.stream
|
|
|
-auto_suspend_stream = args.auto_suspend_stream
|
|
|
-silence_limit = 30
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-# 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, message_received)
|
|
|
-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 = None
|
|
|
-cursor_time = time.time() - BUFFER
|
|
|
-silence_time = 0
|
|
|
-silence_limit_ms = silence_limit * 1000
|
|
|
-
|
|
|
-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 == 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 auto_suspend_stream and (silence_time >= silence_limit_ms) and is_streaming:
|
|
|
- is_streaming = False
|
|
|
- mumble.my_channel().send_text_message("Diretta terminata in automatico dopo "+str(silence_limit)+" secondi circa di silenzio")
|
|
|
- mumble.users.myself.unrecording()
|
|
|
-
|
|
|
- cursor_time += FLOAT_RESOLUTION
|
|
|
- else:
|
|
|
- time.sleep(FLOAT_RESOLUTION)
|
|
|
+
|
|
|
+
|
|
|
+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()
|