Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get safari-friendly audioContext instance #213

Merged
merged 2 commits into from
Jul 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions src/common.browser/MicAudioSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,17 +307,7 @@ export class MicAudioSource implements IAudioSource {
return;
}

// https://developer.mozilla.org/en-US/docs/Web/API/AudioContext
if (typeof (AudioContext) === "undefined") {
throw new Error("Browser does not support Web Audio API (AudioContext is not available).");
}

// Browsers without sampleRate constraint support can't connect nodes with different sample rates
if (navigator.mediaDevices.getSupportedConstraints().sampleRate) {
this.privContext = new AudioContext({ sampleRate: MicAudioSource.AUDIOFORMAT.samplesPerSec });
} else {
this.privContext = new AudioContext();
}
this.privContext = AudioStreamFormatImpl.getAudioContext(MicAudioSource.AUDIOFORMAT.samplesPerSec);
}

private destroyAudioContext = (): void => {
Expand Down
25 changes: 25 additions & 0 deletions src/sdk/Audio/AudioStreamFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,31 @@ export class AudioStreamFormatImpl extends AudioStreamFormat {
return new AudioStreamFormatImpl();
}

/**
* Creates an audio context appropriate to current browser
* @member AudioStreamFormatImpl.getAudioContext
* @function
* @public
* @returns {AudioContext} An audio context instance
*/
public static getAudioContext(sampleRate?: number): AudioContext {
// Workaround for Speech SDK bug in Safari.
const AudioContext = (window as any).AudioContext // our preferred impl
|| (window as any).webkitAudioContext // fallback, mostly when on Safari
|| false; // could not find.

// https://developer.mozilla.org/en-US/docs/Web/API/AudioContext
if (!!AudioContext) {
if (sampleRate !== undefined && navigator.mediaDevices.getSupportedConstraints().sampleRate) {
return new AudioContext({ sampleRate });
} else {
return new AudioContext();
}
} else {
throw new Error("Browser does not support Web Audio API (AudioContext is not available).");
}
}

/**
* Closes the configuration object.
* @member AudioStreamFormatImpl.prototype.close
Expand Down
38 changes: 30 additions & 8 deletions src/sdk/Audio/BaseAudioPlayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ export class BaseAudioPlayer {
/**
* Creates and initializes an instance of this class.
* @constructor
* @param {AudioStreamFormat} audioFormat audio stream format recognized by the player.
*/
public constructor(audioFormat: AudioStreamFormat) {
public constructor(audioFormat?: AudioStreamFormat) {
if (audioFormat === undefined) {
audioFormat = AudioStreamFormat.getDefaultInputFormat();
}
this.init(audioFormat);
}

Expand All @@ -33,13 +37,18 @@ export class BaseAudioPlayer {
* @param newAudioData audio data to be played.
*/
public playAudioSample(newAudioData: ArrayBuffer): void {
this.ensureInitializedContext();
const audioData = this.formatAudioData(newAudioData);
const newSamplesData = new Float32Array(this.samples.length + audioData.length);
newSamplesData.set(this.samples, 0);
newSamplesData.set(audioData, this.samples.length);
this.samples = newSamplesData;
if (!!(window as any).webkitAudioContext) {
this.playAudio(newAudioData);
} else {
this.ensureInitializedContext();
const audioData = this.formatAudioData(newAudioData);
const newSamplesData = new Float32Array(this.samples.length + audioData.length);
newSamplesData.set(this.samples, 0);
newSamplesData.set(audioData, this.samples.length);
this.samples = newSamplesData;
}
}

/**
* stops audio and clears the buffers
*/
Expand Down Expand Up @@ -69,7 +78,7 @@ export class BaseAudioPlayer {

private createAudioContext(): void {
// new ((window as any).AudioContext || (window as any).webkitAudioContext)();
this.audioContext = new AudioContext();
this.audioContext = AudioStreamFormatImpl.getAudioContext();

// TODO: Various examples shows this gain node, it does not seem to be needed unless we plan
// to control the volume, not likely
Expand Down Expand Up @@ -134,4 +143,17 @@ export class BaseAudioPlayer {
// Clear the samples for the next pushed data.
this.samples = new Float32Array();
}

private playAudio(audioData: ArrayBuffer): void {
if (this.audioContext === null) {
this.createAudioContext();
}
const source: AudioBufferSourceNode = this.audioContext.createBufferSource();
const destination: AudioDestinationNode = this.audioContext.destination;
this.audioContext.decodeAudioData(audioData, (newBuffer: AudioBuffer): void => {
source.buffer = newBuffer;
source.connect(destination);
source.start(0);
});
}
}