Browse Source

add

newdev_shunjiawei
wolfplus2048 1 year ago
parent
commit
de40cc1dbf
  1. 110
      local_plugins/bytedance_speech/android/src/main/kotlin/com/deep_voice/bytedance_speech/BytedanceAudioPlayer.kt
  2. 2
      local_plugins/bytedance_speech/android/src/main/kotlin/com/deep_voice/bytedance_speech/BytedanceTTS.kt

110
local_plugins/bytedance_speech/android/src/main/kotlin/com/deep_voice/bytedance_speech/BytedanceAudioPlayer.kt

@ -15,12 +15,13 @@ import com.deep_voice.speech.tts.AudioDataListener
import com.deep_voice.speech.tts.AudioOutputDevice import com.deep_voice.speech.tts.AudioOutputDevice
/** /**
* 高性能音频播放器 - 16kHz采样率 * 语音通信音频播放器 - 16kHz采样率
* 设计要点: * 设计要点:
* • 永远使用 USAGE_MEDIA + MODE_NORMAL 媒体播放通路 * • 使用 USAGE_VOICE_COMMUNICATION + MODE_IN_COMMUNICATION 通信通路
* • 利用 AudioDeviceCallback 监听设备热插拔 * • 利用 AudioDeviceCallback 监听设备热插拔
* • API 31+ 使用 setPreferredDevice() 精准路由 * • API 31+ 使用 setPreferredDevice() 精准路由
* • 有耳机自动从耳机播放,无耳机自动切到扬声器 * • 有耳机自动从耳机播放,无耳机自动切到扬声器
* • 内置回声消除和噪音抑制功能
*/ */
class BytedanceAudioPlayer(private val context: Context) : AudioDataListener, AudioDeviceCallback() { class BytedanceAudioPlayer(private val context: Context) : AudioDataListener, AudioDeviceCallback() {
companion object { companion object {
@ -35,6 +36,35 @@ class BytedanceAudioPlayer(private val context: Context) : AudioDataListener, Au
private var isFirstData = true private var isFirstData = true
private var totalBytesWritten = 0 private var totalBytesWritten = 0
private var sessionActive = true private var sessionActive = true
private var audioFocusRequest: Any? = null // 兼容不同API版本
// 音频焦点变化监听器
private val audioFocusChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
when (focusChange) {
AudioManager.AUDIOFOCUS_LOSS -> {
// 永久失去焦点,停止播放
Log.d(TAG, "音频焦点丢失")
stop()
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
// 暂时失去焦点,暂停播放
Log.d(TAG, "音频焦点暂时丢失")
audioTrack?.pause()
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
// 暂时失去焦点但可降低音量,这里选择暂停
Log.d(TAG, "音频焦点暂时丢失(可降低音量)")
audioTrack?.pause()
}
AudioManager.AUDIOFOCUS_GAIN -> {
// 重新获得焦点,恢复播放
Log.d(TAG, "音频焦点恢复")
if (sessionActive) {
audioTrack?.play()
}
}
}
}
// 回调 // 回调
private var onPlayStarted: (() -> Unit)? = null private var onPlayStarted: (() -> Unit)? = null
@ -62,6 +92,8 @@ class BytedanceAudioPlayer(private val context: Context) : AudioDataListener, Au
init { init {
// 注册设备热插拔监听 // 注册设备热插拔监听
audioManager.registerAudioDeviceCallback(this, Handler(Looper.getMainLooper())) audioManager.registerAudioDeviceCallback(this, Handler(Looper.getMainLooper()))
// 请求音频焦点
requestAudioFocus()
buildTrack(selectOutputDevice()) // 首次创建 buildTrack(selectOutputDevice()) // 首次创建
} }
@ -126,7 +158,7 @@ class BytedanceAudioPlayer(private val context: Context) : AudioDataListener, Au
audioTrack = AudioTrack.Builder() audioTrack = AudioTrack.Builder()
.setAudioAttributes( .setAudioAttributes(
AudioAttributes.Builder() AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA) // 统一媒体通路 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) // 语音通信通路
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build() .build()
) )
@ -159,8 +191,8 @@ class BytedanceAudioPlayer(private val context: Context) : AudioDataListener, Au
track.play() track.play()
} }
// 配置音频管理器 - 统一使用 MODE_NORMAL // 配置音频管理器 - 使用通信模式以启用回声消除和噪音抑制
audioManager.mode = AudioManager.MODE_NORMAL audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
// 切换扬声器开关仅在无耳机时打开 // 切换扬声器开关仅在无耳机时打开
audioManager.isSpeakerphoneOn = (device == null) audioManager.isSpeakerphoneOn = (device == null)
@ -168,6 +200,71 @@ class BytedanceAudioPlayer(private val context: Context) : AudioDataListener, Au
Log.d(TAG, "AudioTrack已创建 - 输出设备: $deviceName, 采样率: ${SAMPLE_RATE}Hz") Log.d(TAG, "AudioTrack已创建 - 输出设备: $deviceName, 采样率: ${SAMPLE_RATE}Hz")
} }
/**
* 请求音频焦点
*/
private fun requestAudioFocus() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Android O及以上使用新的API
val focusRequest = android.media.AudioFocusRequest.Builder(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
)
.setAudioAttributes(
AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build()
)
.setAcceptsDelayedFocusGain(true)
.setOnAudioFocusChangeListener(audioFocusChangeListener)
.build()
val result = audioManager.requestAudioFocus(focusRequest)
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
audioFocusRequest = focusRequest
Log.d(TAG, "音频焦点请求成功")
} else {
Log.w(TAG, "音频焦点请求失败")
}
} else {
// Android O以下使用旧的API
@Suppress("DEPRECATION")
val result = audioManager.requestAudioFocus(
audioFocusChangeListener,
AudioManager.STREAM_VOICE_CALL,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
)
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.d(TAG, "音频焦点请求成功(旧API)")
} else {
Log.w(TAG, "音频焦点请求失败(旧API)")
}
}
} catch (e: Exception) {
Log.e(TAG, "请求音频焦点异常: ${e.message}")
}
}
/**
* 释放音频焦点
*/
private fun releaseAudioFocus() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
audioFocusRequest?.let {
audioManager.abandonAudioFocusRequest(it as android.media.AudioFocusRequest)
}
} else {
@Suppress("DEPRECATION")
audioManager.abandonAudioFocus(audioFocusChangeListener)
}
Log.d(TAG, "音频焦点已释放")
} catch (e: Exception) {
Log.e(TAG, "释放音频焦点异常: ${e.message}")
}
}
/** /**
* 开始新的播放会话 * 开始新的播放会话
*/ */
@ -262,7 +359,10 @@ class BytedanceAudioPlayer(private val context: Context) : AudioDataListener, Au
stop() stop()
audioTrack?.release() audioTrack?.release()
audioTrack = null audioTrack = null
releaseAudioFocus()
audioManager.unregisterAudioDeviceCallback(this) audioManager.unregisterAudioDeviceCallback(this)
// 恢复音频模式
audioManager.mode = AudioManager.MODE_NORMAL
} }
/** /**

2
local_plugins/bytedance_speech/android/src/main/kotlin/com/deep_voice/bytedance_speech/BytedanceTTS.kt

@ -116,7 +116,7 @@ class BytedanceTTS(private val context: Context) : ITtsService, CoroutineScope {
// TTS配置参数 // TTS配置参数
private var appId: String = "" private var appId: String = ""
private var accessToken: String = "" private var accessToken: String = ""
private var speaker: String = "zh_female_shuangkuaisisi_emo_v2_mars_bigtts" // 默认语音,使用Java示例的音色 private var speaker: String = "zh_female_yuanqinvyou_moon_bigtts" // 默认语音,使用Java示例的音色
private var format: String = "pcm" // pcm 格式 private var format: String = "pcm" // pcm 格式
private var sampleRate: Int = 16000 // 使用16kHz采样率 private var sampleRate: Int = 16000 // 使用16kHz采样率
private var enableTimestamp: Boolean = false private var enableTimestamp: Boolean = false

Loading…
Cancel
Save