Firefox Stereo Input ermöglichen

xorg1990

New member
Hi, ich habe noch ein verwirrendes Problem in FF.
Ich möchte einfach nur ein Stero Input in FF haben, in allen anderen Browsern geht das doch auch.


Aktuell ist es so, das ein Elektretmikrofon ja nur mono ist (mono = nur links). Demzufolge dürfte nur Links ein Pegel anliegen tut es aber nicht, die dB's sind rechts genau sol stark wie links. Jetzt könnte man ja annehmen "ok, die machen aus dem mono ein Stereo". Nope, steckt man das Mic in den rechten Kanal ist rechts auch wider links.

Also links ist rechts, rechst ist links. und vice Versa.
Irgendwie das Total durcheinander:confused:

Fakt ist: Wenn getUserMedia bzw. createMediaStreamSource() mono wäre, dann dürfte wenn ein Signal auf den rechten Kanal anliegt, das Singal nie die Web audio api erreichen!!

Tut es aber de facto ist der Eingang Stereo aber wie mache ich die Kanäle aus??????

Habe mal was vorbereitet:
Code:
<!DOCTYPE html>
<html>

<head>
    <title>ScriptProcessor_test</title>
    <script type="text/javascript">
        function run() {
            var audioCtx = new(window.AudioContext || window.webkitAudioContext || mozAudioContext || oAudioContext || msAudioContext || null)();
            var processor = (audioCtx.createScriptProcessor || audioCtx.createJavaScriptNode).call(audioCtx, 16384, 2, 1);
            //making destination to stereo only
            audioCtx.destination.channelCount = 2;
            audioCtx.destination.channelCountMode = "explicit";
            audioCtx.destination.channelInterpretation = "discrete";

            var onRecordFail = function(e) {
                alert("Media caputure not supportet in this Browser");
                console.log(e);
            }


            function audioProcess(e) {
                var inputLe = e.inputBuffer.getChannelData(0); // microphone
                var inputRe = e.inputBuffer.getChannelData(1); //right is transceiver
                var outputLe = e.outputBuffer.getChannelData(0); // one output;
                var len = inputLe.length
                var total1 = total2 = 0;
                var rms1 = rms2 = 0;
                for (var i = 0; i < len; i++) {
                    total1 += Math.abs(inputLe[i]) //left
                    total2 += Math.abs(inputRe[i]) //right
                }
                rms1 = Math.sqrt(total1 / (len / 2)); //left
                rms2 = Math.sqrt(total2 / (len / 2)); //right
                var decibelLe = 20 * Math.log10(rms1);
                var decibelRe = 20 * Math.log10(rms2);
                document.getElementById("dBLeft").textContent = Math.round(decibelLe) + " dB";
                document.getElementById("dBRight").textContent = Math.round(decibelRe) + " dB";

            }

            //Process event handler
            processor.onaudioprocess = audioProcess;

            function gotStream(stream) {
                // Create an AudioNode from the stream.
                window.source = audioCtx.createMediaStreamSource(stream);
                window.source.channelCount = 2;
                window.source.channelCountMode = "explicit"
                window.source.channelInterpretation = 'discrete';
                window.source.connect(processor);
                processor.connect(audioCtx.destination);
            }


            function init() {
                if (navigator.mediaDevices.getUserMedia) {
                    //select constraints
                    var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
                    var isFirefox = navigator.userAgent.search("Firefox");
                    var constraints;
                    if (isChrome) {
                        constraints = {
                            audio: {
                                mandatory: {
                                    echoCancellation: false,
                                    googEchoCancellation: false,
                                    googAutoGainControl: false,
                                    googNoiseSuppression: false,
                                    googHighpassFilter: false
                                },
                                optional: []

                            }
                        };
                    } else if (isFirefox > -1) {
                        constraints = {
                            audio: {
                                echoCancellation: false,
                                mozAutoGainControl: false,
                                mozNoiseSuppression: false
                            }
                        };
                    } else {
                        constraints = {
                            audio: {
                                echoCancellation: false,
                            }
                        };
                    }
                    navigator.mediaDevices.getUserMedia(constraints).then(gotStream).catch(onRecordFail);
                } else if (navigator.getUserMedia) {
                    constraints = {
                        audio: true,
                        video: false
                    }
                    navigator.getUserMedia(constraints, gotStream, onRecordFail);
                } else {
                    alert("Media caputure not supportet in this Browser");
                    onRecordFail();
                }
            }
            init();
        }
    </script>
