Flutter技术问题:如何将flutter_sound录制的音频发送至Socket服务器
Flutter语音消息实现:获取音频信息并通过Socket发送
1. 获取音频文件信息
基础文件属性(大小、路径)
用Dart内置的dart:io库直接读取文件核心属性:
import 'dart:io'; // recordedFilePath 是flutter_sound返回的音频文件路径 final audioFile = File(recordedFilePath); // 获取文件大小(单位:字节) final int fileSize = await audioFile.length(); // 获取文件最后修改时间 final DateTime modifiedTime = await audioFile.lastModified();
音频元数据(时长、编码格式)
如果需要音频时长这类专业信息,推荐用flutter_sound自带的工具类,无需额外依赖:
import 'package:flutter_sound/flutter_sound.dart'; // 获取音频时长(返回Duration类型) final Duration? audioDuration = await FlutterSoundHelper().duration(recordedFilePath); print('音频时长:${audioDuration?.inSeconds}秒');
若需更详细的元数据(如编码格式、采样率),可使用audio_metadata第三方库,添加依赖后调用:
import 'package:audio_metadata/audio_metadata.dart'; final metadata = await MetadataRetriever.fromFile(audioFile); print('编码格式:${metadata.format}'); print('采样率:${metadata.sampleRate}');
2. 通过socket_io_client发送音频到服务器
方案1:直接发送二进制字节(推荐短语音场景)
读取文件字节后,将音频数据与元数据一起通过Socket发送:
import 'dart:io'; import 'package:socket_io_client/socket_io_client.dart' as IO; // 初始化Socket连接(确保已完成配置) final IO.Socket socket = IO.io('http://localhost:3000', { 'transports': ['websocket'], 'autoConnect': true, }); // 读取音频文件字节 final List<int> audioBytes = await audioFile.readAsBytes(); // 发送语音消息事件 socket.emit('voice_message', { 'senderId': '当前用户ID', 'duration': audioDuration?.inSeconds, 'fileSize': fileSize, 'audioData': audioBytes, 'fileName': 'voice_${DateTime.now().millisecondsSinceEpoch}.aac', // 自定义唯一文件名 });
方案2:分块发送(大音频场景)
如果音频文件较大,可拆分字节分块发送,避免单次发送数据过大:
const int chunkSize = 1024 * 100; // 100KB每块 int offset = 0; final String messageId = DateTime.now().millisecondsSinceEpoch.toString(); while (offset < audioBytes.length) { final end = offset + chunkSize > audioBytes.length ? audioBytes.length : offset + chunkSize; final chunk = audioBytes.sublist(offset, end); socket.emit('voice_chunk', { 'messageId': messageId, 'chunk': chunk, 'isLast': end == audioBytes.length, 'metadata': { 'senderId': '当前用户ID', 'duration': audioDuration?.inSeconds, 'fileName': 'voice_${messageId}.aac', } }); offset += chunkSize; }
3. 服务器端接收处理(Node.js示例)
假设你的Socket服务器用Node.js的socket.io搭建,接收并保存音频:
const fs = require('fs'); const path = require('path'); const http = require('http'); const express = require('express'); const { Server } = require('socket.io'); const app = express(); const server = http.createServer(app); const io = new Server(server, { cors: { origin: '*' } // 开发环境临时放开,生产环境需限制域名 }); // 配置静态文件服务,让客户端能访问保存的音频 app.use('/voices', express.static(path.join(__dirname, 'voices'))); // 创建保存音频的目录(不存在则自动创建) if (!fs.existsSync('./voices')) fs.mkdirSync('./voices'); io.on('connection', (socket) => { // 接收完整语音消息 socket.on('voice_message', (data) => { const filePath = path.join(__dirname, 'voices', data.fileName); // 将二进制数据写入文件 fs.writeFileSync(filePath, Buffer.from(data.audioData)); // 转发给其他在线用户 socket.broadcast.emit('receive_voice', { senderId: data.senderId, duration: data.duration, audioUrl: `http://localhost:3000/voices/${data.fileName}` }); }); // 接收分块语音(如果用分块方案) const chunkCache = {}; socket.on('voice_chunk', (data) => { const { messageId, chunk, isLast, metadata } = data; if (!chunkCache[messageId]) { chunkCache[messageId] = { chunks: [], metadata }; } chunkCache[messageId].chunks.push(chunk); if (isLast) { const allBytes = Buffer.concat(chunkCache[messageId].chunks); const filePath = path.join(__dirname, 'voices', metadata.fileName); fs.writeFileSync(filePath, allBytes); // 转发完整语音信息 socket.broadcast.emit('receive_voice', { senderId: metadata.senderId, duration: metadata.duration, audioUrl: `http://localhost:3000/voices/${metadata.fileName}` }); delete chunkCache[messageId]; } }); }); server.listen(3000, () => console.log('服务器运行在3000端口'));
内容的提问来源于stack exchange,提问作者Jood Alk
相关产品推荐
相关产品推荐

