65.9K
CodeProject 正在变化。 阅读更多。
Home

摇晃、震动和滚动:Android 设备上的杜比音效

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2013 年 11 月 5 日

CPOL

8分钟阅读

viewsIcon

18381

摇晃、震动和滚动:Android 设备上的杜比音效

引言

电影偏好当然是一个非常个人化的话题,但我个人在 2013 年(迄今为止)最喜欢的电影是《环太平洋》——它有怪兽、机甲,情节非常可预测,你几乎可以猜到演员口中的下一句话,对我来说,最重要的是,它有 Ramin Djawadi 创作的精彩配乐。我喜欢在编写代码(和文章,是的,我现在就在听)时听电影配乐。事实上,如果一部电影的配乐精彩,我可以原谅它很多缺点,这可能是我小时候第一次接触史诗配乐(像大多数书呆子一样)通过《星球大战》及其精彩的约翰·威廉姆斯配乐时养成的习惯。

精彩的配乐经常能让电影从“一般”变成“哇塞”,随着移动设备在游戏和娱乐平台上的蓬勃发展,这一点也迅速在移动设备应用上得到体现。这在很大程度上解释了为什么杜比(Dolby),也就是那个让你在影院里听到爆破声震动爆米花桶的人,现在正将其声音专业技术带入 Android 生态系统。并非所有 Android 应用都会关注其音效和播放效果,也并非所有 Android 设备都配备杜比解决方案(这里的“解决方案”是对“硬件加软件”的一个巧妙委婉说法),但那些有所需求的应用将希望最大化其设备的音频能力。是的,游戏开发者们,我说的就是你们。现在,杜比提供了一个用于音频播放和管理的 SDK,它将……如果允许我再次开个玩笑……让你的耳朵“炸裂”。

说真的,我们在讨论这个吗?

音质通常是手机游戏和应用功能列表中不那么靠前的东西,因为说实话,很多设备的扬声器都很小,功率也不大。降噪耳机当然能有所帮助,但……对许多开发者来说,花大量时间在音频上似乎并没有什么巨大的回报。

为了打消这个小小的疑虑,最好有一个简单的比较点。首先,让我们创建一个简单的 Android MediaPlayer 应用,使用标准的 MediaPlayer 类(位于 Android 的 android.media 包中)来播放一个 .m4a 音频文件。然后,我们将使用杜比示例应用(随其 SDK 一起提供)来播放同一个文件,以进行一次“苹果对苹果”的比较。请注意,杜比 SDK 示例无法在不支持杜比解决方案的 Android 设备上运行,截至本文撰写之时,亚马逊 Kindle Fire HD 设备是其中之一,但还有更多设备正在开发中。为了运行杜比样本并听到差异,您需要其中一个设备。(我用的是 Kindle Fire HD,挺好的,因为我现在可以在播放精彩配乐的同时阅读书籍。在学习 Java 编码技巧的同时,耳边响起史诗般的音乐,真是太棒了。)

android.media.MediaPlayer

首先,标准的 Android MediaPlayer 示例:这是一个简单的应用,只有一个 Activity,其中包含一个填满整个屏幕的按钮。按下按钮后,MediaPlayer 会开始播放一个名为“audio_dolby_living_room.m4a”的音频文件,该文件被打包为原始资源。

public class MediaPlayerSampleActivity
  extends Activity
  implements MediaPlayer.OnCompletionListener
{
  Button btnPlay;
  MediaPlayer mPlayer;
 
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    btnPlay = new Button(this);
    btnPlay.setText("Play");
    btnPlay.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        if(mPlayer == null) {
          try {
            mPlayer = MediaPlayer.create(
              MediaPlayerSampleActivity.this,
              R.raw.audio_dolby_living_room);
            mPlayer.start();
          }
          catch (Exception e) {
            e.printStackTrace();
          }
        }
        else {
          mPlayer.stop();
          mPlayer.release();
          mPlayer = null;
        }
      }
    });
    setContentView(mPlay);
  }
 
  @Override
  public void onDestroy() {
    super.onDestroy();
    if(mPlayer != null) {
      mPlayer.release();
    }
  }
 
  //OnCompletionListener Methods
  @Override
  public void onCompletion(MediaPlayer mp) {
    mPlayer.release();
    mPlayer = null;
  }
}

