"ossaudiodev"  --- 访问兼容OSS的音频设备
****************************************

======================================================================

该模块允许您访问 OSS（开放式音响系统）音频接口。 OSS 可用于广泛的开源
和商业 Unices，并且是 Linux 和最新版本的 FreeBSD 的标准音频接口。

3.3 版更變: 此模块中过去会引发 "IOError" 的操作现在将引发 "OSError"。

也參考:

  开放之声系统程序员手册
     OSS C API 的官方文档

  该模块定义了大量由OSS设备驱动提供的常量； 请参阅
  ``<sys/soundcard.h>`` Linux 或 FreeBSD 上的列表。

"ossaudiodev" 定义了下列变量和函数:

exception ossaudiodev.OSSAudioError

   此异常会针对特定错误被引发。 其参数为一个描述错误信息的字符串。

   （如果 "ossaudiodev" 从系统调用例如 "open()", "write()" 或
   "ioctl()" 接收到错误，它将引发 "OSError"。 由 "ossaudiodev" 直接检
   测到的错误将引发 "OSSAudioError"。）

   （为了向下兼容，此异常类也可通过 "ossaudiodev.error" 访问。）

ossaudiodev.open(mode)
ossaudiodev.open(device, mode)

   打开一个音频设备并返回 OSS 音频设备对象。 此对象支持许多文件类方法
   ，例如 "read()", "write()" 和 "fileno()" (不过传统的 Unix 读/写语义
   与 OSS 音频设备的存在一些细微的差异)。 它还支持一些音频专属的方法；
   完整的方法列表见下文。

   *device* 是要使用的音频设备文件名。 如果未指定，则此模块会先在环境
   变量 "AUDIODEV" 中查找要使用的设备。 如果未找到，它将回退为
   "/dev/dsp"。

   *mode* 可以为 "'r'" 表示只读（录音）访问，"'w'" 表示只写（回放）访
   问以及 "'rw'" 表示同时读写。 由于许多声卡在同一时间只允许单个进程打
   开录音机或播放器，因此好的做法是只根据活动的需要打开设备。 并且，有
   些声卡是半双工的：它们可以被打开用于读取或写入，但不能同时读写。

   请注意这里特殊的调用语法: *first* 参数是可选的，而第二个参数则是必
   需的。 这是出于历史原因要与 "ossaudiodev" 所替代的 "linuxaudiodev"
   模块保持兼容。

ossaudiodev.openmixer([device])

   打开一个混音设备并返回 OSS 混音设备对象。 *device* 是要使用的混音设
   备文件名。 如果未指定，则此模块会先在环境变量 "MIXERDEV" 中查找要使
   用的设备。 如果未找到，它将回退为 "/dev/mixer"。


音频设备对象
============

在你写入或读取音频设备之前，你必须按照正确的顺序调用三个方法:

1. "setfmt()" 设置输出格式

2. "channels()" 设置声道数量

3. "speed()" 设置采样率

或者，你也可以使用 "setparameters()" 方法一次性地设置全部三个音频参数
。 这更为便捷，但可能不会在所有场景下都一样灵活。

"open()" 所返回的音频设备对象定义了下列方法和（只读）属性:

oss_audio_device.close()

   显式地关闭音频设备。 当你完成写入或读取音频设备后，你应当显式地关闭
   它。 已关闭的设备不可被再次使用。

oss_audio_device.fileno()

   返回与设备相关联的文件描述符。

oss_audio_device.read(size)

   从音频输入设备读取 *size* 个字节并返回为 Python 字符串。 与大多数
   Unix 设备驱动不同，处于阻塞模式（默认）的 OSS 音频设备将阻塞
   "read()" 直到所请求大小的数据全部可用。

oss_audio_device.write(data)

   将一个 *bytes-like object* *data* 写入音频设备并返回写入的字节数。
   如果音频设备处于阻塞模式（默认），则总是会写入完整数据（这还是不同
   于通常的 Unix 设备语义）。 如果设备处于非阻塞模式，则可能会有部分数
   据未被写入 --- 参见 "writeall()"。

   3.5 版更變: 现在支持可写的 *字节类对象*。

oss_audio_device.writeall(data)

   将一个 *bytes-like object* *data* 写入音频设备：等待直到音频设备能
   够接收数据，将根据其所能接收的数据量尽可能多地写入，并重复操作直至
   *data* 被完全写入。 如果设备处于阻塞模式（默认），则其效果与
   "write()" 相同；"writeall()" 仅适用于非阻塞模式。 它没有返回值，因
   为写入的数据量总是等于所提供的数据量。

   3.5 版更變: 现在支持可写的 *字节类对象*。

3.2 版更變: 音频设备对象还支持上下文管理协议，就是说它们可以在 "with"
语句中使用。

