Android 音訊Android Audio

Android OS 為多媒體提供廣泛的支援,同時包含音訊和影片。本指南著重于 Android 中的音訊,並說明如何使用內建的音訊播放機和錄製器類別,以及低層級的音訊 API 來播放和錄製音訊。它也涵蓋了使用其他應用程式廣播的音訊事件,讓開發人員可以建立效能良好的應用程式。The Android OS provides extensive support for multimedia, encompassing both audio and video. This guide focuses on audio in Android and covers playing and recording audio using the built-in audio player and recorder classes, as well as the low-level audio API. It also covers working with Audio events broadcast by other applications, so that developers can build well-behaved applications.

總覽Overview

新式行動裝置採用的功能,先前會有必要的設備,– 攝影機、音樂播放機和錄影機。Modern mobile devices have adopted functionality that formerly would have required dedicated pieces of equipment – cameras, music players and video recorders. 因此,多媒體架構已成為行動 Api 中的第一類功能。Because of this, multimedia frameworks have become a first-class feature in mobile APIs.

Android 提供多媒體的廣泛支援。Android provides extensive support for multimedia. 本文會探討如何使用 Android 中的音訊,並涵蓋下列主題This article examines working with audio in Android, and covers the following topics

  1. 使用內建的 MediaPlayer 類別播放音訊,以MediaPlayer – 播放音訊,包括使用 AudioTrack 類別的本機音訊檔案和資料流程音訊檔案。Playing Audio with MediaPlayer – Using the built-in MediaPlayer class to play audio, including local audio files and streamed audio files with the AudioTrack class.

  2. 使用內建 MediaRecorder 類別錄製音訊 – 記錄音訊。Recording Audio – Using the built-in MediaRecorder class to record audio.

  3. 使用音訊通知 – 使用音訊通知來建立運作正常的應用程式,藉由暫停或取消其音訊輸出,正確回應事件(例如來電)。Working with Audio Notifications – Using audio notifications to create well-behaved applications that respond correctly to events (such as incoming phone calls) by suspending or canceling their audio outputs.

  4. 使用低層級的音訊– 透過 AudioTrack 類別直接寫入記憶體緩衝區來播放音訊。Working with Low-Level Audio – Playing audio using the AudioTrack class by writing directly to memory buffers. 使用 AudioRecord 類別錄製音訊,並直接從記憶體緩衝區讀取。Recording audio using the AudioRecord class and reading directly from memory buffers.

需求Requirements

本指南需要 Android 2.0 (API 層級5)或更高版本。This guide requires Android 2.0 (API level 5) or higher. 請注意,您必須在裝置上完成 Android 上的偵錯工具音訊。Please note that debugging audio on Android must be done on a device.

必須要求androidmanifest.xml中的 RECORD_AUDIO 許可權:It is necessary to request the RECORD_AUDIO permissions in AndroidManifest.XML:

已啟用記錄_音訊之 Android 資訊清單的必要許可權區段

使用 MediaPlayer 類別播放音訊Playing Audio with the MediaPlayer Class

在 Android 中播放音訊最簡單的方式,就是使用內建的MediaPlayer類別。The simplest way to play audio in Android is with the built-in MediaPlayer class. MediaPlayer 可以藉由傳入檔案路徑來播放本機或遠端檔案。MediaPlayer can play either local or remote files by passing in the file path. 不過,MediaPlayer 非常區分狀態,而且在錯誤狀態下呼叫其中一個方法,會導致擲回例外狀況。However, MediaPlayer is very state-sensitive and calling one of its methods in the wrong state will cause an exception to be thrown. 請務必依照下面所述順序與 MediaPlayer 互動,以避免發生錯誤。It's important to interact with MediaPlayer in the order described below to avoid errors.

初始化和播放Initializing and Playing

