0

I work with WebRTC, I receive the stream correctly. If I send the browser, everything works fine, but when I try to check the frequency with AudioContext-createAnalyser. It also continues to work, but I no longer have control over the volume of the audio. Here I leave the code:

function startUserMedia(stream) {

var canvas, ctx, again, fbc_array, bars = 100, bar_x, bar_width, bar_height;
var context = new AudioContext();
var analyser = context.createAnalyser();


source = context.createMediaStreamSource(stream); 
source.connect(analyser);
analyser.connect(context.destination);

canvas = document.getElementById("analyser");
ctx = canvas.getContext("2d");

frameLooper();

function frameLooper(){

    window.requestAnimationFrame(frameLooper);
    fbc_array = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(fbc_array);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "rgb(30, 180, 255)";

    for(var i = 0; i < bars; i++){
        bar_x = i * 3;
        bar_width = 2;
        bar_height = -(fbc_array[i] / 2);
        ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
    }
}
}

Thanks in advance

EDIT:

var connection = new RTCMultiConnection();
connection.socketURL = 'URL...';

connection.socketMessageEvent = 'message';
connection.session = { audio: true, video: false, oneway: true };
connection.mediaConstraints = { audio: true, video: false }
connection.sdpConstraints.mandatory = { OfferToReceiveAudio: false, OfferToReceiveVideo: false };

connection.onstream = function(event){

    var mediaElement = event.mediaElement;

    mediaElement.muted = true;
    mediaElement.volume = 1;
    mediaElement.id = event.streamid;
    $("#elementHtml").append(mediaElement);

    startUserMedia(event.stream);
Xplora
  • 837
  • 3
  • 12
  • 24
  • From where do you try to control the volume? You are directly connecting the analyser's out to the AudioContext's destination, there is no gainNode in between. And if ever you are also setting the stream as the srcObject of a MediaElement, then don't connect your analyser to OUT. – Kaiido Nov 06 '17 at 07:28
  • Thanks for the help, I have edited the question, attaching more code. I would greatly appreciate your help, I am a beginner with that topic. – Islam Linarez Nov 07 '17 at 03:37

1 Answers1

0

I have to admit I don't know the RTCMultiConnection library you are using, and even less its onstream handler, nor where does the event.mediaElement comes from, so you may have to try things out.

But I'll try to enumerate a few basic ways to do it, regardless of how this event.MediaStream is linked to the MediaStream.

  1. You want to control the output volume from an in-screen MediaElement's default controls: In this case, set this MediaElement's srcObject to the MediaStream and don't mute it, and don't connect the analyser node to the audio context's destination:

starter.onclick = function(){
  this.parentNode.removeChild(this);
  getStream(onstream);
 };

function onstream(stream) {
  // Set our in-doc-audio as the audio output
  // I don't know if your event.MediaStream could work as-is... You will have to try.
  var audio = document.querySelector('audio');
  audio.srcObject = stream;
  startUserMedia(stream);
  audio.play();
}


function startUserMedia(stream) {
  var canvas, ctx, again, fbc_array, bars = 100,
    bar_x, bar_width, bar_height;
  var context = new (window.AudioContext || window.webkitAudioContext)();
  var analyser = context.createAnalyser(),

  source = context.createMediaStreamSource(stream);
  source.connect(analyser);
  // In this case we don't connect to the audioCtx destination
  //analyser.connect(context.destination);

  canvas = document.getElementById("analyser");
  ctx = canvas.getContext("2d");

  frameLooper();
  function frameLooper() {
    window.requestAnimationFrame(frameLooper);
    fbc_array = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(fbc_array);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "rgb(30, 180, 255)";
    for (var i = 0; i < bars; i++) {
      bar_x = i * 3;
      bar_width = 2;
      bar_height = -(fbc_array[i] / 2);
      ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
    }
  }
}

// Snippet way to get a MediaStream
function getStream(callback) {
  var aud = new Audio('https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3?dl=03');
  aud.crossOrigin = true;
  aud.onloadedmetadata = function() {
   var ctx = new (window.AudioContext || window.webkitAudioContext)(),
    src = ctx.createMediaElementSource(this),
    streamNode = ctx.createMediaStreamDestination();
    src.connect(streamNode);
    callback(streamNode.stream);
  };
  aud.play();
}
#starter ~ *{
    visibility: hidden;
} 
<button id="starter">start</button>
<audio controls></audio>
<canvas id="analyser"></canvas>
  1. You want to control the output volume from a self-made input: Then don't even use a MediaElement, simply create a gainNode, on which you will connect your AnalyserNode, and that you will connect to the destination. To control the output volume, you then just have to set the gainNode.gain value.

starter.onclick = function(){
  this.parentNode.removeChild(this);
  getStream(startUserMedia);
};

function startUserMedia(stream) {
  var canvas, ctx, again, fbc_array, bars = 100,
    bar_x, bar_width, bar_height;
  var context = new (window.AudioContext || window.webkitAudioContext)();
  var analyser = context.createAnalyser();
  // create a gainNode that will control our output volume
  var gainNode = context.createGain();
  // control it from our <input>
  vol.oninput = function(){
    gainNode.gain.value = this.value;
  };
  source = context.createMediaStreamSource(stream);
  source.connect(analyser);
  // In this case we do connect the analyser output to the gainNode
  analyser.connect(gainNode);
  // and the gainNode to the context's destination
  gainNode.connect(context.destination);

  canvas = document.getElementById("analyser");
  ctx = canvas.getContext("2d");

  frameLooper();
  function frameLooper() {
    window.requestAnimationFrame(frameLooper);
    fbc_array = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(fbc_array);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "rgb(30, 180, 255)";
    for (var i = 0; i < bars; i++) {
      bar_x = i * 3;
      bar_width = 2;
      bar_height = -(fbc_array[i] / 2);
      ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
    }
  }
}

