Using Plugins 1 - The platform-init Plugin
In this first tutorial on soundworks plugins, we will learn why and how to use the platform-init plugin, which aims to simplify the use of certain features (such as the Web Audio API) that require a user gesture to be properly initialized.
The tutorial requires basic knowledge of the soundworks
wizard, so please refer to the getting started tutorial if you didn't check it yet.
Relevant documentation
Installing the plugin
First thing first, let's generate a new empty application with the @soundworks/create
wizard. When the wizard will ask you for the name of the default client, just call it player
(with the browser
target and the default
template) so that the rest of the tutorial will be more simple to follow:
cd /path/to/working/directory
npx @soundworks/create@latest plugin-platform-init
Once done, go to the directory and launch the soundworks
wizard again to install the plugin:
cd plugin-platform-init
npx soundworks
Then select the install / uninstall soundworks plugins
entry:
Select the @soundworks/plugin-platform-init
using the space bar:
And confirm:
After the installation, you can exit the wizard by pressing Ctrl+C
or by selecting the → exit
entry.
TIP
Note that the wizard asks you if you want to install plugins when creating the application. We just followed the long path to show you how to use the wizard within the application.
TIP
If you are confortable with npm
(or yarn
or whatever new fancy tool) and you don't want to use the wizard for some reason, you can also:
npm install --save @soundworks/plugin-platform-init
In this case, the wizard is just there to help you if you don't remember the name of the package and don't want to search for it.
If you open the package.json
file, that among other things allows you to keep a list the dependencies of your project, you should see the @soundworks/plugin-platform-init
appearing under the dependencies
key:
// package.json
"dependencies": {
"@soundworks/core": "^4.0.0-alpha.0",
"@soundworks/helpers": "^1.0.0-alpha.2",
"@soundworks/plugin-platform-init": "^1.0.0-alpha.1",
"json5": "^2.2.2",
"lit": "^2.2.2"
},
INFO
Note that the actual version numbers might change compared the one listed above, as new versions of the core library and of the plugins will be released in the future.
If for some reason you need to re-install the application dependencies (i.e. npm install
) the plugin will be re-installed as well.
Registering the plugin into soundworks
Now that the plugin is installed as a dependency of our application, let's write the code to register the plugin into the application.
Note that by design, all soundworks plugins always come with both a server-side component and a client-side component. So, you will always have to register the plugin on both side of your application.
Server-side registration
Let's start with the server-side part and write the following code in the src/server/index.js
file. First let's import the server-side part of the plugin on top of the file:
// src/server/index.js
import '@soundworks/helpers/polyfills.js';
import { Server } from '@soundworks/core/server.js';
// import the server-side part of the `platform-init` plugin
import pluginPlatformInit from '@soundworks/plugin-platform-init/server.js';
Then register it into the server.pluginManager
component:
// src/server/index.js
const server = new Server(config);
server.useDefaultApplicationTemplate();
// register the plugin into the soundworks' plugin manager
server.pluginManager.register('platform-init', pluginPlatformInit);
The pluginManager.register
method takes at least 2 arguments:
- A user defined
id
(hereplatform-init
) that is used as an internal identifier to retrieve the plugin instance, and allows to register several time the same plugin under different ids in advanced use-cases. - A factory function (i.e.
pluginPlatformInit
) automatically executed by soundworks, that returns the actual plugin instance.
INFO
A factory function is common design pattern that allows for creating a full-featured object from a function call. You can check this tutorial for more information.
In the future, we will provide a full tutorial dedicated to the creation of soundworks
plugins.
That's all for the server-side, so let's now install the plugin on the client-side.
Client-side registration
Let's open the src/clients/player/index.js
and, as for the server-side, import the client-side part of the platform-init plugin:
// src/clients/player/index.js
import { Client } from '@soundworks/core/client.js';
import launcher from '@soundworks/helpers/launcher.js';
// import the client-side part of the `platform-init` plugin
import pluginPlatformInit from '@soundworks/plugin-platform-init/client.js';
TIP
Notice the small difference between the server-side and client-side imports, which is a convention that all soundworks plugins will follow:
// server-side
import pluginPlatformInit from '@soundworks/plugin-platform-init/server.js';
// client-side
import pluginPlatformInit from '@soundworks/plugin-platform-init/client.js';
Now that our plugin is imported, let's also register it into the client.PluginManager
:
// src/clients/player/index.js
const client = new Client(config);
// register the plugin into the soundworks' plugin manager
client.pluginManager.register('platform-init', pluginPlatformInit);
As for the server-side, we passed 2 arguments to the client.PluginManager#register
method: the plugin user-defined id
and the plugin factory function. Note that the user-defined id
is the same on both server-side and client-side, which allows soundworks to automatically match and associate the two components.
If you start the server now (npm run dev
) and go to http://127.0.0.1:8000, you should see the splashscreen that requires a user gesture (i.e. a "click" event) and that is automatically shown due to the fact that the platform-init plugin is registered into soundworks:
Resuming an AudioContext
So far, so good but what we did until now is just to add a slashscreen asking for a click that does nothing particular... Or, as we said in the beginning of the tutorial, the whole aim of the plugin is to simplify the initialization of features, such as the Web Audio API AudioContext
, that require a user-gesture in order to be properly launched. So let's do that.
INFO
An active user gesture is required by browser to access certain advanced features such as Web Audio API, microphone or camera. This is a way to protect end-users against intrusive ads and/or for obvious privacy reasons.
So first, let's first create an new audioContext
:
// src/clients/player/index.js
const config = window.SOUNDWORKS_CONFIG;
// create a global audio context
const audioContext = new AudioContext();
And pass it as third argument to the pluginManager.register
method:
// src/clients/player/index.js
const client = new Client(config);
// register the plugin into the soundworks' plugin manager, and pass it the audioContext
client.pluginManager.register('platform-init', pluginPlatformInit);
client.pluginManager.register('platform-init', pluginPlatformInit, { audioContext });
INFO
By default, the platform-init plugin simplifies access to several features, such as motion sensors, microphone and camera. Refer to the plugin documentation for more information.
Finally, let's create some welcoming sound that will show us that everything works well and that our audioContext
is properly resumed:
// src/clients/player/index.js
launcher.register(client, { initScreensContainer: $container });
// launch application
console.log(`> before start - audioContext is "${audioContext.state}"`);
await client.start();
console.log(`> after start - audioContext is "${audioContext.state}"`);
const now = audioContext.currentTime;
// create a simple envelop
const env = audioContext.createGain();
env.connect(audioContext.destination);
env.gain.setValueAtTime(0, now);
env.gain.linearRampToValueAtTime(0.5, now + 0.01);
env.gain.exponentialRampToValueAtTime(0.0001, now + 1);
const src = audioContext.createOscillator();
src.connect(env);
// randomly pick a frequency on an harmonic spectrum (150, 300, 450, etc...)
src.frequency.value = 150 + Math.floor(Math.random() * 10) * 150;
src.start(now);
src.stop(now + 1);
Reload the page (Cmd+R
) and click, you should now ear an incredibly "nice" sound coming from your speakers!
TIP
Note that if you launch multiple clients in the same window (i.e. http://127.0.0.1:8000/?emulate=4), you should see how the init view component also helps you to start all the clients at once without requiring you to click on each of them:
Notes on the @soundworks/helpers
default views
The spashscreen (and other init / loading views that we have not seen yet) are not directly provided by the platform-init plugin but rather by the @soundworks/helpers
package and more precisely the launcher
object included in the default application. Hence, the views are automatically created by the launcher
when it registers the soundworks client in the initialization of the application:
// src/clients/player.index.js
launcher.register(client, { initScreensContainer: $container });
The launcher offer numerous way to adapt the initialization views to your needs: e.g. change the default styles, adapt the language, or even use completely user defined views.
While won't cover these advanced use-case here (as they will be the subject of a dedicated tutorial), let's just see here the minimal changes you can make to customize the init view.
Let's then open the config/application.json
file which should look like this:
// config/application.json
{
name: 'plugin-platform-init',
author: '',
clients: {
player: {
target: 'browser',
default: true,
},
},
}
This file has been generated for you by the soundworks wizard, and the clients
entry is automatically updated each time you create a new client using the wizard.
However, the first 2 lines can be safely updated and are used by the launcher
to create the splashscreen. Let's just change the name
and author
entries to see it in action:
name: 'plugin-platform-init',
name: 'Hello Plugins',
author: '',
author: 'me & myself',
And tada! If you now go to http://127.0.0.1:8000 you should now see something like:
INFO
By default, the init views try to adapt to the locale of the browser (if the language has not been explicitely defined) and falls back to english if the localized texts are not existing. However, as we only provide english and french versions of the texts for now, it's likely that you have seen the english version.
If you are confortable with another language and are willing to contribute a localized version of this file, please open PR or issue in the @soundworks/helpers
repository!
Conclusion
In this tutorial, you have learned the basics of soundworks plugins usage, and more precisely how to use the platform-init plugin. While this plugin is not per se very complex, it can save you a lot of (quite boring) development time by simplifying the initialization of certains browser features. Along the way, you also discovered the view functionalities provided by the launcher
component that is automatically included in all soundworks applications created using the wizard.
In the next tutorial, we will wrap up what we have learned so far by creating a small working application where several clients can connect and be used as distributed speakers by a central controller.