Python如何实现不依赖外接扬声器调用主板蜂鸣器发声
问题
想咨询Windows平台下是否存在Python实现方案,可独立于电脑外接扬声器,直接驱动系统/主板蜂鸣器发出蜂鸣音。
目前正在编写Windows平台的电脑空闲时长统计脚本,脚本会将空闲时段的起止时间写入文本文件,用于门店场景下配合监控系统核查店内是否有人员值守:用户临时离店后,可通过日志核对对应时段的空闲情况。需要脚本触发提示时,通过主板蜂鸣器发声提醒用户移动鼠标。
现有修改后的代码如下:
import ctypes, ctypes.wintypes from time import strftime from datetime import datetime class LASTINPUTINFO(ctypes.Structure): _fields_ = [ ('cbSize', ctypes.wintypes.UINT), ('dwTime', ctypes.wintypes.DWORD), ] PLASTINPUTINFO = ctypes.POINTER(LASTINPUTINFO) user32 = ctypes.windll.user32 GetLastInputInfo = user32.GetLastInputInfo GetLastInputInfo.restype = ctypes.wintypes.BOOL GetLastInputInfo.argtypes = [PLASTINPUTINFO] kernel32 = ctypes.windll.kernel32 GetTickCount = kernel32.GetTickCount Sleep = kernel32.Sleep def wait_until_idle(idle_time=60): idle_time_ms = int(idle_time*1000) liinfo = LASTINPUTINFO() liinfo.cbSize = ctypes.sizeof(liinfo) while True: GetLastInputInfo(ctypes.byref(liinfo)) elapsed = GetTickCount() - liinfo.dwTime if elapsed>=idle_time_ms: break Sleep(idle_time_ms - elapsed or 1) def wait_until_active(tol=5): liinfo = LASTINPUTINFO() liinfo.cbSize = ctypes.sizeof(liinfo) lasttime = None delay = 1 # ms maxdelay = int(tol*1000) while True: GetLastInputInfo(ctypes.byref(liinfo)) if lasttime is None: lasttime = liinfo.dwTime if lasttime != liinfo.dwTime: break delay = min(2*delay, maxdelay) Sleep(delay) def test(): string = strftime('%I:%M:%S %p ') string2 = strftime('%A %d-%b-%Y') new_line = '\n' wait_until_idle(600) user32.MessageBeep(0) with open("D:\idle.txt", "a") as f: f.write(new_line + string + string2 + ' Start') test() def test2(): wait_until_active(1) user32.MessageBeep(0) now = datetime.now() string = now.strftime('%I:%M:%S %p ') string2 = now.strftime('%A %d-%b-%Y') new_line = '\n' with open("D:\idle.txt", "a") as f: f.write(new_line + string + string2 + ' End') test2() while True: duration1 = test() duration2 = test2() print(duration1) print(duration2)
解答
- 现有代码里使用的
user32.MessageBeep()默认走系统音频通道,声音从外接扬声器/声卡输出,不会直接驱动主板原生蜂鸣器。要实现独立于外接音频设备驱动主板蜂鸣器,直接调用Windows kernel32提供的原生Beep接口即可,这个接口直接向主板蜂鸣器硬件发送控制指令,不依赖系统音频服务。 - 调用方法很简单,在现有代码加载kernel32的部分,补充绑定Beep函数即可:
# 补充在现有kernel32相关定义的后面 Beep = kernel32.Beep Beep.restype = ctypes.wintypes.BOOL Beep.argtypes = [ctypes.wintypes.DWORD, ctypes.wintypes.DWORD]
Beep函数接收两个参数:第一个是蜂鸣频率,单位为Hz,取值范围37~32767;第二个是蜂鸣持续时长,单位为毫秒。
- 替换代码里原来的
user32.MessageBeep(0)即可触发主板蜂鸣,比如空闲超时的时候用3次短蜂提醒,辨识度更高:
# 替换原有的user32.MessageBeep(0) for _ in range(3): Beep(1200, 200) Sleep(100)
- 注意事项:
- 近年新出的消费级主板大多已经取消板载原生蜂鸣器(需要单独接主板SPEAKER插针的小蜂鸣器才会有对应硬件),这类设备上Windows会自动把Beep调用重定向到默认声卡播放,没有原生蜂鸣器硬件无法实现完全脱离扬声器发声。
- 64位Windows系统默认禁用蜂鸣器内核驱动,如果调用无反应,需要用管理员权限打开命令提示符,执行
sc config beep start= system后重启电脑,开启原生蜂鸣器支持。 - 现有代码存在逻辑冗余:进入while循环前已经手动调用了一次
test()和test2(),会导致第一次空闲记录重复写入,且两个函数没有设置返回值,循环里打印的duration1、duration2始终为None,删掉循环外单独的test()、test2()调用即可。
内容的提问来源于stack exchange,提问作者Mohamed Hussein
相关产品推荐
相关产品推荐

