Flutter开发笔记 —— 语音消息功能实现

前言

最近在开发一款即时通讯(IM)的聊天App,在实现语音消息功能模块后,写下该文章以做记录。

注:本文不提供相关图片资源以及IM聊天中具体实现代码,单论语音功能实现思路

需求分析
效果图

比起上来直接贴代码,我们先来逐步分析一下一个正常语音消息的需求是如何的?

  • 长按语音按钮录制用户语音内容

  • 松开按钮后发送语音消息至目标

从上可得,我们需要针对于用户的语音 录制 & 播放 方面下手!

Flutter_sound

目标地址:https://pub.dev/packages/flutter_sound

简介:Flutter_sound 是一款可以处理用户声音库

通过该插件的GitHub示例中可以了解到实现录制语音和播放的相关API为

  • FlutterSoundPlayer下的startRecorder方法 (录制)

  • FlutterSoundPlayer下的startPlayer方法 (播放)

实现思路

初始化Flutter_Sound配置

定义相关变量

  • FlutterSoundPlayer flutterSoundPlayer = FlutterSoundPlayer(); //声音播放器

  • FlutterSoundRecorder recordSound = FlutterSoundRecorder(); //声音录制器

  • Timer? recordTimer // 计时器,用来控制录音时长;

  • String timeString = “” // 用来做回显时长

  • List voicePlayList =[]; //用来控制语音播放列表

  • String voicePath = “”; //临时储存语音文件路径

初始化声音配置方法


  /*
   * @author Marinda
   * @date 2023/6/26 15:25
   * @description 初始化声音设置
   */
  initSoundSetting() async{
    await flutterSoundPlayer.openPlayer();
    await recordSound.openRecorder();
  }

录制用户语音


  /*
   * @author Marinda
   * @date 2023/6/26 15:31
   * @description 录音
   */
   recordSound() async{
    PermissionStatus status = await Permission.microphone.request();
    int time = 0;
    //权限校验
    if (status != PermissionStatus.granted) throw RecordingPermissionException("麦克风权限未授权!");
    var dir = await getExternalStorageDirectory();
    Uuid uuid = Uuid();
    String filePath = p.join(dir?.path ?? "",uuid.v4()+".mp4");
    File file = File(filePath);
    file.openWrite();
    state.voicePath.value = filePath;
    Log.i("录音保存的位置:${filePath}");
    await state.recordSound.startRecorder(
        //目标文件位置
        toFile: filePath,
        //这里可以认为是那种源
        codec: Codec.aacMP4,
        //采样率
        bitRate: 8000,
        //为1即可
        numChannels: 1
    );
  
    recordTimer = Timer.periodic(Duration(seconds: 1), (_) {
      time++;
      timeString = time.toString();
    });
  }

播放实现


  /*
   * @author Marinda
   * @date 2023/10/7 14:28
   * @description 播放语音信息 目前先做本地语音缓存处理
   */
  playVoice(String voiceUrl) async{
    Uint8List uint8list = Uint8List(0);
    //视为网络http
    if(voiceUrl.startsWith("http")){
      uint8list = ...获取MP4文件二进;
    }else{
      File voiceFile = File(voiceUrl);
      //如果不存在
      if(!voiceFile.existsSync()){
        BotToast.showText(text: "语音播放失败");
        return;
      }
      uint8list  = await voiceFile.readAsBytes();
    }

    //如果存在则进行移除播放
    if(voicePlayList.contains(tag)){
      voicePlayList.remove(tag);
      await flutterSoundPlayer.stopPlayer();
      return;
    }
    //加入语音信息队列
    voicePlayList.add(tag);
 
    await flutterSoundPlayer.startPlayer(
      fromURI: data.expandAddress,
      fromDataBuffer: uint8list,
      codec: Codec.aacMP4,
      sampleRate: 8000,
        numChannels: 1,
      whenFinished: (){
      //  播放完毕
        state.voicePlayList.remove(tag);
      }
    );
  }

结束录制


  /*
   * @author Marinda
   * @date 2023/6/26 15:33
   * @description
   */
  stopRecordSound() async{
    await recordSound.stopRecorder();
    if(recordTimer!.isActive){
      recordTimer!.cancel();
      recordTimer = null;
    }
    // 这里实现你的语音消息发送逻辑
    Log.i("停止录制!");
    timeString.value = "";
    voicePath.value = "";
  }

结束语

难度不大,主要是围绕着录音文件进行处理

值得注意的点是在播放录音文件时
记得获取目标的二进制流一并携带至startPlayer方法fromDataBuffer字段中
否则可能会出现无法播放或程序未响应等危险情况!

感谢你的观看!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值