Initialize AudioData from BufferSource

This CL updated AudioDataInit to use a BufferSource data member, instead
of an AudioBuffer member. It also moves fields found in the AudioBuffer
into the top level AudioDataInit.

This allows users to create AudioData in whichever format they want.

Bug: 1205281
Change-Id: If234ace2d64e79470f6561c9c0838643ec390f8e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3025311
Commit-Queue: Thomas Guilbert <tguilbert@chromium.org>
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#901720}
diff --git a/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html b/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html
index 16bea6a..df83e7e 100644
--- a/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html
+++ b/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html
@@ -17,22 +17,25 @@
 
     function makeAudioData(timestamp) {
       const sampleRate = 30000;
-      const buffer = new AudioBuffer({
-        length: sampleRate / 10, // 100ms
-        numberOfChannels: 1,
-        sampleRate: sampleRate
-      });
+
+      let frames = sampleRate / 10;
+      let channels = 1;
+
       // Generate a simple sin wave, so we have something.
-      const array = buffer.getChannelData(0);
+      let data = new Float32Array(frames*channels);
       const hz = 100; // sound frequency
-      for (let i = 0; i < array.length; i++) {
+      for (let i = 0; i < data.length; i++) {
         const t = (i / sampleRate) * hz * (Math.PI * 2);
-        array[i] = Math.sin(t);
+        data[i] = Math.sin(t);
       }
 
       return new AudioData({
         timestamp: timestamp,
-        buffer: buffer
+        numberOfFrames: frames,
+        numberOfChannels: channels,
+        sampleRate: sampleRate,
+        data: data,
+        format: "FLT",
       });
     }
 
diff --git a/webcodecs/audio-data.any.js b/webcodecs/audio-data.any.js
index 02d4f8f..6f133ef 100644
--- a/webcodecs/audio-data.any.js
+++ b/webcodecs/audio-data.any.js
@@ -18,30 +18,56 @@
 }
 
 test(t => {
-  let localBuffer = new AudioBuffer({
-    length: defaultInit.frames,
+  let local_data = new Float32Array(defaultInit.channels * defaultInit.frames);
+
+  let audio_data_init = {
+    timestamp: defaultInit.timestamp,
+    data: local_data,
+    numberOfFrames: defaultInit.frames,
     numberOfChannels: defaultInit.channels,
-    sampleRate: defaultInit.sampleRate
-  });
+    sampleRate: defaultInit.sampleRate,
+    format: 'FLTP',
+  }
 
-  let audioDataInit = {timestamp: defaultInit.timestamp, buffer: localBuffer}
-
-  let data = new AudioData(audioDataInit);
+  let data = new AudioData(audio_data_init);
 
   assert_equals(data.timestamp, defaultInit.timestamp, 'timestamp');
   assert_equals(data.numberOfFrames, defaultInit.frames, 'frames');
   assert_equals(data.numberOfChannels, defaultInit.channels, 'channels');
   assert_equals(data.sampleRate, defaultInit.sampleRate, 'sampleRate');
-  assert_equals(data.format, "FLTP", 'format');
+  assert_equals(
+      data.duration, defaultInit.frames / defaultInit.sampleRate * 1_000_000,
+      'duration');
+  assert_equals(data.format, 'FLTP', 'format');
 
-  assert_throws_js(
-      TypeError, () => {let data = new AudioData({buffer: localBuffer})},
-      'AudioData requires \'timestamp\'')
+  // Create an Int16 array of the right length.
+  let small_data = new Int16Array(defaultInit.channels * defaultInit.frames);
 
-  assert_throws_js(
-      TypeError,
-      () => {let data = new AudioData({timestamp: defaultInit.timestamp})},
-      'AudioData requires \'buffer\'')
+  let wrong_format_init = {...audio_data_init};
+  wrong_format_init.data = small_data;
+
+  // Creating FLTP AudioData from Int16 from should throw.
+  assert_throws_js(TypeError, () => {
+    let data = new AudioData(wrong_format_init);
+  }, `AudioDataInit.data needs to be big enough`);
+
+  var members = [
+    'timestamp',
+    'data',
+    'numberOfFrames',
+    'numberOfChannels',
+    'sampleRate',
+    'format',
+  ];
+
+  for (const member of members) {
+    let incomplete_init = {... audio_data_init};
+    delete incomplete_init[member];
+
+    assert_throws_js(
+      TypeError, () => {let data = new AudioData(incomplete_init)},
+      "AudioData requires '" + member + "'");
+  }
 }, 'Verify AudioData constructors');
 
 test(t => {
diff --git a/webcodecs/utils.js b/webcodecs/utils.js
index 199a136..70af03c 100644
--- a/webcodecs/utils.js
+++ b/webcodecs/utils.js
@@ -1,23 +1,24 @@
-function make_audio_data(timestamp, channels, sampleRate, length) {
-  let buffer = new AudioBuffer({
-    length: length,
-    numberOfChannels: channels,
-    sampleRate: sampleRate
-  });
+function make_audio_data(timestamp, channels, sampleRate, frames) {
 
-  for (var channel = 0; channel < buffer.numberOfChannels; channel++) {
-    // This gives us the actual array that contains the data
-    var array = buffer.getChannelData(channel);
+  let data = new Float32Array(frames*channels);
+
+  // This generates samples in a planar format.
+  for (var channel = 0; channel < channels; channel++) {
     let hz = 100 + channel * 50; // sound frequency
-    for (var i = 0; i < array.length; i++) {
+    let base_index = channel * frames;
+    for (var i = 0; i < frames; i++) {
       let t = (i / sampleRate) * hz * (Math.PI * 2);
-      array[i] = Math.sin(t);
+      data[base_index + i] = Math.sin(t);
     }
   }
 
   return new AudioData({
     timestamp: timestamp,
-    buffer: buffer
+    data: data,
+    numberOfChannels: channels,
+    numberOfFrames: frames,
+    sampleRate: sampleRate,
+    format: "FLTP",
   });
 }