音声の録音、アップロード、再生 WeChat アプレットの練習
最近、インテリジェントなアウトバウンド ロボット製品が発売されました。サウンド エンジニアが実際の録音用にアウトバウンド スピーチ スキルを構成するには、録音、アップロード、オーディオ再生機能を備えた WeChat アプレットを開発する必要がありました。
コードはオープン ソース化されており、データはローカライズされています。初心者が学ぶのに適した完全なネイティブ WeChat アプレットの小さなプロジェクト。
実践分析
依存関係インターフェース
主に以下のAPIを使用
- wx.getRecorderManager : グローバルに一意のレコーディング マネージャーRecorderManagerを取得します
- wx.createInnerAudioContext : 内部オーディオ コンテキストInnerAudioContextオブジェクトを作成します
PS。
- デフォルトの
audio
コンポーネントスタイルは要件を満たしていません。現在、プログレス バーを再生し、コンポーネントInnerAudioContext
と協力して達成する必要があります。process
InnerAudioContext
再生を自動的に停止するには、アプレットを終了します。アプレットを終了する必要がある場合は、引き続き再生できます。BackgroundAudioManager
代わりに
グローバル変数を宣言する理由:
- 録音自体は唯一のグローバル
- 音声再生については、ページを出たり入ったりするたびに動的に生成・破棄されてしまい(バグがあるようです)、複数の音声が同時に再生されてしまいます.この問題を回避するには、グローバルユニークを使用してください.オブジェクト管理
const recorderManager: WechatMiniprogram.RecorderManager = wx.getRecorderManager();
const innerAudioContext: WechatMiniprogram.InnerAudioContext = wx.createInnerAudioContext();
録音
- 記録開始設定
const recordOptions = {
duration: 10 * 60 * 1000, // 最多录音时长 10 分钟
sampleRate: 8000, // 采样率
numberOfChannels: 1, // 1 个录音通道即可
format: 'wav', // 服务端指定格式
};
recorderManager.start(recordOptions)
- 初期状態
- 録音は音声の受信を検出する 音声の受信を検出して波形図を表示
RecorderManager.onFrameRecorded
したい
が、イベントがwav
フォーマット。現在、開始イベントを監視すると、記録タイミングが表示されます。
// 监听已录制完指定帧大小的文件事件。如果设置了 frameSize,则会回调此事件。
recorderManager.onFrameRecorded(({
frameBuffer, isLastFrame }) => {
console.log('frameBuffer.byteLength: ', frameBuffer.byteLength)
console.log('isLastFrame: ', isLastFrame);
});
- 録画開始イベントの監視、録画中の状態の設定、録画タイマーの表示
recorderManager.onStart(() => {
console.log('recorder start');
this.startClock();
this.setData({
...recordingData,
});
});
- 記録イベントが停止すると、ローカルの記録ファイル アドレスと記録時間情報を受信できます。通常は にファイルをアップロードし
CDN
、アドレスを業務用サーバーに保存してから再生を聞きます。
recorderManager.stop();
// 停止录音事件
recorderManager.onStop(async (res) => {
console.log('recorder stop', res)
// 停止后立即更新状态,以免异常
this.stopClock();
this.setData({
...initRData,
});
if (isError) {
isError = false;
return;
}
const {
tempFilePath, duration } = res;
console.log('tempFilePath', tempFilePath);
const url = await uploadFile({
filePath: tempFilePath });
// 快速开始时,获取的都是未录音,会冲掉当前上传试听,这里手动设置一下
if (innerAudioContext.currentTime) {
innerAudioContext.stop();
}
innerAudioContext.src = url;
this.setData({
...initPlayData,
...initRData,
detail: {
...this.data.detail,
url,
duration: Math.ceil(duration / 1000),
},
duration: formatClock(duration, true),
});
// await this.getDetail('CUR');
});
- 監視録画が異常で途切れる、録画が異常で、文書に具体的な記載がない。
たとえば、電話をかけると録音が中断され、一時停止イベントがトリガーされます。承認の拒否は、エラー イベントを発行します。ここでは、異常変数が に設定されtrue
、onStop
イベント、記録の初期状態が復元されます。
// 监听录音错误事件
recorderManager.onError((err) => {
this.noEffectStopRecorder();
showErrMsg(msgMap[err.errMsg] || err.errMsg || '小程序错误');
console.log('recorderManager.onError', err);
});
// 监听录音暂停事件
recorderManager.onPause(() => {
console.log('recorder pause');
// 立马停止,重新开始,没有恢复机制
this.noEffectStopRecorder();
});
- 記録例外はビジネス処理を実行せず、記録を終了するように呼び出します。ここで、記録は再生呼び出しのように副作用が
stop
ない。記録を開始または一時停止しない呼び出しは、例外をスローstop
します。無限ループに注意。
noEffectStopRecorder() {
if (this.data.isRecording) {
isError = true;
recorderManager.stop();
}
}
アップロード
- 関連するビジネス ドメイン名は、アプレットのバックグラウンドで構成する必要があります。
export function uploadFile({
fileName, filePath }: {
fileName?: string;
filePath: string;
}) {
return new Promise<string>((resolve) => {
wx.showLoading({
title: '上传中...',
});
const name = fileName || filePath;
// 获取 CDN token
getNosToken({
fileName: name }).then((data) => {
console.log('uploadToken: ', data);
wx.uploadFile({
url: 'https://nos.com/',
name: 'file', // 服务器获取流的参数名
filePath,
formData: {
Object: data.objectName,
'x-nos-token': data.token,
},
success(res) {
console.log('上传成功回调', res);
wx.hideLoading();
const url = `https://cdn.com/${
data.objectName}`
console.log(url);
resolve(url);
},
fail(err) {
wx.hideLoading();
wx.showToast({
title: err.errMsg,
icon: 'none',
});
reject(err);
},
})
});
});
}
遊ぶ
- 遊んでいない
- 再生開始イベントのリッスン、再生ステータスの設定、再生プログレスバーの表示
// 监听音频播放事件
innerAudioContext.onPlay(() => {
console.log('开始播放');
this.setData({
...playingData,
});
});
- オーディオ再生の進行状況の更新イベントをリッスンし、
process
パーセンテージを
// 监听音频播放进度更新事件
innerAudioContext.onTimeUpdate(() => {
console.log('监听音频播放进度更新事件');
let playPercent = 0;
const duration = this.data.detail.duration || innerAudioContext.duration;
try {
playPercent = Math.ceil(((innerAudioContext.currentTime * 1000) / (duration * 1000)) * 100) || 0;
} catch (e) {
playPercent = 0;
}
playPercent = playPercent && playPercent > 100 ? 100 : playPercent;
const currentTime = formatClock(innerAudioContext.currentTime * 1000, true);
console.log('当前播放时间:', currentTime);
console.log('微信暴露时间:', innerAudioContext.duration);
console.log('后端返回时间:', duration);
console.log('当前播放进度:', playPercent);
this.setData({
currentTime,
playPercent,
});
});
- この要件では、進行状況バーを一時停止したりドラッグしたりする必要はありません。モニタリング音声が正常、異常停止、一時停止の場合は初期状態に戻ります。進行状況を復元またはドラッグする機能が必要です。これは、対応するイベントで単独で処理できます。
// 监听音频自然播放至结束的事件
innerAudioContext.onEnded(() => {
console.log('监听音频自然播放至结束的事件');
this.setData({
...initPlayData
});
});
// 监听音频播放错误事件
innerAudioContext.onError((res) => {
/**
* 10001 系统错误
* 10002 网络错误
* 10003 文件错误
* 10004 格式错误
* -1 未知错误
*/
console.log(res.errCode, res.errMsg);
this.setData({
...initPlayData
});
});
// 监听音频暂停事件
innerAudioContext.onPause(() => {
console.log('监听音频暂停事件');
this.setData({
...initPlayData
});
});
// 监听音频停止事件
innerAudioContext.onStop(() => {
console.log('监听音频停止事件');
this.setData({
...initPlayData,
});
});
ページイベント
- ページの最初のレンダリングが完了し、オーディオの録音と再生のイベントが初期化されます
- ページを再入力するたびに最新のビジネス データを読み込む
- ページは現在のページを離れるか、アプレットを終了し、記録と再生を停止します
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
this.initRecorder();
this.initAudioPlayer();
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
this.getDetail('CUR');
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('切换页面停止录音或播放');
innerAudioContext.stop();
this.noEffectStopRecorder();
},