使用 MediaPlayer 播放音訊需要下列順序:Playing audio with MediaPlayer requires the following sequence:

  1. 具現化新的MediaPlayer物件。Instantiate a new MediaPlayer object.

  2. 設定要透過SetDataSource方法播放的檔案。Configure the file to play via the SetDataSource method.

  3. 呼叫Prepare方法以初始化播放人員。Call the Prepare method to initialize the player.

  4. 呼叫start方法以開始播放音訊。Call the Start method to start the audio playing.

下列程式碼範例說明這種用法:The code sample below illustrates this usage:

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

暫停和繼續播放Suspending and Resuming Playback

您可以藉由呼叫Pause方法來暫停播放:The playback can be suspended by calling the Pause method:

player.Pause();

若要繼續暫停播放,請呼叫Start方法。To resume paused playback, call the Start method. 這會從播放中的暫停位置繼續:This will resume from the paused location in the playback:

player.Start();

呼叫播放程式上的Stop方法會結束進行中的播放:Calling the Stop method on the player ends an ongoing playback:

player.Stop();

當不再需要播放程式時,必須呼叫Release方法來釋放資源:When the player is no longer needed, the resources must be released by calling the Release method:

player.Release();

使用 MediaRecorder 類別錄製音訊Using the MediaRecorder Class to Record Audio

在 Android 中錄製音訊 MediaPlayer 的必然結果是MediaRecorder類別。The corollary to MediaPlayer for recording audio in Android is the MediaRecorder class. 如同 MediaPlayer,它會區分狀態,並會透過數個狀態轉換,以到達可開始錄製的時間點。Like the MediaPlayer, it is state-sensitive and transitions through several states to get to the point where it can start recording. 若要錄製音訊,必須設定 [RECORD_AUDIO] 許可權。In order to record audio, the RECORD_AUDIO permission must be set. 如需如何設定應用程式許可權的指示,請參閱使用 androidmanifest.xmlFor instructions on how to set application permissions see Working with AndroidManifest.xml.

初始化和記錄Initializing and Recording

使用 MediaRecorder 錄製音訊需要下列步驟:Recording audio with the MediaRecorder requires the following steps:

  1. 具現化新的MediaRecorder物件。Instantiate a new MediaRecorder object.

  2. 透過SetAudioSource方法,指定要用來捕獲音訊輸入的硬體裝置。Specify which hardware device to use to capture the audio input via the SetAudioSource method.

  3. 使用SetOutputFormat方法來設定輸出檔案的音訊格式。Set the output file audio format using the SetOutputFormat method. 如需支援的音訊類型清單,請參閱Android 支援的媒體格式For a list of supported audio types see Android Supported Media Formats.

  4. 呼叫SetAudioEncoder方法以設定音訊編碼類型。Call the SetAudioEncoder method to set the audio encoding type.

  5. 呼叫SetOutputFile方法,指定要寫入音訊資料的輸出檔名稱。Call the SetOutputFile method to specify the name of the output file that the audio data is written to.

  6. 呼叫Prepare方法來初始化錄製器。Call the Prepare method to initialize the recorder.

  7. 呼叫start方法以開始錄製。Call the Start method to start recording.

下列程式碼範例說明此順序:The following code sample illustrates this sequence:

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);
  }
}

停止錄製Stopping recording

若要停止錄製,請在 MediaRecorder上呼叫 Stop 方法:To stop the recording, call the Stop method on the MediaRecorder:

recorder.Stop();

清理Cleaning up

一旦 MediaRecorder 停止,請呼叫Reset方法,讓它回到閒置狀態:Once the MediaRecorder has been stopped, call the Reset method to put it back into its idle state:

recorder.Reset();

當不再需要 MediaRecorder 時,其資源必須藉由呼叫Release方法來釋放:When the MediaRecorder is no longer needed, its resources must be released by calling the Release method:

recorder.Release();

管理音訊通知Managing Audio Notifications

AudioManager 類別The AudioManager Class

