Android 音频

Android OS 为多媒体提供广泛的支持,包括音频和视频。 本指南重点介绍 Android 中的音频,介绍如何使用内置音频播放器和录音机类以及低级别音频 API 播放和录制音频。 它还介绍如何使用由其他应用程序广播的音频事件,以便开发人员可以生成行为良好的应用程序。

概述

现代移动设备采用了以前需要专用设备(相机、音乐播放器和视频录制器)的功能。 因此,多媒体框架已成为移动 API 中的一流功能。

Android 提供对多媒体的广泛支持。 本文介绍在 Android 中使用音频,并涵盖以下主题

  1. 使用 MediaPlayer 播放音频 - 使用内置 MediaPlayer 类播放音频,包括本地音频文件和带有 类的 AudioTrack 流音频文件。

  2. 录制音频 - 使用内置 MediaRecorder 类录制音频。

  3. 使用音频通知 - 使用音频通知创建行为良好的应用程序,这些应用程序通过暂停或取消音频输出来正确响应事件 (例如传入电话呼叫) 。

  4. 使用 Low-Level 音频 – 通过直接写入内存缓冲区来使用 AudioTrack 类播放音频。 使用 类录制音频, AudioRecord 并直接从内存缓冲区读取。

要求

本指南需要 Android 2.0 (API 级别 5) 或更高版本。 请注意,必须在设备上调试 Android 上的音频。

有必要在 AndroidManifest.XML中请求RECORD_AUDIO权限:

已启用RECORD_AUDIO的 Android 清单所需的权限部分

使用 MediaPlayer 类播放音频

在 Android 中播放音频的最简单方法是使用内置的 MediaPlayer 类。 MediaPlayer 可以通过传入文件路径来播放本地文件或远程文件。 但是, MediaPlayer 非常区分状态,在错误状态下调用其方法之一将导致引发异常。 请务必按照下述顺序与 MediaPlayer 交互,以避免错误。

初始化和播放

使用 MediaPlayer 播放音频需要以下顺序:

  1. 实例化新的 MediaPlayer 对象。

  2. 将文件配置为通过 SetDataSource 方法播放。

  3. 调用 Prepare 方法以初始化播放器。

  4. 调用 Start 方法以开始播放音频。

下面的代码示例演示了此用法:

protected MediaPlayer player;
public void StartPlayer(String  filePath)
{
  if (player == null) {
    player = new MediaPlayer();
  } else {
    player.Reset();
    player.SetDataSource(filePath);
    player.Prepare();
    player.Start();
  }
}

暂停和恢复播放

可以通过调用 Pause 方法暂停播放:

player.Pause();

若要恢复暂停的播放,请调用 Start 方法。 此操作将从播放中的暂停位置恢复:

player.Start();

在播放器上调用 Stop 方法将结束正在进行的播放:

player.Stop();

当不再需要播放器时,必须通过调用 Release 方法释放资源:

player.Release();

使用 MediaRecorder 类录制音频

在 Android 中录制音频的推论 MediaPlayerMediaRecorder 类。 与 一样, MediaPlayer它是状态敏感的,并通过多个状态转换,以达到可以开始录制的地步。 若要录制音频, RECORD_AUDIO 必须设置权限。 有关如何设置应用程序权限的说明 ,请参阅使用 AndroidManifest.xml

初始化和录制

使用 MediaRecorder 录制音频需要执行以下步骤:

  1. 实例化新的 MediaRecorder 对象。

  2. 指定用于通过 SetAudioSource 方法捕获音频输入的硬件设备。

  3. 使用 SetOutputFormat 方法设置输出文件音频格式。 有关支持的音频类型的列表,请参阅 Android 支持的媒体格式

  4. 调用 SetAudioEncoder 方法以设置音频编码类型。

  5. 调用 SetOutputFile 方法以指定将音频数据写入到的输出文件的名称。

  6. 调用 Prepare 方法以初始化记录器。

  7. 调用 Start 方法开始录制。

以下代码示例演示了此序列:

protected MediaRecorder recorder;
void RecordAudio (String filePath)
{
  try {
    if (File.Exists (filePath)) {
      File.Delete (filePath);
    }
    if (recorder == null) {
      recorder = new MediaRecorder (); // Initial state.
    } else {
      recorder.Reset ();
      recorder.SetAudioSource (AudioSource.Mic);
      recorder.SetOutputFormat (OutputFormat.ThreeGpp);
      recorder.SetAudioEncoder (AudioEncoder.AmrNb);
      // Initialized state.
      recorder.SetOutputFile (filePath);
      // DataSourceConfigured state.
      recorder.Prepare (); // Prepared state
      recorder.Start (); // Recording state.
    }
  } catch (Exception ex) {
    Console.Out.WriteLine( ex.StackTrace);
  }
}

