Skip to content

Commit

Permalink
Webkit fixes (#20)
Browse files Browse the repository at this point in the history
* fixes to support webkit prefix and local video preview

* update docs

* more doc tweaks

* correct some readme typos

* safari needs the sample rates to match

* add configuration step and more todos

* add the default URL to the quick start
  • Loading branch information
k-anderson authored Jul 1, 2020
1 parent 0911033 commit 143693e
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 40 deletions.
35 changes: 32 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,38 @@ The library provides multiple ways to interact with it. The quick start example
$ npm install
```

4. Build the library
4. Replace the following placeholder on the index.html configuration with appropriate values:

- `{SIP_SERVER}`
- `{SIP_USERNAME}`
- `{SIP_PASSWORD}`
- `{SIP_DOMAIN}`

> NOTE: The `{SIP_USERNAME}`, `{SIP_PASSWORD}` and `{SIP_DOMAIN}` can be changed via the lwpUserAgent default form and are not required to be changed in the configuration (they would need to be changed on the form prior to starting the user agent). However, failure to update `{SIP_SERVER}` will cause the library to crash on start up.
5. Start a continuous process that will build the library, rebuild if any source files are changed as well as a webserver to serve the artifacts. Once started it will print a URL to the screen that can be visted, only by the computer it was started on, in the browser to create an example / developer instance of the library.

```bash
$ npm run dev
```

> NOTE: By default the webserver will be running at [http://localhost:8080/](http://localhost:8080/).
## Publishing

1. Build the library

```bash
$ npm run build
```

5. Include the libwebphone build artifact on your website
2. Include the libwebphone build artifact on your website

```
<script src="dist/libwebphone.js" type="text/javascript"></script>
```

6. Create an instance, providing a configuration object with all the minimal parameters for the features you require. A "simple kitchen sink" example might look like:
3. Create an instance, providing a configuration object with all the minimal parameters for the features you require. A "simple kitchen sink" example might look like:

```
<script type="text/javascript">
Expand Down Expand Up @@ -99,8 +118,16 @@ The library provides multiple ways to interact with it. The quick start example

#### npm run dev

Build and automatically rebuild if any of the source files are changed. In addition, it starts a webpack-dev-server to serve the build artifacts for ease of development.

#### npm run watch

Build and automatically rebuild if any of the source files are changed.

#### npm run stats

Creates a 'stats.json' file on the root of the project detailing statistics regarding the webpack artifact for use by tools such as [webpack-visualizer](https://chrisbateman.github.io/webpack-visualizer/).

#### npm run build

Build and minimize the library for a production deployment.
Expand Down Expand Up @@ -302,6 +329,8 @@ Some of these additional features include events when listeners are added / remo
## Todo

- Standardize and cleanup i18n keys
- Add 'remeber me' feature to lwpUserAgent form
- Add entry of websocket to lwpUserAgent form
- Standardize default templates and add default CSS classes
- lwpVideoCanvas : Nearly complete class to render and control video aspects of calls
- Support multiple instances of lwpUserAgent to provide "multi-line" functionality.
Expand Down
4 changes: 2 additions & 2 deletions configuration/development/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
},
devtool: "inline-source-map",
devServer: {
inline: false,
liveReload: false,
inline: true,
liveReload: true,
},
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
"description": "A library of components to build real-time media clients in the browser",
"main": "index.html",
"scripts": {
"dev": "webpack-dev-server --config configuration/development/webpack.config.js",
"dev": "webpack-dev-server --config configuration/development/webpack.config.js --watch",
"watch": "webpack --config configuration/development/webpack.config.js --watch",
"stats": "webpack --json > stats.json",
"build": "webpack --config configuration/production/webpack.config.js",
"lint": "npx eslint src/*"
},
Expand Down
4 changes: 4 additions & 0 deletions src/libwebphone.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export default class extends EventEmitter {
return this._audioContext;
}

getUtils() {
return lwpUtils;
}

geti18n() {
return i18next;
}
Expand Down
119 changes: 96 additions & 23 deletions src/lwpAudioContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,9 @@ export default class extends lwpRenderer {
this.startAudioContext();

const duration = this._config.channels.tones.duration;
const sampleRate = 8000; //this._tonesAudio.context.sampleRate;
const buffer = this._tonesAudio.context.createBuffer(
const sampleRate = this._tonesAudio.context.sampleRate;
const buffer = this._shimCreateBuffer(
this._tonesAudio.context,
tones.length,
sampleRate,
sampleRate
Expand All @@ -190,7 +191,7 @@ export default class extends lwpRenderer {
}
}

const bufferSource = this._tonesAudio.context.createBufferSource();
const bufferSource = this._shimCreateBufferSource(this._tonesAudio.context);
bufferSource.buffer = buffer;
bufferSource.connect(this._getOutputGainNode("tones"));
bufferSource.start();
Expand Down Expand Up @@ -364,22 +365,30 @@ export default class extends lwpRenderer {

this._outputAudio.context = this._audioContext;

this._outputAudio.masterGain = this._outputAudio.context.createGain();
this._outputAudio.masterGain = this._shimCreateGain(
this._outputAudio.context
);
this._outputAudio.masterGain.gain.value = this._config.channels.master.volume;

this._outputAudio.ringerGain = this._outputAudio.context.createGain();
this._outputAudio.ringerGain = this._shimCreateGain(
this._outputAudio.context
);
this._outputAudio.ringerGain.gain.value = this._config.channels.ringer.volume;
if (this._config.channels.ringer.connectToMaster) {
this._outputAudio.ringerGain.connect(this._outputAudio.masterGain);
}

this._outputAudio.tonesGain = this._outputAudio.context.createGain();
this._outputAudio.tonesGain = this._shimCreateGain(
this._outputAudio.context
);
this._outputAudio.tonesGain.gain.value = this._config.channels.tones.volume;
if (this._config.channels.tones.connectToMaster) {
this._outputAudio.tonesGain.connect(this._outputAudio.masterGain);
}

this._outputAudio.remoteGain = this._outputAudio.context.createGain();
this._outputAudio.remoteGain = this._shimCreateGain(
this._outputAudio.context
);
this._outputAudio.remoteGain.gain.value = this._config.channels.remote.volume;
if (
this._config.channels.remote.connectToMaster &&
Expand All @@ -388,13 +397,15 @@ export default class extends lwpRenderer {
this._outputAudio.remoteGain.connect(this._outputAudio.masterGain);
}

this._outputAudio.previewGain = this._outputAudio.context.createGain();
this._outputAudio.previewGain = this._shimCreateGain(
this._outputAudio.context
);
this._outputAudio.previewGain.gain.value = this._config.channels.preview.volume;
if (this._config.channels.preview.connectToMaster) {
this._outputAudio.previewGain.connect(this._outputAudio.masterGain);
}

this._outputAudio.destinationStream = this._createMediaStreamDestination(
this._outputAudio.destinationStream = this._shimCreateMediaStreamDestination(
this._outputAudio.context
);
this._outputAudio.masterGain.connect(this._outputAudio.destinationStream);
Expand All @@ -420,17 +431,25 @@ export default class extends lwpRenderer {

this._ringerAudio.ringerConnected = false;

this._ringerAudio.carrierGain = this._ringerAudio.context.createGain();
this._ringerAudio.carrierGain = this._shimCreateGain(
this._ringerAudio.context
);

this._ringerAudio.carrierNode = this._ringerAudio.context.createOscillator();
this._ringerAudio.carrierNode = this._shimCreateOscillator(
this._ringerAudio.context
);
this._ringerAudio.carrierNode.frequency.value = this._config.channels.ringer.carrier.frequency;
this._ringerAudio.carrierNode.connect(this._ringerAudio.carrierGain);

this._ringerAudio.modulatorNode = this._ringerAudio.context.createOscillator();
this._ringerAudio.modulatorNode = this._shimCreateOscillator(
this._ringerAudio.context
);
this._ringerAudio.modulatorNode.frequency.value = this._config.channels.ringer.modulator.frequency;
this._ringerAudio.modulatorNode.connect(this._ringerAudio.carrierGain.gain);

this._ringerAudio.ringerGain = this._ringerAudio.context.createGain();
this._ringerAudio.ringerGain = this._shimCreateGain(
this._ringerAudio.context
);
this._ringerAudio.carrierGain.connect(this._ringerAudio.ringerGain);
}

Expand All @@ -457,13 +476,16 @@ export default class extends lwpRenderer {

this._previewAudio.toneActive = false;

this._previewAudio.oscillatorNode = this._previewAudio.context.createOscillator();
this._previewAudio.oscillatorNode = this._shimCreateOscillator(
this._previewAudio.context
);
this._previewAudio.oscillatorNode.frequency.value = this._config.channels.preview.tone.frequency;
this._previewAudio.oscillatorNode.type = this._config.channels.preview.tone.type;

this._previewAudio.loopbackActive = false;

this._previewAudio.loopbackDelayNode = this._previewAudio.context.createDelay(
this._previewAudio.loopbackDelayNode = this._shimCreateDelay(
this._previewAudio.context,
this._config.channels.preview.loopback.delay + 1.5
);
this._previewAudio.loopbackDelayNode.delayTime.value = this._config.channels.preview.loopback.delay;
Expand Down Expand Up @@ -729,16 +751,18 @@ export default class extends lwpRenderer {
);
}

_createMediaStreamDestination(context) {
return context.createMediaStreamDestination();
}

_createLocalMediaStreamSource(mediaStream) {
return this._previewAudio.context.createMediaStreamSource(mediaStream);
return this._shimCreateMediaStreamSource(
this._previewAudio.context,
mediaStream
);
}

_createRemoteMediaStreamSource(mediaStream) {
return this._remoteAudio.context.createMediaStreamSource(mediaStream);
return this._shimCreateMediaStreamSource(
this._remoteAudio.context,
mediaStream
);
}

_connectLocalSourceStream(sourceStream = null) {
Expand Down Expand Up @@ -830,14 +854,63 @@ export default class extends lwpRenderer {
}
}

/** Shims */

_shimCreateBuffer(context, ...args) {
return (context.createBuffer || context.webkitCreateBuffer).apply(
context,
args
);
}

_shimCreateBufferSource(context, ...args) {
return (
context.createBufferSource || context.webkitCreateBufferSource
).apply(context, args);
}

_shimCreateDelay(context, ...args) {
return (context.createDelay || context.webkitCreateDelay).apply(
context,
args
);
}

_shimCreateGain(context, ...args) {
return (context.createGain || context.webkitCreateGain).apply(
context,
args
);
}

_shimCreateOscillator(context, ...args) {
return (context.createOscillator || context.webkitCreateOscillator).apply(
context,
args
);
}

_shimCreateMediaStreamDestination(context, ...args) {
return (
context.createMediaStreamDestination ||
context.webkitCreateMediaStreamDestination
).apply(context, args);
}

_shimCreateMediaStreamSource(context, ...args) {
return (
context.createMediaStreamSource || context.webkitCreateMediaStreamSource
).apply(context, args);
}

_shimAudioContext() {
if (lwpUtils.isChrome()) {
return new AudioContext({
return new (window.AudioContext || window.webkitAudioContext)({
latencyHint: "interactive",
sampleRate: 44100,
});
} else {
return new AudioContext({
return new (window.AudioContext || window.webkitAudioContext)({
latencyHint: "interactive",
});
}
Expand Down
7 changes: 5 additions & 2 deletions src/lwpMediaDevices.js
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,10 @@ export default class extends lwpRenderer {

_importInputDevices(devices) {
devices.forEach((device) => {
if (!device.deviceId || 0 === device.deviceId.length) {
return;
}

const enumeratedDevice = this._deviceParameters(device);
const availableDevice = this._findAvailableDevice(
device.kind,
Expand Down Expand Up @@ -1148,9 +1152,8 @@ export default class extends lwpRenderer {
}

_deviceParameters(device) {
const deviceId = device.deviceId;
return {
id: deviceId,
id: device.deviceId,
label: device.label,
deviceKind: device.kind,
name: this._getDeviceName(device),
Expand Down
18 changes: 9 additions & 9 deletions src/lwpVideoCanvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -1275,16 +1275,16 @@ export default class extends lwpRenderer {
this._canvasGetImage(canvasRender, this._config.remoteVideo.name)
);

return;
}
if (this._config.localVideo.enabled) {
this._renderCanvasImage(
canvasRender,
this._canvasGetImage(canvasRender, this._config.localVideo.name, {
checkShouldShow: true,
})
);
}

if (this._config.localVideo.enabled) {
this._renderCanvasImage(
canvasRender,
this._canvasGetImage(canvasRender, this._config.localVideo.name, {
checkShouldShow: true,
})
);
return;
}

const image = this._canvasRender.data.images.find((image) => {
Expand Down

0 comments on commit 143693e

Please sign in to comment.