AudioManager類別提供音訊通知的存取,可讓應用程式在發生音訊事件時知道。The AudioManager class provides access to audio notifications that let applications know when audio events occur. 此服務也提供其他音訊功能的存取權,例如音量和響鈴模式控制。This service also provides access to other audio features, such as volume and ringer mode control. AudioManager 可讓應用程式處理音訊通知以控制音訊播放。The AudioManager allows an application to handle audio notifications to control audio playback.

管理音訊焦點Managing Audio Focus

裝置的音訊資源(內建的播放程式和錄製器)會由所有執行中的應用程式共用。The audio resources of the device (the built-in player and recorder) are shared by all running applications.

在概念上,這類似于只有一個應用程式具有鍵盤焦點的桌上型電腦上的應用程式:選取其中一個執行中的應用程式之後,鍵盤輸入才會進入該應用程式。Conceptually, this is similar to applications on a desktop computer where only one application has the keyboard focus: after selecting one of the running applications by mouse-clicking it, the keyboard input goes only to that application.

音訊焦點是一種類似的想法,可防止多個應用程式同時播放或錄製音訊。Audio focus is a similar idea and prevents more than one application from playing or recording audio at the same time. 它比鍵盤焦點更為複雜,因為它是自願的 – 應用程式可能會忽略目前沒有音訊焦點和播放,而不 –,而且因為有不同類型的音訊焦點可以要求。It is more complicated than keyboard focus because it is voluntary – the application can ignore that fact that it does not currently have audio focus and play regardless – and because there are different types of audio focus that can be requested. 例如,如果要求者只預期在很短的時間播放音訊,它可能會要求暫時性焦點。For example, if the requestor is only expected to play audio for a very short time, it may request transient focus.

音訊焦點可能會立即授與或一開始拒絕,並于稍後授與。Audio focus may be granted immediately, or initially denied and granted later. 例如,如果應用程式在撥打電話期間要求音訊焦點,則會遭到拒絕,但當通話完成後,焦點可能會被授與。For example, if an application requests audio focus during a phone call, it will be denied, but focus may well be granted once the phone call is finished. 在此情況下,會註冊接聽程式,以便在將音訊焦點移開時,據以回應。In this case, a listener is registered in order to respond accordingly if audio focus is taken away. 要求音訊焦點是用來判斷是否可以播放或錄製音訊。Requesting audio focus is used to determine whether or not it is OK to play or record audio.

如需有關音訊焦點的詳細資訊,請參閱管理音訊焦點For more information about audio focus, see Managing Audio Focus.

為音訊焦點註冊回呼Registering the Callback for Audio Focus

IOnAudioChangeListener 註冊 FocusChangeListener 回呼是取得和釋放音訊焦點的重要部分。Registering the FocusChangeListener callback from the IOnAudioChangeListener is an important part of obtaining and releasing audio focus. 這是因為授與音訊焦點的時間可能會延遲到稍後為止。This is because the granting of audio focus may be deferred until a later time. 例如,應用程式可能會要求在進行通話時播放音樂。For example, an application may request to play music while there is a phone call in progress. 在通話完成之前,不會授與音訊焦點。Audio focus will not be granted until the phone call is finished.

基於這個理由,回呼物件會當做參數傳遞至 AudioManagerGetAudioFocus 方法中,而這就是註冊回呼的這個呼叫。For this reason, the callback object is passed as a parameter into the GetAudioFocus method of the AudioManager, and it is this call that registers the callback. 如果一開始拒絕音訊焦點,但後來被授與,則在回呼上叫用 OnAudioFocusChange,就會通知應用程式。If audio focus is initially denied but later granted, the application is informed by invoking OnAudioFocusChange on the callback. 相同的方法會用來告訴應用程式正在取出音訊焦點。The same method is used to tell the application that audio focus is being taken away.

當應用程式完成使用音訊資源時,它會呼叫 AudioManagerAbandonFocus 方法,然後再次傳入回呼。When the application has finished using the audio resources, it calls the AbandonFocus method of the AudioManager, and again passes in the callback. 這會取消註冊回呼並釋放音訊資源,讓其他應用程式可以取得音訊焦點。This deregisters the callback and releases the audio resources, so that other applications may obtain audio focus.

