<!--
This is a light weighted demo page used to verify SoftMicPlatformService.
Start a http server by running this python3 command in the directory
cobalt/demos/content/soft-mic-platform-service/:
python3 -m http.server 8000
Then run in Cobalt using this command:
out/linux-x64x11_debug/cobalt --url=http://localhost:8000/soft_mic_platform_service_demo.html
-->
<!DOCTYPE html>
<meta charset="utf-8">
<body>
  <script>
    'use strict';

    /**
    * @param {ArrayBuffer} data to be converted to a String.
    */
    function ab2str(data) {
      try {
        var string_data = new TextDecoder("utf-8").decode(data);
        return string_data;
      } catch(error) {
        console.error(`ab2str() error: ${error}, decoding data: ${data}`);
      }
    }

    /**
    * @param {String} data to be converted to an ArrayBuffer.
    */
    function str2ab(data) {
      try {
        var array_buffer_data = new TextEncoder().encode(data).buffer;
        return array_buffer_data;
      } catch(error) {
        console.error(`str2ab() error: ${error}, decoding data: ${data}`);
      }
    }

    async function testSoftMicPlatformService() {
      // These default boolean values represent the default assumption for
      // platforms that do not implement the extension.
      var has_soft_mic = true;
      var has_hard_mic = false;

      if (!H5vccPlatformService) {
        // H5vccPlatformService is not implemented. Fallback to current Soft Mic
        // implementation.
        console.error("H5vccPlatformService is not implemented");
        return;
      }

      var SOFT_MIC_SERVICE_NAME = "com.google.youtube.tv.SoftMic";

      if (!H5vccPlatformService.has(SOFT_MIC_SERVICE_NAME)) {
        // SOFT_MIC_SERVICE_NAME is not implemented. Fallback to current
        // Soft Mic implementation.
        console.error(`H5vccPlatformService.Has(${SOFT_MIC_SERVICE_NAME}) returned false.`);
        return;
      }

      /**
      * @param {ArrayBuffer} data
      */
      function receiveCallback(service, data) {
        var str_response = ab2str(data);

        try {
          var response = JSON.parse(str_response);
          has_hard_mic = response["hasHardMicSupport"];
          has_soft_mic = response["hasSoftMicSupport"];
          console.log(`receiveCallback, has_hard_mic: ${has_hard_mic}, has_soft_mic: ${has_soft_mic}`);
        } catch (error) {
          console.error(`receiveCallback() error: ${error}, str_response: ${str_response}`);
        }
      }

      // Open the service and pass the receive_callback.
      var soft_mic_service = H5vccPlatformService.open(SOFT_MIC_SERVICE_NAME,
                                  receiveCallback);

      // Async web app message for "getMicSupport".
      soft_mic_service.send(str2ab(JSON.stringify("getMicSupport")));

      // Test notifySearchActive and notifySearchInactive web app messages to the platform.
      soft_mic_service.send(str2ab(JSON.stringify("notifySearchActive")));
      soft_mic_service.send(str2ab(JSON.stringify("notifySearchInactive")));

      // Close the service when we are done.
      var TIME_BEFORE_CLOSE = 10000;
      await new Promise(r => setTimeout(r, TIME_BEFORE_CLOSE));
      soft_mic_service.close();
    }

    testSoftMicPlatformService();

  </script>
</body>
