@alan-ai/alan-sdk-web 1.8.38 → 1.8.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/alan_lib.js CHANGED
@@ -493,18 +493,22 @@
493
493
  var isIE = false || !!document.documentMode;
494
494
  var isEdge = !isIE && !!window.StyleMedia;
495
495
  var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
496
+ var isMobileIos = navigator.userAgent.match(/safari/i) && navigator.vendor.match(/apple/i) && navigator.maxTouchPoints;
496
497
 
497
498
  if (isEdge || isChrome) {
498
499
  audioContext = new AudioContext({sampleRate: config.sampleRate});
499
500
  } else {
500
501
  audioContext = new AudioContext();
501
502
  }
502
-
503
+
503
504
  audioContext.resume().then(()=> fireEvent(AUDIO_RUNNING));
504
505
 
505
506
  var microphoneStream = null;
506
507
  var microphoneNode = null;
507
508
  var gainNode = audioContext.createGain();
509
+ var audioGainNode = audioContext.createGain();
510
+ audioGainNode.gain.value = 1;
511
+ var audioBufferSource = null;
508
512
  var encoderNode = audioContext.createScriptProcessor(config.bufferLength, 1, 1);
509
513
  encoderNode.onaudioprocess = ({inputBuffer}) => encodeBuffers(inputBuffer);
510
514
  encoderNode.connect(audioContext.destination);
@@ -561,27 +565,87 @@
561
565
  });
562
566
  }
563
567
 
568
+ function onPlayEnded() {
569
+ playState = PLAY_IDLE;
570
+ _handleQueue(true);
571
+ }
572
+
564
573
  function getAudioElement() {
565
574
  if (audioElement) {
566
575
  return audioElement;
567
576
  }
568
577
  audioElement = document.createElement("audio");
569
578
  audioElement.addEventListener("ended", function() {
570
- playState = PLAY_IDLE;
571
- _handleQueue(true);
579
+ onPlayEnded();
572
580
  });
573
581
  document.body.appendChild(audioElement);
574
582
  audioElement.setAttribute("autoplay", "true");
575
583
  return audioElement;
576
584
  }
577
585
 
