Merge pull request #1 from livekit/fix-web-audio
fix audio not playing in web environments
This commit is contained in:
@@ -155,6 +155,7 @@ class _RoomState extends State<RoomWidget> with RoomDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// displays a participant in view
|
||||||
class VideoView extends StatefulWidget {
|
class VideoView extends StatefulWidget {
|
||||||
final Participant participant;
|
final Participant participant;
|
||||||
final VideoQuality quality;
|
final VideoQuality quality;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import 'room.dart';
|
import 'room.dart';
|
||||||
|
import 'signal_client.dart';
|
||||||
|
|
||||||
class LiveKitClient {
|
class LiveKitClient {
|
||||||
// TODO: take in connect options
|
static Future<Room> connect(String url, String token,
|
||||||
static Future<Room> connect(String url, String token) {
|
[JoinOptions? options]) {
|
||||||
var room = Room();
|
var room = Room();
|
||||||
return room.connect(url, token);
|
return room.connect(url, token, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||||
|
import 'package:livekit_client/src/track/audio_track.dart';
|
||||||
import '../proto/livekit_models.pb.dart';
|
import '../proto/livekit_models.pb.dart';
|
||||||
import '../signal_client.dart';
|
import '../signal_client.dart';
|
||||||
import '../track/remote_track_publication.dart';
|
import '../track/remote_track_publication.dart';
|
||||||
@@ -49,7 +50,9 @@ class RemoteParticipant extends Participant {
|
|||||||
|
|
||||||
Track? track;
|
Track? track;
|
||||||
if (pub.kind == TrackType.AUDIO) {
|
if (pub.kind == TrackType.AUDIO) {
|
||||||
track = new Track(pub.kind, pub.name, mediaTrack);
|
var audioTrack = new AudioTrack(pub.name, mediaTrack, stream);
|
||||||
|
audioTrack.start();
|
||||||
|
track = audioTrack;
|
||||||
} else if (pub.kind == TrackType.VIDEO) {
|
} else if (pub.kind == TrackType.VIDEO) {
|
||||||
track = new VideoTrack(pub.name, mediaTrack, stream);
|
track = new VideoTrack(pub.name, mediaTrack, stream);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class SignalClient {
|
|||||||
|
|
||||||
Future<void> join(String url, String token, JoinOptions? options) async {
|
Future<void> join(String url, String token, JoinOptions? options) async {
|
||||||
var rtcUrl = '$url/rtc';
|
var rtcUrl = '$url/rtc';
|
||||||
var params = _paramsForToken(token);
|
var params = _joinParams(token);
|
||||||
if (options != null && options.autoSubscribe != null) {
|
if (options != null && options.autoSubscribe != null) {
|
||||||
params += '&auto_subscribe=${options.autoSubscribe! ? '1' : '0'}';
|
params += '&auto_subscribe=${options.autoSubscribe! ? '1' : '0'}';
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ class SignalClient {
|
|||||||
_ws = null;
|
_ws = null;
|
||||||
|
|
||||||
url += '/rtc';
|
url += '/rtc';
|
||||||
var params = _paramsForToken(token);
|
var params = _joinParams(token);
|
||||||
params += '&reconnect=1';
|
params += '&reconnect=1';
|
||||||
var uri = Uri.parse(url + params);
|
var uri = Uri.parse(url + params);
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ class SignalClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _paramsForToken(String token) {
|
String _joinParams(String token) {
|
||||||
return '?access_token=$token&protocol=$protocolVersion';
|
return '?access_token=$token&protocol=$protocolVersion';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||||
|
|
||||||
|
void startAudio(String id, MediaStreamTrack stream) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopAudio(String id) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// ignore: avoid_web_libraries_in_flutter
|
||||||
|
import 'dart:html' as html;
|
||||||
|
|
||||||
|
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||||
|
// ignore: implementation_imports
|
||||||
|
import 'package:flutter_webrtc/src/web/media_stream_track_impl.dart';
|
||||||
|
|
||||||
|
const audioContainerId = 'livekit_audio_container';
|
||||||
|
const audioPrefix = 'livekit_audio_';
|
||||||
|
|
||||||
|
void startAudio(String id, MediaStreamTrack track) {
|
||||||
|
if (!(track is MediaStreamTrackWeb)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var elementId = audioPrefix + id;
|
||||||
|
var audioElement = html.document.getElementById(elementId);
|
||||||
|
if (audioElement == null) {
|
||||||
|
audioElement = html.AudioElement()
|
||||||
|
..id = elementId
|
||||||
|
..autoplay = true;
|
||||||
|
findOrCreateAudioContainer().append(audioElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(audioElement is html.AudioElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var audioStream = html.MediaStream();
|
||||||
|
audioStream.addTrack(track.jsTrack);
|
||||||
|
audioElement.srcObject = audioStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopAudio(String id) {
|
||||||
|
var audioElement = html.document.getElementById(audioPrefix + id);
|
||||||
|
if (audioElement != null) {
|
||||||
|
if (audioElement is html.AudioElement) {
|
||||||
|
audioElement.srcObject = null;
|
||||||
|
}
|
||||||
|
audioElement.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html.DivElement findOrCreateAudioContainer() {
|
||||||
|
var div = html.document.getElementById(audioContainerId);
|
||||||
|
if (div != null) {
|
||||||
|
return div as html.DivElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
div = html.DivElement();
|
||||||
|
div.id = audioContainerId;
|
||||||
|
div.style.display = 'none';
|
||||||
|
html.document.body?.append(div);
|
||||||
|
return div as html.DivElement;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||||
|
|
||||||
|
import '../proto/livekit_models.pbenum.dart';
|
||||||
|
import 'local_audio_track.dart';
|
||||||
|
import 'track.dart';
|
||||||
|
import '_audio_api.dart' if (dart.library.html) '_audio_html.dart' as audio;
|
||||||
|
|
||||||
|
class AudioTrack extends Track {
|
||||||
|
MediaStream? mediaStream;
|
||||||
|
|
||||||
|
AudioTrack(String name, MediaStreamTrack track, this.mediaStream)
|
||||||
|
: super(TrackType.AUDIO, name, track);
|
||||||
|
|
||||||
|
start() {
|
||||||
|
if (!(this is LocalAudioTrack)) {
|
||||||
|
audio.startAudio(getCid(), mediaTrack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
stop() {
|
||||||
|
mediaStream?.dispose();
|
||||||
|
mediaStream = null;
|
||||||
|
audio.stopAudio(getCid());
|
||||||
|
super.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||||
|
import 'package:livekit_client/src/track/audio_track.dart';
|
||||||
|
|
||||||
import '../errors.dart';
|
import '../errors.dart';
|
||||||
import '../proto/livekit_models.pb.dart';
|
|
||||||
import 'options.dart';
|
import 'options.dart';
|
||||||
import 'track.dart';
|
|
||||||
|
|
||||||
class LocalAudioTrack extends Track {
|
class LocalAudioTrack extends AudioTrack {
|
||||||
MediaStream? mediaStream;
|
LocalAudioTrack(String name, MediaStreamTrack track, MediaStream stream)
|
||||||
|
: super(name, track, stream);
|
||||||
LocalAudioTrack(String name, MediaStreamTrack track, this.mediaStream)
|
|
||||||
: super(TrackType.AUDIO, name, track);
|
|
||||||
|
|
||||||
static Future<LocalAudioTrack> createTrack(
|
static Future<LocalAudioTrack> createTrack(
|
||||||
[LocalAudioTrackOptions? options]) async {
|
[LocalAudioTrackOptions? options]) async {
|
||||||
@@ -28,11 +25,4 @@ class LocalAudioTrack extends Track {
|
|||||||
return Future.error(e);
|
return Future.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
stop() {
|
|
||||||
super.stop();
|
|
||||||
mediaStream?.dispose();
|
|
||||||
mediaStream = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||||
|
|
||||||
import '../track/video_track.dart';
|
import '../track/video_track.dart';
|
||||||
import '../track/local_video_track.dart';
|
import '../track/local_video_track.dart';
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ class _VideoTrackRendererState extends State<VideoTrackRenderer> {
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
widget.track.removeListener(_trackChanged);
|
widget.track.removeListener(_trackChanged);
|
||||||
|
_renderer.srcObject = null;
|
||||||
_renderer.dispose();
|
_renderer.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
@@ -38,6 +40,7 @@ class _VideoTrackRendererState extends State<VideoTrackRenderer> {
|
|||||||
void didUpdateWidget(covariant VideoTrackRenderer oldWidget) {
|
void didUpdateWidget(covariant VideoTrackRenderer oldWidget) {
|
||||||
oldWidget.track.removeListener(_trackChanged);
|
oldWidget.track.removeListener(_trackChanged);
|
||||||
widget.track.addListener(_trackChanged);
|
widget.track.addListener(_trackChanged);
|
||||||
|
_trackChanged();
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user