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 = ""; //临时储存语音文件路径

初始化声音配置方法

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

录制用户语音

dart 复制代码
  /*
   * @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();
    });
  }

播放实现

dart 复制代码
  /*
   * @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);
      }
    );
  }

结束录制

dart 复制代码
  /*
   * @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 天前
Flutter---生命周期
flutter
Cathy Bryant1 天前
矩阵乘以向量?向量乘以向量?
笔记·神经网络·考研·机器学习·数学建模
递归不收敛1 天前
Conda 常用命令汇总(新手入门笔记)
笔记·conda
LiWeNHuI1 天前
Flutter开发:发布插件到Pub
flutter
前端橙一陈1 天前
Salesforce Developer Edition(开发者版) 搭建测试环境
经验分享·笔记·其他
电子小子洋酱1 天前
BearPi小熊派 鸿蒙入门开发笔记(4)
笔记·华为·harmonyos
摇滚侠1 天前
Spring Boot 3零基础教程,WEB 开发 通过配置类代码方式修改静态资源配置 笔记32
java·spring boot·笔记
衿璃1 天前
Flutter应用架构设计的思考
前端·flutter
聪明的笨猪猪1 天前
Java JVM “内存(1)”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
_dindong1 天前
Linux网络编程:Socket编程TCP
linux·服务器·网络·笔记·学习·tcp/ip