Switch to default audio input device when it's connected in js - twilio

I'm using twilio sdk to implement web calling app. Let's say I'm making a call to someone with my laptop devices (mic and speakers). During the call I plugged-in my headset. In the system both audio input and output devices are changed. The call audio output signal is transferred fine (I can here my counterpart through my headphones). But the audio input device stays the same - app doesn't start to use the mic on my headset.
It there any way to update audio input track to switch to a headset once it's connected?

First of all, get local praticipant tracks and filter audio track.
const publications = Array.from(this.participant.tracks.values());
const audioPublication = publications.find(item => item.kind === 'audio');
Then set the deviceId like this.
const constraints = { deviceId: { exact: deviceId } };
audioPublication.track.restart(constraints);

Related

AVAudioEngine recording music from external microphone

I have set up a simple graph, using AVAudioEngine, to simply take the default input node's data and put it in the headphones (audio monitoring) - this should simply make your headphones replicate whatever it hears through the microphone and it does, the background noise is redirected right into your ears, when running this app, however, there is one problem: it will always take the built-in mic's input, even if an external mic is plugged into the iPad.
AVAudioSession tells me, that the input should be using the external microphone (through [[AVAudioSession sharedInstance] currentRoute]) and if I record audio with AVAudioRecorder, it does use that input, however not AVAudioEngine, it sticks to the built-in mic. Am I doing something wrong? Is there a setting I missed?
Try setting the preferred Input to the external mic:
//get all avaialable Inputs
var listOfInputs = AVAudioSession.sharedInstance().availableInputs
println(listOfInputs)
//pick which one you want (change index)
var availableInput: AVAudioSessionPortDescription = listOfInputs[0] as AVAudioSessionPortDescription
//set the Preffered Input
AVAudioSession.sharedInstance().setPreferredInput(availableInput, error: nil)
Careful though, this is without error handling for simplicities sake. You will want to offer a default option if your external mic is unplugged or not available.

IOS WebAudio only works on headphones

