170 lines
5.4 KiB
TypeScript
170 lines
5.4 KiB
TypeScript
import { CallStatus, NAME, CallRole } from '../const/index';
|
|
import { IBellParams } from '../interface/index';
|
|
import { isUndefined } from '../utils/common-utils';
|
|
import DEFAULT_CALLER_BELL_FILEPATH from '../assets/phone_dialing.mp3';
|
|
import DEFAULT_CALLEE_BELL_FILEPATH from '../assets/phone_ringing.mp3';
|
|
|
|
export class BellContext {
|
|
private _bellContext: any = null;
|
|
private _isMuteBell: boolean = false;
|
|
private _calleeBellFilePath: string = DEFAULT_CALLEE_BELL_FILEPATH;
|
|
private _callRole: string = CallRole.UNKNOWN;
|
|
private _callStatus: string = CallStatus.IDLE;
|
|
private _isPlaying: boolean = false;
|
|
|
|
constructor() {
|
|
// @ts-ignore
|
|
this._bellContext = wx.createInnerAudioContext({ useWebAudioImplement: false });
|
|
this._addListenBellContextEvent();
|
|
this._bellContext.loop = true;
|
|
}
|
|
|
|
setBellSrc() {
|
|
// @ts-ignore
|
|
const fs = wx.getFileSystemManager();
|
|
try {
|
|
let playBellFilePath = DEFAULT_CALLER_BELL_FILEPATH;
|
|
if (this._callRole === CallRole.CALLEE) {
|
|
playBellFilePath = this._calleeBellFilePath || DEFAULT_CALLEE_BELL_FILEPATH;
|
|
}
|
|
fs.readFileSync(playBellFilePath, 'utf8', 0);
|
|
this._bellContext.src = playBellFilePath;
|
|
} catch (error) {
|
|
console.warn(`${NAME.PREFIX}Failed to setBellSrc, ${error}`);
|
|
}
|
|
}
|
|
|
|
setBellProperties(bellParams: IBellParams) {
|
|
this._callRole = bellParams.callRole || this._callRole;
|
|
this._callStatus = bellParams.callStatus || this._callStatus;
|
|
this._calleeBellFilePath = bellParams.calleeBellFilePath || this._calleeBellFilePath;
|
|
// undefined/false || isMuteBell => isMuteBell (不符合预期)
|
|
this._isMuteBell = isUndefined(bellParams.isMuteBell) ? this._isMuteBell : bellParams.isMuteBell;
|
|
}
|
|
|
|
async play() {
|
|
try {
|
|
if (this._callStatus !== CallStatus.CALLING) {
|
|
return;
|
|
}
|
|
// iOS 优化:增加更严格的状态检查
|
|
if (this._callStatus !== CallStatus.CALLING || this._isPlaying) {
|
|
console.warn(`${NAME.PREFIX}play skipped, callStatus: ${this._callStatus}, isPlaying: ${this._isPlaying}`);
|
|
return;
|
|
}
|
|
this._isPlaying = true;
|
|
this.setBellSrc();
|
|
if (this._callRole === CallRole.CALLEE && !this._isMuteBell) {
|
|
// 再次检查状态,避免在设置过程中状态已变更
|
|
if (!this._isPlaying || this._callStatus !== CallStatus.CALLING) return;
|
|
await this._bellContext.play();
|
|
return;
|
|
}
|
|
if (this._callRole === CallRole.CALLER) {
|
|
// 再次检查状态,避免在设置过程中状态已变更
|
|
if (!this._isPlaying || this._callStatus !== CallStatus.CALLING) return;
|
|
await this._bellContext.play();
|
|
return;
|
|
}
|
|
} catch (error) {
|
|
console.warn(`${NAME.PREFIX}Failed to play audio file, ${error}`);
|
|
}
|
|
}
|
|
|
|
async stop() {
|
|
try {
|
|
this._isPlaying = false;
|
|
// iOS 小程序音频停止优化:先暂停再停止,并添加延时确保操作完成
|
|
if (this._bellContext) {
|
|
// 先暂停音频
|
|
this._bellContext.pause();
|
|
// iOS 需要短暂延时确保暂停操作完成
|
|
await this._delay(100);
|
|
|
|
// 再停止音频
|
|
this._bellContext.stop();
|
|
|
|
// 重置音频源,确保彻底停止
|
|
this._bellContext.src = '';
|
|
|
|
// 再次延时确保所有操作完成
|
|
await this._delay(100);
|
|
}
|
|
} catch (error) {
|
|
console.warn(`${NAME.PREFIX}Failed to stop audio file, ${error}`);
|
|
}
|
|
}
|
|
|
|
async setBellMute(enable: boolean) {
|
|
if (this._callStatus !== CallStatus.CALLING && this._callRole !== CallRole.CALLEE) {
|
|
return;
|
|
}
|
|
if (enable) {
|
|
await this.stop();
|
|
} else {
|
|
await this.play();
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
try {
|
|
this._isMuteBell = false;
|
|
this._calleeBellFilePath = '';
|
|
this._callRole = CallRole.UNKNOWN;
|
|
this._callStatus = CallStatus.IDLE;
|
|
this._isPlaying = false;
|
|
this?._removeListenBellContextEvent();
|
|
this._bellContext.destroy();
|
|
this._bellContext = null;
|
|
} catch (error) {
|
|
console.warn(`${NAME.PREFIX}Failed to destroy, ${error}`);
|
|
}
|
|
}
|
|
|
|
private _delay(ms: number): any {
|
|
return new Promise((resolve: any) => setTimeout(resolve, ms));
|
|
}
|
|
|
|
private _delayCallback(callback: () => void, ms: number) {
|
|
setTimeout(callback, ms);
|
|
}
|
|
|
|
private _handleAudioInterruptionBegin = async () => {
|
|
await this.stop();
|
|
};
|
|
|
|
private _handleAudioInterruptionEnd = async () => {
|
|
if (this._callStatus !== CallStatus.CALLING) {
|
|
await this.stop();
|
|
} else {
|
|
// 音频中断结束后,延时一下再重新播放,确保系统音频资源释放完成
|
|
this._delayCallback(async () => {
|
|
if (this._callStatus === CallStatus.CALLING && !this._isPlaying) {
|
|
await this.play();
|
|
}
|
|
}, 100);
|
|
}
|
|
};
|
|
|
|
private _addListenBellContextEvent() {
|
|
this._bellContext.onPlay(() => {
|
|
if (!this._isPlaying) {
|
|
this._bellContext?.pause();
|
|
this._bellContext?.stop();
|
|
}
|
|
});
|
|
|
|
// @ts-ignore
|
|
wx.onAudioInterruptionBegin(this._handleAudioInterruptionBegin);
|
|
// @ts-ignore
|
|
wx.onAudioInterruptionEnd(this._handleAudioInterruptionEnd);
|
|
}
|
|
|
|
private _removeListenBellContextEvent() {
|
|
// @ts-ignore
|
|
wx.offAudioInterruptionBegin(this._handleAudioInterruptionBegin);
|
|
// @ts-ignore
|
|
wx.offAudioInterruptionEnd(this._handleAudioInterruptionEnd);
|
|
}
|
|
}
|