Skip to content

Commit

Permalink
fix: if crossorigin=anonymous fails on <audio> element, automatically…
Browse files Browse the repository at this point in the history
… try removing crossorigin. Resolves CORS issue

when an identifier was a url that would redirect
  • Loading branch information
jkeen committed May 22, 2023
1 parent b786dfd commit 984eba7
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 29 deletions.
1 change: 1 addition & 0 deletions ember-stereo/src/-private/utils/strategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default class Strategy {

sharedAudioAccess = null;
error = null;
erroredSound = null;
success = false;
tried = false;

Expand Down
3 changes: 2 additions & 1 deletion ember-stereo/src/services/stereo.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ export default class Stereo extends Service.extend(EmberEvented) {
});
if (result.error) {
strategy.error = result.error;
strategy.erroredSound = result.erroredSound;
failures.push(strategy);
}
if (result.sound) {
Expand Down Expand Up @@ -956,7 +957,7 @@ export default class Stereo extends Service.extend(EmberEvented) {
);
this._unregisterEvents(sound);
strategy.error = sound.error;
let result = { error: sound.error };
let result = { error: sound.error, erroredSound: sound };

return result;
}
Expand Down
15 changes: 10 additions & 5 deletions ember-stereo/src/stereo-connections/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,12 +366,17 @@ export default class Sound extends Evented {
this.isLoading = false;
this.isPlaying = false;
}
this.isErrored = true;
this.error = error;
if (audioLoadError) {
audioLoadError(this);
}

this.debug('audio-load-error');
if (this.shouldRetry && this.retry) {
this.retry();
} else {
this.isErrored = true;
this.error = error;
if (audioLoadError) {
audioLoadError(this);
}
}
});

this.on('audio-loaded', () => {
Expand Down
35 changes: 16 additions & 19 deletions ember-stereo/src/stereo-connections/native-audio.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export default class NativeAudio extends BaseSound {
let audio = this.requestControl();
audio.src = this.url;
this._registerEvents(audio);
this.retryCount = 0;

if (macroCondition(isTesting())) {
audio.muted = true;
Expand Down Expand Up @@ -400,9 +401,8 @@ export default class NativeAudio extends BaseSound {
}

@task({ restartable: true })
*playTask({ position /*, retryCount */ }) {
*playTask({ position }) {
this.isLoading = true;
// retryCount = retryCount || 0
let audio = this.requestControl();

// since we clear the `src` attr on pause for streams, restore it here
Expand All @@ -419,30 +419,27 @@ export default class NativeAudio extends BaseSound {
throw e;
});
} catch (e) {
// if (retryCount < 2) {
// try {
// yield this.playTask.perform({ position, retryCount: retryCount + 1 })
// }
// catch (e) {
// if (!didCancel(e)) {
// throw e;
// }
// }
// }
this._onAudioError(e);
} finally {
this.isLoading = false;
}
}

get shouldRetry() {
return this.retryCount < 1;
}

retry() {
this.debug(`retrying load with crossorigin not set`);
this.audioElement.removeAttribute('crossorigin');

this.retryCount = this.retryCount + 1;
this.audioElement.src = this.url;
this.audioElement.load();
}

play({ position } = {}) {
try {
return this.playTask.perform({ position });
} catch (e) {
if (!didCancel(e)) {
throw e;
}
}
return this.playTask.perform({ position });
}

pause() {
Expand Down
4 changes: 3 additions & 1 deletion ember-stereo/src/test-support/utils/fake-media-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ export default class FakeMediaElement extends Evented {
@tracked played = false;
@tracked loaded = false;
@tracked readyState;
@tracked crossOrigin;

constructor() {
super(...arguments);

debug('ember-stereo:fake-element')(
`initializing fake ${arguments[0]} element`
`initializing fake ${arguments[0] ?? ''} element`
);
this.setInitialState();
}
Expand All @@ -43,6 +44,7 @@ export default class FakeMediaElement extends Evented {
this.duration = NaN;
this._currentTime = 0;
this.loaded = false;
this.crossorigin = 'anonymous';
}

async load() {
Expand Down
5 changes: 2 additions & 3 deletions test-app/tests/unit/services/stereo-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ module('Unit | Service | stereo', function (hooks) {
sandbox
);

await service.load('/first/test.mp3', {
await service.load('/good/1000/test.mp3', {
silenceErrors: true,
useConnections: ['NativeAudio', 'LocalDummyConnection'],
});
Expand All @@ -509,7 +509,7 @@ module('Unit | Service | stereo', function (hooks) {
'native audio should have been tried before local'
);

await service.play('/second/test.mp3', {
await service.play('/good/1000/test-2.mp3', {
silenceErrors: true,
useConnections: ['NativeAudio'],
});
Expand Down Expand Up @@ -1116,7 +1116,6 @@ module('Unit | Service | stereo', function (hooks) {
let findSpy = sandbox.spy(soundCache, 'find');

service.one('pre-load', (urls) => {
console.log('running preload hook');
urls.forEach((url) => {
url.href = `${url.href}?foo=bar`;
});
Expand Down
31 changes: 31 additions & 0 deletions test-app/tests/unit/stereo-connections/native-audio-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,4 +365,35 @@ module('Unit | Connection | Native Audio', function (hooks) {
await sound1.play(); // sound 1 has control
await sound2.play(); // sound 2 has control
});

test('automatically retries upon CORS failure', async function (assert) {
assert.expect(4);
let stereo = this.owner.lookup('service:stereo');
let url1 = '/good/5000/silence.mp3';

let { sound: sound1 } = await stereo.load(url1, {
silenceErrors: true,
useConnections: ['NativeAudio'],
});

assert.strictEqual(sound1.retryCount, 0);
assert.strictEqual(
sound1.audioElement.getAttribute('crossorigin'),
'anonymous',
'first try should be anonymous'
);

let { failures } = await stereo.load('/bad/http-301/silence.mp3', {
useConnections: ['NativeAudio'],
silenceErrors: true,
});

let erroredSound = failures[0].erroredSound;
assert.strictEqual(erroredSound.retryCount, 1);
assert.strictEqual(
erroredSound.audioElement.getAttribute('crossorigin'),
null,
'second try should be null'
);
});
});

0 comments on commit 984eba7

Please sign in to comment.