</head>

<body onload="run()">
    Left Channel:
    <div id="dBLeft"></div>

    <br> Right Channel:
    <div id="dBRight"></div>
</body>
</html>
Habe auch schon mit den ChannelSplitter und ChannelMerger gearbeitet bringt nix, da kommen nur Fehlermeldungen:
Code:
DOMException [IndexSizeError: "Index or size is negative or greater than the allowed amount"
code: 1
nsresult: 0x80530001
Das kommt aus dem console.log in onRecordFail()

Zu eruieren reicht ein normales Elektretmikrofon aus, wenn alles richtig funktioniert sind auf den linken Kanal mehr Decibel als au den Rechten.

Am ende brauche ich beide Kanäle getrennt ScriptProcessor.
 
Zuletzt bearbeitet:
Ist definitiv ein bug:
https://bugzilla.mozilla.org/show_bug.cgi?id=971528

Interessant ist der Beitrag von Brad:
This attachment is an updated example demonstrating the lack of stereo audio capture support with getUserMedia. It uses the MediaDevices.getUserMedia() method along with setting constraints to disable echo cancellation and setting channel count to 2. Tested in Firefox v47.0a1. For testing, I recommend using this audio file: http://www.kozco.com/tech/LRMonoPhase4.wav You can use a loopback audio driver (VB-Audio Virtual Apps) to test without extra hardware.
Bei mir ist in seinem attachment nix stereo.
Vielleicht ging das in FF v47.0a1 und jetzt nicht mehr.

channelCount auf 2 hatte ich auch schon bringt nix, vor allem wird es nicht mal unterstürzt:
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getSupportedConstraints
In jedem browser steht in der Ausgabe channelCount nur im FF nicht.
 
Habe noch ein paar bugs die ich gerne mit euch Teilen möchte, diese betreffe aber mehrere Browser. Ich gebe die Browser immer mit an
@mikdoe, kannst du den beigrat bitte umbenennen in "Probleme mit getUserMedia und der Web-Audio-API".
Dann hätte man ein sammelthread.

Ich fange dann man an.
Firefox:
AudioContext.createMediaStreamSource() bricht nach einer weile das Aufzeichen ab:
https://bugzilla.mozilla.org/show_bug.cgi?id=934512
Lösung:
.createMediaStreamSource() als globale Variable speichern also im window object:
Code:
navigator.getUserMedia({ audio: true }, function(stream) {
  window.source = context.createMediaStreamSource(stream);
  source.connect(context.destination);
}, alert);

Firefox:
Wenn man den onaudioprocess vom scriptprocessor beenden möchte reicht es in Chrome aus scriptprocessor.disconnect() aufzurufen. In FF nicht:
Außerdem sollte man immer die Reverenzen zu onaudioprocess auf null stellen, da der scriptprocessor nicht automatisch garbage collected wird.
javascript - How can I stop/pause a WebAudioScriptProcessor node? - Stack Overflow
Antwort von Chris Wilson beachten und dern Kommentare.
Lösung:
scriptprocessor.disconnect()
scriptprocessor.onaudioprocess = null;
scriptprocessor = null;


Chrome:
audioCtx.createBuffer feuert onended nicht wenn die Samplerate ungleich der zu Audio API ist, aber nur wenn man die playbackRate verändert.
Code:
<!DOCTYPE html>
<html>
 <script type="text/javascript">
 function run() {
   	var audioCtx = new(window.AudioContext || window.webkitAudioContext || mozAudioContext || oAudioContext || msAudioContext || null)();
   	var Fs = audioCtx.sampleRate;

   	var noiseBuf = new Float32Array(Fs)// 1sec noise
   	for(var i=0;i<noiseBuf.length;i++){
   		noiseBuf[i] = Math.random()*2-1;
   	}

   	function ende(){
   		alert("Ende");
   	}

	var sourceOut = audioCtx.createBufferSource();
	var outRate = Fs*2;
   	var audioBuffer = audioCtx.createBuffer(1,noiseBuf.length,outRate);
	audioBuffer.getChannelData(0).set(noiseBuf);
	sourceOut.buffer = audioBuffer;
	sourceOut.playbackRate.value = 1/10;
	sourceOut.onended = ende;
	sourceOut.connect(audioCtx.destination);
	sourceOut.start();
   }
 </script>
<body onload="run()">
</body>
</html>
Es ist von System zu System Unterschiedlich, bei mir in Linux muss ich var outRate = Fs/2; schrieben damit der Bug auftritt in Windows *2.
Stoppt man das ganze via stop() Method bevor der Puffer zu ende ist, dann wird onended ohne Problme gefeuert.
Die einzige Lösung ist stop() aufzurufen bevor der Puffer zu ende ist.

Audio API allgemein:
Der Tiefpass(BiquadFilterNode) ist nicht in Ordnung, ich weiß noch nicht ob das eine reguläres verhalten ist oder ob da was verbugt ist.
Mir ist vor Langer zeit schon aufgefallen dass der Tiefpass kaum etwas unterdrückt und stellt man die güte über 1 wird aus z.B aus einem weißen rauschen ein Sinus, weil das PassBand Ripple zu "bauchig" wird.
ripple.png
Die frequency response. Passt nie zu dem was gefiltert wird, nicht mal annähernd.
http://googlechrome.github.io/web-audio-samples/samples/audio/frequency-response.html
Schickt man eine reinen Sinus durch den filter wird die Wellenform hörbar verändert.
Hier toggle ich den Filter alle 3000 sec:
Code:
<!DOCTYPE html>
<html>

<head>
	<title></title>
<script type="text/javascript">
function run(){
	var audioCtx = new(window.AudioContext || window.webkitAudioContext || mozAudioContext || oAudioContext || msAudioContext || null)();
	var oscillator;
	var biquadFilter = audioCtx.createBiquadFilter();
	biquadFilter.type = "lowpass";
	biquadFilter.frequency.value = 1000;
	biquadFilter.Q.value = 0.5;

	var toggle = true;

	function toggleFilter(){
		toggle = !toggle;
		if(oscillator){
		oscillator.stop(0);
		oscillator.disconnect();
		oscillator = null;
		}
		oscillator = audioCtx.createOscillator();
		oscillator.type = 'sine';
		oscillator.frequency.value = 400; 
		if(toggle){
			oscillator.connect(biquadFilter).connect(audioCtx.destination);
		}else{
			oscillator.connect(audioCtx.destination);
		}
		oscillator.start(audioCtx.currentTime+1);
	}

setInterval(toggleFilter, 3000);
toggleFilter();

	}
	</script>
	</head>
	<body onload="run()">
	</body>
	</html>
Das ganze nochmal in Bildern:
Sinus Bad
sineBad.png
Sinus Ok:
sineOk.png
Spektrum: Wie gesagt 400Hz ist ok, alles andere Produziert der Filter
tiefpassSpectrum.jpg
Beim Hochpass ist das nicht reproduzierbar.
Ich würde einfach die Finger vom BiquadFilter lassen.
Die von Fili.js sind bedeutet besser:
https://github.com/markert/fili.js/tree/master
Asso, die Cutoff stet bei 1000Hz also höher als der Träger, das ist eigentlich sinn frei, nur Produziert der Oszilator Oberwellen die ich heraus gefiltert haben möchte. So bin ich auch auf das Problem gestoßen.

Kleiner Nachtrag zu: "audioCtx.createBuffer feuert onended nicht":
Das ganze zu beenden via stop() funzt nicht wirklich. Der Puffer wird ja verlangsamt ums 10 fache (sourceOut.playbackRate.value = 1/10;)
Eigentlich müsste es so funktionieren stop(audioCtx.currentTime+audioBuffer.duration*10) selbst wenn man noch 1sec abziehe onended wird nicht gefeuert. Alles komisch.
Entweder interpoliert man zuvor auf de korrekte Samplerate oder man versucht was über den https://developer.mozilla.org/de/docs/Web/API/OfflineAudioContext
Allerdings ist das auch verbugt
 
Zuletzt bearbeitet:
Hi, es gibt ein kleines update hierzu, in Firefox Version >=56 hat sich das Channel Input, sprich Stereo Input Problem gelöst.

Dafür geht in Chrome kein Sound Input mehr, wenn sich die Webseite nicht auf einen https Host befindet.
Selbst mit der unsafely-treat-insecure-origin-as-secure="http://example.com" Flag geht es nun nicht mehr. Das ging bisher immer.
Unter Linux geht es einwandfrei unter Windows nicht.
Ich habe das soweit "reverse engineeered" das es sich um ein Profil Fehler handelt, denn um unsafely-treat-insecure-origin-as-secure nutzen zu können muss man ein alternativen Profil Ordner angeben.
https://stackoverflow.com/questions...rigin-as-secure-flag-is-not-working-on-chrome
Wenn ich für die Seite den Sound input zulasse, wird die Einstellung nicht übernommen.
https://support.google.com/chrome/answer/2693767?hl=en-GB
 
Zuletzt bearbeitet:
Kleiner Nachtrag, es empfiehlt sich immer mal einen Blick in die zu Unterstützenden Media Constraints zu machen.
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getSupportedConstraints

Da ist bei Firefox einiges hinzugekommen, bei Chrome wurde etwas abgespeckt.
Was ich aber nicht versteh warum man z.B die echoCancellation oder die NoiseSuppression nicht als DSP Knoten in der WEB-Audio-API anbietet.
Zumal immer wenn man etwas davon Aktivieren/Deaktivieren möchte die Aufnahme neu gestartet wird . Es kommt immer wider dieses Fester "Mikrofon Zugriff zulassen ja/nein".

Das ist in meinem Augen nur von der Wand bis zur Tapete gedacht.

Und warum kommt nicht endlich mal ein Web AUDIO WEB-Worker????? Wo ist das Problem?
Audio workers provide the ability for direct scripted audio processing to be done inside a web worker context, and are defined by a couple of interfaces (new as of 29th August 2014). These are not implemented in any browsers yet. When implemented, they will replace ScriptProcessorNode, and the other features discussed in the Audio processing in JavaScript section above.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API#Audio_Workers
 
Zuletzt bearbeitet:
Noch ein bisschen Nerd wissen zu gUM.

Die echoCancellation ist in Chrome bei default ein.

In Firefox kann man die Rauschunterdrückung in about:config einstellen nach media.getusermedia.noise suchen.
Bei verändern des Wertes passeirt was . Was der Wert aber zu sagen hat, k.a..
Eigenltich bräuchte man so eine art Threshold. autoGain das gleiche media.getusermedia.agc.


In Chorme stellt man das über die constraints selber ein (angeblich den Wert dahinter schrieben):
Code:
audio: {
        mandatory: {
             echoCancelation: false,
            googNoiseSurpression: 85 //-85db Threshhold z.B.
        }
    }

Generell habe ich bis Dato nur die echoCancelation in Chrome in gang gebracht bei der Rauschunterdrückung passiert nix und der agc auch nix.

Die Aufnahme startet sich auch nur in Chrome neu, da die MediaStreamTrack.applyConstraints() Methode hier noch nicht funktioniert.
https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/applyConstraints
 
Zurück
Oben