I've been running into an issue now for a while where on some ios devices my webaudio system only seems to work with headphones where as other devices (exact same os, model, etc) the audio plays perfectly fine through the speakers or headphones. I've searched for a solution to this but haven't found anything on this exact issue. The only thing I can think of is that maybe it's an audio channel issue or something.
How can I fix this?
#Alastair is correct, the mute toggle switch does mute WebAudio, but it does not mute HTML5 tags. Thanks to his work I managed to find a work around for the web which enables WebAudio to play even when the mute toggle switch is on. I'd post this as a comment on his reply, but I don't have the reputation.
In order to play WebAudio you must also play at least one WebAudio sound source node and one HTML5 tag during a user action. It is fine if these sounds are short bits of silence. I found that this self contained code works without any extra files needed:
EDIT 11/29/19:
Removed vestigial typescript typedefs. Thanks #Joep. I also realized the code below is woefully out of date and janky. Just consider it an example. Editing this post prompted me to create an open source solution for this. You can see a demo of it here: https://spencer-evans.com/share/github/unmute/ and check out the repo here: https://github.com/swevans/unmute
/**
* PLEASE DONT USE THIS AS IT IS, THIS IS JUST EXAMPLE CODE.
* If you want a drop in solution I have a script on git hub
* Demo:
* #see https://spencer-evans.com/share/github/unmute/
* Github Repo:
* #see https://github.com/swevans/unmute
*/
var isWebAudioUnlocked = false;
var isHTMLAudioUnlocked = false;
function unlock() {
if (isWebAudioUnlocked && isHTMLAudioUnlocked) return;
// Unlock WebAudio - create short silent buffer and play it
// This will allow us to play web audio at any time in the app
var buffer = myContext.createBuffer(1, 1, 22050); // 1/10th of a second of silence
var source = myContext.createBufferSource();
source.buffer = buffer;
source.connect(myContext.destination);
source.onended = function()
{
console.log("WebAudio unlocked!");
isWebAudioUnlocked = true;
if (isWebAudioUnlocked && isHTMLAudioUnlocked)
{
console.log("WebAudio unlocked and playable w/ mute toggled on!");
window.removeEventListener("mousedown", unlock);
}
};
source.start();
// Unlock HTML5 Audio - load a data url of short silence and play it
// This will allow us to play web audio when the mute toggle is on
var silenceDataURL = "data:audio/mp3;base64,//MkxAAHiAICWABElBeKPL/RANb2w+yiT1g/gTok//lP/W/l3h8QO/OCdCqCW2Cw//MkxAQHkAIWUAhEmAQXWUOFW2dxPu//9mr60ElY5sseQ+xxesmHKtZr7bsqqX2L//MkxAgFwAYiQAhEAC2hq22d3///9FTV6tA36JdgBJoOGgc+7qvqej5Zu7/7uI9l//MkxBQHAAYi8AhEAO193vt9KGOq+6qcT7hhfN5FTInmwk8RkqKImTM55pRQHQSq//MkxBsGkgoIAABHhTACIJLf99nVI///yuW1uBqWfEu7CgNPWGpUadBmZ////4sL//MkxCMHMAH9iABEmAsKioqKigsLCwtVTEFNRTMuOTkuNVVVVVVVVVVVVVVVVVVV//MkxCkECAUYCAAAAFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV";
var tag = document.createElement("audio");
tag.controls = false;
tag.preload = "auto";
tag.loop = false;
tag.src = silenceDataURL;
tag.onended = function()
{
console.log("HTMLAudio unlocked!");
isHTMLAudioUnlocked = true;
if (isWebAudioUnlocked && isHTMLAudioUnlocked)
{
console.log("WebAudio unlocked and playable w/ mute toggled on!");
window.removeEventListener("mousedown", unlock);
}
};
var p = tag.play();
if (p) p.then(function(){console.log("play success")}, function(reason){console.log("play failed", reason)});
}
window.addEventListener("mousedown", unlock);
This is likely because the iPhone's side switch is on "mute". It's very confusing - HTML5 <audio> tags still play fine when the phone is muted, but WebAudio does not. Why? Who knows. But it's a restriction I currently haven't found a way around.
If the iPhone mute button is down, meaning that the iPhone is muted, what is played through Web Audio Api will be muted.
Unfortunately there is no way to check if that physical button (located on the left edge towards the top of the iPhone) is on or off through Javascript.
This issue is completely independent from the fact that in iOS Safari the audio has to be started by a user action for it to be unmuted. There are some tricks that can be done to overcome that fact, including the one suggested by here Spencer, were you use "any action or a specific action" started by the user to "play" a silent audio file to allow subsequently playing audio files to play unmuted.
had same issue, and finally understood problem.
indeed WebView don't play sound on internal speakers if phone is in mute.
when i dig deeper i found a workaround :)
original post => https://stackoverflow.com/a/37874619/8064246
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
//print("AVAudioSession Category Playback OK")
do {
try AVAudioSession.sharedInstance().setActive(true)
//print("AVAudioSession is Active")
} catch _ as NSError {
//print(error.localizedDescription)
}
} catch _ as NSError {
//print(error.localizedDescription)
}

Native video in Air on iOS stopping sound and microphone

I'm trying to play a native video in a StageWebView in an Air for iPad app that plays sound and requires user interaction via the microphone.
Everything seems to work, but when I start playing the video, sound and microphone stop.
If I dispose the StageWebView, sound and mic get back but only after 15 seconds (and I need sound and mic to work at least straight after the StageWebView is released).
I tried to get this work on an iOS5 iPad1, and on an iOS6 iPad2, using Air 3.4, 3.5 and 3.6 beta. I tried to switch the mute button of the iPad, and I also tried to change the SoundMixer.audioPlaybackMode to Media and Ambient.
But it didn't worked and I'm stucked.
Here is my code that deals with the microphone :
var microphone:Microphone = Microphone.getMicrophone();
microphone.addEventListener(SampleDataEvent.SAMPLE_DATA, __micHandler);
private function micHandler(event : SampleDataEvent) : void {
trace("mic is working !");
}
For the audio :
_snd = new Sound();
_snd.load(new URLRequest(path));
_sndChannel = _snd.play();
private function soundStopHandler(event : MouseEvent) : void {
if(_sndChannel) _sndChannel.stop();
}
And for the video player :
_webview = new StageWebView();
_webview.stage = stage;
_webview.viewPort = new Rectangle(10, 120, 480, 300);
_webview.loadURL(path);
private function videoStopHandler(event : MouseEvent) : void {
if(_webview) {
_webview.dispose();
_webview = null;
}
}
Did anyone faced this problem before me ? Is there anything I forgot or did in a wrong way ?
Maybe this problem is related to the iOS System.
In iOS perspective, as far as I know, officially it is not possible. When you start the recording sessions, except for recording does not occupy it. Once you playback and recording sessions in the session must be solved. recording and playback session, the session can not be occupied simultaneously.
refer a apple documentation: Audio Session
AVAudioSessionCategoryPlayAndRecord or the equivalent kAudioSessionCategory_PlayAndRecord—Use this category for an application that inputs and outputs audio. The input and output need not occur simultaneously, but can if needed. This is the category to use for audio chat applications.
In AIR, if you code no problem. most likely this reason.