// Snippet way to get a MediaStream
function getStream(callback) {
  var aud = new Audio('https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3?dl=03');
  aud.crossOrigin = true;
  aud.onloadedmetadata = function() {
   var ctx = new (window.AudioContext || window.webkitAudioContext)(),
    src = ctx.createMediaElementSource(this),
    streamNode = ctx.createMediaStreamDestination();
    src.connect(streamNode);
    callback(streamNode.stream)
  };
  aud.play();
}
#starter ~ *{
    visibility: hidden;
}
<button id="starter">start</button>
<label>volume: <input type="range" min="0" max="1" value="1" step="0.05" id="vol"></label><br>
<canvas id="analyser"></canvas>
  1. You want to control the input [and output] volume from a self-made input: Like in 2., except that you will add an other gainNode in between the mediaStreamSource and the analyser:

starter.onclick = function(){
  this.parentNode.removeChild(this);
  getStream(startUserMedia);
 };

function startUserMedia(stream) {
  var canvas, ctx, again, fbc_array, bars = 100,
    bar_x, bar_width, bar_height;
  var context = new (window.AudioContext || window.webkitAudioContext)();
  var analyser = context.createAnalyser();
  // create two gainNodes
  var gainNode_in = context.createGain();
  vol_in.oninput = function(){
    gainNode_in.gain.value = this.value;
  };
  var gainNode_out = context.createGain();
  vol_out.oninput = function(){
    gainNode_out.gain.value = this.value;
  };
  
  source = context.createMediaStreamSource(stream);
  source.connect(gainNode_in);  // connect to the input gainNode
  gainNode_in.connect(analyser);
  analyser.connect(gainNode_out);
  // and the gainNode to the context's destination
  gainNode_out.connect(context.destination);

  canvas = document.getElementById("analyser");
  ctx = canvas.getContext("2d");

  frameLooper();
  function frameLooper() {
    window.requestAnimationFrame(frameLooper);
    fbc_array = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(fbc_array);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "rgb(30, 180, 255)";
    for (var i = 0; i < bars; i++) {
      bar_x = i * 3;
      bar_width = 2;
      bar_height = -(fbc_array[i] / 2);
      ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
    }
  }
}

// Snippet way to get a MediaStream
function getStream(callback) {
  var aud = new Audio('https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3?dl=03');
  aud.crossOrigin = true;
  aud.onloadedmetadata = function() {
   var ctx = new (window.AudioContext || window.webkitAudioContext)(),
    src = ctx.createMediaElementSource(this),
    streamNode = ctx.createMediaStreamDestination();
    src.connect(streamNode);
    callback(streamNode.stream)
  };
  aud.play();
}
#starter ~ *{
    visibility: hidden;
}
<button id="starter">start</button>
<label>volume in: <input type="range" min="0" max="1" value="1" step="0.05" id="vol_in"></label><br>
<label>volume out: <input type="range" min="0" max="1" value="1" step="0.05" id="vol_out"></label><br>
<canvas id="analyser"></canvas>
  1. You want to control the input volume from a MediaElement: For a cross-browser experience, you will have to listen to the element's volumechange, and add a gainNode_in like in 3.:

starter.onclick = function(){
  this.parentNode.removeChild(this);
  getStream(onstream);
};

function onstream(stream) {
  var audio = document.querySelector('audio');
  audio.srcObject = stream;
  startUserMedia(stream, audio);
  audio.play();
}


function startUserMedia(stream, audio) {
  var canvas, ctx, again, fbc_array, bars = 100,
    bar_x, bar_width, bar_height;
  var context = new (window.AudioContext || window.webkitAudioContext)();
  var analyser = context.createAnalyser(),
  source = context.createMediaStreamSource(stream),
  gainNode = context.createGain();
  
  audio.onvolumechange = function(){
    gainNode.gain.value = this.volume;
  };
  
  source.connect(gainNode);
  gainNode.connect(analyser);

  canvas = document.getElementById("analyser");
  ctx = canvas.getContext("2d");

  frameLooper();
  function frameLooper() {
    window.requestAnimationFrame(frameLooper);
    fbc_array = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(fbc_array);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "rgb(30, 180, 255)";
    for (var i = 0; i < bars; i++) {
      bar_x = i * 3;
      bar_width = 2;
      bar_height = -(fbc_array[i] / 2);
      ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
    }
  }
}

// Snippet way to get a MediaStream
function getStream(callback) {
  var aud = new Audio('https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3?dl=03');
  aud.crossOrigin = true;
  aud.onloadedmetadata = function() {
   var ctx = new (window.AudioContext || window.webkitAudioContext)(),
    src = ctx.createMediaElementSource(this),
    streamNode = ctx.createMediaStreamDestination();
    src.connect(streamNode);
    callback(streamNode.stream)
  };
  aud.play();
}
#starter ~ *{
    visibility: hidden;
} 
<button id="starter">start</button>
<audio controls></audio>
<canvas id="analyser"></canvas>
Kaiido
  • 123,334
  • 13
  • 219
  • 285