这是一个相当直接的应用,甚至没有使用基于资源的布局将按钮放在屏幕中央。

使用调试密钥编译并将其安装到您的设备上(假设设备通过 USB 连接,如果您和我一样是命令行爱好者,则为“ant installd”),然后启动应用。音频文件会经过一系列音频“杂技”,仿佛其创建者想让扬声器活动一下。播放需要一到两分钟,准备好继续前进时,再次点击按钮即可停止播放。

com.dolby.dap.DolbyAudioProcessing

杜比应用要稍微复杂一些:我们仍然使用标准的 MediaPlayer 来播放片段,但在 MediaPlayer 开始播放之前,我们将查询底层设备硬件,查看它是否具有杜比硬件,如果有,则激活该硬件。

但首先,必须下载杜比 SDK;它可以在 http://developer.dolby.com 下载,下载后会有一套 Javadoc、一个示例应用程序和一个 JAR 文件。

实际上,使用杜比处理支持相对容易:除了基本的 MediaPlayer 用法外,应用程序开发者还需要获取一个 DolbyAudioProcessing 类的实例,使用它来启用处理(顺便说一句,请务必遵守用户操作,根据 Android Media Guide 中描述的标准 Android 行为停止或调整您的音频播放),还可以选择一个音频配置文件进行播放,并在应用程序关闭时清理处理实例。

从编程角度来看,整体效果如下:

// other imports, as before
import com.dolby.dap.*;
 
public class DolbyMediaSampleActivity
  extends Activity
  implements MediaPlayer.OnCompletionListener,
    OnDolbyAudioProcessingEventListener
{
  Button btnPlay;
  MediaPlayer mPlayer;
  DolbyAudioProcessing mDolbyAudioProcessing;
 
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    btnPlay = new Button(this);
    btnPlay.setText("Play");
    btnPlay.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        if(mPlayer == null) {
          try {
            mPlayer = MediaPlayer.create(
              DolbyMediaSampleActivity.this,
              R.raw.audio_dolby_living_room);
            mPlayer.start();
          }
          catch (Exception e) {
            e.printStackTrace();
          }
        }
        else {
          mPlayer.stop();
          mPlayer.release();
          mPlayer = null;
        }
      }
    });
    setContentView(btnPlay);
 
    mDolbyAudioProcessing =
      DolbyAudioProcessing.getDolbyAudioProcessing(this, DolbyAudioProcessing.PROFILE.GAME, this);
    if (mDolbyAudioProcessing == null) {
        Toast.makeText(this,
          "Dolby Audio Processing not available on this device.",
          Toast.LENGTH_SHORT).show();
        finish();
        return;
    }
  }
 
  @Override
  public void onDestroy() {
    super.onDestroy();
    mDolbyAudioProcessing.releaseDolbyAudioProcessing();
    if(mPlayer != null) {
      mPlayer.release();
    }
  }
 
  //OnCompletionListener Methods
  @Override
  public void onCompletion(MediaPlayer mp) {
    mPlayer.release();
    mPlayer = null;
  }
 
  @Override
  public void onClientConnected() {
  }
 
  @Override
  public void onEnabled(boolean on) {
  }
 
  @Override
  public void onProfileSelected(int profile) {
  }
 
  @Override
  public void onClientDisconnected() {
  }
}

逐一分析,我们需要做以下事情:

Logistics

DolbyAudioProcessing 类及其相关的事件监听器接口位于“com.dolby.dap”包中,包含该代码的 JAR 文件必须位于 Android 项目的“libs”目录下。

