chromium/extensions/test/data/api_test/audio/test.js

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * Asserts that device property values match properties in |expectedProperties|.
 * The method will *not* assert that the device contains *only* properties
 * specified in expected properties.
 * @param {Object} expectedProperties Expected device properties.
 * @param {Object} device Device object to test.
 */
function assertDeviceMatches(expectedProperties, device) {
  Object.keys(expectedProperties).forEach(function(key) {
    chrome.test.assertEq(expectedProperties[key], device[key],
        'Property ' + key + ' of device ' + device.id);
  });
}

/**
 * Verifies that list of devices contains all and only devices from set of
 * expected devices. If will fail the test if an unexpected device is found.
 *
 * @param {Object.<string, Object>} expectedDevices Expected set of test
 *     devices. Maps device ID to device properties.
 * @param {Array.<Object>} devices List of input devices.
 */
function assertDevicesMatch(expectedDevices, devices) {
  var deviceIds = {};
  devices.forEach(function(device) {
    chrome.test.assertFalse(!!deviceIds[device.id],
                            'Duplicated device id: \'' + device.id + '\'.');
    deviceIds[device.id] = true;
  });

  function sortedKeys(obj) {
    return Object.keys(obj).sort();
  }
  chrome.test.assertEq(sortedKeys(expectedDevices), sortedKeys(deviceIds));

  devices.forEach(function(device) {
    assertDeviceMatches(expectedDevices[device.id], device);
  });
}

/**
 *
 * @param {Array.<Object>} devices List of devices returned by
 *    chrome.audio.getInfo or chrome.audio.getDevices.
 * @return {Object.<string, Object>} List of devices formatted as map of
 *      expected devices used to assert devices match expectation.
 */
function deviceListToExpectedDevicesMap(devices) {
  var expectedDevicesMap = {};
  devices.forEach(function(device) {
    expectedDevicesMap[device.id] = device;
  });
  return expectedDevicesMap;
}

/**
 * @param {Array.<Object>} devices List of devices returned by
 *    chrome.audio.getInfo or chrome.audio.getDevices.
 * @return {Array.<string>} Sorted list devices IDs for devices in |devices|.
 */
function getDeviceIds(devices) {
  return devices.map(function(device) {return device.id;}).sort();
}

var deviceChangedListener = null;

