/// import * as events from 'events'; import * as Tp from 'thingpedia'; import type DeviceDatabase from '../../engine/devices/database'; import { AudioDevice, AudioPlayer, CustomPlayerSpec } from './interface'; /** * Coordinate access to audio between multiple skills. * * This class coordinates between N players (speakers) and M skills * that can play media (news, music/spotify, radio, etc.). * * Each player is associated with a conversation (through the unique * conversation ID). It is expected that commands coming from a conversation * will control the player associated with that conversation. * * There are two modes of usage. * * If the skill can control its own playback through some internal * API (as is the case with Spotify), the skill will call {@link prepare} * and then {@link requestAudio} when it first handles a command to play. * After {@link requestAudio} succeeds, the skill call the internal API * to actually start the playback. Subsequent control occurs over the internal * API. * * If the skill cannot control playback directly (it only retrieves URLs), * it will call {@link playURLs} instead. Subsequent control is handled * by the audio controller directly. */ export default class AudioController extends events.EventEmitter { private _devices; private _deviceRemovedListener; private _players; constructor(devices: DeviceDatabase); addPlayer(player: AudioPlayer): Promise; removePlayer(player: AudioPlayer): Promise; start(): Promise; stop(): Promise; private _getPlayer; /** * Retrieve the player associated with the given conversation, if any. * * This method should not be called outside of Genie. * * @param conversationId */ getPlayer(conversationId?: string): AudioPlayer | undefined; /** * Resume playing audio. * * The method will instruct the currently playing skill to resume playing. * * @param conversationId the conversation on which to resume playing; if unspecified, * any conversation that can be resumed will be resumed */ resumeAudio(conversationId?: string): Promise; private _normalizeCompatIface; /** * Check if the custom player backend is available. * * This function will check whether the backend is supported, and will * attempt to initialize it using the given spec. * * The function is safe to call if the backend is unsupported, and will * return false. * * @param spec the player to check * @param conversationId the conversation ID associated with the current command; * if specified, it will affect the choice of which player to play on * @returns */ checkCustomPlayer(spec: CustomPlayerSpec, conversationId?: string): Promise; /** * Request audio on behalf of the given device (skill). * * This method must be called before starting a background playback operation, * using a media-player capability or using a device-specific service. * * The provided interface will be used to pause/resume audio when a different device * request audio at a later time, or when the user requests to "stop" or "resume" * without specifying what device to use. * * This method can be called multiple times for the same device, with no effect. * * @param device the device that requests to play audio * @param iface the interface to control playback while the device is current * @param conversationId the conversation ID associated with the current command; * if specified, it will affect the choice of which player to play on * @param spec parameters affecting which player to choose */ requestAudio(device: Tp.BaseDevice, iface: AudioDevice | (() => Promise), conversationId?: string, spec?: CustomPlayerSpec): Promise; /** * Request to play the given audio URLs * @param device the skill on behalf of which playback occurs * @param urls the urls to play * @param conversationId the conversation ID associated with the current command; * if specified, it will affect the choice of which player to play on */ playURLs(device: Tp.BaseDevice, urls: string[], conversationId?: string): Promise; /** * Request audio on behalf of the system itself. * * This method must not be called outside of Genie */ requestSystemAudio(iface: AudioDevice, conversationId?: string): Promise; /** * Release the control of background audio on behalf of the given device. * * This method has no effect if the given device is not currently controlling * audio. */ releaseAudio(device: Tp.BaseDevice, conversationId?: string): void; /** * Pause all audio coming from this assistant. * * This method will inform the currently playing device that it must pause * playing. It corresponds to the command "pause". * * This command differs from {@link stopAudio} because the audio device * should interpret this request in a way that makes the audio resumable. * * @param the conversation ID associated with the command; if specified, * only audio associated with that conversation will be paused */ pauseAudio(conversationId?: string): Promise; /** * Stop all audio coming from this assistant. * * This method will inform the currently playing device that it must stop * playing. It corresponds to the command "stop". * * @param the conversation ID associated with the command; if specified, * only audio associated with that conversation will be stopped */ stopAudio(conversationId?: string): Promise; private _onDeviceRemoved; }