要求音訊焦點Requesting Audio Focus

要求裝置的音訊資源所需執行的步驟如下:The steps required to request the audio resources of the device are as follow:

  1. 取得 AudioManager 系統服務的控制碼。Obtain a handle to the AudioManager system service.

  2. 建立回呼類別的實例。Create an instance of the callback class.

  3. 藉由在 AudioManager 上呼叫 RequestAudioFocus 方法,來要求裝置的音訊資源。Request the audio resources of the device by calling the RequestAudioFocus method on the AudioManager . 這些參數是回呼物件、資料流程類型(音樂、語音通話、響鈴等)和所要求的存取權類型(例如,可以短暫要求音訊資源,或不限時間)。The parameters are the callback object, the stream type (music, voice call, ring etc.) and the type of the access right being requested (the audio resources can be requested momentarily or for an indefinite period, for example).

  4. 如果已授與要求,則會立即叫用 playMusic 方法,而音訊會開始播放。If the request is granted, the playMusic method is invoked immediately, and the audio starts to play back.

  5. 如果要求遭到拒絕,則不會採取進一步的動作。If the request is denied, no further action is taken. 在此情況下,只有在稍後授與要求時,才會播放音訊。In this case, the audio will only play if the request is granted at a later time.

下列程式碼範例顯示這些步驟:The code sample below shows these steps:

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);
}

釋放音訊焦點Releasing Audio Focus

播放軌播放完成時,會叫用 AudioManager 上的 AbandonFocus 方法。When the playback of the track is complete, the AbandonFocus method on AudioManager is invoked. 這可讓另一個應用程式取得裝置的音訊資源。This allows another application to gain the audio resources of the device. 如果其他應用程式已註冊自己的接聽項,則會收到此音訊焦點變更的通知。Other applications will receive a notification of this audio focus change if they have registered their own listeners.

低層級的音訊 APILow Level Audio API

低層級的音訊 Api 可讓您更有效地控制音訊播放和錄製,因為它們會直接與記憶體緩衝區互動,而不是使用檔案 Uri。The low-level audio APIs provide a greater control over audio playing and recording because they interact directly with memory buffers instead of using file URIs. 在某些情況下,最好採用此方法。There are some scenarios where this approach is preferable. 這類案例包括:Such scenarios include:

  1. 從加密的音訊檔案播放時。When playing from encrypted audio files.

  2. 播放連續的短剪輯時。When playing a succession of short clips.

  3. 音訊串流。Audio streaming.

AudioTrack 類別AudioTrack Class

AudioTrack類別會使用低層級的音訊 api 進行錄製,而且是 MediaPlayer 類別的低層級對等。The AudioTrack class uses the low-level audio APIs for recording, and is the low-level equivalent of the MediaPlayer class.

初始化和播放Initializing and Playing

若要播放音訊,必須具現化 AudioTrack 的新實例。To play audio, a new instance of AudioTrack must be instantiated. 傳入此函式的引數清單會指定如何播放包含在緩衝區中的音訊範例。The argument list passed into the constructor specifies how to play the audio sample contained in the buffer. 引數為:The arguments are:

  1. 串流類型 – 語音、鈴聲、音樂、系統或鬧鐘。Stream type – Voice, ringtone, music, system or alarm.

  2. 頻率 – 以 Hz 表示的取樣率。Frequency – The sampling rate expressed in Hz.

  3. 頻道設定 – Mono 或身歷聲。Channel Configuration – Mono or stereo.

  4. 音訊格式 – 8 位或16位編碼。Audio format – 8 bit or 16 bit encoding.

  5. 緩衝區大小 – 以位元組為單位。Buffer size – in bytes.

  6. 緩衝區模式 – 資料流程或靜態。Buffer mode – streaming or static.

