前面几篇文章紹介了MediaCodec
、MediaMuxer
、AudioRecord
等音视频関連知識、これらは Android 音视频開発で必ず習得しなければならないもので、関連する記事のリンクは以下の通りです:
Android で一般的に使用される音声再生インターフェースにはMediaPlayer
、AudioTrack
、SoundPool
があり、音声のレンダリングで最も一般的なのはAudioTrack
とOpenSL ES
です。以下にAudioTrack
に関する知識を紹介します。主な内容は以下の通りです:
- AudioTrack の紹介
- AudioTrack の作成
- AudioTrack 音声データの書き込み
- AudioTrack のライフサイクル
- AudioTrack の使用
AudioTrack の紹介#
AudioTrack
は原始pcm
形式の音声データを再生するために使用され、AudioTrack
には 2 つの再生モードがあります:
MODE_STATIC
:このモードでは音声データを一度音声バッファに書き込み、メモリが少なく、できるだけ遅延の少ない短い音声シーン(ゲーム音声、着信音、システム通知音など)を処理するのに適しています。この場合、このモードのオーバーヘッドは最小です。MODE_STREAM
:このモードでは音声データを継続的に書き込み、音声データを継続的に受け取る必要があるシーンに適しています。このモードは、特定の音声データの持続時間が長い、または音声特性(高サンプリングレート、高ビット深度など)により一度にメモリに書き込むことができない場合に使用され、通常のPCM
原始音声データの再生にはこのモードを選択します。
MediaPlayer
と比較すると、MediaPlayer
は異なるタイプ、異なる形式の音声ファイルを再生でき、底層で対応する音声デコーダを作成しますが、AudioTrack
はPCM
原始音声データのみを受け取ります。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:再生モードを表し、
AudioTrack
はMODE_STATIC
とMODE_STREAM
の 2 つの方法を提供します。MODE_STATIC
は音声リソースを一度に音声バッファに書き込むため、着信音、システム通知音など遅延が小さく、音声リソースのメモリ占有が少ないシーンに適しています。MODE_STREAM
はwrite
メソッドを通じてデータを継続的に書き込む必要があるシーンに適しており、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 以上で、音声データの読み取りに関する一般的な例外は以下の通りです:
- ERROR_INVALID_OPERATION:
AudioTrack
が初期化されていないことを示します。 - ERROR_BAD_VALUE:パラメータが無効であることを示します。
- ERROR_DEAD_OBJECT:すでにいくつかの音声データが転送された場合にエラーコードを返さず、次回の
write
でエラーコードを返します。
これはAudioRecord
のread
関数に似ており、具体的な詳細は公式ドキュメントを参照してください。
AudioTrack のライフサイクル#
AudioTrack
のライフサイクルは主にSTATE_UNINITIALIZED
、STATE_INITIALIZED
、STATE_NO_STATIC_DATA
であり、STATE_INITIALIZED
はSTREAM_MODE
に対応し、STATE_NO_STATIC_DATA
はSTATIC_MODE
に対応します。再生状態はあまり重要ではありません。以下の図のようになります:
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
による音声再生に関する関連コードが興味があれば、コメントを残してください。