title: How to save a text to speech audio file client side?
body: <p><strong>desired behaviour</strong></p>
  
  <p>allow user to download text to speech audio file by clicking a button, like this official demo:</p>
  
  <p><a href="https://text-to-speech-starter-kit.ng.bluemix.net" rel="nofollow noreferrer">https://text-to-speech-starter-kit.ng.bluemix.net</a>  </p>
  
  <p><a href="https://i.stack.imgur.com/7ztga.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/7ztga.png" alt="enter image description here"></a></p>
  
  <p><strong>what i've tried</strong></p>
  
  <p>i am using:</p>
  
  <p><a href="https://github.com/watson-developer-cloud/node-sdk" rel="nofollow noreferrer">https://github.com/watson-developer-cloud/node-sdk</a></p>
  
  <p>i can generate an audio file server side but can't figure out how to send that file back to the client for them to save - so i am trying to generate it client side instead.  </p>
  
  <p><strong>attempt 01:  generate audio file server side</strong>     </p>
  
  <p><em>server.js (works)</em>  </p>
  
  <pre class="lang-js prettyprint-override"><code>const fs = require('fs');
  const TextToSpeechV1 = require('ibm-watson/text-to-speech/v1');
  
  const textToSpeech = new TextToSpeechV1({
      iam_apikey: '{apikey}',
  });
  
  const synthesizeParams = {
      text: 'Hello world',
      accept: 'audio/wav',
      voice: 'en-US_AllisonVoice',
  };
  
  textToSpeech.synthesize(synthesizeParams)
      .then(audio =&gt; {
          audio.pipe(fs.createWriteStream('hello_world.wav'));
      })
      .catch(err =&gt; {
          console.log('error:', err);
      });
  </code></pre>
  
  <p>for reference, according to <a href="https://cloud.ibm.com/apidocs/text-to-speech?code=node#synthesize-audio" rel="nofollow noreferrer">the docs</a>, the <code>.synthesize()</code> method response type is:</p>
  
  <pre><code>NodeJS.ReadableStream|FileObject|Buffer   
  </code></pre>
  
  <p><strong>attempt 02:  generate audio file client side</strong></p>
  
  <p><em>server.js - required to get token (works)</em></p>
  
  <pre class="lang-js prettyprint-override"><code>var AuthorizationV1 = require('ibm-watson/authorization/v1');
  
  var iam_apikey = local_settings.TEXT_TO_SPEECH_IAM_APIKEY;
  var url = local_settings.TEXT_TO_SPEECH_URL;
  
  var authorization = new AuthorizationV1({
      iam_apikey: iam_apikey,
      url: url
  });
  
  const api_tts_token_get = async (req, res) =&gt; {
  
      authorization.getToken(function(err, token) {
          if (!token) {
              console.log('error:', err);
          } else {
              res.json({ token: token, url: url });
          }
      });
  
  }
  
  app.route("/api/:api_version/text-to-speech/token")
      .get(api_tts_token_get); 
  </code></pre>
  
  <p><em>client.js (doesn’t work)</em></p>
  
  <pre class="lang-js prettyprint-override"><code>var TextToSpeechV1 = require('ibm-watson/text-to-speech/v1');
  
  const get_token = (parameters) =&gt; {
  
      $.ajax({
          url: "/api/v1/text-to-speech/token",
          data: parameters,
          dataType: 'json',
          cache: false,
          headers: headers,
          success: function(results) {
  
              var token = results.token;
              var url = results.url;
  
              var textToSpeech = new TextToSpeechV1({ token: token, url: url });
  
              var synthesizeParams = {
                  text: 'hello world!',
                  accept: 'audio/wav',
                  voice: 'en-US_AllisonV3Voice'
              };
  
              textToSpeech.synthesize(synthesizeParams, function(err, result) {
                  if (err) {
                      return console.log(err);
                  }
                  console.log(result);
              });
  
          },
          statusCode: {
              500: function() {
  
                  console.log("that didn't work");
  
              }
          }
      });
  
  }
  
  </code></pre>
  
  <p><em>webpack.config.js</em></p>
  
  <p>added per instructions at:  </p>
  
  <p><a href="https://github.com/watson-developer-cloud/node-sdk/tree/master/examples/webpack#important-notes" rel="nofollow noreferrer">https://github.com/watson-developer-cloud/node-sdk/tree/master/examples/webpack#important-notes</a>  </p>
  
  <pre class="lang-js prettyprint-override"><code>node: {
      // see http://webpack.github.io/docs/configuration.html#node
      // and https://webpack.js.org/configuration/node/
      fs: 'empty',
      net: 'empty',
      tls: 'empty'
  },
  </code></pre>
  
  <p>chrome dev tools errors:</p>
  
  <pre><code>xhr.js:108 Refused to set unsafe header "User-Agent"
  
  The provided value 'stream' is not a valid enum value of type XMLHttpRequestResponseType.
  
  Access to XMLHttpRequest at 'https://***.watsonplatform.net/text-to-speech/api/v1/synthesize?voice=en-US_AllisonV3Voice'
  from origin 'http://localhost:3000' has been blocked by CORS policy: 
  Request header field x-ibmcloud-sdk-analytics is not allowed by 
  Access-Control-Allow-Headers in preflight response.
  
  Error: Response not received. Body of error is HTTP ClientRequest object
  at RequestWrapper.formatError (requestwrapper.js:218)
  at eval (requestwrapper.js:206)
  </code></pre>