在結構之後,會叫用 AudioTrackPlay方法,將其設定為開始播放。After construction, the Play method of AudioTrack is invoked, to set it up to start playing. 將音訊緩衝區寫入 AudioTrack 會開始播放:Writing the audio buffer to the AudioTrack starts the playback:

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);
}

暫停和停止播放Pausing and Stopping the Playback

呼叫pause方法以暫停播放:Call the Pause method to pause the playback:

audioTrack.Pause();

呼叫Stop方法將會永久終止播放:Calling the Stop method will terminate the playback permanently:

audioTrack.Stop();

清除Cleanup

當不再需要 AudioTrack 時,其資源必須藉由呼叫Release來釋放:When the AudioTrack is no longer needed, its resources must be released by calling Release:

audioTrack.Release();

AudioRecord 類別The AudioRecord Class

AudioRecord類別等同于錄製端上的 AudioTrackThe AudioRecord class is the equivalent of AudioTrack on the recording side. 如同 AudioTrack,它會直接使用記憶體緩衝區來取代檔案和 Uri。Like AudioTrack, it uses memory buffers directly, in place of files and URIs. 它需要在資訊清單中設定 RECORD_AUDIO 許可權。It requires that the RECORD_AUDIO permission be set in the manifest.

初始化和記錄Initializing and Recording

第一個步驟是建立新的AudioRecord物件。The first step is to construct a new AudioRecord object. 傳入此函式的引數清單會提供記錄所需的所有資訊。The argument list passed into the constructor provides all the information required for recording. 不同于 AudioTrack,其中引數主要是列舉,AudioRecord 中的對等引數是整數。Unlike in AudioTrack, where the arguments are largely enumerations, the equivalent arguments in AudioRecord are integers. 它們包括:These include:

  1. 硬體音訊輸入來源,例如麥克風。Hardware audio input source such as microphone.

  2. 串流類型 – 語音、鈴聲、音樂、系統或鬧鐘。Stream type – Voice, ringtone, music, system or alarm.

  3. 頻率 – 以 Hz 表示的取樣率。Frequency – The sampling rate expressed in Hz.

  4. 頻道設定 – Mono 或身歷聲。Channel Configuration – Mono or stereo.

  5. 音訊格式 – 8 位或16位編碼。Audio format – 8 bit or 16 bit encoding.

  6. 緩衝區大小(以位元組為單位)Buffer size-in bytes

一旦建立 AudioRecord 之後,就會叫用其StartRecording方法。Once the AudioRecord is constructed, its StartRecording method is invoked. 現在已準備好開始錄製。It is now ready to begin recording. AudioRecord 會持續讀取音訊緩衝區以進行輸入,並將此輸入寫出至音訊檔案。The AudioRecord continuously reads the audio buffer for input, and writes this input out to an audio file.

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;
    }
  }
}

停止錄製Stopping the Recording

呼叫Stop方法會終止記錄:Calling the Stop method terminates the recording:

audRecorder.Stop();

清除Cleanup

當不再需要 AudioRecord 物件時,呼叫其Release方法會釋放與它相關聯的所有資源:When the AudioRecord object is no longer needed, calling its Release method releases all resources associated with it:

audRecorder.Release();

總結Summary

Android OS 提供強大的架構來播放、錄製和管理音訊。The Android OS provides a powerful framework for playing, recording and managing audio. 本文涵蓋如何使用高階 MediaPlayerMediaRecorder 類別來播放和錄製音訊。This article covered how to play and record audio using the high-level MediaPlayer and MediaRecorder classes. 接下來,它會探索如何使用音訊通知,在不同的應用程式之間共用裝置的音訊資源。Next, it explored how to use audio notifications to share the audio resources of the device between different applications. 最後,它會處理如何使用低層級的 Api 來播放和錄製音訊,而這是直接與記憶體緩衝區互動的介面。Finally, it dealt with how to playback and record audio using the low-level APIs, which interface directly with memory buffers.