音声の録音、アップロード、再生 WeChat アプレットの練習

音声の録音、アップロード、再生 WeChat アプレットの練習


最近、インテリジェントなアウトバウンド ロボット製品が発売されました。サウンド エンジニアが実際の録音用にアウトバウンド スピーチ スキルを構成するには、録音、アップロード、オーディオ再生機能を備えた WeChat アプレットを開発する必要がありました。

コードはオープン ソース化されており、データはローカライズされています。初心者が学ぶのに適した完全なネイティブ WeChat アプレットの小さなプロジェクト。

実践分析

依存関係インターフェース

主に以下のAPIを使用

  1. wx.getRecorderManager : グローバルに一意のレコーディング マネージャーRecorderManagerを取得します
  2. wx.createInnerAudioContext : 内部オーディオ コンテキストInnerAudioContextオブジェクトを作成します

PS。

  1. デフォルトのaudioコンポーネントスタイルは要件を満たしていません。現在、プログレス バーを再生し、コンポーネントInnerAudioContextと協力して達成する必要があります。process
  2. InnerAudioContext再生を自動的に停止するには、アプレットを終了します。アプレットを終了する必要がある場合は、引き続き再生できます。BackgroundAudioManager代わりに

グローバル変数を宣言する理由:

  1. 録音自体は唯一のグローバル
  2. 音声再生については、ページを出たり入ったりするたびに動的に生成・破棄されてしまい(バグがあるようです)、複数の音声が同時に再生されてしまいます.この問題を回避するには、グローバルユニークを使用してください.オブジェクト管理
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');
});
  • 監視録画が異常で途切れる、録画が異常で、文書に具体的な記載がない。
    たとえば、電話をかけると録音が中断され、一時停止イベントがトリガーされます。承認の拒否は、エラー イベントを発行します。ここでは、異常変数が に設定されtrueonStopイベント、記録の初期状態が復元されます。
// 监听录音错误事件
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,
  });
});

ページイベント

  1. ページの最初のレンダリングが完了し、オーディオの録音と再生のイベントが初期化されます
  2. ページを再入力するたびに最新のビジネス データを読み込む
  3. ページは現在のページを離れるか、アプレットを終了し、記録と再生を停止します
/**
   * 生命周期函数--监听页面初次渲染完成
   */
onReady() {
    
    
  this.initRecorder();
  this.initAudioPlayer();
},

/**
 * 生命周期函数--监听页面显示
 */
onShow() {
    
    
  this.getDetail('CUR');
},

/**
 * 生命周期函数--监听页面卸载
 */
onUnload() {
    
    
  console.log('切换页面停止录音或播放');
  innerAudioContext.stop();

  this.noEffectStopRecorder();
},

参考

  1. 元の住所
  2. Githubアドレス

おすすめ

転載: blog.csdn.net/guduyibeizi/article/details/125703676