# from playsound import playsound # import os # from tools.log import CustomLogger # class AudioPlayer: # def __init__(self,audio_file=None): # self.audio_file = audio_file # self.logger = CustomLogger(log_name=audio_file) # if audio_file: # self.logger.enable_file_logging() # def play(self,file_path,remove_file=True): # try: # if self.audio_file: # self.logger.log_info(f"Playing audio file: {file_path}") # playsound(file_path) # if remove_file: # os.remove(file_path) # except Exception as e: # self.logger.log_info(f"Error playing audio file: {e}") # if __name__ == "__main__": # player = AudioPlayer() # player.play('audio.wav') import pygame import os import threading import sys # current_dir = os.path.dirname(os.path.abspath(__file__)) # parent_parent_dir = os.path.abspath(os.path.join(current_dir, os.pardir, os.pardir)) # sys.path.append(parent_parent_dir) from tools.log import CustomLogger class AudioPlayer: _current_priority = -1 # 初始优先级为 -1,表示没有音频在播放 _current_thread = None # 当前播放的线程 def __init__(self, audio_file=None): self.audio_file = audio_file self.logger = CustomLogger() pygame.mixer.init() # 初始化混音器 pygame.mixer.music.set_volume(0.75) self.queue = [] # 音频播放队列 self.queue_lock = threading.Lock() # 用于同步队列的锁 self.is_playing_queue = False # 标志位,用于指示是否正在播放队列中的音频 self.queue_thread = None # 播放队列的线程 def play(self, file_path, remove_file=True, priority=10, fade_duration=5): """ 播放音频,并在播放结束时淡出。添加淡入淡出效果避免爆音。 :param file_path: 音频文件路径 :param remove_file: 是否在播放结束后删除文件 :param priority: 播放优先级 :param fade_duration: 淡入淡出效果的时长,单位为毫秒 """ if priority >= AudioPlayer._current_priority: # 检查优先级 if self.audio_file: self.logger.log_info( f"Stopping any ongoing audio with priority {AudioPlayer._current_priority} and playing new file with priority {priority}: {file_path}" ) # if pygame.mixer.music.get_busy(): # 检查是否有音频正在播放 # pygame.mixer.music.fadeout(fade_duration) # 使用fadeout淡出当前音频 # AudioPlayer._current_priority = priority # 更新当前播放的优先级 # AudioPlayer._current_thread = threading.current_thread() # 更新当前线程 # pygame.mixer.music.load(file_path) # 加载新的音频文件 # pygame.mixer.music.set_volume(0.75) # pygame.mixer.music.play(fade_ms=fade_duration) # 使用fade_ms淡入新的音频 AudioPlayer._current_priority = priority # 更新当前播放的优先级 AudioPlayer._current_thread = threading.current_thread() # 更新当前线程 pygame.mixer.music.load(file_path) # 加载新的音频文件 pygame.mixer.music.set_volume(0.75) pygame.mixer.music.play() while ( pygame.mixer.music.get_busy() and AudioPlayer._current_thread == threading.current_thread() ): # 等待音频播放结束 pygame.time.Clock().tick(10) if remove_file: os.remove(file_path) if ( AudioPlayer._current_thread == threading.current_thread() ): # 如果当前线程仍是播放线程 AudioPlayer._current_priority = -1 # 播放完成后重置优先级 else: if self.audio_file: self.logger.log_info( f"Skipped playing file {file_path} with lower priority {priority}" ) # 队列播放函数 def queue_play(self, file_path_list, priority=10): # 将文件路径和优先级添加到队列 with self.queue_lock: self.queue.append((file_path_list, priority)) # 如果没有在播放队列,启动一个线程开始播放 if not self.is_playing_queue: self.is_playing_queue = True self.queue_thread = threading.Thread(target=self._process_queue) self.queue_thread.start() # 处理队列中的音频播放 def _process_queue(self): while self.queue: # 取出队列中的第一个音频列表和优先级 with self.queue_lock: file_paths, priority = self.queue.pop(0) # 依次播放队列中的音频文件 for file_path in file_paths: self.play(file_path, remove_file=True, priority=priority) self.is_playing_queue = False # 队列播放完成后重置标志位 # 停止播放当前音频 def stop(self): if pygame.mixer.music.get_busy(): pygame.mixer.music.stop() # 停止当前播放 AudioPlayer._current_priority = -1 # 停止后重置优先级 AudioPlayer._current_thread = None # 清除当前线程 # 停止队列播放 def stop_queue(self): if self.queue_thread and self.queue_thread.is_alive(): self.queue = [] # 清空队列 self.is_playing_queue = False # 重置队列播放标志 self.stop() # 停止当前音频播放 if __name__ == "__main__": import time player = AudioPlayer() def thread_play(file_path, priority): player.play(file_path, priority=priority, remove_file=False) # 启动线程A,优先级为5 threading.Thread( target=thread_play, args=("/home/jsfb/jsfb_ws/MassageRobot_Dobot/Language/pre_mp3/按摩已结束.mp3", 10), ).start() # time.sleep(2) # 启动线程B,优先级为7(更高),强制停止A并播放新的音频 threading.Thread( target=thread_play, args=("/home/jsfb/jsfb_ws/MassageRobot_Dobot/Language/pre_mp3/我在/audio_1.mp3", 10), ).start() time.sleep(2) # 启动线程C,优先级为3(更低),不会打断线程B的播放 threading.Thread( target=thread_play, args=("/home/jsfb/jsfb_ws/MassageRobot_Dobot/Language/pre_mp3/完成复位.mp3", 3), ).start() time.sleep(2) # 启动线程D,优先级为5 threading.Thread( target=thread_play, args=("/home/jsfb/jsfb_ws/MassageRobot_Dobot/Language/pre_mp3/connect_successfully.mp3", 5), ).start() time.sleep(2)