Flutter与Angular通过WebRTC传输音频流无声音问题
解决方案:Flutter与Angular WebRTC音频无声音问题
一、Flutter端排查与修复
1. 验证本地媒体流采集状态
先确认Flutter端是否正常获取麦克风权限并采集到音频,在_getUserMedia中添加状态校验:
_getUserMedia() async { final Map<String, dynamic> mediaConstraints = { 'audio': true, 'video': false }; try { MediaStream stream = await navigator.mediaDevices.getUserMedia(mediaConstraints); // 打印本地轨道状态,确认是否正常采集 stream.getAudioTracks().forEach((track) { print('本地音频轨道: enabled=${track.enabled}, muted=${track.muted}'); }); return stream; } catch (e) { print('获取媒体流失败: $e'); rethrow; } }
如果本地轨道muted为true,说明麦克风权限未授权或设备故障,需先解决本地采集问题。
2. 更新SDP约束格式
旧的mandatory约束已被废弃,改用标准的RTCOfferOptions:
// 替换原有的offerSdpConstraints final offerOptions = RTCOfferOptions( offerToReceiveAudio: true, offerToReceiveVideo: false, ); // 创建PeerConnection时使用新约束 _peerConnection = await createPeerConnection(configuration, offerOptions);
旧格式可能导致SDP协商异常,影响音频轨道传输。
3. 确保ICE候选完整传输
需将所有ICE候选(包括最后一个标识收集完成的null候选)发送给Angular端:
_peerConnection?.onIceCandidate = (e) { // 即使candidate为null也要发送,通知对方候选收集完成 print(json.encode({ 'candidate': e.candidate?.toString(), 'sdpMid': e.sdpMid.toString(), 'sdpMlineIndex': e.sdpMLineIndex, })); };
Angular端收到candidate为null时,无需调用addIceCandidate即可。
二、Angular端排查与修复
1. 处理浏览器自动播放限制
现代浏览器要求音频播放必须触发于用户交互(如点击按钮),修改音频元素与播放逻辑:
<!-- 移除autoplay,改为手动触发 --> <div *ngIf="inCall"> <audio id="remote_audio" #remote_audio controls></audio> </div>
在用户操作(如开始通话按钮点击)后触发播放:
startCall() { this.inCall = true; setTimeout(() => { if (this.remoteAudio.srcObject) { this.remoteAudio.play().catch(err => { console.log('自动播放失败,请点击播放按钮:', err); }); } }, 100); }
2. 修正远程流绑定逻辑
优先使用轨道自身关联的流,避免event.streams[0]的潜在关联错误:
private handleTrackEvent = (event: RTCTrackEvent) => { console.log('收到远程音频轨道:', event.track); const remoteStream = event.track.stream; // 检查远程轨道状态 console.log('远程轨道状态: enabled=' + event.track.enabled + ', muted=' + event.track.muted); this.remoteAudio.srcObject = remoteStream; // 需在用户交互后调用play this.remoteAudio.play().catch(err => console.log('播放失败:', err)); }
3. 检查媒体权限状态
初始化时验证浏览器麦克风权限:
checkMediaPermission() { navigator.permissions.query({ name: 'microphone' as PermissionName }) .then(status => { console.log('麦克风权限状态:', status.state); if (status.state === 'denied') { alert('请授予浏览器麦克风访问权限'); } }); }
三、通用排查步骤
- 打开Chrome开发者工具
Media面板(更多工具 > Media),查看是否有远程音频轨道数据传输,无轨道则说明协商或连接异常。 - 检查SDP内容,确认Offer和Answer中存在
m=audio的媒体描述行。 - 在Flutter端调用
addTrack后,打印_peerConnection?.getSenders(),确认音频发送者已存在。
内容的提问来源于stack exchange,提问作者ROB99
相关产品推荐
相关产品推荐