下列方法各自映射一个 "ioctl()" 系统调用。 对应关系很明显：例如，
"setfmt()" 对应 "SNDCTL_DSP_SETFMT" ioctl，而 "sync()" 对应
"SNDCTL_DSP_SYNC" (这在查阅 OSS 文档时很有用)。 如果下层的 "ioctl()"
失败，它们将引发 "OSError"。

oss_audio_device.nonblock()

   将设备转为非阻塞模式。 一旦处于非阻塞模式，将无法将其转回阻塞模式。

oss_audio_device.getfmts()

   返回声卡所支持的音频输出格式的位掩码。 OSS 支持的一部分格式如下:

   +---------------------------+-----------------------------------------------+
   | 文件格式                  | 描述                                          |
   |===========================|===============================================|
   | "AFMT_MU_LAW"             | 一种对数编码格式（被 Sun ".au" 文件和         |
   |                           | "/dev/audio" 所使用）                         |
   +---------------------------+-----------------------------------------------+
   | "AFMT_A_LAW"              | 一种对数编码格式                              |
   +---------------------------+-----------------------------------------------+
   | "AFMT_IMA_ADPCM"          | 一种 4:1 压缩格式，由 Interactive Multimedia  |
   |                           | Association 定义                              |
   +---------------------------+-----------------------------------------------+
   | "AFMT_U8"                 | 无符号的 8 位音频                             |
   +---------------------------+-----------------------------------------------+
   | "AFMT_S16_LE"             | 有符号的 16 位音频，采用小端字节序（如 Intel  |
   |                           | 处理器所用的）                                |
   +---------------------------+-----------------------------------------------+
   | "AFMT_S16_BE"             | 有符号的 16 位音频，采用大端字节序（如 68k,   |
   |                           | PowerPC, Sparc 所用的）                       |
   +---------------------------+-----------------------------------------------+
   | "AFMT_S8"                 | 有符号的 8 位音频                             |
   +---------------------------+-----------------------------------------------+
   | "AFMT_U16_LE"             | 无符号的 16 位小端字节序音频                  |
   +---------------------------+-----------------------------------------------+
   | "AFMT_U16_BE"             | 无符号的 16 位大端字节序音频                  |
   +---------------------------+-----------------------------------------------+

   请参阅 OSS 文档获取音频格式的完整列表，还要注意大多数设备都只支持这
   些列表的一个子集。 某些较旧的设备仅支持 "AFMT_U8"；目前最为常用的格
   式是 "AFMT_S16_LE"。

oss_audio_device.setfmt(format)

   尝试将当前音频格式设为 *format* --- 请参阅 "getfmts()" 获取格式列表
   。 返回为设备设置的音频格式，这可能并非所请求的格式。 也可被用来返
   回当前音频格式 --- 这可以通过传入特殊的 "音频格式" "AFMT_QUERY" 来
   实现。

oss_audio_device.channels(nchannels)

   将输出声道数设为 *nchannels*。 值为 1 表示单声道，2 表示立体声。 某
   些设备可能拥有 2 个以上的声道，并且某些高端设备还可能不支持单声道。
   返回为设备设置的声道数。

oss_audio_device.speed(samplerate)

   尝试将音频采样率设为每秒 *samplerate* 次采样。 返回实际设置的采样率
   。 大多数设备都不支持任意的采样率。 常见的采样率为:

   +---------+---------------------------------------------+
   | 采样率  | 描述                                        |
   |=========|=============================================|
   | 8000    | "/dev/audio" 的默认采样率                   |
   +---------+---------------------------------------------+
   | 11025   | 语音录音                                    |
   +---------+---------------------------------------------+
   | 22050   |                                             |
   +---------+---------------------------------------------+
   | 44100   | CD品质的音频（16位采样和2通道）             |
   +---------+---------------------------------------------+
   | 96000   | DVD品质的音频（24位采样）                   |
   +---------+---------------------------------------------+

oss_audio_device.sync()

   等待直到音频设备播放完其缓冲区中的所有字节。 （这会在设备被关闭时隐
   式地发生。） OSS 建议关闭再重新打开设备而不是使用 "sync()"。

oss_audio_device.reset()

   立即停止播放或录制并使设备返回可接受命令的状态。 OSS 文档建议在调用
   "reset()" 之后关闭并重新打开设备。

oss_audio_device.post()

   告知设备在输出中可能有暂停，使得设备可以更智能地处理暂停。 你可以在
   播放一个定点音效之后、等待用户输入之前或执行磁盘 I/O 之前使用此方法
   。

下列便捷方法合并了多个 ioctl，或是合并了一个 ioctl 与某些简单的运算。

