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

Improve audio settings #1582

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

daleglass
Copy link
Contributor

@daleglass daleglass commented Jan 26, 2022

This implements configurable config settings for audio codecs. It's still at an early stage, and only being submitted for feedback and collaboration.

TODO list:

  • Cleanup code
  • API Documentation
  • Figure out the final list of audio parameters
  • Implement settings in interface
  • Fix Audio.getEncoderFeatures()

Initial API for audio codecs, client side:

Audio.getCodec() -- returns current codec
Audio.getCodecs() -- list of known codecs
Audio.getAllowedCodecs() -- list of codecs the interface is willing to use. All codecs are accepted if the list is empty. Will check that the names correspond with something in getCodecs(), and filter out any unknown entries.
Audio.setAllowedCodecs() -- set list of allowed codecs for the interface.
Audio.getEncoderVBR() -- is VBR enabled
Audio.setEncoderVBR(bool) -- enable/disable Variable Bit Rate
Audio.getEncoderBitrate()
Audio.getEncoderBitrate(int bitrate) -- Bit rate, in bits/s. 2400 to 512000. Default is 128000 (128kbps)
Audio.getEncoderComplexity()
Audio.getEncoderComplexity(int complexity) -- How CPU intensive compression is, 0 to 100.
Audio.getEncoderFEC() -- is VBR enabled
Audio.setEncoderFEC(bool) -- enable/disable Forward Error Correction
Audio.getEncoderPacketLossPercent()
Audio.setEncoderPacketLossPercent(int percent) -- how much data loss to allow for

Not working:
Audio.getEncoderFeatures() -- returns a feature list for the current encoder

Testing:

  • You can test with yourself by using this console command: Audio.setServerEcho(true). This will bounce audio off the domain at yourself. Microphone has to be on for it to work.

  • Use for instance Audio.setAllowedCodecs(["zlib"]) in the console, and observe the rise in bandwidth usage.

  • Use Audio.setEncoderBitrate(5000) to see the effect of 5 kbps audio

  • Use Audio.setEncoderComplexity(1) to see the effect of less CPU intensive encoding

  • Use Audio.setEncoderFEC(true) and Audio.setEncoderPacketLossPercent(10) to try error correction. Needs a connection with some packet loss.

Feedback would be very welcome -- especially regarding whether the API makes sense, and if there are threading issues anywhere in this.

Experimentally verified that nothing is heard below this value.
Codec feature info doesn't actually work yet, type needs registering
@digisomni digisomni added the enhancement New feature or request label Jan 30, 2022
@digisomni digisomni added the scripting api change Change is made in the scripting API label Feb 3, 2022
@daleglass daleglass marked this pull request as ready for review February 3, 2022 22:21
@digisomni digisomni requested a review from namark February 5, 2022 19:08
@namark
Copy link
Contributor

namark commented Feb 6, 2022

These two constants are no longer used
https://github.com/vircadia/vircadia/blob/9b06c9070dd61ba97c075b0de08b71ad84374ec0/plugins/opusCodec/src/OpusEncoder.h#L67-L68
DEFAULT_APPLICATION is technically used in the constructor, but then it's immediately overwritten.

Copy link
Contributor

@namark namark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the scripting interface, I would generally prefer to deal objects for this kind of things in JavaScript, instead of bunch of get/set functions, something similar in spirit to the settings JSON API we have, but that also seems like something way out of scope for this PR. I'm also not sure what the intended use cases are, so might be overthinking it.

