summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/protocol.xml14
-rw-r--r--src/command/AllCommands.cxx1
-rw-r--r--src/command/PartitionCommands.cxx70
-rw-r--r--src/command/PartitionCommands.hxx3
4 files changed, 88 insertions, 0 deletions
diff --git a/doc/protocol.xml b/doc/protocol.xml
index be156c758..dc305d328 100644
--- a/doc/protocol.xml
+++ b/doc/protocol.xml
@@ -2376,6 +2376,20 @@ OK
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="command_newpartition">
+ <term>
+ <cmdsynopsis>
+ <command>newpartition</command>
+ <arg choice="req"><replaceable>NAME</replaceable></arg>
+ </cmdsynopsis>
+ </term>
+ <listitem>
+ <para>
+ Create a new partition.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</section>
diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx
index bcd0e368e..75e15d94d 100644
--- a/src/command/AllCommands.cxx
+++ b/src/command/AllCommands.cxx
@@ -133,6 +133,7 @@ static constexpr struct command commands[] = {
#endif
{ "move", PERMISSION_CONTROL, 2, 2, handle_move },
{ "moveid", PERMISSION_CONTROL, 2, 2, handle_moveid },
+ { "newpartition", PERMISSION_ADMIN, 1, 1, handle_newpartition },
{ "next", PERMISSION_CONTROL, 0, 0, handle_next },
{ "notcommands", PERMISSION_NONE, 0, 0, handle_not_commands },
{ "outputs", PERMISSION_READ, 0, 0, handle_devices },
diff --git a/src/command/PartitionCommands.cxx b/src/command/PartitionCommands.cxx
index 1ccf5f85a..873b1dbe0 100644
--- a/src/command/PartitionCommands.cxx
+++ b/src/command/PartitionCommands.cxx
@@ -24,6 +24,8 @@
#include "Partition.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
+#include "player/Thread.hxx"
+#include "util/CharUtil.hxx"
CommandResult
handle_listpartitions(Client &client, Request, Response &r)
@@ -34,3 +36,71 @@ handle_listpartitions(Client &client, Request, Response &r)
return CommandResult::OK;
}
+
+static constexpr bool
+IsValidPartitionChar(char ch)
+{
+ return IsAlphaNumericASCII(ch) || ch == '-' || ch == '_';
+}
+
+gcc_pure
+static bool
+IsValidPartitionName(const char *name)
+{
+ do {
+ if (!IsValidPartitionChar(*name))
+ return false;
+ } while (*++name != 0);
+
+ return true;
+}
+
+gcc_pure
+static bool
+HasPartitionNamed(const Instance &instance, const char *name)
+{
+ for (const auto &partition : instance.partitions)
+ if (partition.name == name)
+ return true;
+
+ return false;
+}
+
+CommandResult
+handle_newpartition(Client &client, Request request, Response &response)
+{
+ const char *name = request.front();
+ if (!IsValidPartitionName(name)) {
+ response.Error(ACK_ERROR_ARG, "bad name");
+ return CommandResult::ERROR;
+ }
+
+ auto &instance = client.partition.instance;
+ if (HasPartitionNamed(instance, name)) {
+ response.Error(ACK_ERROR_EXIST, "name already exists");
+ return CommandResult::ERROR;
+ }
+
+ if (instance.partitions.size() >= 16) {
+ /* arbitrary limit for now */
+ response.Error(ACK_ERROR_UNKNOWN, "too many partitions");
+ return CommandResult::ERROR;
+ }
+
+ instance.partitions.emplace_back(instance, name,
+ // TODO: use real configuration
+ 16384,
+ 1024,
+ 128,
+ AudioFormat::Undefined(),
+ ReplayGainConfig());
+ auto &partition = instance.partitions.back();
+ partition.outputs.AddNullOutput(instance.io_thread.GetEventLoop(),
+ ReplayGainConfig(),
+ partition.pc);
+ partition.UpdateEffectiveReplayGainMode();
+ StartPlayerThread(partition.pc);
+ partition.pc.LockUpdateAudio();
+
+ return CommandResult::OK;
+}
diff --git a/src/command/PartitionCommands.hxx b/src/command/PartitionCommands.hxx
index e64bcf059..6c51beeb4 100644
--- a/src/command/PartitionCommands.hxx
+++ b/src/command/PartitionCommands.hxx
@@ -29,4 +29,7 @@ class Response;
CommandResult
handle_listpartitions(Client &client, Request request, Response &response);
+CommandResult
+handle_newpartition(Client &client, Request request, Response &response);
+
#endif