oss_audio_device.setparameters(format, nchannels, samplerate[, strict=False])

   在一次方法调用中设置关键的音频采样参数 --- 采样格式、声道数和采样率
   。 *format*,  *nchannels* 和 *samplerate* 应当与在 "setfmt()",
   "channels()" 和 "speed()"  方法中所指定的一致。 如果 *strict* 为真
   值，则 "setparameters()" 会检查每个参数是否确实被设置为所请求的值，
   如果不是则会引发 "OSSAudioError"。 返回一个元组 (*format*,
   *nchannels*, *samplerate*) 指明由设备驱动实际设置的参数值 (即与
   "setfmt()", "channels()" 和 "speed()" 的返回值相同)。

   例如，:

      (fmt, channels, rate) = dsp.setparameters(fmt, channels, rate)

   等价于

      fmt = dsp.setfmt(fmt)
      channels = dsp.channels(channels)
      rate = dsp.rate(rate)

oss_audio_device.bufsize()

   返回硬件缓冲区的大小，以采样数表示。

oss_audio_device.obufcount()

   返回硬件缓冲区中待播放的采样数。

oss_audio_device.obuffree()

   返回可以被加入硬件缓冲区队列以非阻塞模式播放的采样数。

音频设备对象还支持几个只读属性:

oss_audio_device.closed

   指明设备是否已被关闭的布尔值。

oss_audio_device.name

   包含设备文件名称的字符串。

oss_audio_device.mode

   文件的 I/O 模式，可以为 ""r"", ""rw"" 或 ""w""。


混音器设备对象
==============

混音器对象提供了两个文件类方法:

oss_mixer_device.close()

   此方法会关闭打开的混音器设备文件。 在文件被关闭后任何继续使用混音器
   的尝试都将引发 "OSError"。

oss_mixer_device.fileno()

   返回打开的混音器设备文件的文件处理句柄号。

3.2 版更變: 混音器设备还支持上下文管理协议。

其余方法都是混音专属的:

oss_mixer_device.controls()

   此方法返回一个表示可用的混音控件的位掩码 ("控件" 是专用的可混合 "声
   道"，例如 "SOUND_MIXER_PCM" 或 "SOUND_MIXER_SYNTH")。 该掩码会指定
   所有可用混音控件的一个子集 --- 它们是在模块层级上定义的
   "SOUND_MIXER_*" 常量。 举例来说，要确定当前混音器对象是否支持 PCM
   混音器，就使用以下 Python 代码:

      mixer=ossaudiodev.openmixer()
      if mixer.controls() & (1 << ossaudiodev.SOUND_MIXER_PCM):
          # PCM is supported
          ... code ...

   对于大多数目的来说，"SOUND_MIXER_VOLUME" (主音量) 和
   "SOUND_MIXER_PCM" 控件应该足够了 --- 但使用混音器的代码应当在选择混
   音器控件时保持灵活。 例如在 Gravis Ultrasound 上，
   "SOUND_MIXER_VOLUME" 是不存在的。

oss_mixer_device.stereocontrols()

   返回一个表示立体声混音控件的位掩码。 如果设置了比特位，则对应的控件
   就是立体声的；如果未设置，则控件为单声道或者不被混音器所支持（请配
   合 "controls()" 使用以确定是哪种情况）。

   请查看 "controls()" 函数的代码示例了解如何从位掩码获取数据。

oss_mixer_device.reccontrols()

   返回一个指明可被用于录音的混音器控件的位掩码。 请查看 "controls()"
   的代码示例了解如何读取位掩码。

oss_mixer_device.get(control)

   返回给定混音控件的音量。 返回的音量是一个 2 元组
   "(left_volume,right_volume)"。 音量被表示为从 0 (静音) 到 100 (最大
   音量) 的数字。 如果控件是单声道的，仍然会返回一个 2 元组，但两个音
   量必定相同。

   如果指定了无效的控件则会引发 "OSSAudioError"，或者如果指定了不受支
   持的控件则会引发 "OSError"。

oss_mixer_device.set(control, (left, right))

   将给定混音控件的音量设为 "(left,right)"。 "left" 和 "right" 必须为
   整数并在 0 (静音) 至 100 (最大音量) 之间。 当执行成功的，新的音量将
   以 2 元组形式返回。 请注意这可能不完全等于所指定的音量，因为某些声
   卡的混音器有精度限制。

   如果指定了无效的混音控件，或者指定的音量超出限制则会引发
   "OSSAudioError"。

oss_mixer_device.get_recsrc()

   此方法返回一个表示当前被用作录音源的的控件的位掩码。

oss_mixer_device.set_recsrc(bitmask)

   调用此函数来指定一个录音源。 如果成功则返回一个指明新录音源的位掩码
   ；如果指定了无效的源则会引发 "OSError"。 如果要将当前录音源设为麦克
   风输入:

      mixer.setrecsrc (1 << ossaudiodev.SOUND_MIXER_MIC)