chrome.test.runTests([
  function getDevicesTest() {
    // Test output devices. Maps device ID -> tested device properties.
    var kTestDevices = {
      '30001': {
        id: '30001',
        stableDeviceId: '0',
        displayName: 'Jabra Speaker 1',
        deviceName: 'Jabra Speaker',
        streamType: 'OUTPUT'
      },
      '30002': {
        id: '30002',
        stableDeviceId: '1',
        displayName: 'Jabra Speaker 2',
        deviceName: 'Jabra Speaker',
        streamType: 'OUTPUT'
      },
      '30003': {
        id: '30003',
        stableDeviceId: '2',
        displayName: 'HDA Intel MID',
        deviceName: 'HDMI output',
        streamType: 'OUTPUT'
      },
      '40001': {
        id: '40001',
        stableDeviceId: '3',
        displayName: 'Jabra Mic 1',
        deviceName: 'Jabra Mic',
        streamType: 'INPUT'
      },
      '40002': {
        id: '40002',
        stableDeviceId: '4',
        displayName: 'Jabra Mic 2',
        deviceName: 'Jabra Mic',
        streamType: 'INPUT'
      },
      '40003': {
        id: '40003',
        stableDeviceId: '5',
        displayName: 'Logitech Webcam',
        deviceName: 'Webcam Mic',
        streamType: 'INPUT'
      }
    };

    chrome.audio.getDevices(chrome.test.callbackPass(function(devices) {
      assertDevicesMatch(kTestDevices, devices);
    }));
  },

  function getDevicesWithEmptyFilterTest() {
    // Test output devices. Maps device ID -> tested device properties.
    var kTestDevices = {
      '30001': {
        id: '30001',
        stableDeviceId: '0',
        displayName: 'Jabra Speaker 1',
        deviceName: 'Jabra Speaker',
        streamType: 'OUTPUT'
      },
      '30002': {
        id: '30002',
        stableDeviceId: '1',
        displayName: 'Jabra Speaker 2',
        deviceName: 'Jabra Speaker',
        streamType: 'OUTPUT'
      },
      '30003': {
        id: '30003',
        stableDeviceId: '2',
        displayName: 'HDA Intel MID',
        deviceName: 'HDMI output',
        streamType: 'OUTPUT'
      },
      '40001': {
        id: '40001',
        stableDeviceId: '3',
        displayName: 'Jabra Mic 1',
        deviceName: 'Jabra Mic',
        streamType: 'INPUT'
      },
      '40002': {
        id: '40002',
        stableDeviceId: '4',
        displayName: 'Jabra Mic 2',
        deviceName: 'Jabra Mic',
        streamType: 'INPUT'
      },
      '40003': {
        id: '40003',
        stableDeviceId: '5',
        displayName: 'Logitech Webcam',
        deviceName: 'Webcam Mic',
        streamType: 'INPUT'
      }
    };

    chrome.audio.getDevices({}, chrome.test.callbackPass(function(devices) {
      assertDevicesMatch(kTestDevices, devices);
    }));
  },

  function getInputDevicesTest() {
    var kTestDevices = {
      '40001': {
        id: '40001',
        streamType: 'INPUT'
      },
      '40002': {
        id: '40002',
        streamType: 'INPUT'
      },
      '40003': {
        id: '40003',
        streamType: 'INPUT'
      }
    };

    chrome.audio.getDevices({
      streamTypes: ['INPUT']
    }, chrome.test.callbackPass(function(devices) {
      assertDevicesMatch(kTestDevices, devices);
    }));
  },

  function getOutputDevicesTest() {
    var kTestDevices = {
      '30001': {
        id: '30001',
        streamType: 'OUTPUT'
      },
      '30002': {
        id: '30002',
        streamType: 'OUTPUT'
      },
      '30003': {
        id: '30003',
        streamType: 'OUTPUT'
      },
    };

    chrome.audio.getDevices({
      streamTypes: ['OUTPUT']
    }, chrome.test.callbackPass(function(devices) {
      assertDevicesMatch(kTestDevices, devices);
    }));
  },

  function getActiveDevicesTest() {
    chrome.audio.getDevices(chrome.test.callbackPass(function(initial) {
      var initialActiveDevices = initial.filter(function(device) {
        return device.isActive;
      });
      chrome.test.assertTrue(initialActiveDevices.length > 0);

      chrome.audio.getDevices({
        isActive: true
      }, chrome.test.callbackPass(function(devices) {
        assertDevicesMatch(
            deviceListToExpectedDevicesMap(initialActiveDevices),
            devices);
     }));

      var initialActiveInputs = initialActiveDevices.filter(function(device) {
        return device.streamType === 'INPUT';
      });
      chrome.test.assertTrue(initialActiveInputs.length > 0);

      chrome.audio.getDevices({
        isActive: true,
        streamTypes: ['INPUT']
      }, chrome.test.callbackPass(function(devices) {
        assertDevicesMatch(
            deviceListToExpectedDevicesMap(initialActiveInputs),
            devices);
      }));

      var initialActiveOutputs = initialActiveDevices.filter(function(device) {
        return device.streamType === 'OUTPUT';
      });
      chrome.test.assertTrue(initialActiveOutputs.length > 0);

      chrome.audio.getDevices({
        isActive: true,
        streamTypes: ['OUTPUT']
      }, chrome.test.callbackPass(function(devices) {
        assertDevicesMatch(
            deviceListToExpectedDevicesMap(initialActiveOutputs),
            devices);
      }));
    }));
  },

  function getInactiveDevicesTest() {
    chrome.audio.getDevices(chrome.test.callbackPass(function(initial) {
      var initialInactiveDevices = initial.filter(function(device) {
        return !device.isActive;
      });
      chrome.test.assertTrue(initialInactiveDevices.length > 0);

      chrome.audio.getDevices({
        isActive: false
      }, chrome.test.callbackPass(function(devices) {
        assertDevicesMatch(
            deviceListToExpectedDevicesMap(initialInactiveDevices),
            devices);
      }));
    }));
  },

  function setPropertiesTest() {
    chrome.audio.getDevices(chrome.test.callbackPass(function(initial) {
      var expectedDevices = deviceListToExpectedDevicesMap(initial);

      // Update expected input devices with values that should be changed in
      // test.
      var updatedInput = expectedDevices['40002'];
      chrome.test.assertFalse(updatedInput.gain === 65);
      updatedInput.level = 65;

      // Update expected output devices with values that should be changed in
      // test.
      var updatedOutput = expectedDevices['30001'];
      chrome.test.assertFalse(updatedOutput.volume === 45);
      updatedOutput.level = 45;

      chrome.audio.setProperties('30001', {
        level: 45
      }, chrome.test.callbackPass(function() {
        chrome.audio.setProperties('40002', {
          level: 65
        }, chrome.test.callbackPass(function() {
          chrome.audio.getDevices(chrome.test.callbackPass(function(devices) {
            assertDevicesMatch(expectedDevices, devices);
          }));
        }));
      }));
    }));
  },


  function inputMuteTest() {
    var getMute = function(callback) {
      chrome.audio.getMute('INPUT', chrome.test.callbackPass(callback));
    };
    getMute(function(originalValue) {
      chrome.audio.setMute(
          'INPUT', !originalValue, chrome.test.callbackPass(function() {
            getMute(function(value) {
              chrome.test.assertEq(!originalValue, value);
            });
          }));
    });
  },

  function outputMuteTest() {
    var getMute = function(callback) {
      chrome.audio.getMute('OUTPUT', chrome.test.callbackPass(callback));
    };
    getMute(function(originalValue) {
      chrome.audio.setMute(
          'OUTPUT', !originalValue, chrome.test.callbackPass(function() {
            getMute(function(value) {
              chrome.test.assertEq(!originalValue, value);
            });
          }));
    });
  },

  function setActiveDevicesTest() {
    chrome.audio.setActiveDevices({
      input: ['40002', '40003'],
      output: ['30001']
    }, chrome.test.callbackPass(function() {
      chrome.audio.getDevices({
        isActive: true
      }, chrome.test.callbackPass(function(activeDevices) {
        chrome.test.assertEq(['30001', '40002', '40003'],
                             getDeviceIds(activeDevices));
      }));
    }));
  },

  function setActiveDevicesOutputOnlyTest() {
    chrome.audio.getDevices({
      streamTypes: ['INPUT'],
      isActive: true
    }, chrome.test.callbackPass(function(initial) {
      var initialActiveInputs = getDeviceIds(initial);
      chrome.test.assertTrue(initialActiveInputs.length > 0);

      chrome.audio.setActiveDevices({
        output: ['30003']
      }, chrome.test.callbackPass(function() {
        chrome.audio.getDevices({
            isActive: true
        }, chrome.test.callbackPass(function(devices) {
          var expected = ['30003'].concat(initialActiveInputs).sort();
          chrome.test.assertEq(expected, getDeviceIds(devices));
        }));
      }));
    }));
  },

  function setActiveDevicesFailInputTest() {
    chrome.audio.getDevices({
      isActive: true
    }, chrome.test.callbackPass(function(initial) {
      var initialActiveIds = getDeviceIds(initial);
      chrome.test.assertTrue(initialActiveIds.length > 0);

      chrome.audio.setActiveDevices({
        input: ['0000000'],  /* does not exist */
        output: []
      }, chrome.test.callbackFail('Failed to set active devices.', function() {
        chrome.audio.getDevices({
          isActive: true
        }, chrome.test.callbackPass(function(devices) {
          chrome.test.assertEq(initialActiveIds, getDeviceIds(devices));
        }));
      }));
    }));
  },

  function setActiveDevicesFailOutputTest() {
    chrome.audio.getDevices({
      isActive: true
    }, chrome.test.callbackPass(function(initial) {
      var initialActiveIds = getDeviceIds(initial);
      chrome.test.assertTrue(initialActiveIds.length > 0);

      chrome.audio.setActiveDevices({
        input: [],
        output: ['40001'] /* id is input node ID */
      }, chrome.test.callbackFail('Failed to set active devices.', function() {
        chrome.audio.getDevices({
          isActive: true
        }, chrome.test.callbackPass(function(devices) {
          chrome.test.assertEq(initialActiveIds, getDeviceIds(devices));
        }));
      }));
    }));
  },

  function clearActiveDevicesTest() {
    chrome.audio.getDevices({
      isActive: true
    }, chrome.test.callbackPass(function(initial) {
      chrome.test.assertTrue(getDeviceIds(initial).length > 0);

      chrome.audio.setActiveDevices({
        input: [],
        output: []
      }, chrome.test.callbackPass(function() {
        chrome.audio.getDevices({
          isActive: true
        }, chrome.test.callbackPass(function(devices) {
          chrome.test.assertEq([], devices);
        }));
      }));
    }));
  },
]);