获取 DolbyAudioProcessing 实例

与许多其他 Android API 一样,这是通过 DolbyAudioProcessing 类本身的静态工厂方法完成的,调用静态方法“getDolbyAudioProcessing”,并将 Activity 作为两个必需参数传递。完成后,DolbyAudioProcessing 对象基本上“附加”到 Activity,并充当您的应用和杜比硬件之间的桥梁。

实现 OnDolbyAudioProcessingListener

正如 MediaPlayer.OnCompletionListener 接口提供了 MediaPlayer 通知 Activity 媒体播放器状态变化的必要钩子(例如,在这种情况下,播放已完成),杜比硬件系统也可能不时地想要或需要通知您的应用程序有关其发生的各种事情。该接口由四个方法组成:

  • "onClientConnected" 及其同类方法
  • "onClientDisconnected",在第一种情况下通知 Activity 杜比处理已连接完毕,在第二种情况下通知其已关闭,
  • "onEnabled",根据布尔参数的值,通知 Activity 处理已启用或禁用,以及
  • "onProfileSelected",通知 Activity 正在选择哪个配置文件。

(我们将稍后详细讨论“配置文件”。)

请记住,这些回调可能会(并且经常会)从 UI 线程以外的线程调用,因此如果 Activity 想要更改其 UI,它应该通过 Android Handler/handleMessage 机制来完成,以返回到主 UI 线程。

启用 DolbyAudioProcessing

这是一个简单的 setAudioProcessingEnabled() 调用,传递 true 来启用它,传递 false 来禁用它。只有在处理已连接到 Activity 后才能启用处理,所以这通常最好在 onClientConnected 回调中完成。

释放 DolbyAudioProcessing 实例

在 Activity 的 onCleanup 方法中,调用 releaseDolbyAudioProcessing() 来清理 Activity 最初获取处理实例时分配的所有资源。通常在 onCreate() 中获取并在 onCleanup() 中释放是顺理成章的,因此这些几乎总是样板代码。

配置文件

如前所述,杜比系统维护着几个不同的“配置文件”,用于根据播放的音频类型优化听觉体验——例如,“音乐”配置文件将针对大多数音乐进行优化,而“语音”配置文件将更侧重于使人声更清晰。

这些配置文件是使用一些传统的 Android 策略获得的:配置文件的总数由 getNumProfiles() 调用给出,每个配置文件都像数组一样进行整数索引。所以,例如,要查看列表中第二个配置文件的名称,请调用 getProfileName(1)。要确定当前选定的配置文件,请调用 getSelectedProfile() 获取其整数索引,要更改配置文件,则再次调用 setSelectedProfile() 并使用要使用的配置文件的整数索引。

良好的公民行为

顺便说一句,虽然这应该是不言而喻的,但一个好的 Android 应用在应用进入后台时应该放弃对扬声器的控制。虽然应用在后台运行时可以继续做很多事情(下载数据、在已关闭的窗口上播放动画等),而不会负面影响用户对设备的正常使用(除了不该消耗的 CPU 之外),但通过扬声器播放音乐绝对是其中最分散注意力的事情之一。当您试图与奶奶谈论她的脚病时,让史诗配乐通过扬声器播放,起初可能听起来是个好主意,但这可能不会让您的用户满意。相信我。

摘要

总的来说,启用杜比支持相当简单,特别是因为它主要是在调用 MediaPlayer 的相同区域进行半打左右的方法调用——在 Activity 的初始化和清理期间,每当用户更改应用程序设置时,以及与传统的 Android Media 行为一起。老实说,这些对 Android 应用程序来说是相当小的改动,但换来了非常显著的音质差异,即使使用相同的音频文件。例如,编写上述示例应用程序大约只花了一个小时。为现有应用添加杜比支持,使用现有的声音,可能会花费更少的时间。

现在,如果各位允许我,我要调高《环太平洋》的配乐音量,让自己更史诗一会儿。

© . All rights reserved.