Ipad html5 load multiple audio files

I want to preload multiple audio files. To do this, I tried to create multiple Audio elements in JavaScript.
function loadAudio(){
audio1 = new Audio();
audio1.addEventListener('canplaythrough', isLoaded, false);
audio1.src = 'assets/audio/Maid with the Flaxen Hair.mp3';
audio1.load();
}
function isLoaded(){
audio1.removeEventListener('canplaythrough', isAppLoaded);
alert('maid');
alert('start audio 2');
audio2 = new Audio();
audio2.addEventListener('canplaythrough', isLoaded2, false);
audio2.src = 'assets/audio/Kalimba.mp3';
audio2.load();
}
function isLoaded2(){
alert('kalimba');
}
I only get the first alert, the second one never works.
I found that I can only play one sound at a time, but can I also only load one? Does the script need another user input for every new Audio object I create? Or does anyone have another way to create a preloader for audio?
this could have to do with the limitations on autoplaying (and, as far as i know autoloading) audiofiles on ios-devices (see here: Limitations of HTML5 Audio on iOS 4?).
In short: You cannot programmatically start audio-playback on ios devices, this is only allowed from within event-handlers for trusted (=initiated by the user) events.
Yo can play multiple audio on IOS device
using following way
$("#btn").on("click",function(){
alert("audio clicked");
var aud=new Audio();
aud.src="music.mp3";
aud.play();
var aud1=new Audio();
aud1.src="intro.mp3";
aud1.play();
})
The above code play multiple audio on device

Detect attached audio devices iOS

I'm trying to figure out how to detect which if any audio devices are connected on iphone/ipad/ipod. I know all about the audio route calls and route change callbacks but these don't tell me anything about what's attached. They only report where the audio is currently routing. I need to know, for instance, if headphones and/or bluetooth are still attached while audio is routed through the speakers. Or, for instance, if a user plugs in the headset while using bluetooth then decides to disconnect bluetooth, I need to know that the bluetooth is disconnected even as audio is still routing through headphones.
Unfortunately, as of iOS11, it seems there's no API to reliably get the list of the output devices that are currently attached - as soon as the current route changes, you only see 1 device (currently routed) via AVAudioSession's currentRoute.outputs, even though multiple devices may still be attached.
However, for the input, and that includes Bluetooth devices with HFP profile, if the proper Audio Session mode is used (AVAudioSessionModeVoiceChat or AVAudioSessionModeVideoChat for example), one can get the list of the available input via AVAudioSession's availableInputs, and those inputs are listed there even when that device is not an active route - this is very useful when a user is doing a manual override via MPVolumeView from Bluetooth to the speaker, for example, and since HFP is a 2-way IO (has both input and output), you can judge whether output HFP Bluetooth is still available by looking at the inputs.
BOOL isBtInputAvailable = NO;
NSArray *inputs = [[AVAudioSession sharedInstance] availableInputs];
for (AVAudioSessionPortDescription* port in inputs) {
if ([port.portType isEqualToString:AVAudioSessionPortBluetoothHFP]) {
isBtInputAvailable = YES;
break;
}
}
In case of iOS 5 you should use:
CFStringRef newRoute;
size = sizeof(CFStringRef);
XThrowIfError(AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &size, &newRoute), "couldn't get new audio route");
if (newRoute)
{
CFShow(newRoute);
if (CFStringCompare(newRoute, CFSTR("HeadsetInOut"), NULL) == kCFCompareEqualTo) // headset plugged in
{
colorLevels[0] = .3;
colorLevels[5] = .5;
}
else if (CFStringCompare(newRoute, CFSTR("SpeakerAndMicrophone"), NULL) == kCFCompareEqualTo)
}
You can get from AudioSession properties a list of InputSources and OutputDestinations.
Check out these Session Properties:
kAudioSessionProperty_InputSources
kAudioSessionProperty_OutputDestinations
And to query the details of each, you can use:
kAudioSessionProperty_InputSource
kAudioSessionProperty_OutputDestination

Resources