1

I'm using Selenium to emulate an user on a web that has audio chat. I need to emulate the user speaking through the microphone.

I only got questions about listening to the microphone in javascript, but none about sending sound through the microphone using javascript.

My current attempt looks like this:

First I check that AudioContext is available

private boolean isAudioContextSupported() {
  JavascriptExecutor js = (JavascriptExecutor) getDriver();
  Object response = js.executeAsyncScript(
  "var callback = arguments[arguments.length - 1];" +
  "var context;" + 
  "try {" + 
  "  window.AudioContext = window.AudioContext||window.webkitAudioContext;" + 
  "  context = new AudioContext();" +
  "  callback('');" +
  "}" + 
  "catch(e) {" + 
  "  callback('Web Audio API is not supported in this browser');" + 
  "}");
  String responseAsString = response == null?"":(String)response;
  return responseAsString.isEmpty();
}

Second I try to do this to get audio from an url

JavascriptExecutor js = (JavascriptExecutor) getDriver();
Object response = js.executeAsyncScript(
  "var callback = arguments[arguments.length - 1];" +
  "window.AudioContext = window.AudioContext || window.webkitAudioContext;" + 
  "var context = new AudioContext();" +
  "var url = '<ogg file url>';" +
  "var request = new XMLHttpRequest();" +
  "request.open('GET', url, true);" + 
  "request.responseType = 'arraybuffer';" +
  "request.onload = function() {" + 
  "  context.decodeAudioData(request.response, function(buffer) {" + 
  "  <send the buffer data through the microphone>" +
  "}, callback(request.statusText));" + 
  "};" + 
  "request.send();" +
  "callback('OK');"
);

The part I'm missing is how to send the buffer data (obtained from the ogg file) through the microphone.

EDIT:

The answer in Chrome: fake microphone input for test purpose does not answer this question, I already read that one.

EDIT 2:

There are some things to be considered:

1) The solution I'm looking can include using another language or tool.

2) I can't use hardware to emulate mic input (e.g.: output sound via speakers so the microphone can pick it up)

DrStein
  • 75
  • 2
  • 13
  • The link provided does not answer the question, it just show the `--use-fake-device-for-media-stream` option without actually providing a way to send sound. And the link inside that answer is a code to send sound through microphone using java. – DrStein Sep 01 '19 at 22:07
  • The Java tag is not valid, if one reads the code, the main problem is in javascript, the java code is just a wrapper. – DrStein Sep 02 '19 at 23:35

2 Answers2

0

I think you don't need to use JavascriptExecutor.

There is a hack for your problem.

Solution:

Use java instead.

Step 1:

Execute the chat voice listener.

enter image description here enter image description here

Step 2:

Now play a random voice programmatically.

Use: import javazoom.jl.player.Player;

public void playAudio(String audioPath)  { 

        try {
            FileInputStream fileInputStream = new FileInputStream(audioPath);
            Player player = new Player((fileInputStream));
            player.play();
            System.out.println("Song is playing");
        }catch (Exception ex)  { 
            System.out.println("Error with playing sound."); 
            ex.printStackTrace(); 

        } 
    } 

Step 3:

To enable microphone access, kindly use the below argument:

options.addArguments("use-fake-ui-for-media-stream"); 

Above code will play the sound for you and your chat listener can listen the played audio.

Abhishek Dhoundiyal
  • 1,359
  • 1
  • 12
  • 19
  • I'll try this and get back to you to tell if it worked. Thank you very much – DrStein Sep 12 '19 at 15:57
  • Hi, I'm missing information on the first step, what is the chat listener? – DrStein Sep 18 '19 at 15:15
  • You said [I'm using Selenium to emulate a user on a web that has audio chat.] There is some button or utility that trigger the audio chat. After clicking the button, it will automatically trigger your laptop/device voice system listener. – Abhishek Dhoundiyal Sep 19 '19 at 03:20
  • Ok, I understood the audio chat part. But there is something I'm not getting, how is the Player object related to the microphone? Wouldn't that code just output the audio via the computer's speakers? – DrStein Sep 20 '19 at 16:45
  • yes, it would play the audio via a speaker, as I already told you its just a hack. – Abhishek Dhoundiyal Sep 21 '19 at 05:48
  • For reference - https://www.vinsguru.com/selenium-webdriver-google-voice-search-automation-using-arquillian-graphene/ – Abhishek Dhoundiyal Sep 22 '19 at 13:54
  • I understood "a hack" as an ugly code or solution, I didn't get that you where referring to use the speakers. Thanks nevertheless. – DrStein Sep 24 '19 at 19:43
0

I don't know much about running Selenium with Java. But it looks like you can execute arbitrary JavaScript code before running the tests. I guess your code does at some point call getUserMedia() to get the microphone input. Therefore it might work if you just replace that function with a function that returns a MediaStream of your audio file.

navigator.mediaDevices.getUserMedia = () => {
    const audioContext = new AudioContext();

    return fetch('/your/audio/file.ogg')
        .then((response) => response.arrayBuffer())
        .then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer))
        .then((audioBuffer) => {
            const audioBufferSourceNode = audioContext.createBufferSource();
            const mediaStreamAudioDestinationNode = audioContext.createMediaStreamDestination();

            audioBufferSourceNode.buffer = audioBuffer;
            // Maybe it makes sense to loop the buffer.
            audioBufferSourceNode.loop = true;

            audioBufferSourceNode.start();

            audioBufferSourceNode.connect(mediaStreamAudioDestinationNode);

            return mediaStreamAudioDestinationNode.stream;
        });
};

Maybe you also have to disable the autoplay policy in order to make it work.

Unfortunately the code for Safari needs to be a bit more complicated because decodeAudioData() doesn't return a promise in Safari. I did not add the workaround here to keep the code as simple as possible.

chrisguttandin
  • 7,025
  • 15
  • 21