<!--
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 {
        return String.fromCharCode.apply(null, new Uint8Array(data));
      } catch(error) {
        console.error(`ab2str() error: ${error}, decoding data: ${data}`);
      }
    }

    /**
    * @param {String} data to be converted to an ArrayBuffer.
    */
    function str2ab(data) {
      try {
        return Uint8Array.from(data.split(''), (s) => {return s.charCodeAt(0)}).buffer;
      } catch(error) {
        console.error(`str2ab() error: ${error}, decoding data: ${data}`);
      }
    }

    async function testSoftMicPlatformService() {
      // Set to true once the service.send() calls are complete.
      var service_send_done = false;

      // 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"];
          var mic_gesture = response["micGesture"];
          console.log(`receiveCallback() response:\n
                       has_hard_mic: ${has_hard_mic}\n
                       has_soft_mic: ${has_soft_mic}\n
                       micGesture: ${mic_gesture}`);

          // It is now safe to close the platform service.
          if (service_send_done)
            soft_mic_service.close();
        } 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".
      var get_mic_support_sync_response = soft_mic_service.send(str2ab(JSON.stringify("getMicSupport")));
      try {
        if (new Int8Array(get_mic_support_sync_response)[0])
          console.log("getMicSupport send() platform response success.");
        else
          console.log("getMicSupport send() platform response failure.");
      } catch (error) {
        console.log(`Error in response from platform for getMicSupport: ${error}`);
      }

      // Test notifySearchActive send() and response from platform.
      var notify_search_active_message = str2ab(JSON.stringify("notifySearchActive"));
      var notify_search_active_response = soft_mic_service.send(notify_search_active_message);
      try {
        if (new Int8Array(notify_search_active_response)[0])
          console.log("notifySearchActive send() platform response success.");
        else
          console.log("notifySearchActive send() platform response failure.");
      } catch (error) {
        console.log(`Error in response from platform for notifySearchActive: ${error}`);
      }

      // Test notifySearchInactive send() and response from platform.
      var notify_search_inactive_message = str2ab(JSON.stringify("notifySearchInactive"));
      var notify_search_inactive_response = soft_mic_service.send(notify_search_inactive_message);
      try {
        if (new Int8Array(notify_search_inactive_response)[0])
          console.log("notifySearchInactive send() platform response success.");
        else
          console.log("notifySearchInactive send() platform response failure.");
      } catch (error) {
        console.log(`Error in response from platform for notifySearchInactive: ${error}`);
      }

      service_send_done = true;

      // Close the service after a timeout. This is in case there is an error on
      // the platform and a response is not received in the receiveCallback().
      var TIME_BEFORE_CLOSE = 10000;
      await new Promise(r => setTimeout(r, TIME_BEFORE_CLOSE));
      soft_mic_service.close();
    }

    testSoftMicPlatformService();

  </script>
</body>
