I've been wondering how can I stop the audio stream even if the user checks the audio checkbox in the sharescreen Chrome pop-up. Is there any setting, any flag that I can tick as false that won't share the audio?
The sharescreen popup
I was jumping between chime-sdk, and chime-sdk-react-components documentations and wasn't able to find the thing I am looking for.
This is the function I'm currently using and I suppose that if there is any way of stopping the audio stream I would put it right here.
const createSession = async () => {
try {
const contentShareStream = await meetingSession.audioVideo!.startContentShareFromScreenCapture();
meetingSession.audioVideo!.addContentShareObserver(observer);
} catch (e) {
console.log(e);
}
};
Related
I'm trying to add filter effects to an audio stream I have playing on my website. I'm able to connect the Tone.js library to the audio stream but I'm not hearing any changes in the audio stream playing on the website. I'm not seeing any errors in the console and I've tried adjusting the filter from 50 to 5000 but nothing seems to have any effect on the audio. Do I need to set up the new Tone.Player() to actually hear the audio? If so, how do you go about setting up the Player if there is no src for the existing audio element.
$('#testBtn').click(async function () {
const audioElement = document.getElementById('theAudioStream');
const mediaElementSource = Tone.context.createMediaElementSource(audioElement);
const filter = new Tone.Filter(50, 'lowpass').toDestination();
Tone.connect(mediaElementSource, filter);
await Tone.start();
console.log("Started?");
});
The audio stream I'm trying to modify is set up from a JsSip call. The code to start the stream is as follows:
var audioStream = document.getElementById('theAudioStream')
//further down in code
currentSession.answer(options);
if (currentSession.connection) {
currentSession.connection.ontrack = function (e) {
audioStream.srcObject = e.streams[0];
audioStream.play();
}
}
I click the test button after the call has started so I know the audio stream is present before initializing the Tone.js Filters
Working solution:
Removing the audioStream.play() from where the JsSIP call is answered solves the issue.
I don't know the exact reason why this solves the issue (it might even be a workaround) but after much trial and error this way allows the audio to be available to ToneJS for effecting.
Any other solutions are welcome.
I want to bind an event listener to the windows object that checks if the browser is using the speaker and microphone.
My use-case is as follows: I have an application where the user can record audio and play it back. However, if the application has been idle for 60sec then I want it to reload.
I have added listeners to mousemove and keypress which prevent the application from reloading if they're getting called but I also want to prevent the reloading if the user is recording audio or playing it back.
The approach I can think of is adding similar event listeners for these cases (record+playback), but I cannot figure out how I can add listeners for them.
I need something like,
windows.addEventListener('speaker', () => console.log('user using speaker')
windows.addEventListener('microphone', () => console.log('user using microphone')
Does any such event exist? Or is there any way I can check if the browser is using the speaker+microphone?
Any lead will be appreciated!
No, there is not a microphone or speaker event.
But, you can create your own events with the Event constructor. I've made an example here which creates a microphonestart and microphonestop event. These events will be dispatched whenever a microphone stream starts or when the stream has been stopped.
async function getMicrophone() {
// Use audio only.
const constraints = { audio: true };
// Create the events.
const microphoneStartEvent = new Event('microphonestart');
const microphoneStopEvent = new Event('microphonestop');
// Create the stream.
const stream = await navigator.mediaDevices.getUserMedia(constraints);
// You'll want to know if a stream has randomly stopped without the user's intent.
const tracks = stream.getAudioTracks();
for (const track of tracks) {
track.addEventListener('ended', () => {
window.dispatchEvent(microphoneStopEvent);
});
}
// Internal function to stop the stream and fire the microphonestop event.
const stopStream = () => {
const tracks = stream.getAudioTracks();
for (const track of tracks) {
track.stop();
}
window.dispatchEvent(microphoneStopEvent);
}
// Stream is running, fire microphonestart event.
window.dispatchEvent(microphoneStartEvent);
// Return both the stream and the stopStream function.
return {
stream,
stopStream
};
}
Now you can use this just like your example, the only difference is there are now two added events: microphonestart and microphonestop. You can listen for them on the window object.
// Listen to the microphonestart event.
window.addEventListener('microphonestart', () => {
console.log('user using microphone');
});
// Listen to the microphonestop event.
window.addEventListener('microphonestop', () => {
console.log('user stopped using microphone');
});
// Start the stream.
getMicrophone().then(({ stream, stopStream }) => {
// Use the stream.
console.log(stream);
// Stop the stream when you need.
stopStream();
}).catch(error => {
console.error(error);
});
As for you speaker; it's the same principle. However it does depend on what technology you're using. Do you use an HTMLAudioElement or the Web Audio API?
Safari on iOS puts a scrubber on its lock screen for simple HTMLAudioElements. For example:
const a = new Audio();
a.src = 'https://example.com/audio.m4a'
a.play();
JSFiddle: https://jsfiddle.net/0seckLfd/
The lock screen will allow me to choose a position in the currently playing audio file.
How can I disable the ability for the user to scrub the file on the lock screen? The metadata showing is fine, and being able to pause/play is also acceptable, but I'm also fine with disabling it all if I need to.
DISABLE Player on lock screen completely
if you want to completely remove the lock screen player you could do something like
const a = new Audio();
document.querySelector('button').addEventListener('click', (e) => {
a.src = 'http://sprott.physics.wisc.edu/wop/sounds/Bicycle%20Race-Full.m4a'
a.play();
});
document.addEventListener('visibilitychange', () => {
if (document.hidden) a.src = undefined
})
https://jsfiddle.net/5s8c9eL0/3/
that is stoping the player when changing tab or locking screen
(code to be cleaned improved depending on your needs)
From my understanding you can't block/hide the scrubbing commands unless you can tag the audio as a live stream. That being said, you can use js to refuse scrubbing server-side. Reference the answer here. Although that answer speaks of video, it also works with audio.
The lock screen / control center scrubber can also be avoided by using Web Audio API.
This is an example of preloading a sound and playing it, with commentary and error handling:
try {
// <audio> element is simpler for sound effects,
// but in iOS/iPad it shows up in the Control Center, as if it's music you'd want to play/pause/etc.
// Also, on subsequent plays, it only plays part of the sound.
// And Web Audio API is better for playing sound effects anyway because it can play a sound overlapping with itself, without maintaining a pool of <audio> elements.
window.audioContext = window.audioContext || new AudioContext(); // Interoperate with other things using Web Audio API, assuming they use the same global & pattern.
const audio_buffer_promise =
fetch("audio/sound.wav")
.then(response => response.arrayBuffer())
.then(array_buffer => audioContext.decodeAudioData(array_buffer))
var play_sound = async function () {
audioContext.resume(); // in case it was not allowed to start until a user interaction
// Note that this should be before waiting for the audio buffer,
// so that it works the first time (it would no longer be "within a user gesture")
// This only works if play_sound is called during a user gesture (at least once), otherwise audioContext.resume(); needs to be called externally.
const audio_buffer = await audio_buffer_promise; // Promises can be awaited any number of times. This waits for the fetch the first time, and is instant the next time.
// Note that if the fetch failed, it will not retry. One could instead rely on HTTP caching and just fetch() each time, but that would be a little less efficient as it would need to decode the audio file each time, so the best option might be custom caching with request error handling.
const source = audioContext.createBufferSource();
source.buffer = audio_buffer;
source.connect(audioContext.destination);
source.start();
};
} catch (error) {
console.log("AudioContext not supported", error);
play_sound = function() {
// no-op
// console.log("SFX disabled because AudioContext setup failed.");
};
}
I did a search, in search of a way to help you, but I did not find an effective way to disable the commands, however, I found a way to customize them, it may help you, follow the apple tutorial link
I think what's left to do now is wait, see if ios 13 will bring some option that will do what you want.
I am building a project that captures an image from the webcam in the browser. After the image is taken, I no longer need to use the camera, so I am trying to stop it with the following function:
function stopCamera(container) {
console.log("Stopping the camera.");
video = container.querySelector('.video-streamer');
console.log(video);
video.srcObject = null;
navigator.mediaDevices.getUserMedia({ video: true }).then(
function (stream) {
console.log(stream.getTracks().length);
stream.getTracks().forEach(function (track) {
console.log("Found a stream that needs to be stopped.")
track.stop();
});
console.log(stream.getTracks().length);
}).catch(
function (error) {
console.log('getUserMedia() error', error);
});
}
However, even after the function is called, the webcam access light stays on, and I see that the browser (both Firefox and Chrome) still show that the page is using the camera.
What is missing in the code above?
navigator.mediaDevices.getUserMedia returns a new stream (a clone), not the existing stream.
You have to stop all tracks from all stream clones returned from different calls to getUserMedia, before the light goes out.
In your case, that includes the tracks of the stream you're already playing. Use the following:
function stopCamera(container) {
const video = container.querySelector('.video-streamer');
for (const track of video.srcObject.getTracks()) {
track.stop();
}
video.srcObject = null;
}
Once all tracks are stopped, the light should go out instantly.
If you neglect to do this, the light should still go out 3-10 seconds after video.srcObject = null thanks to garbage collection (assuming it was the lone held reference to the stream).
If you've created any track clones, you need to stop them too.
Safari on iOS puts a scrubber on its lock screen for simple HTMLAudioElements. For example:
const a = new Audio();
a.src = 'https://example.com/audio.m4a'
a.play();
JSFiddle: https://jsfiddle.net/0seckLfd/
The lock screen will allow me to choose a position in the currently playing audio file.
How can I disable the ability for the user to scrub the file on the lock screen? The metadata showing is fine, and being able to pause/play is also acceptable, but I'm also fine with disabling it all if I need to.
DISABLE Player on lock screen completely
if you want to completely remove the lock screen player you could do something like
const a = new Audio();
document.querySelector('button').addEventListener('click', (e) => {
a.src = 'http://sprott.physics.wisc.edu/wop/sounds/Bicycle%20Race-Full.m4a'
a.play();
});
document.addEventListener('visibilitychange', () => {
if (document.hidden) a.src = undefined
})
https://jsfiddle.net/5s8c9eL0/3/
that is stoping the player when changing tab or locking screen
(code to be cleaned improved depending on your needs)
From my understanding you can't block/hide the scrubbing commands unless you can tag the audio as a live stream. That being said, you can use js to refuse scrubbing server-side. Reference the answer here. Although that answer speaks of video, it also works with audio.
The lock screen / control center scrubber can also be avoided by using Web Audio API.
This is an example of preloading a sound and playing it, with commentary and error handling:
try {
// <audio> element is simpler for sound effects,
// but in iOS/iPad it shows up in the Control Center, as if it's music you'd want to play/pause/etc.
// Also, on subsequent plays, it only plays part of the sound.
// And Web Audio API is better for playing sound effects anyway because it can play a sound overlapping with itself, without maintaining a pool of <audio> elements.
window.audioContext = window.audioContext || new AudioContext(); // Interoperate with other things using Web Audio API, assuming they use the same global & pattern.
const audio_buffer_promise =
fetch("audio/sound.wav")
.then(response => response.arrayBuffer())
.then(array_buffer => audioContext.decodeAudioData(array_buffer))
var play_sound = async function () {
audioContext.resume(); // in case it was not allowed to start until a user interaction
// Note that this should be before waiting for the audio buffer,
// so that it works the first time (it would no longer be "within a user gesture")
// This only works if play_sound is called during a user gesture (at least once), otherwise audioContext.resume(); needs to be called externally.
const audio_buffer = await audio_buffer_promise; // Promises can be awaited any number of times. This waits for the fetch the first time, and is instant the next time.
// Note that if the fetch failed, it will not retry. One could instead rely on HTTP caching and just fetch() each time, but that would be a little less efficient as it would need to decode the audio file each time, so the best option might be custom caching with request error handling.
const source = audioContext.createBufferSource();
source.buffer = audio_buffer;
source.connect(audioContext.destination);
source.start();
};
} catch (error) {
console.log("AudioContext not supported", error);
play_sound = function() {
// no-op
// console.log("SFX disabled because AudioContext setup failed.");
};
}
I did a search, in search of a way to help you, but I did not find an effective way to disable the commands, however, I found a way to customize them, it may help you, follow the apple tutorial link
I think what's left to do now is wait, see if ios 13 will bring some option that will do what you want.