正在停止录制

若要停止录制,请在 StopMediaRecorder调用 方法:

recorder.Stop();

清理

MediaRecorder停止后,调用 Reset 方法将其恢复为空闲状态:

recorder.Reset();

MediaRecorder不再需要 时,必须通过调用 Release 方法释放其资源:

recorder.Release();

管理音频通知

AudioManager 类

AudioManager 类提供对音频通知的访问,让应用程序知道何时发生音频事件。 此服务还允许访问其他音频功能,例如音量和铃声模式控制。 允许 AudioManager 应用程序处理音频通知以控制音频播放。

管理音频焦点

设备 (内置播放器和录音机) 的音频资源由所有正在运行的应用程序共享。

从概念上讲,这类似于桌面计算机上的应用程序,其中只有一个应用程序具有键盘焦点:通过鼠标单击选择其中一个正在运行的应用程序后,键盘输入将仅转到该应用程序。

音频焦点是一个类似的想法,可以防止多个应用程序同时播放或录制音频。 它比键盘焦点更复杂,因为它是自愿的 - 应用程序可以忽略它当前没有音频焦点的事实,并播放无论如何 - 并且有不同类型的音频焦点可以请求。 例如,如果请求者只预期在很短的时间内播放音频,则它可能会请求暂时性焦点。

音频焦点可以立即授予,或者最初拒绝,稍后再授予。 例如,如果应用程序在电话呼叫期间请求音频焦点,它将被拒绝,但很可能在电话呼叫完成后授予焦点。 在这种情况下,将注册侦听器,以便在音频焦点被移走时相应地做出响应。 请求音频焦点用于确定播放或录制音频是否正常。

有关音频焦点的详细信息,请参阅 管理音频焦点

注册音频焦点的回调

FocusChangeListenerIOnAudioChangeListener 注册回调是获取和释放音频焦点的一个重要部分。 这是因为音频焦点的授予可能会推迟到以后的时间。 例如,应用程序可能会请求在进行电话呼叫时播放音乐。 在电话呼叫完成之前,不会授予音频焦点。

出于此原因,回调对象作为参数传递到 GetAudioFocusAudioManager方法中,并且正是此调用注册了回调。 如果最初拒绝音频焦点,但后来又授予了音频焦点,则应用程序将通过调用 OnAudioFocusChange 回调来通知应用程序。 相同的方法用于告知应用程序音频焦点正在被夺走。

当应用程序使用完音频资源后,它会调用 AbandonFocusAudioManager方法,并再次传入回调。 这会取消注册回调并释放音频资源,以便其他应用程序可能获取音频焦点。

请求音频焦点

请求设备的音频资源所需的步骤如下:

  1. 获取系统服务的句柄 AudioManager

  2. 创建回调类的实例。

  3. 通过调用 RequestAudioFocus 上的 AudioManager 方法请求设备的音频资源。 参数是回调对象、流类型 (音乐、语音呼叫、铃声等) ,以及 (音频资源可以暂时请求或无限期请求的访问权类型,例如) 。

  4. 如果授予请求,将 playMusic 立即调用 方法,并且音频开始播放。

  5. 如果请求被拒绝,则不采取进一步操作。 在这种情况下,只有在以后授予请求时,才会播放音频。

下面的代码示例演示了以下步骤:

Boolean RequestAudioResources(INotificationReceiver parent)
{
  AudioManager audioMan = (AudioManager) GetSystemService(Context.AudioService);
  AudioManager.IOnAudioFocusChangeListener listener  = new MyAudioListener(this);
  var ret = audioMan.RequestAudioFocus (listener, Stream.Music, AudioFocus.Gain );
  if (ret == AudioFocusRequest.Granted) {
    playMusic();
    return (true);
  } else if (ret == AudioFocusRequest.Failed) {
    return (false);
  }
  return (false);
}

释放音频焦点

曲目播放完成后, AbandonFocus 将调用 上的 AudioManager 方法。 这允许另一个应用程序获取设备的音频资源。 如果其他应用程序注册了自己的侦听器,则会收到有关此音频焦点更改的通知。

