301 lines · 11.5 KB · C
RawDownload
////  AudioScriptingInterface.h//  libraries/audio/src////  Created by Stephen Birarda on 1/2/2014.//  Copyright 2014 High Fidelity, Inc.//  Copyright 2023 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html//  SPDX-License-Identifier: Apache-2.0// /// @addtogroup ScriptEngine/// @{ #ifndef hifi_AudioScriptingInterface_h#define hifi_AudioScriptingInterface_h #include "AbstractAudioInterface.h"#include "AudioInjector.h"#include <DependencyManager.h>#include "Sound.h" class ScriptAudioInjector;class ScriptEngine; /// Provides the <code><a href="https://apidocs.overte.org/Audio.html">Audio</a></code> scripting APIclass AudioScriptingInterface : public QObject, public Dependency {    Q_OBJECT    SINGLETON_DEPENDENCY     // JSDoc for property is in Audio.h.    Q_PROPERTY(bool isStereoInput READ isStereoInput WRITE setStereoInput NOTIFY isStereoInputChanged)    Q_PROPERTY(bool isSoloing READ isSoloing)    Q_PROPERTY(QVector<QUuid> soloList READ getSoloList) public:    virtual ~AudioScriptingInterface() = default;    void setLocalAudioInterface(AbstractAudioInterface* audioInterface);     bool isSoloing() const {        return _localAudioInterface->getAudioSolo().isSoloing();    }     QVector<QUuid> getSoloList() const {        return _localAudioInterface->getAudioSolo().getUUIDs();    }     /*@jsdoc     * Adds avatars to the audio solo list. If the audio solo list is not empty, only audio from the avatars in the list is     * played.     * @function Audio.addToSoloList     * @param {Uuid[]} ids - Avatar IDs to add to the solo list.      * @example <caption>Listen to a single nearby avatar for a short while.</caption>     * // Find nearby avatars.     * var RANGE = 100; // m     * var nearbyAvatars = AvatarList.getAvatarsInRange(MyAvatar.position, RANGE);     *     * // Remove own avatar from list.     * var myAvatarIndex = nearbyAvatars.indexOf(MyAvatar.sessionUUID);     * if (myAvatarIndex !== -1) {     *     nearbyAvatars.splice(myAvatarIndex, 1);     * }     *     * if (nearbyAvatars.length > 0) {     *     // Listen to only one of the nearby avatars.     *     var avatarName = AvatarList.getAvatar(nearbyAvatars[0]).displayName;     *     print("Listening only to " + avatarName);     *     Audio.addToSoloList([nearbyAvatars[0]]);     *     *     // Stop listening to only the one avatar after a short while.     *     Script.setTimeout(function () {     *         print("Finished listening only to " + avatarName);     *         Audio.resetSoloList();     *     }, 10000); // 10s     *     * } else {     *     print("No nearby avatars");     * }     */    Q_INVOKABLE void addToSoloList(QVector<QUuid> uuidList) {        _localAudioInterface->getAudioSolo().addUUIDs(uuidList);    }     /*@jsdoc     * Removes avatars from the audio solo list. If the audio solo list is not empty, only audio from the avatars in the list     * is played.     * @function Audio.removeFromSoloList     * @param {Uuid[]} ids - Avatar IDs to remove from the solo list.     */    Q_INVOKABLE void removeFromSoloList(QVector<QUuid> uuidList) {        _localAudioInterface->getAudioSolo().removeUUIDs(uuidList);    }     /*@jsdoc     * Clears the audio solo list.     * @function Audio.resetSoloList     */    Q_INVOKABLE void resetSoloList() {        _localAudioInterface->getAudioSolo().reset();    }     /*@jsdoc     * Gets whether your microphone audio is echoed back to you from the server. When enabled, microphone audio is echoed only     * if you're unmuted or are using push-to-talk.     * @function Audio.getServerEcho     * @returns {boolean} <code>true</code> if echoing microphone audio back to you from the server is enabled,     *     <code>false</code> if it isn't.     */    Q_INVOKABLE bool getServerEcho();     /*@jsdoc     * Sets whether your microphone audio is echoed back to you from the server. When enabled, microphone audio is echoed     * only if you're unmuted or are using push-to-talk.     * @function Audio.setServerEcho     * @param {boolean} serverEcho - <code>true</code> to enable echoing microphone back to you from the server,     *     <code>false</code> to disable.     */    Q_INVOKABLE void setServerEcho(bool serverEcho);     /*@jsdoc     * Toggles the echoing of microphone audio back to you from the server. When enabled, microphone audio is echoed only if     * you're unmuted or are using push-to-talk.     * @function Audio.toggleServerEcho     */    Q_INVOKABLE void toggleServerEcho();     /*@jsdoc     * Gets whether your microphone audio is echoed back to you by the client. When enabled, microphone audio is echoed     * even if you're muted or not using push-to-talk.     * @function Audio.getLocalEcho     * @returns {boolean} <code>true</code> if echoing microphone audio back to you from the client is enabled,     *     <code>false</code> if it isn't.     */    Q_INVOKABLE bool getLocalEcho();     /*@jsdoc     * Sets whether your microphone audio is echoed back to you by the client. When enabled, microphone audio is echoed     * even if you're muted or not using push-to-talk.     * @function Audio.setLocalEcho     * @parm {boolean} localEcho - <code>true</code> to enable echoing microphone audio back to you from the client,     *     <code>false</code> to disable.     * @example <caption>Echo local audio for a few seconds.</caption>     * Audio.setLocalEcho(true);     * Script.setTimeout(function () {     *     Audio.setLocalEcho(false);     * }, 3000); // 3s     */    Q_INVOKABLE void setLocalEcho(bool localEcho);     /*@jsdoc     * Toggles the echoing of microphone audio back to you by the client. When enabled, microphone audio is echoed even if     * you're muted or not using push-to-talk.     * @function Audio.toggleLocalEcho     */    Q_INVOKABLE void toggleLocalEcho();  protected:    AudioScriptingInterface() = default;     // these methods are protected to stop C++ callers from calling, but invokable from script     /*@jsdoc     * Starts playing or "injecting" the content of an audio file. The sound is played globally (sent to the audio     * mixer) so that everyone hears it, unless the <code>injectorOptions</code> has <code>localOnly</code> set to     * <code>true</code> in which case only the client hears the sound played. No sound is played if sent to the audio mixer     * but the client is not connected to an audio mixer. The {@link AudioInjector} object returned by the function can be used     * to control the playback and get information about its current state.     * @function Audio.playSound     * @param {SoundObject} sound - The content of an audio file, loaded using {@link SoundCache.getSound}. See     * {@link SoundObject} for supported formats.     * @param {AudioInjector.AudioInjectorOptions} [injectorOptions={}] - Configures where and how the audio injector plays the     *     audio file.     * @returns {AudioInjector} The audio injector that plays the audio file.     * @example <caption>Play a sound.</caption>     * var sound = SoundCache.getSound("https://apidocs.overte.org/examples/beach-tide-amplified.wav");     *     * function playSound() {     *     var injectorOptions = {     *         position: MyAvatar.position     *     };     *     var injector = Audio.playSound(sound, injectorOptions);     * }     *     * function onSoundReady() {     *     sound.ready.disconnect(onSoundReady);     *     playSound();     * }     *     * if (sound.downloaded) {     *     playSound();     * } else {     *     sound.ready.connect(onSoundReady);     * }     */    Q_INVOKABLE ScriptAudioInjector* playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());     /*@jsdoc     * Starts playing the content of an audio file locally (isn't sent to the audio mixer). This is the same as calling     * {@link Audio.playSound} with {@link AudioInjector.AudioInjectorOptions} <code>localOnly</code> set <code>true</code> and     * the specified <code>position</code>.     * @function Audio.playSystemSound     * @param {SoundObject} sound - The content of an audio file, which is loaded using {@link SoundCache.getSound}. See     * {@link SoundObject} for supported formats.     * @returns {AudioInjector} The audio injector that plays the audio file.     */    Q_INVOKABLE ScriptAudioInjector* playSystemSound(SharedSoundPointer sound);     /*@jsdoc     * Sets whether the audio input should be used in stereo. If the audio input doesn't support stereo then setting a value     * of <code>true</code> has no effect.     * @function Audio.setStereoInput     * @param {boolean} stereo - <code>true</code> if the audio input should be used in stereo, otherwise <code>false</code>.     */    Q_INVOKABLE void setStereoInput(bool stereo);     /*@jsdoc     * Gets whether the audio input is used in stereo.     * @function Audio.isStereoInput     * @returns {boolean} <code>true</code> if the audio input is used in stereo, otherwise <code>false</code>.     */    Q_INVOKABLE bool isStereoInput(); signals:     /*@jsdoc     * Triggered when the client is muted by the mixer because their loudness value for the noise background has reached the     * threshold set for the domain (in the server settings).     * @function Audio.mutedByMixer     * @returns {Signal}     */    void mutedByMixer();     /*@jsdoc     * Triggered when the client is muted by the mixer because they're within a certain radius (50m) of someone who requested     * the mute through Developer &gt; Audio &gt; Mute Environment.     * @function Audio.environmentMuted     * @returns {Signal}     */    void environmentMuted();     /*@jsdoc     * Triggered when the client receives its first packet from the audio mixer.     * @function Audio.receivedFirstPacket     * @returns {Signal}     */    void receivedFirstPacket();     /*@jsdoc     * Triggered when the client is disconnected from the audio mixer.     * @function Audio.disconnected     * @returns {Signal}     */    void disconnected();     /*@jsdoc     * Triggered when the noise gate is opened. The input audio signal is no longer blocked (fully attenuated) because it has     * risen above an adaptive threshold set just above the noise floor. Only occurs if <code>Audio.noiseReduction</code> is     * <code>true</code>.     * @function Audio.noiseGateOpened     * @returns {Signal}     */    void noiseGateOpened();     /*@jsdoc     * Triggered when the noise gate is closed. The input audio signal is blocked (fully attenuated) because it has fallen     * below an adaptive threshold set just above the noise floor. Only occurs if <code>Audio.noiseReduction</code> is     * <code>true</code>.     * @function Audio.noiseGateClosed     * @returns {Signal}     */    void noiseGateClosed();     /*@jsdoc     * Triggered when a frame of audio input is processed.     * @function Audio.inputReceived     * @param {Int16Array} inputSamples - The audio input processed.     * @returns {Signal}     */    void inputReceived(const QByteArray& inputSamples);     /*@jsdoc     * Triggered when the input audio use changes between mono and stereo.     * @function Audio.isStereoInputChanged     * @param {boolean} isStereo - <code>true</code> if the input audio is stereo, otherwise <code>false</code>.     * @returns {Signal}     */    void isStereoInputChanged(bool isStereo); private:    AbstractAudioInterface* _localAudioInterface { nullptr };}; void registerAudioMetaTypes(ScriptEngine* engine); #endif // hifi_AudioScriptingInterface_h /// @}