author | Paul Adenot <paul@paul.cx> |
Thu, 28 May 2020 09:50:55 +0000 | |
changeset 532740 | 99be85a6ec5c09982fbda237c9c5c9d80889473d |
parent 532739 | 61336bfc758449a130882874551df6c358ecd0ae |
child 532741 | eb232dca19b05733a3103e1689acad7c028ef063 |
push id | 117348 |
push user | padenot@mozilla.com |
push date | Thu, 28 May 2020 09:58:56 +0000 |
treeherder | autoland@5e969a4bab42 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | achronop |
bugs | 1628779 |
milestone | 78.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
dom/media/CubebUtils.cpp | file | annotate | diff | comparison | revisions | |
dom/media/CubebUtils.h | file | annotate | diff | comparison | revisions |
--- a/dom/media/CubebUtils.cpp +++ b/dom/media/CubebUtils.cpp @@ -32,16 +32,18 @@ #ifdef MOZ_WIDGET_ANDROID # include "mozilla/java/GeckoAppShellWrappers.h" #endif #ifdef XP_WIN # include "mozilla/mscom/EnsureMTA.h" #endif #include "audioipc_server_ffi_generated.h" #include "audioipc_client_ffi_generated.h" +#include <cmath> +#include <thread> #define AUDIOIPC_POOL_SIZE_DEFAULT 1 #define AUDIOIPC_STACK_SIZE_DEFAULT (64 * 4096) #define PREF_VOLUME_SCALE "media.volume_scale" #define PREF_CUBEB_BACKEND "media.cubeb.backend" #define PREF_CUBEB_OUTPUT_DEVICE "media.cubeb.output_device" #define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms" @@ -685,16 +687,116 @@ cubeb_stream_prefs GetDefaultStreamPrefs return CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING; } #endif return CUBEB_STREAM_PREF_NONE; } bool RouteOutputAsVoice() { return sRouteOutputAsVoice; } +long datacb(cubeb_stream*, void*, const void*, void*, long nframes) { + return nframes; +} + +void statecb(cubeb_stream*, void*, cubeb_state) {} + +bool EstimatedRoundTripLatencyDefaultDevices(double* aMean, double* aStdDev) { + nsTArray<double> roundtripLatencies; + // Create a cubeb stream with the correct latency and default input/output + // devices (mono/stereo channels). Wait for two seconds, get the latency a few + // times. + int rv; + uint32_t rate; + uint32_t latencyFrames; + rv = cubeb_get_preferred_sample_rate(GetCubebContext(), &rate); + if (rv != CUBEB_OK) { + MOZ_LOG(gCubebLog, LogLevel::Error, ("Could not get preferred rate")); + return false; + } + + cubeb_stream_params output_params; + output_params.format = CUBEB_SAMPLE_FLOAT32NE; + output_params.rate = rate; + output_params.channels = 2; + output_params.layout = CUBEB_LAYOUT_UNDEFINED; + output_params.prefs = GetDefaultStreamPrefs(); + + latencyFrames = GetCubebMTGLatencyInFrames(&output_params); + + cubeb_stream_params input_params; + input_params.format = CUBEB_SAMPLE_FLOAT32NE; + input_params.rate = rate; + input_params.channels = 1; + input_params.layout = CUBEB_LAYOUT_UNDEFINED; + input_params.prefs = GetDefaultStreamPrefs(); + + cubeb_stream* stm; + rv = cubeb_stream_init(GetCubebContext(), &stm, + "about:support latency estimation", NULL, + &input_params, NULL, &output_params, latencyFrames, + datacb, statecb, NULL); + if (rv != CUBEB_OK) { + MOZ_LOG(gCubebLog, LogLevel::Error, ("Could not get init stream")); + return false; + } + + rv = cubeb_stream_start(stm); + if (rv != CUBEB_OK) { + MOZ_LOG(gCubebLog, LogLevel::Error, ("Could not start stream")); + return false; + } + // +-2s + for (uint32_t i = 0; i < 40; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + uint32_t inputLatency, outputLatency, rvIn, rvOut; + rvOut = cubeb_stream_get_latency(stm, &outputLatency); + if (rvOut) { + MOZ_LOG(gCubebLog, LogLevel::Error, ("Could not get output latency")); + } + rvIn = cubeb_stream_get_input_latency(stm, &inputLatency); + if (rvIn) { + MOZ_LOG(gCubebLog, LogLevel::Error, ("Could not get input latency")); + } + if (rvIn != CUBEB_OK || rvOut != CUBEB_OK) { + continue; + } + + double roundTrip = static_cast<double>(outputLatency + inputLatency) / rate; + roundtripLatencies.AppendElement(roundTrip); + } + rv = cubeb_stream_stop(stm); + if (rv != CUBEB_OK) { + MOZ_LOG(gCubebLog, LogLevel::Error, ("Could not stop the stream")); + } + + *aMean = 0.0; + *aStdDev = 0.0; + double variance = 0.0; + for (uint32_t i = 0; i < roundtripLatencies.Length(); i++) { + *aMean += roundtripLatencies[i]; + } + + *aMean /= roundtripLatencies.Length(); + + for (uint32_t i = 0; i < roundtripLatencies.Length(); i++) { + variance += pow(roundtripLatencies[i] - *aMean, 2.); + } + variance /= roundtripLatencies.Length(); + + *aStdDev = sqrt(variance); + + MOZ_LOG(gCubebLog, LogLevel::Debug, + ("Default device roundtrip latency in seconds %lf (stddev: %lf)", + *aMean, *aStdDev)); + + cubeb_stream_destroy(stm); + + return true; +} + #ifdef MOZ_WIDGET_ANDROID uint32_t AndroidGetAudioOutputSampleRate() { int32_t sample_rate = java::GeckoAppShell::GetAudioOutputSampleRate(); MOZ_ASSERT(sample_rate > 0); return sample_rate; } uint32_t AndroidGetAudioOutputFramesPerBuffer() { int32_t frames = java::GeckoAppShell::GetAudioOutputFramesPerBuffer();
--- a/dom/media/CubebUtils.h +++ b/dom/media/CubebUtils.h @@ -50,16 +50,21 @@ char* GetForcedOutputDevice(); // No-op on all platforms but Android, where it tells the device's AudioManager // to switch to "communication mode", which might change audio routing, // bluetooth communication type, etc. void SetInCommunication(bool aInCommunication); // Returns true if the output streams should be routed like a stream containing // voice data, and not generic audio. This can influence audio processing and // device selection. bool RouteOutputAsVoice(); +// Returns, in seconds, the roundtrip latency Gecko thinks there is between the +// default input and output devices. This is for diagnosing purposes, the +// latency figures are best used directly from the cubeb streams themselves, as +// the devices being used matter. This is blocking. +bool EstimatedRoundTripLatencyDefaultDevices(double* aMean, double* aStdDev); # ifdef MOZ_WIDGET_ANDROID uint32_t AndroidGetAudioOutputSampleRate(); uint32_t AndroidGetAudioOutputFramesPerBuffer(); # endif # ifdef ENABLE_SET_CUBEB_BACKEND void ForceSetCubebContext(cubeb* aCubebContext);