wasapi2: Add support for process loopback capture
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / wasapi2 / gstwasapi2src.c
index 60123ec..0b612eb 100644 (file)
@@ -53,10 +53,72 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS (GST_WASAPI2_STATIC_CAPS));
 
+/**
+ * GstWasapi2SrcLoopbackMode:
+ *
+ * Loopback capture mode
+ *
+ * Since: 1.22
+ */
+typedef enum
+{
+  /**
+   * GstWasapi2SrcLoopbackMode::default:
+   *
+   * Default loopback mode
+   *
+   * Since: 1.22
+   */
+  GST_WASAPI2_SRC_LOOPBACK_DEFAULT,
+
+  /**
+   * GstWasapi2SrcLoopbackMode::include-process-tree:
+   *
+   * Captures only specified process and its child process
+   *
+   * Since: 1.22
+   */
+  GST_WASAPI2_SRC_LOOPBACK_INCLUDE_PROCESS_TREE,
+
+  /**
+   * GstWasapi2SrcLoopbackMode::exclude-process-tree:
+   *
+   * Excludes specified process and its child process
+   *
+   * Since: 1.22
+   */
+  GST_WASAPI2_SRC_LOOPBACK_EXCLUDE_PROCESS_TREE,
+} GstWasapi2SrcLoopbackMode;
+
+#define GST_TYPE_WASAPI2_SRC_LOOPBACK_MODE (gst_wasapi2_src_loopback_mode_get_type ())
+static GType
+gst_wasapi2_src_loopback_mode_get_type (void)
+{
+  static GType loopback_type = 0;
+  static const GEnumValue types[] = {
+    {GST_WASAPI2_SRC_LOOPBACK_DEFAULT, "Default", "default"},
+    {GST_WASAPI2_SRC_LOOPBACK_INCLUDE_PROCESS_TREE,
+          "Include process and its child processes",
+        "include-process-tree"},
+    {GST_WASAPI2_SRC_LOOPBACK_EXCLUDE_PROCESS_TREE,
+          "Exclude process and its child processes",
+        "exclude-process-tree"},
+    {0, NULL, NULL}
+  };
+
+  if (g_once_init_enter (&loopback_type)) {
+    GType gtype = g_enum_register_static ("GstWasapi2SrcLoopbackMode", types);
+    g_once_init_leave (&loopback_type, gtype);
+  }
+
+  return loopback_type;
+}
+
 #define DEFAULT_LOW_LATENCY   FALSE
 #define DEFAULT_MUTE          FALSE
 #define DEFAULT_VOLUME        1.0
 #define DEFAULT_LOOPBACK      FALSE
+#define DEFAULT_LOOPBACK_MODE GST_WASAPI2_SRC_LOOPBACK_DEFAULT
 
 enum
 {
@@ -67,6 +129,8 @@ enum
   PROP_VOLUME,
   PROP_DISPATCHER,
   PROP_LOOPBACK,
+  PROP_LOOPBACK_MODE,
+  PROP_LOOPBACK_TARGET_PID,
 };
 
 struct _GstWasapi2Src
@@ -80,6 +144,8 @@ struct _GstWasapi2Src
   gdouble volume;
   gpointer dispatcher;
   gboolean loopback;
+  GstWasapi2SrcLoopbackMode loopback_mode;
+  guint loopback_pid;
 
   gboolean mute_changed;
   gboolean volume_changed;
@@ -173,6 +239,41 @@ gst_wasapi2_src_class_init (GstWasapi2SrcClass * klass)
           GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
           G_PARAM_STATIC_STRINGS));
 
