#!/usr/bin/env python

"""
beep.py - Make a beep sound

Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

import os
import sys
import wave  # 用于处理 WAV 文件格式

# 指定蜂鸣音频文件的路径
BEEP_WAV_FILENAME = os.path.join(os.path.dirname(__file__), "beep.wav")

def beep():
    """根据操作系统播放蜂鸣声。"""
    try:
        # 检测操作系统并调用相应的播放方法
        if sys.platform.startswith("win"):
            _win_wav_play(BEEP_WAV_FILENAME)  # Windows 系统使用 WAV 播放
        elif sys.platform.startswith("darwin"):
            _mac_beep()  # macOS 系统使用系统蜂鸣
        elif sys.platform.startswith("cygwin"):
            _cygwin_beep(BEEP_WAV_FILENAME)  # Cygwin 使用音频文件播放
        elif any(sys.platform.startswith(_) for _ in ("linux", "freebsd")):
            _linux_wav_play(BEEP_WAV_FILENAME)  # Linux 和 FreeBSD 系统使用 WAV 播放
        else:
            _speaker_beep()  # 其他系统使用控制台蜂鸣
    except:
        # 捕获异常并使用控制台蜂鸣
        _speaker_beep()

def _speaker_beep():
    """在控制台播放蜂鸣声（警报声）。"""
    sys.stdout.write('\a')  # 在现代 Linux 系统上可能无效

    try:
        sys.stdout.flush()  # 尝试刷新标准输出
    except IOError:
        pass  # 忽略任何 I/O 错误

# Cygwin 使用系统命令播放音频文件
def _cygwin_beep(filename):
    os.system("play-sound-file '%s' 2>/dev/null" % filename)

# macOS 系统使用 Carbon 库的 SysBeep 函数
def _mac_beep():
    import Carbon.Snd  # 导入 Carbon 库
    Carbon.Snd.SysBeep(1)  # 播放系统蜂鸣声

# Windows 系统播放 WAV 文件
def _win_wav_play(filename):
    import winsound  # 导入 winsound 库

    winsound.PlaySound(filename, winsound.SND_FILENAME)  # 播放指定的 WAV 文件

# Linux 系统播放 WAV 文件的实现
def _linux_wav_play(filename):
    # 尝试使用不同的命令播放音频文件
    for _ in ("aplay", "paplay", "play"):
        if not os.system("%s '%s' 2>/dev/null" % (_, filename)):
            return  # 成功播放音乐后返回

    import ctypes  # 导入 ctypes 库以调用 C 函数

    # PulseAudio 的相关常量定义
    PA_STREAM_PLAYBACK = 1
    PA_SAMPLE_S16LE = 3
    BUFFSIZE = 1024  # 缓冲区大小

    # 定义 PulseAudio 样本规格的结构
    class struct_pa_sample_spec(ctypes.Structure):
        _fields_ = [("format", ctypes.c_int), ("rate", ctypes.c_uint32), ("channels", ctypes.c_uint8)]

    try:
        pa = ctypes.cdll.LoadLibrary("libpulse-simple.so.0")  # 加载 PulseAudio 库
    except OSError:
        return  # 如果加载失败，则返回

    # 打开 WAV 文件
    wave_file = wave.open(filename, "rb")

    # 设置 PulseAudio 样本规格
    pa_sample_spec = struct_pa_sample_spec()
    pa_sample_spec.rate = wave_file.getframerate()  # 获取采样频率
    pa_sample_spec.channels = wave_file.getnchannels()  # 获取声道数
    pa_sample_spec.format = PA_SAMPLE_S16LE  # 设置样本格式

    error = ctypes.c_int(0)

    # 创建 PulseAudio 流
    pa_stream = pa.pa_simple_new(None, filename, PA_STREAM_PLAYBACK, None,
                                  "playback", ctypes.byref(pa_sample_spec), None, None, ctypes.byref(error))
    if not pa_stream:
        raise Exception("Could not create pulse audio stream: %s" % pa.strerror(ctypes.byref(error)))

    while True:
        # 获取延迟
        latency = pa.pa_simple_get_latency(pa_stream, ctypes.byref(error))
        if latency == -1:
            raise Exception("Getting latency failed")

        buf = wave_file.readframes(BUFFSIZE)  # 从 WAV 文件读取帧
        if not buf:
            break  # 如果没有更多帧可读，退出循环

        # 播放读取的帧
        if pa.pa_simple_write(pa_stream, buf, len(buf), ctypes.byref(error)):
            raise Exception("Could not play file")

    wave_file.close()  # 关闭 WAV 文件

    # 确保所有数据都已播放完成
    if pa.pa_simple_drain(pa_stream, ctypes.byref(error)):
        raise Exception("Could not simple drain")

    pa.pa_simple_free(pa_stream)  # 释放 PulseAudio 流资源

if __name__ == "__main__":
    beep()  # 调用蜂鸣函数