586
+ function _base64ToArrayBuffer(base64) {
587
+ var binary_string = window.atob(base64);
588
+ var len = binary_string.length;
589
+ var bytes = new Uint8Array(len);
590
+ for (var i = 0; i < len; i++) {
591
+ bytes[i] = binary_string.charCodeAt(i);
592
+ }
593
+ return bytes.buffer;
594
+ }
595
+
596
+ function playAudio(audio) {
597
+ if (isMobileIos) {
598
+ const base64prefix = "data:audio/mpeg;base64,";
599
+ if (audio.startsWith(base64prefix)) {
600
+ audio = audio.substring(base64prefix.length);
601
+ }
602
+ var audioData = _base64ToArrayBuffer(audio);
603
+ audioContext.decodeAudioData(
604
+ audioData,
605
+ (buffer) => {
606
+ audioBufferSource = audioContext.createBufferSource();
607
+ audioBufferSource.addEventListener('ended', e => onPlayEnded());
608
+ audioBufferSource.connect(gainNode);
609
+ audioBufferSource.connect(audioGainNode);
610
+ audioGainNode.connect(audioContext.destination);
611
+ audioBufferSource.loop = false;
612
+ audioBufferSource.buffer = buffer;
613
+ audioBufferSource.start(0);
614
+ },
615
+ (err) => console.error(`Error with decoding audio data: ${err.err}`)
616
+ );
617
+ } else {
618
+ getAudioElement().setAttribute("src", audio);
619
+ }
620
+ }
621
+
622
+ function stopPlaying() {
623
+ if (isMobileIos) {
624
+ if (audioBufferSource) {
625
+ audioBufferSource.stop();
626
+ }
627
+ } else {
628
+ if (audioElement) {
629
+ audioElement.pause();
630
+ audioElement.currentTime = 0;
631
+ audioElement.src = "";
632
+ }
633
+ }
634
+ }
635
+
636
+ function onStopPlaying() {
637
+ if (!isMobileIos) {
638
+ getAudioElement().setAttribute("src", "");
639
+ }
640
+ onPlayStop();
641
+ }
642
+
578
643
  function _handleQueue(nowPlaying) {
579
644
  if (audioContext.state === 'suspended') {
580
645
  return;
581
646
  }
582
647
  if (nowPlaying && !audioQueue.length) {
583
- getAudioElement().setAttribute("src", "");
584
- onPlayStop();
648
+ onStopPlaying();
585
649
  }
586
650
  if (!audioQueue.length || playState === PLAY_ACTIVE) {
587
651
  return;
@@ -598,7 +662,7 @@
598
662
  if (playState === PLAY_IDLE) {
599
663
  playState = PLAY_ACTIVE;
600
664
  fireEvent('playStart');
601
- getAudioElement().setAttribute("src", o.audio);
665
+ playAudio(o.audio);
602
666
  }
603
667
  } else {
604
668
  console.error('invalid queue item');
@@ -724,11 +788,16 @@
724
788
  getAudioElement().setAttribute("src", "");
725
789
  playState = PLAY_IDLE;
726
790
  openMicrophone()
727
- .then(()=> {
791
+ .then(()=> {
728
792
  micState = MIC_ACTIVE;
729
793
  fireEvent('micStart');
730
794
  })
731
- .then(()=> { setMicAllowed(true); audioContext.resume();})
795
+ .then(()=> {
796
+ setMicAllowed(true);
797
+ if (!isMobileIos) {
798
+ audioContext.resume();
799
+ }
800
+ })
732
801
  .catch(err => { fireEvent('micFail', err); });
733
802
  if (onStarted) {
734
803
  onStarted();
@@ -748,11 +817,7 @@
748
817
  fireEvent('micStop');
749
818
  playState = PLAY_STOPPED;
750
819
  audioQueue = [];
751
- if (audioElement) {
752
- audioElement.pause();
753
- audioElement.currentTime = 0;
754
- audioElement.src = "";
755
- }
820
+ stopPlaying();
756
821
  };
757
822
 
758
823
  ns.skipExternalSounds = function(skip) {
@@ -781,7 +846,7 @@
781
846
 
782
847
  /// <reference types="../global" />
783
848
  (function (ns) {
784
- var alanButtonVersion = '1.8.38';
849
+ var alanButtonVersion = '1.8.40';
785
850
  if (window.alanBtn) {
786
851
  console.warn('Alan: the Alan Button source code has already added (v.' + alanButtonVersion + ')');
787
852
  }
@@ -2032,6 +2097,19 @@
2032
2097
  firstClick = true;
2033
2098
  sendClientEvent({ firstClick: true });
2034
2099
  }
2100
+ if (state === 'default') {
2101
+ coldPlayForSoundNext();
2102
+ }
2103
+ if (currentErrMsg) {
2104
+ if (currentErrMsg === MIC_BLOCKED_MSG) {
2105
+ sendClientEvent({ buttonClicked: true, micAllowed: false });
2106
+ showAlert(currentErrMsg);
2107
+ }
2108
+ else {
2109
+ showAlert(currentErrMsg);
2110
+ }
2111
+ return;
2112
+ }
2035
2113
  var activatePromise = new Promise(function (resolve, reject) {
2036
2114
  if (btnDisabled) {
2037
2115
  reject({ err: BTN_IS_DISABLED_CODE });
@@ -2251,19 +2329,8 @@
2251
2329
  if (!dndBackAnimFinished)
2252
2330
  return;
2253
2331
  hidePopup(null);
2254
- if (currentErrMsg) {
2255
- if (currentErrMsg === MIC_BLOCKED_MSG) {
2256
- sendClientEvent({ buttonClicked: true, micAllowed: false });
2257
- showAlert(currentErrMsg);
2258
- }
2259
- else {
2260
- showAlert(currentErrMsg);
2261
- }
2262
- return;
2263
- }
2264
2332
  if (alanAudio) {
2265
2333
  if (state === 'default') {
2266
- coldPlayForSoundNext();
2267
2334
  activateAlanButton();
2268
2335
  }
2269
2336
  else {