-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathProgram.cs
More file actions
144 lines (126 loc) · 5.41 KB
/
Copy pathProgram.cs
File metadata and controls
144 lines (126 loc) · 5.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System.Globalization;
using System.Runtime.Versioning;
namespace PipeWire.NET.SampleConsole;
// Command-driven explorer for both packages: graph inspection and control on one side,
// streaming and in-graph DSP on the other. With no arguments it connects and lists the
// graph, which is also what CI runs headless: connecting and enumerating must always work,
// while anything that makes sound or changes state needs an explicit command.
internal static class Program
{
internal const int Ok = 0;
/// <summary>The command ran, and what it needed was not there: no default sink, no session
/// manager, a producer that never appeared, or a Ctrl+C before it finished.</summary>
internal const int NothingToDo = 1;
internal const int UsageError = 2;
[SupportedOSPlatform("linux")]
public static async Task<int> Main(string[] args)
{
if (!OperatingSystem.IsLinux())
{
Console.Error.WriteLine("This sample is Linux-only (PipeWire is a Linux daemon).");
return UsageError;
}
using var cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true;
cts.Cancel();
};
string command = args.Length > 0 ? args[0] : "list";
string[] rest = args.Length > 1 ? args[1..] : [];
// Ctrl+C during setup (connect, link, wait) surfaces as cancellation from library
// awaits. The per-second loops handle it themselves; this is the backstop for the rest.
try
{
return command switch
{
"list" => await GraphCommands.ListAsync(cts.Token).ConfigureAwait(false),
"monitor" => await GraphCommands.MonitorAsync(cts.Token).ConfigureAwait(false),
"volume" => await GraphCommands.VolumeAsync(rest, cts.Token).ConfigureAwait(false),
"defaults" => await GraphCommands.DefaultsAsync(cts.Token).ConfigureAwait(false),
"capture-audio" => await StreamCommands
.CaptureAudioAsync(rest, cts.Token)
.ConfigureAwait(false),
"capture-video" => await StreamCommands
.CaptureVideoAsync(rest, cts.Token)
.ConfigureAwait(false),
"filter" => await ServeCommands.FilterAsync(rest, cts.Token).ConfigureAwait(false),
"serve" => await ServeCommands.ServeAsync(cts.Token).ConfigureAwait(false),
"help" or "--help" or "-h" => Usage(),
_ => Unknown(command),
};
}
catch (OperationCanceledException)
{
return NothingToDo;
}
}
private static int Usage()
{
Console.WriteLine("Usage: PipeWire.NET.SampleConsole [command] [options]");
Console.WriteLine(" list connect and print the graph (default)");
Console.WriteLine(
" monitor print a line per graph change until Ctrl+C"
);
Console.WriteLine(
" volume [target] print volume and mute (default: default sink)"
);
Console.WriteLine(" --set 0..1 set the volume; needs an explicit value");
Console.WriteLine(" --mute | --unmute flip the mute flag");
Console.WriteLine(
" defaults default sink/source and graph clock settings"
);
Console.WriteLine(" capture-audio [--seconds N] capture stats from the default source");
Console.WriteLine(" capture-video [--seconds N] capture stats from the default source");
Console.WriteLine(" filter [--seconds N] tone -> gain node -> default sink");
Console.WriteLine(" serve publish a virtual source until Ctrl+C");
Console.WriteLine("Targets are node ids or name fragments. Ctrl+C stops any command.");
return Ok;
}
private static int Unknown(string command)
{
Console.Error.WriteLine($"Unknown command '{command}'. Try 'help'.");
return UsageError;
}
// --seconds N, defaulting when absent or unparsable. Never throws on user input.
internal static int Seconds(string[] args, int fallback)
{
for (int i = 0; i < args.Length - 1; i++)
{
if (!string.Equals(args[i], "--seconds", StringComparison.Ordinal))
continue;
if (
int.TryParse(
args[i + 1],
NumberStyles.Integer,
CultureInfo.InvariantCulture,
out int seconds
)
&& seconds > 0
&& seconds <= 3600
)
return seconds;
Console.Error.WriteLine($"Ignoring bad --seconds value '{args[i + 1]}'.");
return fallback;
}
return fallback;
}
internal static bool HasFlag(string[] args, string flag)
{
foreach (string arg in args)
{
if (string.Equals(arg, flag, StringComparison.Ordinal))
return true;
}
return false;
}
internal static string? OptionValue(string[] args, string option)
{
for (int i = 0; i < args.Length - 1; i++)
{
if (string.Equals(args[i], option, StringComparison.Ordinal))
return args[i + 1];
}
return null;
}
}