|
|
|
@ -17,12 +17,14 @@ class XunFeiAsrHelper(private val context: Context) { |
|
|
|
private val tag = "XunFeiAsrHelper" |
|
|
|
|
|
|
|
private val appId = "43d87d22" |
|
|
|
private val accessKeyId = "83f063755e8d342670002f50a4471d42" |
|
|
|
private val accessKeyId = "2bd01ce06ac35957fc0c082f9b6284ec" |
|
|
|
private val accessKeySecret = "ODU3OTUyYjhjMjY5NDhkMmMxYWY2Zjlm" |
|
|
|
|
|
|
|
private var webSocket: WebSocket? = null |
|
|
|
private val client = OkHttpClient() |
|
|
|
|
|
|
|
private var currentSessionId = "" |
|
|
|
private var sessionId = "" |
|
|
|
|
|
|
|
fun start(callback: AzureAsrHelper.ContinuousRecognizeCallback) { |
|
|
|
try { |
|
|
|
@ -73,7 +75,7 @@ class XunFeiAsrHelper(private val context: Context) { |
|
|
|
fun stop() { |
|
|
|
try { |
|
|
|
webSocket?.let { ws: WebSocket -> |
|
|
|
ws.send("{\"end\": true}") |
|
|
|
ws.send("{\"end\": true, \"sessionId\": \"$sessionId\"}") |
|
|
|
ws.close(1000, "User stopped") |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
@ -89,10 +91,15 @@ class XunFeiAsrHelper(private val context: Context) { |
|
|
|
) { |
|
|
|
try { |
|
|
|
val jsonData = JSONObject(resultData) |
|
|
|
val action = jsonData.optString("action") |
|
|
|
|
|
|
|
when (action) { |
|
|
|
"started" -> { |
|
|
|
Log.d(tag, "-------------------$jsonData") |
|
|
|
val msgType = jsonData.optString("msg_type") |
|
|
|
|
|
|
|
when (msgType) { |
|
|
|
"action" -> { |
|
|
|
val sid = jsonData.optString("sessionId") |
|
|
|
if (!sid.isNullOrEmpty()) { |
|
|
|
sessionId = sid |
|
|
|
} |
|
|
|
Log.d(tag, "Handshake success") |
|
|
|
} |
|
|
|
|
|
|
|
@ -127,8 +134,13 @@ class XunFeiAsrHelper(private val context: Context) { |
|
|
|
} |
|
|
|
|
|
|
|
"error" -> { |
|
|
|
Log.e(tag, "Error: $resultData") |
|
|
|
callback.onError(currentSessionId, 1005, "Xunfei error: $resultData") |
|
|
|
Log.e(tag, "Error: $resultData") |
|
|
|
} |
|
|
|
|
|
|
|
else -> { |
|
|
|
callback.onError(currentSessionId, 1006, "Xunfei unknown msg_type: $msgType") |
|
|
|
Log.w(tag, "Unknown msg_type: $msgType") |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
@ -137,27 +149,57 @@ class XunFeiAsrHelper(private val context: Context) { |
|
|
|
} |
|
|
|
|
|
|
|
private fun getWebSocketUrl(): String { |
|
|
|
val url = "wss://rtasr.xfyun.cn/v1/ws" |
|
|
|
val ts = (System.currentTimeMillis() / 1000).toString() |
|
|
|
val baseString = appId + ts |
|
|
|
val signa = md5(baseString) |
|
|
|
val signatureSha = hmacSha1(signa, accessKeyId) |
|
|
|
val signature = Base64.encodeToString(signatureSha, Base64.NO_WRAP) |
|
|
|
val encodedSignature = URLEncoder.encode(signature, "UTF-8") |
|
|
|
|
|
|
|
return "$url?appid=$appId&ts=$ts&signa=$encodedSignature" |
|
|
|
val baseWsUrl = "wss://office-api-ast-dx.iflyaisol.com/ast/communicate/v1" |
|
|
|
|
|
|
|
val params = java.util.TreeMap<String, String>() |
|
|
|
params["audio_encode"] = "pcm_s16le" |
|
|
|
params["lang"] = "autodialect" |
|
|
|
params["samplerate"] = "16000" |
|
|
|
params["accessKeyId"] = accessKeyId |
|
|
|
params["appId"] = appId |
|
|
|
params["utc"] = getUtcTime() |
|
|
|
|
|
|
|
val signature = calculateSignature(params) |
|
|
|
params["signature"] = signature |
|
|
|
|
|
|
|
val sb = StringBuilder() |
|
|
|
var first = true |
|
|
|
for ((key, value) in params) { |
|
|
|
if (!first) { |
|
|
|
sb.append("&") |
|
|
|
} |
|
|
|
sb.append(URLEncoder.encode(key, "UTF-8")).append("=").append(URLEncoder.encode(value, "UTF-8")) |
|
|
|
first = false |
|
|
|
} |
|
|
|
|
|
|
|
return "$baseWsUrl?$sb" |
|
|
|
} |
|
|
|
|
|
|
|
private fun md5(string: String): String { |
|
|
|
val md = MessageDigest.getInstance("MD5") |
|
|
|
val digest = md.digest(string.toByteArray(StandardCharsets.UTF_8)) |
|
|
|
return digest.joinToString("") { "%02x".format(it) } |
|
|
|
private fun getUtcTime(): String { |
|
|
|
val sdf = java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") |
|
|
|
sdf.timeZone = java.util.TimeZone.getTimeZone("GMT+8") |
|
|
|
return sdf.format(java.util.Date()) |
|
|
|
} |
|
|
|
|
|
|
|
private fun hmacSha1(data: String, key: String): ByteArray { |
|
|
|
val secretKeySpec = SecretKeySpec(key.toByteArray(StandardCharsets.UTF_8), "HmacSHA1") |
|
|
|
private fun calculateSignature(params: Map<String, String>): String { |
|
|
|
val baseStr = StringBuilder() |
|
|
|
var first = true |
|
|
|
for ((key, value) in params) { |
|
|
|
if ("signature" == key) continue |
|
|
|
if (value.isEmpty()) continue |
|
|
|
|
|
|
|
if (!first) { |
|
|
|
baseStr.append("&") |
|
|
|
} |
|
|
|
baseStr.append(URLEncoder.encode(key, "UTF-8")).append("=").append(URLEncoder.encode(value, "UTF-8")) |
|
|
|
first = false |
|
|
|
} |
|
|
|
|
|
|
|
val mac = Mac.getInstance("HmacSHA1") |
|
|
|
mac.init(secretKeySpec) |
|
|
|
return mac.doFinal(data.toByteArray(StandardCharsets.UTF_8)) |
|
|
|
val keySpec = SecretKeySpec(accessKeySecret.toByteArray(StandardCharsets.UTF_8), "HmacSHA1") |
|
|
|
mac.init(keySpec) |
|
|
|
val signBytes = mac.doFinal(baseStr.toString().toByteArray(StandardCharsets.UTF_8)) |
|
|
|
|
|
|
|
return Base64.encodeToString(signBytes, Base64.NO_WRAP) |
|
|
|
} |
|
|
|
} |
|
|
|
|