Skip to content
This repository has been archived by the owner on Aug 25, 2021. It is now read-only.

Commit

Permalink
Stop unused media tracks (#97, #27)
Browse files Browse the repository at this point in the history
- automatically stop media tracks that are not being used
- implement mute via RTCRtpSender.replaceTrack(null) instead of MediaStreamTrack.enabled = false
- replace MediaStreamHandle with LocalMediaStream and RemoteMediaStream
- replace RoomHandle.inject_local_stream with RoomHandle.set_local_media_settings

Additionally:
- make Clippy happy with clippy::enum_glob_use lint
  • Loading branch information
alexlapa authored Apr 30, 2020
1 parent 379dc19 commit 000173d
Show file tree
Hide file tree
Showing 44 changed files with 1,952 additions and 1,116 deletions.
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,6 @@ endif

cargo.lint:
cargo clippy --all -- -D clippy::pedantic -D warnings \
-A clippy::enum_glob_use \
-A clippy::wildcard_imports


Expand Down
13 changes: 8 additions & 5 deletions crates/medea-coturn-telnet-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ pub enum CoturnTelnetError {

impl From<CoturnCliCodecError> for CoturnTelnetError {
fn from(err: CoturnCliCodecError) -> Self {
use CoturnCliCodecError::*;
use CoturnCliCodecError::{BadResponse, IoFailed};

match err {
IoFailed(e) => Self::from(e),
BadResponse(e) => Self::from(e),
Expand Down Expand Up @@ -108,7 +109,7 @@ impl CoturnTelnetConnection {
&mut self,
username: String,
) -> Result<Vec<String>, CoturnTelnetError> {
use CoturnTelnetError::*;
use CoturnTelnetError::{Disconnected, UnexpectedMessage};

self.0
.send(CoturnCliRequest::PrintSessions(username))
Expand Down Expand Up @@ -141,7 +142,7 @@ impl CoturnTelnetConnection {
&mut self,
session_id: String,
) -> Result<(), CoturnTelnetError> {
use CoturnTelnetError::*;
use CoturnTelnetError::{Disconnected, UnexpectedMessage};

self.0
.send(CoturnCliRequest::CloseSession(session_id))
Expand Down Expand Up @@ -193,7 +194,9 @@ impl CoturnTelnetConnection {
/// - First message received is not [`CoturnCliResponse::EnterPassword`].
/// - Second message received is not [`CoturnCliResponse::Ready`].
async fn auth(&mut self, pass: Bytes) -> Result<(), CoturnTelnetError> {
use CoturnTelnetError::*;
use CoturnTelnetError::{
Disconnected, UnexpectedMessage, WrongPassword,
};

let response = self.0.next().await.ok_or(Disconnected)??;
if let CoturnCliResponse::EnterPassword = response {
Expand Down Expand Up @@ -222,7 +225,7 @@ impl CoturnTelnetConnection {
/// [Coturn]: https://github.com/coturn/coturn
/// [Telnet]: https://en.wikipedia.org/wiki/Telnet
pub async fn ping(&mut self) -> Result<(), CoturnTelnetError> {
use CoturnTelnetError::*;
use CoturnTelnetError::{Disconnected, UnexpectedMessage};

self.0.send(CoturnCliRequest::Ping).await?;

Expand Down
5 changes: 3 additions & 2 deletions crates/medea-coturn-telnet-client/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl TryFrom<BytesMut> for CoturnCliResponse {
type Error = CoturnResponseParseError;

fn try_from(mut msg: BytesMut) -> Result<Self, Self::Error> {
use CoturnResponseParseError::*;
use CoturnResponseParseError::{BadResponseFormat, BadResponseType};

// delete cursor if message ends with it
if msg.ends_with(CURSOR.as_bytes()) {
Expand Down Expand Up @@ -165,7 +165,8 @@ pub enum CoturnCliRequest {

impl From<CoturnCliRequest> for Bytes {
fn from(req: CoturnCliRequest) -> Self {
use CoturnCliRequest::*;
use CoturnCliRequest::{Auth, CloseSession, Ping, PrintSessions};

match req {
Auth(pass) => pass,
PrintSessions(username) => format!("ps {}", username).into(),
Expand Down
10 changes: 6 additions & 4 deletions jason/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ All user visible changes to this project will be documented in this file. This p
### BC Breaks

- Library API:
- Replace `MediaStreamHandle` with `LocalMediaStream` and `RemoteMediaStream` ([#97]);
- Expose `on_local_stream` callback in `Room` instead of `Jason` ([#54]);
- Remove error argument from `on_local_stream` callback ([#54]);
- Room initialization ([#46]):
Expand All @@ -25,7 +26,7 @@ All user visible changes to this project will be documented in this file. This p

- Media management:
- Library API:
- Mute/unmute local video/audio ([#40], [#81]):
- Mute/unmute local video/audio ([#40], [#81], [#97]):
- `Room.mute_audio()`;
- `Room.unmute_audio()`;
- `Room.mute_video()`;
Expand All @@ -35,15 +36,15 @@ All user visible changes to this project will be documented in this file. This p
- `MediaManager.enumerate_devices()`;
- `MediaManager.init_local_stream()`.
- Local media stream constraints:
- `MediaStreamConstraints`, `AudioTrackConstraints` classes ([#46]);
- `MediaStreamSettings`, `AudioTrackConstraints` classes ([#46], [#97]);
- `DeviceVideoTrackConstraints`, `DisplayVideoTrackConstraints` classes ([#78]).
- Room initialization ([#46]):
- `Jason.init_room()`;
- `Room.join()`;
- Ability to inject local video/audio stream into `Room` via `Room.inject_local_stream()` ([#54]);
- Ability to configure local media stream used by `Room` via `Room.set_local_media_settings()` ([#54], [#97]);
- `Room.on_failed_local_stream` callback ([#54]);
- `Room.on_close` callback for WebSocket close initiated by server ([#55]);
- `RtcIceTransportPolicy` configuration ([#79]).
- `RtcIceTransportPolicy` configuration ([#79]).
- Room management:
- Library API:
- `Room.on_connection_loss` callback that JS side can start Jason reconnection on connection loss with ([#75]);
Expand Down Expand Up @@ -77,6 +78,7 @@ All user visible changes to this project will be documented in this file. This p
[#81]: /../../pull/81
[#87]: /../../pull/87
[#90]: /../../pull/90
[#97]: /../../pull/97



Expand Down
136 changes: 91 additions & 45 deletions jason/demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
<script type="module">
import init, {
Jason,
MediaStreamConstraints, AudioTrackConstraints, DeviceVideoTrackConstraints, DisplayVideoTrackConstraints
MediaStreamSettings,
AudioTrackConstraints,
DeviceVideoTrackConstraints,
DisplayVideoTrackConstraints,
} from './js/medea_jason.js';

let inited = false;
Expand Down Expand Up @@ -99,7 +102,7 @@
inited = true;
const jason = new Jason();

async function getDevices(audio_select, video_select, current_stream) {
async function fillMediaDevicesInputs(audio_select, video_select, current_stream) {
const current_audio = current_stream.getAudioTracks().pop().label
|| "disable";
const current_video = current_stream.getVideoTracks().pop().label
Expand Down Expand Up @@ -129,10 +132,8 @@
video_select.append(option);
}

async function getStream(audio_select, video_select) {

let constraints = new MediaStreamConstraints();

async function build_constraints(audio_select, video_select) {
let constraints = new MediaStreamSettings();
let audio = new AudioTrackConstraints();
let audioSource = audio_select.options[audio_select.selectedIndex];
if (audioSource) {
Expand All @@ -154,9 +155,13 @@
constraints.device_video(new DeviceVideoTrackConstraints());
}

return await jason.media_manager().init_local_stream(constraints);
return constraints;
}

let isCallStarted = false;
let localStream = null;
let isAudioMuted = false;
let isVideoMuted = false;
let chooseRoomDiv = document.getElementById('choose-room');
let videoCallDiv = document.getElementById('video-call');
let chooseRoomButton = document.getElementById('choose-room__join');
Expand All @@ -177,28 +182,40 @@

let room = await jason.init_room();

const updateLocalVideo = async function (stream) {
localVideo.srcObject = stream;
const updateLocalVideo = async (stream) => {
localVideo.srcObject = stream.get_media_stream();
await localVideo.play();
};

audioSelect.addEventListener('change', async () => {
try {
const stream = await getStream(audioSelect, videoSelect);
await updateLocalVideo(stream);
room.inject_local_stream(stream);
const constraints = await build_constraints(audioSelect, videoSelect);
if (localStream && localStream.ptr > 0 ){
localStream.free();
}
if (!isAudioMuted) {
localStream = await jason.media_manager().init_local_stream(constraints)
await updateLocalVideo(localStream);
}
await room.set_local_media_settings(constraints);
} catch (e) {
logError("Changing audio source failed", e);
console.error("Changing audio source failed: " + e);
}
});

videoSelect.addEventListener('change', async () => {
try {
const stream = await getStream(audioSelect, videoSelect);
await updateLocalVideo(stream);
room.inject_local_stream(stream);
const constraints = await build_constraints(audioSelect, videoSelect);
if (localStream && localStream.ptr > 0 ){
localStream.free();
}
if (!isVideoMuted) {
localStream = await jason.media_manager().init_local_stream(constraints)
await updateLocalVideo(localStream);
}
await room.set_local_media_settings(constraints);
} catch (e) {
logError("Changing video source failed", e);
console.error("Changing video source failed: " + e);
}
});

Expand All @@ -207,6 +224,7 @@
});

room.on_new_connection((connection) => {
isCallStarted = true;
connection.on_remote_stream(async (stream) => {
let videoDiv = document.getElementById("remote-videos");
let video = document.createElement("video");
Expand All @@ -223,6 +241,11 @@
});
});

room.on_local_stream((stream) => {
updateLocalVideo(stream);
stream.free();
});

let connectionState = document.getElementById('connection-state__state');
room.on_connection_loss(async (reconnectHandle) => {
connectionState.className = 'badge badge-warning';
Expand Down Expand Up @@ -250,29 +273,50 @@

let muteAudio = document.getElementById('control__mute_audio');
let muteVideo = document.getElementById('control__mute_video');
let isAudioMuted = false;
let isVideoMuted = false;

muteAudio.addEventListener('click', async () => {
if(isAudioMuted) {
await room.unmute_audio();
isAudioMuted = false;
muteAudio.textContent = "Mute audio";
} else {
await room.mute_audio();
isAudioMuted = true;
muteAudio.textContent = "Unmute audio";
try {
if (isAudioMuted) {
if (isCallStarted) {
await room.unmute_audio();
}
isAudioMuted = false;
muteAudio.textContent = "Mute audio";
} else {
if (isCallStarted) {
await room.mute_audio();
if (localStream && localStream.ptr > 0 ){
localStream.free_audio();
}
}
isAudioMuted = true;
muteAudio.textContent = "Unmute audio";
}
} catch (e) {
console.error(e.message());
}
});
muteVideo.addEventListener('click', async () => {
if(isVideoMuted) {
await room.unmute_video();
isVideoMuted = false;
muteVideo.textContent = "Mute video";
} else {
await room.mute_video();
isVideoMuted = true;
muteVideo.textContent = "Unmute video";
try {
if (isVideoMuted) {
if (!isCallStarted) {
const constraints = await build_constraints(audioSelect, videoSelect);
localStream = await jason.media_manager().init_local_stream(constraints)
await updateLocalVideo(localStream);
}
await room.unmute_video();
isVideoMuted = false;
muteVideo.textContent = "Mute video";
} else {
await room.mute_video();
if (localStream && localStream.ptr > 0 ){
localStream.free_video();
}
isVideoMuted = true;
muteVideo.textContent = "Unmute video";
}
} catch (e) {
console.error(e.message());
}
});

Expand Down Expand Up @@ -320,12 +364,13 @@
videoCallDiv.style.display = "";

try {
const stream = await getStream(audioSelect, videoSelect);
await updateLocalVideo(stream);
await getDevices(audioSelect, videoSelect, stream);
room.inject_local_stream(stream);
const constraints = await build_constraints(audioSelect, videoSelect);
localStream = await jason.media_manager().init_local_stream(constraints)
await updateLocalVideo(localStream);
await fillMediaDevicesInputs(audioSelect, videoSelect, localStream.get_media_stream());
await room.set_local_media_settings(constraints);
} catch (e) {
logError("Init local video failed", e);
console.error("Init local video failed: " + e.message());
}

} else {
Expand All @@ -336,12 +381,13 @@
bindJoinButtons(roomId);

try {
const stream = await getStream(audioSelect, videoSelect);
await updateLocalVideo(stream);
await getDevices(audioSelect, videoSelect, stream);
room.inject_local_stream(stream);
const constraints = await build_constraints(audioSelect, videoSelect);
localStream = await jason.media_manager().init_local_stream(constraints)
await updateLocalVideo(localStream);
await fillMediaDevicesInputs(audioSelect, videoSelect, localStream.get_media_stream());
await room.set_local_media_settings(constraints);
} catch (e) {
logError("Init local video failed", e);
console.error("Init local video failed: " + e.message());
}

chooseRoomDiv.style.display = "none";
Expand Down
Loading

0 comments on commit 000173d

Please sign in to comment.