低级别音频 API

低级别音频 API 可以更好地控制音频播放和录制,因为它们直接与内存缓冲区交互,而不是使用文件 URI。 在某些情况下,此方法更可取。 这些情况包括:

  1. 从加密的音频文件播放时。

  2. 播放一系列短剪辑时。

  3. 音频流式处理。

AudioTrack 类

AudioTrack 类使用低级音频 API 进行录制,并且是类的MediaPlayer低级等效项。

初始化和播放

若要播放音频,必须实例化 的新 AudioTrack 实例。 传递到 构造函数 的参数列表指定如何播放缓冲区中包含的音频示例。 参数包括:

  1. 流类型 – 语音、铃声、音乐、系统或闹钟。

  2. 频率 – 以 Hz 表示的采样率。

  3. 通道配置 - 单声道或立体声。

  4. 音频格式 - 8 位或 16 位编码。

  5. 缓冲区大小 - 以字节为单位。

  6. 缓冲区模式 - 流式处理或静态。

构造后,调用 的 AudioTrackPlay 方法,将其设置为开始播放。 将音频缓冲区写入 到 开始 AudioTrack 播放:

void PlayAudioTrack(byte[] audioBuffer)
{
  AudioTrack audioTrack = new AudioTrack(
    // Stream type
    Stream.Music,
    // Frequency
    11025,
    // Mono or stereo
    ChannelOut.Mono,
    // Audio encoding
    Android.Media.Encoding.Pcm16bit,
    // Length of the audio clip.
    audioBuffer.Length,
    // Mode. Stream or static.
    AudioTrackMode.Stream);

    audioTrack.Play();
    audioTrack.Write(audioBuffer, 0, audioBuffer.Length);
}

暂停和停止播放

调用 Pause 方法以暂停播放:

audioTrack.Pause();

调用 Stop 方法将永久终止播放:

audioTrack.Stop();

清理

AudioTrack当不再需要 时,必须通过调用 Release 释放其资源:

audioTrack.Release();

AudioRecord 类

AudioRecord 类等效于AudioTrack录制端。 与 一样 AudioTrack,它直接使用内存缓冲区来代替文件和 URI。 它要求在 RECORD_AUDIO 清单中设置权限。

初始化和录制

第一步是构造新的 AudioRecord 对象。 传递到 构造函数 的参数列表提供记录所需的所有信息。 与 ( AudioTrack其中参数主要是枚举)不同,中的 AudioRecord 等效参数是整数。 其中包括:

  1. 硬件音频输入源,如麦克风。

  2. 流类型 – 语音、铃声、音乐、系统或闹钟。

  3. 频率 – 以 Hz 表示的采样率。

  4. 通道配置 - 单声道或立体声。

  5. 音频格式 - 8 位或 16 位编码。

  6. 缓冲区大小-字节数

AudioRecord构造后,将调用其 StartRecording 方法。 它现在已准备好开始录制。 持续 AudioRecord 读取输入的音频缓冲区,并将此输入写入音频文件。

void RecordAudio()
{
  byte[] audioBuffer = new byte[100000];
  var audRecorder = new AudioRecord(
    // Hardware source of recording.
    AudioSource.Mic,
    // Frequency
    11025,
    // Mono or stereo
    ChannelIn.Mono,
    // Audio encoding
    Android.Media.Encoding.Pcm16bit,
    // Length of the audio clip.
    audioBuffer.Length
  );
  audRecorder.StartRecording();
  while (true) {
    try
    {
      // Keep reading the buffer while there is audio input.
      audRecorder.Read(audioBuffer, 0, audioBuffer.Length);
      // Write out the audio file.
    } catch (Exception ex) {
      Console.Out.WriteLine(ex.Message);
      break;
    }
  }
}

停止录制

调用 Stop 方法将终止录制:

audRecorder.Stop();

清理

当不再需要对象 AudioRecord 时,调用其 Release 方法会释放与其关联的所有资源:

audRecorder.Release();

总结

Android OS 提供了用于播放、录制和管理音频的强大框架。 本文介绍如何使用高级 MediaPlayer 和类播放和 MediaRecorder 录制音频。 接下来,它探讨了如何使用音频通知在不同的应用程序之间共享设备的音频资源。 最后,它介绍如何使用直接与内存缓冲区接口的低级别 API 播放和录制音频。