Unified · Split
| @@ -13,24 +13,28 @@ import QtQuick.Controls 1.4 · 12 unmodified lines | |||
| 13 | import QtQuick.Layouts 1.3 | 13 | import QtQuick.Layouts 1.3 |
| 14 | 14 | ||
| 15 | ColumnLayout { | 15 | ColumnLayout { |
| 16 | id: jitter | ||
| 16 | property var max | 17 | property var max |
| 17 | property var avg | 18 | property var avg |
| 18 | property var maxWindow | 19 | property var maxWindow |
| 19 | property var avgWindow | 20 | property var avgWindow |
| 21 | property bool showGraphs: false | ||
| 20 | 22 | ||
| 21 | MovingValuePair { | 23 | MovingValuePair { |
| 22 | label: "Total" | 24 | label: "Total" |
| 23 | label1: "Average" | 25 | label1: "Maximum" |
| 24 | label2: "Maximum" | 26 | label2: "Average" |
| 25 | source1: avg | 27 | source1: max |
| 26 | source2: max | 28 | source2: avg |
| 29 | showGraphs: jitter.showGraphs | ||
| 27 | } | 30 | } |
| 28 | MovingValuePair { | 31 | MovingValuePair { |
| 29 | label: "Window" | 32 | label: "Window" |
| 30 | label1: "Average" | 33 | label1: "Maximum" |
| 31 | label2: "Maximum" | 34 | label2: "Average" |
| 32 | source1: avgWindow | 35 | source1: maxWindow |
| 33 | source2: maxWindow | 36 | source2: avgWindow |
| 37 | showGraphs: jitter.showGraphs | ||
| 34 | } | 38 | } |
| 35 | } | 39 | } |
| 36 | 40 | ||
| @@ -11,12 +11,14 @@ · 10 unmodified lines | |||
| 11 | import QtQuick 2.5 | 11 | import QtQuick 2.5 |
| 12 | import QtQuick.Controls 1.4 | 12 | import QtQuick.Controls 1.4 |
| 13 | import QtQuick.Layouts 1.3 | 13 | import QtQuick.Layouts 1.3 |
| 14 | import "../lib/plotperf" | ||
| 14 | 15 | ||
| 15 | RowLayout { | 16 | RowLayout { |
| 16 | id: value | 17 | id: value |
| 17 | property string label | 18 | property string label |
| 18 | property var source | 19 | property var source |
| 19 | property string unit: "ms" | 20 | property string unit: "ms" |
| 21 | property bool showGraphs: false | ||
| 20 | 22 | ||
| 21 | width: parent.width | 23 | width: parent.width |
| 22 | property int dataPixelWidth: 150 | 24 | property int dataPixelWidth: 150 |
| @@ -26,15 +28,20 @@ RowLayout { · 3 unmodified lines | |||
| 26 | text: value.label | 28 | text: value.label |
| 27 | } | 29 | } |
| 28 | Label { | 30 | Label { |
| 31 | visible: !value.showGraphs | ||
| 29 | Layout.preferredWidth: 0 | 32 | Layout.preferredWidth: 0 |
| 30 | horizontalAlignment: Text.AlignRight | 33 | horizontalAlignment: Text.AlignRight |
| 31 | text: value.source + ' ' + unit | 34 | text: value.source + ' ' + unit |
| 32 | } | 35 | } |
| 33 | Label { | 36 | PlotPerf { |
| 37 | visible: value.showGraphs | ||
| 34 | Layout.fillWidth: true | 38 | Layout.fillWidth: true |
| 35 | horizontalAlignment: Text.AlignRight | 39 | height: 70 |
| 36 | Layout.alignment: Qt.AlignRight | 40 | |
| 37 | text: "Placeholder" | 41 | valueUnit: value.unit |
| 42 | valueNumDigits: 0 | ||
| 43 | |||
| 44 | plots: [{ binding: "source" }] | ||
| 38 | } | 45 | } |
| 39 | } | 46 | } |
| 40 | 47 | ||
| @@ -11,16 +11,17 @@ · 10 unmodified lines | |||
| 11 | import QtQuick 2.5 | 11 | import QtQuick 2.5 |
| 12 | import QtQuick.Controls 1.4 | 12 | import QtQuick.Controls 1.4 |
| 13 | import QtQuick.Layouts 1.3 | 13 | import QtQuick.Layouts 1.3 |
| 14 | import "../lib/plotperf" | ||
| 14 | 15 | ||
| 15 | RowLayout { | 16 | RowLayout { |
| 16 | id: value | 17 | id: value |
| 17 | property string label | 18 | property string label |
| 18 | property string label1 | 19 | property string label1 |
| 19 | property string label2 | 20 | property string label2 |
| 20 | property var source | ||
| 21 | property var source1 | 21 | property var source1 |
| 22 | property var source2 | 22 | property var source2 |
| 23 | property string unit: "ms" | 23 | property string unit: "ms" |
| 24 | property bool showGraphs: false | ||
| 24 | 25 | ||
| 25 | property int labelPixelWidth: 50 | 26 | property int labelPixelWidth: 50 |
| 26 | property int dataPixelWidth: 100 | 27 | property int dataPixelWidth: 100 |
| @@ -37,6 +38,7 @@ RowLayout { · 10 unmodified lines | |||
| 37 | text: value.label1 | 38 | text: value.label1 |
| 38 | } | 39 | } |
| 39 | Label { | 40 | Label { |
| 41 | visible: !value.showGraphs | ||
| 40 | Layout.preferredWidth: 0 | 42 | Layout.preferredWidth: 0 |
| 41 | horizontalAlignment: Text.AlignRight | 43 | horizontalAlignment: Text.AlignRight |
| 42 | text: value.source1 + ' ' + unit | 44 | text: value.source1 + ' ' + unit |
| @@ -48,18 +50,22 @@ RowLayout { · 5 unmodified lines | |||
| 48 | text: value.label2 | 50 | text: value.label2 |
| 49 | } | 51 | } |
| 50 | Label { | 52 | Label { |
| 53 | visible: !value.showGraphs | ||
| 51 | Layout.preferredWidth: 0 | 54 | Layout.preferredWidth: 0 |
| 52 | horizontalAlignment: Text.AlignRight | 55 | horizontalAlignment: Text.AlignRight |
| 53 | text: value.source2 + ' ' + unit | 56 | text: value.source2 + ' ' + unit |
| 54 | } | 57 | } |
| 55 | } | 58 | } |
| 56 | } | 59 | } |
| 57 | Label { | 60 | PlotPerf { |
| 61 | visible: value.showGraphs | ||
| 62 | |||
| 58 | Layout.fillWidth: true | 63 | Layout.fillWidth: true |
| 59 | horizontalAlignment: Text.AlignRight | 64 | height: 70 |
| 60 | Layout.alignment: Qt.AlignRight | ||
| 61 | text: "Placeholder" | ||
| 62 | } | ||
| 63 | 65 | ||
| 64 | } | 66 | valueUnit: value.unit |
| 67 | valueNumDigits: 0 | ||
| 65 | 68 | ||
| 69 | plots: [{ binding: "source1" }, { binding: "source2" }] | ||
| 70 | } | ||
| 71 | } | ||
| @@ -13,7 +13,9 @@ import QtQuick.Controls 1.4 · 12 unmodified lines | |||
| 13 | import QtQuick.Layouts 1.3 | 13 | import QtQuick.Layouts 1.3 |
| 14 | 14 | ||
| 15 | ColumnLayout { | 15 | ColumnLayout { |
| 16 | id: root | ||
| 16 | property var stream | 17 | property var stream |
| 18 | property bool showGraphs: false | ||
| 17 | 19 | ||
| 18 | Label { | 20 | Label { |
| 19 | Layout.alignment: Qt.AlignCenter | 21 | Layout.alignment: Qt.AlignCenter |
| @@ -24,10 +26,12 @@ ColumnLayout { · 4 unmodified lines | |||
| 24 | label: "Desired" | 26 | label: "Desired" |
| 25 | source: stream.framesDesired | 27 | source: stream.framesDesired |
| 26 | unit: "frames" | 28 | unit: "frames" |
| 29 | showGraphs: root.showGraphs | ||
| 27 | } | 30 | } |
| 28 | MovingValue { | 31 | MovingValue { |
| 29 | label: "Unplayed" | 32 | label: "Unplayed" |
| 30 | source: stream.unplayedMsMax | 33 | source: stream.unplayedMsMax |
| 34 | showGraphs: root.showGraphs | ||
| 31 | } | 35 | } |
| 32 | Value { | 36 | Value { |
| 33 | label: "Available (avg)" | 37 | label: "Available (avg)" |
| @@ -44,6 +48,7 @@ ColumnLayout { · 10 unmodified lines | |||
| 44 | avg: stream.timegapMsAvg | 48 | avg: stream.timegapMsAvg |
| 45 | maxWindow: stream.timegapMsMaxWindow | 49 | maxWindow: stream.timegapMsMaxWindow |
| 46 | avgWindow: stream.timegapMsAvgWindow | 50 | avgWindow: stream.timegapMsAvgWindow |
| 51 | showGraphs: root.showGraphs | ||
| 47 | } | 52 | } |
| 48 | 53 | ||
| 49 | Label { | 54 | Label { |
| @@ -17,7 +17,7 @@ var qml = Script.resolvePath('stats.qml'); · 16 unmodified lines | |||
| 17 | var window = new OverlayWindow({ | 17 | var window = new OverlayWindow({ |
| 18 | title: 'Audio Interface Statistics', | 18 | title: 'Audio Interface Statistics', |
| 19 | source: qml, | 19 | source: qml, |
| 20 | width: 400, height: 720 // stats.qml may be too large for some screens | 20 | width: 800, height: 720 // stats.qml may be too large for some screens |
| 21 | }); | 21 | }); |
| 22 | window.setPosition(INITIAL_OFFSET, INITIAL_OFFSET); | 22 | window.setPosition(INITIAL_OFFSET, INITIAL_OFFSET); |
| 23 | 23 | ||
| @@ -13,52 +13,85 @@ import QtQuick.Controls 1.4 · 12 unmodified lines | |||
| 13 | import QtQuick.Layouts 1.3 | 13 | import QtQuick.Layouts 1.3 |
| 14 | 14 | ||
| 15 | Column { | 15 | Column { |
| 16 | id: stats | ||
| 16 | width: parent.width | 17 | width: parent.width |
| 17 | height: parent.height | 18 | height: parent.height |
| 19 | property bool showGraphs: toggleGraphs.checked | ||
| 18 | 20 | ||
| 19 | Section { | 21 | RowLayout { |
| 20 | label: "Latency" | 22 | width: parent.width |
| 21 | description: "Audio pipeline latency, broken out and summed" | 23 | height: 30 |
| 22 | control: ColumnLayout { | 24 | |
| 23 | MovingValue { label: "Input Read"; source: AudioStats.inputReadMsMax } | 25 | Button { |
| 24 | MovingValue { label: "Input Ring"; source: AudioStats.inputUnplayedMsMax } | 26 | id: toggleGraphs |
| 25 | MovingValue { label: "Network (client->mixer)"; source: AudioStats.pingMs / 2 } | 27 | property bool checked: false |
| 26 | MovingValue { label: "Mixer Ring"; source: AudioStats.mixerStream.unplayedMsMax } | 28 | |
| 27 | MovingValue { label: "Network (mixer->client)"; source: AudioStats.pingMs / 2 } | 29 | Layout.alignment: Qt.AlignCenter |
| 28 | MovingValue { label: "Output Ring"; source: AudioStats.clientStream.unplayedMsMax } | 30 | |
| 29 | MovingValue { label: "Output Read"; source: AudioStats.outputUnplayedMsMax } | 31 | text: checked ? "Hide graphs" : "Show graphs" |
| 30 | MovingValue { label: "TOTAL" | 32 | onClicked: function() { checked = !checked; } |
| 31 | source: AudioStats.inputReadMsMax + | ||
| 32 | AudioStats.inputUnplayedMsMax + | ||
| 33 | AudioStats.outputUnplayedMsMax + | ||
| 34 | AudioStats.mixerStream.unplayedMsMax + | ||
| 35 | AudioStats.clientStream.unplayedMsMax + | ||
| 36 | AudioStats.pingMs | ||
| 37 | } | ||
| 38 | } | 33 | } |
| 39 | } | 34 | } |
| 40 | 35 | ||
| 41 | Section { | 36 | Grid { |
| 42 | label: "Upstream Jitter" | 37 | width: parent.width |
| 43 | description: "Timegaps in packets sent to the mixer" | 38 | height: parent.height - 30 |
| 44 | control: Jitter { | 39 | |
| 45 | max: AudioStats.sentTimegapMsMax | 40 | Column { |
| 46 | avg: AudioStats.sentTimegapMsAvg | 41 | width: parent.width / 2 |
| 47 | maxWindow: AudioStats.sentTimegapMsMaxWindow | 42 | height: parent.height |
| 48 | avgWindow: AudioStats.sentTimegapMsAvgWindow | 43 | |
| 44 | Section { | ||
| 45 | label: "Latency" | ||
| 46 | description: "Audio pipeline latency, broken out and summed" | ||
| 47 | control: ColumnLayout { | ||
| 48 | MovingValue { label: "Input Read"; source: AudioStats.inputReadMsMax; showGraphs: stats.showGraphs } | ||
| 49 | MovingValue { label: "Input Ring"; source: AudioStats.inputUnplayedMsMax; showGraphs: stats.showGraphs } | ||
| 50 | MovingValue { label: "Network (client->mixer)"; source: AudioStats.pingMs / 2; showGraphs: stats.showGraphs } | ||
| 51 | MovingValue { label: "Mixer Ring"; source: AudioStats.mixerStream.unplayedMsMax; showGraphs: stats.showGraphs } | ||
| 52 | MovingValue { label: "Network (mixer->client)"; source: AudioStats.pingMs / 2; showGraphs: stats.showGraphs } | ||
| 53 | MovingValue { label: "Output Ring"; source: AudioStats.clientStream.unplayedMsMax; showGraphs: stats.showGraphs } | ||
| 54 | MovingValue { label: "Output Read"; source: AudioStats.outputUnplayedMsMax; showGraphs: stats.showGraphs } | ||
| 55 | MovingValue { label: "TOTAL"; showGraphs: stats.showGraphs | ||
| 56 | source: AudioStats.inputReadMsMax + | ||
| 57 | AudioStats.inputUnplayedMsMax + | ||
| 58 | AudioStats.outputUnplayedMsMax + | ||
| 59 | AudioStats.mixerStream.unplayedMsMax + | ||
| 60 | AudioStats.clientStream.unplayedMsMax + | ||
| 61 | AudioStats.pingMs | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | Section { | ||
| 67 | label: "Upstream Jitter" | ||
| 68 | description: "Timegaps in packets sent to the mixer" | ||
| 69 | control: Jitter { | ||
| 70 | max: AudioStats.sentTimegapMsMax | ||
| 71 | avg: AudioStats.sentTimegapMsAvg | ||
| 72 | maxWindow: AudioStats.sentTimegapMsMaxWindow | ||
| 73 | avgWindow: AudioStats.sentTimegapMsAvgWindow | ||
| 74 | showGraphs: stats.showGraphs | ||
| 75 | } | ||
| 76 | } | ||
| 49 | } | 77 | } |
| 50 | } | ||
| 51 | 78 | ||
| 52 | Section { | 79 | Column { |
| 53 | label: "Mixer (upstream)" | 80 | width: parent.width / 2 |
| 54 | description: "This client's remote audio stream, as seen by the server's mixer" | 81 | height: parent.height |
| 55 | control: Stream { stream: AudioStats.mixerStream } | ||
| 56 | } | ||
| 57 | 82 | ||
| 58 | Section { | 83 | Section { |
| 59 | label: "Client (downstream)" | 84 | label: "Mixer (upstream)" |
| 60 | description: "This client's received audio stream, between the network and the OS" | 85 | description: "This client's remote audio stream, as seen by the server's mixer" |
| 61 | control: Stream { stream: AudioStats.clientStream } | 86 | control: Stream { stream: AudioStats.mixerStream; showGraphs: stats.showGraphs } |
| 87 | } | ||
| 88 | |||
| 89 | Section { | ||
| 90 | label: "Client (downstream)" | ||
| 91 | description: "This client's received audio stream, between the network and the OS" | ||
| 92 | control: Stream { stream: AudioStats.clientStream; showGraphs: stats.showGraphs } | ||
| 93 | } | ||
| 94 | } | ||
| 62 | } | 95 | } |
| 63 | } | 96 | } |
| 64 | 97 | ||
| @@ -55,9 +55,17 @@ Item { · 54 unmodified lines | |||
| 55 | function createValues() { | 55 | function createValues() { |
| 56 | for (var i =0; i < plots.length; i++) { | 56 | for (var i =0; i < plots.length; i++) { |
| 57 | var plot = plots[i]; | 57 | var plot = plots[i]; |
| 58 | var object = plot["object"] || root.object; | ||
| 59 | var value = plot["prop"]; | ||
| 60 | var isBinding = plot["binding"]; | ||
| 61 | if (isBinding) { | ||
| 62 | object = root.parent; | ||
| 63 | value = isBinding; | ||
| 64 | } | ||
| 58 | _values.push( { | 65 | _values.push( { |
| 59 | object: (plot["object"] !== undefined ? plot["object"] : root.object), | 66 | object: object, |
| 60 | value: plot["prop"], | 67 | value: value, |
| 68 | fromBinding: isBinding, | ||
| 61 | valueMax: 1, | 69 | valueMax: 1, |
| 62 | numSamplesConstantMax: 0, | 70 | numSamplesConstantMax: 0, |
| 63 | valueHistory: new Array(), | 71 | valueHistory: new Array(), |
| @@ -218,7 +226,6 @@ Item { · 154 unmodified lines | |||
| 218 | anchors.rightMargin: -hitboxExtension | 226 | anchors.rightMargin: -hitboxExtension |
| 219 | 227 | ||
| 220 | onClicked: { | 228 | onClicked: { |
| 221 | print("PerfPlot clicked!") | ||
| 222 | resetMax(); | 229 | resetMax(); |
| 223 | } | 230 | } |
| 224 | } | 231 | } |