jsbeeb 1.11.0 → 1.12.0

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.
@@ -1,4 +1,3 @@
1
- import { SmoothieChart, TimeSeries } from "smoothie";
2
1
  import { FakeSoundChip, SoundChip } from "../soundchip.js";
3
2
  import { DdNoise, FakeDdNoise } from "../ddnoise.js";
4
3
  import { RelayNoise, FakeRelayNoise } from "../relaynoise.js";
@@ -15,17 +14,14 @@ export class AudioHandler {
15
14
  constructor({ warningNode, statsNode, audioFilterFreq, audioFilterQ, noSeek } = {}) {
16
15
  this.warningNode = warningNode;
17
16
  toggle(this.warningNode, false);
18
- this.chart = new SmoothieChart({
19
- tooltip: true,
20
- labels: { precision: 0 },
21
- yRangeFunction: (range) => {
22
- return { min: 0, max: range.max };
23
- },
24
- });
25
17
  this.stats = {};
26
- this._addStat("queueSize", { strokeStyle: "rgb(51,126,108)" });
27
- this._addStat("queueAge", { strokeStyle: "rgb(162,119,22)" });
28
- this.chart.streamTo(statsNode, 100);
18
+ if (statsNode) {
19
+ this._initStats(statsNode).catch((error) => {
20
+ console.error("Unable to initialise audio stats", error);
21
+ this.stats = {};
22
+ toggle(statsNode, false);
23
+ });
24
+ }
29
25
  this.audioContext = createAudioContext();
30
26
  this._jsAudioNode = null;
31
27
  if (this.audioContext && this.audioContext.audioWorklet) {
@@ -75,6 +71,22 @@ export class AudioHandler {
75
71
  }
76
72
  }
77
73
 
74
+ // Lazily load smoothie and set up the audio stats chart.
75
+ async _initStats(statsNode) {
76
+ const { SmoothieChart, TimeSeries } = await import("smoothie");
77
+ this._TimeSeries = TimeSeries;
78
+ this.chart = new SmoothieChart({
79
+ tooltip: true,
80
+ labels: { precision: 0 },
81
+ yRangeFunction: (range) => {
82
+ return { min: 0, max: range.max };
83
+ },
84
+ });
85
+ this._addStat("queueSize", { strokeStyle: "rgb(51,126,108)" });
86
+ this._addStat("queueAge", { strokeStyle: "rgb(162,119,22)" });
87
+ this.chart.streamTo(statsNode, 100);
88
+ }
89
+
78
90
  async _setup(audioFilterFreq, audioFilterQ) {
79
91
  await this.audioContext.audioWorklet.addModule(rendererUrl);
80
92
  if (audioFilterFreq !== 0) {
@@ -99,7 +111,7 @@ export class AudioHandler {
99
111
  }
100
112
 
101
113
  _addStat(stat, info) {
102
- const timeSeries = new TimeSeries();
114
+ const timeSeries = new this._TimeSeries();
103
115
  this.stats[stat] = timeSeries;
104
116
  info.tooltipLabel = stat;
105
117
  this.chart.addTimeSeries(timeSeries, info);
@@ -110,9 +122,14 @@ export class AudioHandler {
110
122
  }
111
123
 
112
124
  // Recent browsers, particularly Safari and Chrome, require a user interaction in order to enable sound playback.
125
+ // Errors are swallowed — resume() can fail due to autoplay policy and callers can't do anything about it.
113
126
  async tryResume() {
114
- if (this.audioContext) await this.audioContext.resume();
115
- if (this.audioContextM5000) await this.audioContextM5000.resume();
127
+ try {
128
+ if (this.audioContext) await this.audioContext.resume();
129
+ if (this.audioContextM5000) await this.audioContextM5000.resume();
130
+ } catch {
131
+ // Autoplay policy prevented resume; will retry on next user gesture.
132
+ }
116
133
  }
117
134
 
118
135
  _onBufferMusic5000(buffer) {