banner
jzman

jzman

Coding、思考、自觉。
github

Android音声再生AudioTrackの詳細

前面几篇文章紹介了MediaCodecMediaMuxerAudioRecord等音视频関連知識、これらは Android 音视频開発で必ず習得しなければならないもので、関連する記事のリンクは以下の通りです:

Android で一般的に使用される音声再生インターフェースにはMediaPlayerAudioTrackSoundPoolがあり、音声のレンダリングで最も一般的なのはAudioTrackOpenSL ESです。以下にAudioTrackに関する知識を紹介します。主な内容は以下の通りです:

  1. AudioTrack の紹介
  2. AudioTrack の作成
  3. AudioTrack 音声データの書き込み
  4. AudioTrack のライフサイクル
  5. AudioTrack の使用

AudioTrack の紹介#

AudioTrackは原始pcm形式の音声データを再生するために使用され、AudioTrackには 2 つの再生モードがあります:

  • MODE_STATIC:このモードでは音声データを一度音声バッファに書き込み、メモリが少なく、できるだけ遅延の少ない短い音声シーン(ゲーム音声、着信音、システム通知音など)を処理するのに適しています。この場合、このモードのオーバーヘッドは最小です。
  • MODE_STREAM:このモードでは音声データを継続的に書き込み、音声データを継続的に受け取る必要があるシーンに適しています。このモードは、特定の音声データの持続時間が長い、または音声特性(高サンプリングレート、高ビット深度など)により一度にメモリに書き込むことができない場合に使用され、通常のPCM原始音声データの再生にはこのモードを選択します。

MediaPlayerと比較すると、MediaPlayerは異なるタイプ、異なる形式の音声ファイルを再生でき、底層で対応する音声デコーダを作成しますが、AudioTrackPCM原始音声データのみを受け取ります。MediaPlayerは底層でAudioTrackを作成し、デコードされたPCMデータストリームをAudioTrackに渡し、AudioTrackはそれをAudioFlingerに渡してミキシングを行い、その後ハードウェアに再生を渡します。

AudioTrack の作成#

AudioTrackの作成は以下の方法で行います:

// Android5.0以降
AudioTrack(
    attributes: AudioAttributes!, 
    format: AudioFormat!, 
    bufferSizeInBytes: Int, 
    mode: Int, 
    sessionId: Int)

上記のコンストラクタに対応するパラメータの意味は以下の通りです:

  • attributes:音声ストリーム情報の属性の集合を表し、Android5.0 以降はAudioAttributesを使用してストリームタイプの設定を置き換え、ストリームタイプ設定よりも多くの情報を伝達できます。一般的に音声の用途、音声の内容などを設定するために使用されます。
  • format:AudioTrackが受け入れる音声フォーマットを表し、線形PCMの場合、各サンプルのサイズ(8、16、32 ビット)および表現形式(整数型、浮動小数点型)を反映します。音声フォーマットはAudioFormatで定義されており、一般的な音声データフォーマットの中でAudioFormat.ENCODING_PCM_16BITのみがすべてのデバイスで正常に使用できることが保証されており、AudioFormat.ENCODING_PCM_8BITはすべてのデバイスで正常に使用できることを保証しません。
  • bufferSizeInBytes:音声データバッファのサイズを表し、単位はバイトで、そのサイズは一般的に音声フレームサイズの非ゼロ倍数です。再生モードがMODE_STATICの場合、バッファサイズは今回再生する音声のサイズです。再生モードがMODE_STREAMの場合、バッファサイズは最小バッファサイズより小さくてはならず、つまりgetMinBufferSizeが返すサイズより小さくてはなりません。
  • mode:再生モードを表し、AudioTrackMODE_STATICMODE_STREAMの 2 つの方法を提供します。MODE_STATICは音声リソースを一度に音声バッファに書き込むため、着信音、システム通知音など遅延が小さく、音声リソースのメモリ占有が少ないシーンに適しています。MODE_STREAMwriteメソッドを通じてデータを継続的に書き込む必要があるシーンに適しており、MODE_STATICに比べて一定の遅延がありますが、音声データを継続的に受け取ることができます。
  • sessionId:音声セッション ID で、ここではAudioManager.AUDIO_SESSION_ID_GENERATEを使用して、底層音声フレームワークが自動的にsessionIdを生成します。

AudioTrack 音声データの書き込み#

ストリームモード (STREAM_MODE) でも静的バッファモード (STATIC_MODE) でも、音声データを再生するためにwriteメソッドを通じて書き込む必要があります。主なwriteメソッドは以下の通りです:

// AudioTrackコンストラクタで指定されたフォーマットはAudioFormat#ENCODING_PCM_8BITである必要があります
open fun write(audioData: ByteArray, offsetInBytes: Int, sizeInBytes: Int): Int
// AudioTrackコンストラクタで指定されたフォーマットはAudioFormat#ENCODING_PCM_16BITである必要があります 
open fun write(audioData: ShortArray, offsetInShorts: Int, sizeInShorts: Int): Int
// AudioTrackコンストラクタで指定されたフォーマットはAudioFormat#ENCODING_PCM_FLOATである必要があります
open fun write(audioData: FloatArray, offsetInFloats: Int, sizeInFloats: Int, writeMode: Int): Int

音声データの書き込みの戻り値は 0 以上で、音声データの読み取りに関する一般的な例外は以下の通りです:

  1. ERROR_INVALID_OPERATION:AudioTrackが初期化されていないことを示します。
  2. ERROR_BAD_VALUE:パラメータが無効であることを示します。
  3. ERROR_DEAD_OBJECT:すでにいくつかの音声データが転送された場合にエラーコードを返さず、次回のwriteでエラーコードを返します。

これはAudioRecordread関数に似ており、具体的な詳細は公式ドキュメントを参照してください。

AudioTrack のライフサイクル#

AudioTrackのライフサイクルは主にSTATE_UNINITIALIZEDSTATE_INITIALIZEDSTATE_NO_STATIC_DATAであり、STATE_INITIALIZEDSTREAM_MODEに対応し、STATE_NO_STATIC_DATASTATIC_MODEに対応します。再生状態はあまり重要ではありません。以下の図のようになります:

Mermaid Loading...

AudioTrack の使用#

AudioTrackの使用は主にPCMファイルからデータを読み取り、読み取った音声をAudioTrackに書き込んで再生することです。その重要なコードは以下の通りです:

// AudioTrackの初期化
private fun initAudioTrack() {
    bufferSize = AudioTrack
        .getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT)
    attributes = AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_MEDIA) // 音声の用途を設定
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) // 音声の内容タイプを設定
        .build()
    audioFormat = AudioFormat.Builder()
        .setSampleRate(SAMPLE_RATE)
        .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
        .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
        .build()
    audioTrack = AudioTrack(
        attributes, audioFormat, bufferSize,
        AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE
    )
}
// AudioTrackに音声データを書き込む
private fun writeAudioData(){
    scope.launch(Dispatchers.IO){
        val pcmFile = File(pcmFilePath)
        val ins = FileInputStream(pcmFile)
        val bytes = ByteArray(bufferSize)
        var len: Int
        while (ins.read(bytes).also { len = it } > 0){
            audioTrack.write(bytes, 0, len)
        }
        audioTrack.stop()
    }
}
// 再生を開始
private fun start(){
    audioTrack.play()
    writeAudioData()
}

AudioTrackの使用は基本的にこのようになります。AudioTrackによる音声再生に関する関連コードが興味があれば、コメントを残してください。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。