feat: stereo support, updated pymumble.

This commit is contained in:
Terry Geng 2020-06-05 15:01:06 +08:00
parent 92b3a3c7be
commit 37082a82f3
No known key found for this signature in database
GPG Key ID: F982F8EA1DF720E7
4 changed files with 21 additions and 9 deletions

View File

@ -31,6 +31,7 @@ username = botamusique
comment = Hi, I'm here to play radio, local music or youtube/soundcloud music. Have fun! comment = Hi, I'm here to play radio, local music or youtube/soundcloud music. Have fun!
# default volume from 0 to 1. # default volume from 0 to 1.
volume = 0.1 volume = 0.1
stereo = True
# playback mode should be one of "one-shot", "repeat", "random", "autoplay" # playback mode should be one of "one-shot", "repeat", "random", "autoplay"
playback_mode = one-shot playback_mode = one-shot
autoplay_length = 5 autoplay_length = 5

View File

@ -39,6 +39,9 @@ port = 64738
# 'admin': Users allowed to kill the bot, or ban URLs. Separated by ';' # 'admin': Users allowed to kill the bot, or ban URLs. Separated by ';'
#admin = User1;User2; #admin = User1;User2;
# 'stereo': After 1.4.0, mumble starts to support stereo stream. Enable this option for stereo
# stream transmission. Otherwise the bot will down mix stereo sound into mono.
#stereo = True
# 'volume' is default volume from 0 to 1. # 'volume' is default volume from 0 to 1.
# This option will be overridden by value in the database. # This option will be overridden by value in the database.

View File

@ -38,12 +38,13 @@ class MumbleBot:
self.log.info(f"bot: botamusique version {self.version}, starting...") self.log.info(f"bot: botamusique version {self.version}, starting...")
signal.signal(signal.SIGINT, self.ctrl_caught) signal.signal(signal.SIGINT, self.ctrl_caught)
self.cmd_handle = {} self.cmd_handle = {}
self.volume_set = var.config.getfloat('bot', 'volume') self.volume_set = var.config.getfloat('bot', 'volume', fallback=0.1)
if var.db.has_option('bot', 'volume'): if var.db.has_option('bot', 'volume'):
self.volume_set = var.db.getfloat('bot', 'volume') self.volume_set = var.db.getfloat('bot', 'volume')
self.volume = self.volume_set self.volume = self.volume_set
self.stereo = var.config.getboolean('bot', 'stereo', fallback=True)
if args.channel: if args.channel:
self.channel = args.channel self.channel = args.channel
else: else:
@ -62,6 +63,7 @@ class MumbleBot:
self.song_start_at = -1 self.song_start_at = -1
self.last_ffmpeg_err = "" self.last_ffmpeg_err = ""
self.read_pcm_size = 0 self.read_pcm_size = 0
self.pcm_buffer_size = 0
# self.download_threads = [] # self.download_threads = []
self.wait_for_ready = False # flag for the loop are waiting for download to complete in the other thread self.wait_for_ready = False # flag for the loop are waiting for download to complete in the other thread
self.on_killing = threading.Lock() # lock to acquire when killing ffmpeg thread is asked but ffmpeg is not self.on_killing = threading.Lock() # lock to acquire when killing ffmpeg thread is asked but ffmpeg is not
@ -104,7 +106,9 @@ class MumbleBot:
self.username = var.config.get("bot", "username") self.username = var.config.get("bot", "username")
self.mumble = pymumble.Mumble(host, user=self.username, port=port, password=password, tokens=tokens, self.mumble = pymumble.Mumble(host, user=self.username, port=port, password=password, tokens=tokens,
debug=var.config.getboolean('debug', 'mumbleConnection'), certfile=certificate) stereo=self.stereo,
debug=var.config.getboolean('debug', 'mumbleConnection'),
certfile=certificate)
self.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_TEXTMESSAGERECEIVED, self.message_received) self.mumble.callbacks.set_callback(pymumble.constants.PYMUMBLE_CLBK_TEXTMESSAGERECEIVED, self.message_received)
self.mumble.set_codec_profile("audio") self.mumble.set_codec_profile("audio")
@ -369,8 +373,11 @@ class MumbleBot:
else: else:
ffmpeg_debug = "warning" ffmpeg_debug = "warning"
channels = 2 if self.stereo else 1
self.pcm_buffer_size = 960*channels
command = ("ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-i', command = ("ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-i',
uri, '-ss', f"{start_from:f}", '-ac', '1', '-f', 's16le', '-ar', '48000', '-') uri, '-ss', f"{start_from:f}", '-ac', str(channels), '-f', 's16le', '-ar', '48000', '-')
self.log.debug("bot: execute ffmpeg command: " + " ".join(command)) self.log.debug("bot: execute ffmpeg command: " + " ".join(command))
# The ffmpeg process is a thread # The ffmpeg process is a thread
@ -381,7 +388,7 @@ class MumbleBot:
else: else:
pipe_rd, pipe_wd = None, None pipe_rd, pipe_wd = None, None
self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480) self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=self.pcm_buffer_size)
def async_download_next(self): def async_download_next(self):
# Function start if the next music isn't ready # Function start if the next music isn't ready
@ -452,8 +459,8 @@ class MumbleBot:
self.song_start_at = time.time() - self.playhead self.song_start_at = time.time() - self.playhead
self.playhead = time.time() - self.song_start_at self.playhead = time.time() - self.song_start_at
raw_music = self.thread.stdout.read(480) raw_music = self.thread.stdout.read(self.pcm_buffer_size)
self.read_pcm_size += 480 self.read_pcm_size += self.pcm_buffer_size
if self.redirect_ffmpeg_log: if self.redirect_ffmpeg_log:
try: try:
@ -476,7 +483,8 @@ class MumbleBot:
if not self.is_pause and (self.thread is None or self.thread.poll() is not None): if not self.is_pause and (self.thread is None or self.thread.poll() is not None):
# bot is not paused, but ffmpeg thread has gone. # bot is not paused, but ffmpeg thread has gone.
# indicate that last song has finished, or the bot just resumed from pause, or something is wrong. # indicate that last song has finished, or the bot just resumed from pause, or something is wrong.
if self.read_pcm_size < 481 and len(var.playlist) > 0 and var.playlist.current_index != -1 \ if self.read_pcm_size < self.pcm_buffer_size and len(var.playlist) > 0 \
and var.playlist.current_index != -1 \
and self.last_ffmpeg_err: and self.last_ffmpeg_err:
current = var.playlist.current_item() current = var.playlist.current_item()
self.log.error("bot: cannot play music %s", current.format_debug_string()) self.log.error("bot: cannot play music %s", current.format_debug_string())

View File

@ -7,5 +7,5 @@ Pillow
mutagen mutagen
requests requests
packaging packaging
pymumble pymumble>=1.2
pyradios pyradios