概要
※Docomo Developer Suport経由の音声合成API(エーアイ社提供は終了しました)
日頃、個人開発でDocomo Developer Supportにて提供をされている音声合成API(エーアイ社提供)にお世話になっているのですが、昨年12月こんな新着情報が。。
2019年3月よりSDKを利用していたコードは動かなくなるとのことでした。
それに伴って既存のSDKを利用していたAndroidのソースコードを改修したので、その時のメモです。
※2019.12月追記: Docomo Developer Support経由の音声合成API(エーアイ社提供)はすでに終了しています。
実装
必要なもの
・Docomo Developer Supportへの登録
・アプリケーション登録(API KEYの入手)
・ガイドラインの確認
仕様
必要な情報は機能別リファレンスに一通り記載があります。
これまで提供されていたSDKは、主に
・音声合成APIとの通信処理
・レスポンスの再生処理
を行なっていたので、自前でその機能を用意してやります。
通信部分の処理
OkHttp3を使っている利用した前提でのメモになります。
リクエスト
Request.Builder()
.url(ApiUrls.AI_TALK_API_URL + "?APIKEY=$apiKey")
.addHeader("Content-Type", "application/ssml+xml")
.addHeader("Accept", "audio/L16")
.post(createRequestBody()) // 後述
.build()
リクエストで指定するのは、ApiKey、Content-Type、Accecptの3点です。
Content-Typeに関しては機能別リファレンスを確認して、利用するContent-Typeを指定しましょう。
今回は「application/ssml+xml」を指定しています。
リクエストのBodyについては下記。
private fun createRequestBody(text: String): RequestBody =
RequestBody.create(
MediaType.parse("application/ssml+xml"),
"<?xml version=\"1.0\" encoding=\"utf-8\" ?><speak version=\"1.1\"><voice name=\"nozomi\">$text</voice></speak>"
)
Bodyに必要なのは、MediaTypeとSSMLの中身。
SSMLは直書きしていますが、実運用する際は記述を工夫した方が良いです。textは読み上げたい文字列です。
※SSMLとは、音声合成用のマークアップ言語のことで、XML形式で読み上げのスピードやピッチ等を指定することができます。
https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=text_to_speech&p_name=api_1#tag01
レスポンスの処理
上記のリクエストを行うと音声データがBinary形式でレスポンスが返ってきます。(Acceptにaudio/L16を指定した場合)
音声データは下記のフォーマットになっているので、AudioTrackを対応したパラメータを指定して生成してやれば、再生が可能です。
【符号化方式】
リニアPCM
【チャネル数】
1(モノラル)
【サンプル周波数】
16000
【ビット深度】
16bit(ビッグエンディアン)
val body = response.body().bytes()
convertByteOrder16(body)
val bufSize = AudioTrack.getMinBufferSize(16000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT)
val player = AudioTrack.Builder()
.setAudioFormat(AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(16000)
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build())
.setBufferSizeInBytes(bufSize)
.build()
途中登場している「convertByteOrder16(body)」は、AudioTrackで再生をするためにビッグエンディアンをリトルエンディアンに変換しています。
fun convertByteOrder16(var1: ByteArray?) {
if (var1 == null) {
throw IllegalArgumentException("Input Parameter is Invalid.")
} else {
var var3 = 0
while (var3 < var1.size) {
val var2 = var1[var3 + 1]
var1[var3 + 1] = var1[var3]
var1[var3] = var2
var3 += 2
}
}
}
あとはAudioTrack再生するだけです。
player.play()
player.write(body, 0, body.size)
以上、細かいところをかい摘んでのメモではありますが、Docomo音声合成APIをSDKなしで利用した際の記録でした。