+  if (gst_wasapi2_can_process_loopback ()) {
+    /**
+     * GstWasapi2Src:loopback-mode:
+     *
+     * Loopback mode. "target-process-id" must be specified in case of
+     * process loopback modes.
+     *
+     * This feature requires "Windows 10 build 20348"
+     *
+     * Since: 1.22
+     */
+    g_object_class_install_property (gobject_class, PROP_LOOPBACK_MODE,
+        g_param_spec_enum ("loopback-mode", "Loopback Mode",
+            "Loopback mode to use", GST_TYPE_WASAPI2_SRC_LOOPBACK_MODE,
+            DEFAULT_LOOPBACK_MODE,
+            GST_PARAM_CONDITIONALLY_AVAILABLE | GST_PARAM_MUTABLE_READY |
+            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+    /**
+     * GstWasapi2Src:loopback-target-pid:
+     *
+     * Target process id to be recorded or excluded depending on loopback mode
+     *
+     * This feature requires "Windows 10 build 20348"
+     *
+     * Since: 1.22
+     */
+    g_object_class_install_property (gobject_class, PROP_LOOPBACK_TARGET_PID,
+        g_param_spec_uint ("loopback-target-pid", "Loopback Target PID",
+            "Process ID to be recorded or excluded for process loopback mode",
+            0, G_MAXUINT32, 0,
+            GST_PARAM_CONDITIONALLY_AVAILABLE | GST_PARAM_MUTABLE_READY |
+            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  }
+
   gst_element_class_add_static_pad_template (element_class, &src_template);
   gst_element_class_set_static_metadata (element_class, "Wasapi2Src",
       "Source/Audio/Hardware",
@@ -191,6 +292,9 @@ gst_wasapi2_src_class_init (GstWasapi2SrcClass * klass)
 
   GST_DEBUG_CATEGORY_INIT (gst_wasapi2_src_debug, "wasapi2src",
       0, "Windows audio session API source");
+
+  if (gst_wasapi2_can_process_loopback ())
+    gst_type_mark_as_plugin_api (GST_TYPE_WASAPI2_SRC_LOOPBACK_MODE, 0);
 }
 
 static void
@@ -238,6 +342,12 @@ gst_wasapi2_src_set_property (GObject * object, guint prop_id,
     case PROP_LOOPBACK:
       self->loopback = g_value_get_boolean (value);
       break;
+    case PROP_LOOPBACK_MODE:
+      self->loopback_mode = g_value_get_enum (value);
+      break;
+    case PROP_LOOPBACK_TARGET_PID:
+      self->loopback_pid = g_value_get_uint (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -266,6 +376,12 @@ gst_wasapi2_src_get_property (GObject * object, guint prop_id,
     case PROP_LOOPBACK:
       g_value_set_boolean (value, self->loopback);
       break;
+    case PROP_LOOPBACK_MODE:
+      g_value_set_enum (value, self->loopback_mode);
+      break;
+    case PROP_LOOPBACK_TARGET_PID:
+      g_value_set_uint (value, self->loopback_pid);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -350,14 +466,27 @@ gst_wasapi2_src_create_ringbuffer (GstAudioBaseSrc * src)
   GstWasapi2ClientDeviceClass device_class =
       GST_WASAPI2_CLIENT_DEVICE_CLASS_CAPTURE;
 
-  if (self->loopback)
+  if (self->loopback_pid) {
+    if (self->loopback_mode == GST_WASAPI2_SRC_LOOPBACK_INCLUDE_PROCESS_TREE) {
+      device_class =
+          GST_WASAPI2_CLIENT_DEVICE_CLASS_INCLUDE_PROCESS_LOOPBACK_CAPTURE;
+    } else if (self->loopback_mode ==
+        GST_WASAPI2_SRC_LOOPBACK_EXCLUDE_PROCESS_TREE) {
+      device_class =
+          GST_WASAPI2_CLIENT_DEVICE_CLASS_EXCLUDE_PROCESS_LOOPBACK_CAPTURE;
+    }
+  } else if (self->loopback) {
     device_class = GST_WASAPI2_CLIENT_DEVICE_CLASS_LOOPBACK_CAPTURE;
+  }
+
+  GST_DEBUG_OBJECT (self, "Device class %d", device_class);
 
   name = g_strdup_printf ("%s-ringbuffer", GST_OBJECT_NAME (src));
 
   ringbuffer =
       gst_wasapi2_ring_buffer_new (device_class,
-      self->low_latency, self->device_id, self->dispatcher, name);
+      self->low_latency, self->device_id, self->dispatcher, name,
+      self->loopback_pid);
   g_free (name);
 
   return ringbuffer;