Comment on lines +56 to +68
/*
struct CodecSettings {
QString codec;
Encoder::Bandpass bandpass = Encoder::Bandpass::Fullband;
Encoder::ApplicationType applicationType = Encoder::ApplicationType::Audio;
Encoder::SignalType signalType = Encoder::SignalType::Auto;
int bitrate = 128000;
int complexity = 100;
bool enableFEC = 0;
int packetLossPercent = 0;
bool enableVBR = 1;
};
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is identical to the definition in the included plugins/CodecPlugin.h, not sure if it's here for reference, but seems out of place anyway

Suggested change
/*
struct CodecSettings {
QString codec;
Encoder::Bandpass bandpass = Encoder::Bandpass::Fullband;
Encoder::ApplicationType applicationType = Encoder::ApplicationType::Audio;
Encoder::SignalType signalType = Encoder::SignalType::Auto;
int bitrate = 128000;
int complexity = 100;
bool enableFEC = 0;
int packetLossPercent = 0;
bool enableVBR = 1;
};
*/

static int getStaticJitterFrames() { return _numStaticJitterFrames; }
static bool shouldMute(float quietestFrame) { return quietestFrame > _noiseMutingThreshold; }
static float getAttenuationPerDoublingInDistance() { return _attenuationPerDoublingInDistance; }
static const std::vector<ZoneDescription>& getAudioZones() { return _audioZones; }
static const std::vector<ZoneSettings>& getZoneSettings() { return _zoneSettings; }
static const std::vector<ReverbSettings>& getReverbSettings() { return _zoneReverbSettings; }
static const std::pair<QString, CodecPluginPointer> negotiateCodec(std::vector<QString> codecs);
static const std::vector<Encoder::CodecSettings> getCodecSettings() { return _codecSettings; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this comes from the line above, but return const value seems odd, unless I'm missing some coding standard. Hard to think of any actual use cases for it though in general, outside of some really weird proxy types maybe.

Suggested change
static const std::vector<Encoder::CodecSettings> getCodecSettings() { return _codecSettings; }
static const std::vector<Encoder::CodecSettings>& getCodecSettings() { return _codecSettings; }

I would change negotiateCodec as well to return a plain value without const, but that would be out of scope of this PR.

@@ -1417,10 +1417,109 @@
{
"name": "codec_preference_order",
"label": "Audio Codec Preference Order",
"help": "List of codec names in order of preferred usage",
"help": "List of codec names in order of preferred usage -- mod2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't figure out what mod2 means here...

/**
* @brief Represents the settings loaded from the domain's configuration page
*
* Encoder classes are created EntityScriptServer, Agent, AudioMixerClientData and AudioClient,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Encoder classes are created EntityScriptServer, Agent, AudioMixerClientData and AudioClient,
* Encoder classes are created by EntityScriptServer, Agent, AudioMixerClientData and AudioClient,

@@ -55,8 +55,8 @@ AthenaOpusEncoder::AthenaOpusEncoder(int sampleRate, int numChannels) {

setBitrate(DEFAULT_BITRATE);
setComplexity(DEFAULT_COMPLEXITY);
setApplication(DEFAULT_APPLICATION);
setSignal(DEFAULT_SIGNAL);
setApplication(Encoder::ApplicationType::Audio);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like the default application type was VOIP before, not sure if this change is intentional. If I understand correctly this gets overwritten by CodecSettings' default which is also set to Audio.

@@ -10,14 +10,196 @@
//
#pragma once

#include <algorithm>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary include?

@namark
Copy link
Contributor

namark commented Feb 7, 2022

I'm thinking something like single set/get pair for all encoder settings, that would accept and return an object. The returned object would contain only what the current encoder supports, removing the need for getEncoderFeatures, and the object that the setter accepts could be partial, only setting whatever is specified.

@namark
Copy link
Contributor

namark commented Jul 5, 2022

I've introduced some conflicts with this PR by moving the opus and PCM codec code into a library and decoupling the plugin and codec interfaces to make it all easier to reuse in context of the client library and Unity SDK. It's might be a while before that needs to be merged with master, so ideally we should get this finished up and merged first, if there aren't any major issues.

@stale
Copy link

stale bot commented Jan 1, 2023

Hello! Is this still an issue?

@stale stale bot added the stale Issue / PR has not had activity label Jan 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request needs CR (code review) scripting api change Change is made in the scripting API stale Issue / PR has not had activity
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants