8280982: [Wayland] [XWayland] java.awt.Robot taking screenshots
Reviewed-by: prr, kizune, psadhukhan
This commit is contained in:
parent
a1ab377d99
commit
9d7bf5329e
@ -68,6 +68,7 @@ EXCLUDE_FILES += \
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
# exclude all X11 on Mac.
|
||||
EXCLUDES += \
|
||||
sun/awt/screencast \
|
||||
sun/awt/X11 \
|
||||
sun/java2d/x11 \
|
||||
sun/java2d/jules \
|
||||
|
@ -191,6 +191,9 @@ ifeq ($(call isTargetOs, windows macosx), false)
|
||||
|
||||
LIBAWT_XAWT_EXCLUDES := medialib debug
|
||||
|
||||
LIBPIPEWIRE_HEADER_DIRS := \
|
||||
$(TOPDIR)/src/$(MODULE)/unix/native/libpipewire/include
|
||||
|
||||
LIBAWT_XAWT_EXTRA_HEADER_DIRS := \
|
||||
$(LIBAWT_DEFAULT_HEADER_DIRS) \
|
||||
libawt_xawt/awt \
|
||||
@ -200,7 +203,7 @@ ifeq ($(call isTargetOs, windows macosx), false)
|
||||
common/font \
|
||||
common/java2d/opengl \
|
||||
common/java2d/x11 \
|
||||
#
|
||||
$(LIBPIPEWIRE_HEADER_DIRS)
|
||||
|
||||
LIBAWT_XAWT_CFLAGS += -DXAWT -DXAWT_HACK \
|
||||
$(FONTCONFIG_CFLAGS) \
|
||||
|
@ -35,21 +35,43 @@ import sun.awt.SunToolkit;
|
||||
import sun.awt.UNIXToolkit;
|
||||
import sun.awt.X11GraphicsConfig;
|
||||
import sun.awt.X11GraphicsDevice;
|
||||
import sun.awt.screencast.ScreencastHelper;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
final class XRobotPeer implements RobotPeer {
|
||||
|
||||
private static final boolean tryGtk;
|
||||
private static final String screenshotMethod;
|
||||
private static final String METHOD_X11 = "x11";
|
||||
private static final String METHOD_SCREENCAST = "dbusScreencast";
|
||||
|
||||
static {
|
||||
loadNativeLibraries();
|
||||
|
||||
tryGtk = Boolean.parseBoolean(
|
||||
AccessController.doPrivileged(
|
||||
new GetPropertyAction("awt.robot.gtk", "true")
|
||||
));
|
||||
AccessController.doPrivileged(
|
||||
new GetPropertyAction("awt.robot.gtk",
|
||||
"true")
|
||||
));
|
||||
|
||||
boolean isOnWayland = false;
|
||||
|
||||
if (Toolkit.getDefaultToolkit() instanceof SunToolkit sunToolkit) {
|
||||
isOnWayland = sunToolkit.isRunningOnWayland();
|
||||
}
|
||||
|
||||
screenshotMethod = AccessController.doPrivileged(
|
||||
new GetPropertyAction(
|
||||
"awt.robot.screenshotMethod",
|
||||
isOnWayland
|
||||
? METHOD_SCREENCAST
|
||||
: METHOD_X11
|
||||
));
|
||||
}
|
||||
|
||||
private static volatile boolean useGtk;
|
||||
private final X11GraphicsConfig xgc;
|
||||
private final X11GraphicsConfig xgc;
|
||||
|
||||
XRobotPeer(X11GraphicsDevice gd) {
|
||||
xgc = (X11GraphicsConfig) gd.getDefaultConfiguration();
|
||||
@ -100,15 +122,31 @@ final class XRobotPeer implements RobotPeer {
|
||||
@Override
|
||||
public int getRGBPixel(int x, int y) {
|
||||
int[] pixelArray = new int[1];
|
||||
getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray, useGtk);
|
||||
if (screenshotMethod.equals(METHOD_SCREENCAST)
|
||||
&& ScreencastHelper.isAvailable()) {
|
||||
|
||||
ScreencastHelper.getRGBPixels(x, y, 1, 1, pixelArray);
|
||||
} else {
|
||||
getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray, useGtk);
|
||||
}
|
||||
return pixelArray[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int [] getRGBPixels(Rectangle bounds) {
|
||||
int[] pixelArray = new int[bounds.width*bounds.height];
|
||||
getRGBPixelsImpl(xgc, bounds.x, bounds.y, bounds.width, bounds.height,
|
||||
pixelArray, useGtk);
|
||||
public int[] getRGBPixels(Rectangle bounds) {
|
||||
int[] pixelArray = new int[bounds.width * bounds.height];
|
||||
if (screenshotMethod.equals(METHOD_SCREENCAST)
|
||||
&& ScreencastHelper.isAvailable()) {
|
||||
|
||||
ScreencastHelper.getRGBPixels(bounds.x, bounds.y,
|
||||
bounds.width, bounds.height,
|
||||
pixelArray);
|
||||
} else {
|
||||
getRGBPixelsImpl(xgc,
|
||||
bounds.x, bounds.y,
|
||||
bounds.width, bounds.height,
|
||||
pixelArray, useGtk);
|
||||
}
|
||||
return pixelArray;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.awt.screencast;
|
||||
|
||||
import sun.awt.UNIXToolkit;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.security.AccessController;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Helper class for grabbing pixels from the screen using the
|
||||
* <a href="https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.ScreenCast">
|
||||
* org.freedesktop.portal.ScreenCast API</a>
|
||||
*/
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
public class ScreencastHelper {
|
||||
|
||||
static final boolean SCREENCAST_DEBUG;
|
||||
private static final boolean IS_NATIVE_LOADED;
|
||||
|
||||
|
||||
private static final int ERROR = -1;
|
||||
private static final int DENIED = -11;
|
||||
private static final int OUT_OF_BOUNDS = -12;
|
||||
|
||||
private ScreencastHelper() {
|
||||
}
|
||||
|
||||
static {
|
||||
SCREENCAST_DEBUG = Boolean.parseBoolean(
|
||||
AccessController.doPrivileged(
|
||||
new GetPropertyAction(
|
||||
"awt.robot.screenshotDebug",
|
||||
"false"
|
||||
)
|
||||
));
|
||||
|
||||
boolean loadFailed = false;
|
||||
|
||||
if (!(Toolkit.getDefaultToolkit() instanceof UNIXToolkit tk
|
||||
&& tk.loadGTK())
|
||||
|| !loadPipewire(SCREENCAST_DEBUG)) {
|
||||
|
||||
System.err.println(
|
||||
"Could not load native libraries for ScreencastHelper"
|
||||
);
|
||||
|
||||
loadFailed = true;
|
||||
}
|
||||
|
||||
IS_NATIVE_LOADED = !loadFailed;
|
||||
}
|
||||
|
||||
public static boolean isAvailable() {
|
||||
return IS_NATIVE_LOADED;
|
||||
}
|
||||
|
||||
private static native boolean loadPipewire(boolean screencastDebug);
|
||||
|
||||
private static native int getRGBPixelsImpl(
|
||||
int x, int y, int width, int height,
|
||||
int[] pixelArray,
|
||||
int[] affectedScreensBoundsArray,
|
||||
String token
|
||||
);
|
||||
|
||||
private static List<Rectangle> getSystemScreensBounds() {
|
||||
return Arrays
|
||||
.stream(GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment()
|
||||
.getScreenDevices())
|
||||
.map(graphicsDevice ->
|
||||
graphicsDevice.getDefaultConfiguration().getBounds()
|
||||
).toList();
|
||||
}
|
||||
|
||||
public static synchronized void getRGBPixels(
|
||||
int x, int y, int width, int height, int[] pixelArray
|
||||
) {
|
||||
if (!IS_NATIVE_LOADED) return;
|
||||
|
||||
Rectangle captureArea = new Rectangle(x, y, width, height);
|
||||
|
||||
List<Rectangle> affectedScreenBounds = getSystemScreensBounds()
|
||||
.stream()
|
||||
.filter(captureArea::intersects)
|
||||
.toList();
|
||||
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.printf("// getRGBPixels in %s, affectedScreenBounds %s\n",
|
||||
captureArea, affectedScreenBounds);
|
||||
}
|
||||
|
||||
if (affectedScreenBounds.isEmpty()) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.println("// getRGBPixels - requested area "
|
||||
+ "outside of any screen");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int retVal;
|
||||
Set<TokenItem> tokensForRectangle =
|
||||
TokenStorage.getTokens(affectedScreenBounds);
|
||||
|
||||
int[] affectedScreenBoundsArray = affectedScreenBounds
|
||||
.stream()
|
||||
.filter(captureArea::intersects)
|
||||
.flatMapToInt(bounds -> IntStream.of(
|
||||
bounds.x, bounds.y,
|
||||
bounds.width, bounds.height
|
||||
))
|
||||
.toArray();
|
||||
|
||||
for (TokenItem tokenItem : tokensForRectangle) {
|
||||
retVal = getRGBPixelsImpl(
|
||||
x, y, width, height,
|
||||
pixelArray,
|
||||
affectedScreenBoundsArray,
|
||||
tokenItem.token
|
||||
);
|
||||
|
||||
if (retVal >= 0) { // we have received a screen data
|
||||
return;
|
||||
} else if (!checkReturnValue(retVal)) {
|
||||
return;
|
||||
} // else, try other tokens
|
||||
}
|
||||
|
||||
// we do not have a saved token or it did not work,
|
||||
// try without the token to show the system's permission request window
|
||||
retVal = getRGBPixelsImpl(
|
||||
x, y, width, height,
|
||||
pixelArray,
|
||||
affectedScreenBoundsArray,
|
||||
null
|
||||
);
|
||||
|
||||
checkReturnValue(retVal);
|
||||
}
|
||||
|
||||
private static boolean checkReturnValue(int retVal) {
|
||||
if (retVal == DENIED) {
|
||||
// user explicitly denied the capture, no more tries.
|
||||
throw new SecurityException(
|
||||
"Screen Capture in the selected area was not allowed"
|
||||
);
|
||||
} else if (retVal == ERROR) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.println("Screen capture failed.");
|
||||
}
|
||||
} else if (retVal == OUT_OF_BOUNDS) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.println(
|
||||
"Token does not provide access to requested area.");
|
||||
}
|
||||
}
|
||||
return retVal != ERROR;
|
||||
}
|
||||
}
|
154
src/java.desktop/unix/classes/sun/awt/screencast/TokenItem.java
Normal file
154
src/java.desktop/unix/classes/sun/awt/screencast/TokenItem.java
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.awt.screencast;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static sun.awt.screencast.ScreencastHelper.SCREENCAST_DEBUG;
|
||||
|
||||
/**
|
||||
* Helper class used by {@link TokenStorage} as restore token record
|
||||
* with its associated screen boundaries.
|
||||
*
|
||||
* It helps in serialization/deserialization of screen boundaries
|
||||
* to/from string format.
|
||||
*
|
||||
* The screen boundary is represented as {@code _x_y_width_height}
|
||||
* and can be repeated several times.
|
||||
*/
|
||||
final class TokenItem {
|
||||
|
||||
final String token;
|
||||
final List<Rectangle> allowedScreensBounds;
|
||||
|
||||
public TokenItem(String token, int[] allowedScreenBounds) {
|
||||
if (token == null || token.isBlank()) {
|
||||
throw new RuntimeException("empty or null tokens are not allowed");
|
||||
}
|
||||
if (allowedScreenBounds.length % 4 != 0) {
|
||||
throw new RuntimeException("array with incorrect length provided");
|
||||
}
|
||||
|
||||
this.token = token;
|
||||
|
||||
this.allowedScreensBounds = IntStream
|
||||
.iterate(0,
|
||||
i -> i < allowedScreenBounds.length,
|
||||
i -> i + 4)
|
||||
.mapToObj(i -> new Rectangle(
|
||||
allowedScreenBounds[i], allowedScreenBounds[i+1],
|
||||
allowedScreenBounds[i+2], allowedScreenBounds[i+3]
|
||||
))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public boolean hasAllScreensWithExactMatch(List<Rectangle> bounds) {
|
||||
return allowedScreensBounds.containsAll(bounds);
|
||||
}
|
||||
|
||||
public boolean hasAllScreensOfSameSize(List<Dimension> screenSizes) {
|
||||
// We also need to consider duplicates, since there may be
|
||||
// multiple screens of the same size.
|
||||
// The token item must also have at least the same number
|
||||
// of screens with that size.
|
||||
|
||||
List<Dimension> tokenSizes = allowedScreensBounds
|
||||
.stream()
|
||||
.map(bounds -> new Dimension(bounds.width, bounds.height))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
return screenSizes.size() == screenSizes
|
||||
.stream()
|
||||
.filter(tokenSizes::remove)
|
||||
.count();
|
||||
}
|
||||
|
||||
private static final int MAX_SIZE = 50000;
|
||||
private static final int MIN_SIZE = 1;
|
||||
|
||||
public boolean hasValidBounds() {
|
||||
//This check is very rough, in order to filter out abnormal values
|
||||
for (Rectangle bounds : allowedScreensBounds) {
|
||||
if (bounds.x < -MAX_SIZE || bounds.x > MAX_SIZE
|
||||
|| bounds.y < -MAX_SIZE || bounds.y > MAX_SIZE
|
||||
|| bounds.width < MIN_SIZE || bounds.width > MAX_SIZE
|
||||
|| bounds.height < MIN_SIZE || bounds.height > MAX_SIZE
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String dump() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Rectangle bounds : allowedScreensBounds) {
|
||||
sb.append("_%d_%d_%d_%d"
|
||||
.formatted(bounds.x, bounds.y, bounds.width, bounds.height));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static TokenItem parse(String token, Object input) {
|
||||
if (token == null || input == null) return null;
|
||||
|
||||
try {
|
||||
int[] integers = Arrays.stream(String.valueOf(input)
|
||||
.split("_"))
|
||||
.filter(s -> !s.isBlank())
|
||||
.mapToInt(Integer::parseInt)
|
||||
.toArray();
|
||||
|
||||
if (integers.length % 4 == 0) {
|
||||
TokenItem tokenItem = new TokenItem(token, integers);
|
||||
if (tokenItem.hasValidBounds()) {
|
||||
return tokenItem;
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException ignored) {}
|
||||
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.printf("Malformed record for token %s: %s\n",
|
||||
token, input);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("Token: " + token + "\n");
|
||||
for (Rectangle bounds : allowedScreensBounds) {
|
||||
sb.append("\t").append(bounds).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.awt.screencast;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Rectangle;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.WatchEvent;
|
||||
import java.nio.file.WatchKey;
|
||||
import java.nio.file.WatchService;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
|
||||
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
|
||||
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
|
||||
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
|
||||
import static sun.awt.screencast.ScreencastHelper.SCREENCAST_DEBUG;
|
||||
|
||||
/**
|
||||
* Helper class for persistent storage of ScreenCast restore tokens
|
||||
* and associated screen boundaries.
|
||||
*
|
||||
* The restore token allows the ScreenCast session to be restored
|
||||
* with previously granted screen access permissions.
|
||||
*/
|
||||
final class TokenStorage {
|
||||
|
||||
private TokenStorage() {}
|
||||
|
||||
private static final String REL_NAME =
|
||||
".awt/robot/screencast-tokens.properties";
|
||||
|
||||
private static final Properties PROPS = new Properties();
|
||||
private static final Path PROPS_PATH;
|
||||
private static final Path PROP_FILENAME;
|
||||
|
||||
static {
|
||||
PROPS_PATH = setupPath();
|
||||
if (PROPS_PATH != null) {
|
||||
PROP_FILENAME = PROPS_PATH.getFileName();
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.println("Token storage: using " + PROPS_PATH);
|
||||
}
|
||||
setupWatch();
|
||||
} else {
|
||||
// We can still work with tokens,
|
||||
// but they are not saved between sessions.
|
||||
PROP_FILENAME = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Path setupPath() {
|
||||
String userHome = System.getProperty("user.home", null);
|
||||
if (userHome == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Path path = Path.of(userHome, REL_NAME);
|
||||
Path workdir = path.getParent();
|
||||
|
||||
if (!Files.exists(workdir)) {
|
||||
try {
|
||||
Files.createDirectories(workdir);
|
||||
} catch (Exception e) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.printf("Token storage: cannot create" +
|
||||
" directory %s %s\n", workdir, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Files.isWritable(workdir)) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.printf("Token storage: %s is not writable\n", workdir);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
Files.setPosixFilePermissions(
|
||||
workdir,
|
||||
Set.of(PosixFilePermission.OWNER_READ,
|
||||
PosixFilePermission.OWNER_WRITE,
|
||||
PosixFilePermission.OWNER_EXECUTE)
|
||||
);
|
||||
} catch (IOException e) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.printf("Token storage: cannot set permissions " +
|
||||
"for directory %s %s\n", workdir, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (Files.exists(path)) {
|
||||
if (!setFilePermission(path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
readTokens(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private static boolean setFilePermission(Path path) {
|
||||
try {
|
||||
Files.setPosixFilePermissions(
|
||||
path,
|
||||
Set.of(PosixFilePermission.OWNER_READ,
|
||||
PosixFilePermission.OWNER_WRITE)
|
||||
);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.printf("Token storage: failed to set " +
|
||||
"property file permission %s %s\n", path, e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class WatcherThread extends Thread {
|
||||
private final WatchService watcher;
|
||||
|
||||
public WatcherThread(WatchService watchService) {
|
||||
this.watcher = watchService;
|
||||
setName("ScreencastWatcher");
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.println("ScreencastWatcher: started");
|
||||
}
|
||||
for (;;) {
|
||||
WatchKey key;
|
||||
try {
|
||||
key = watcher.take();
|
||||
} catch (InterruptedException e) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.println("ScreencastWatcher: interrupted");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (WatchEvent<?> event: key.pollEvents()) {
|
||||
WatchEvent.Kind<?> kind = event.kind();
|
||||
if (kind == OVERFLOW
|
||||
|| !event.context().equals(PROP_FILENAME)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.printf("ScreencastWatcher: %s %s\n",
|
||||
kind, event.context());
|
||||
}
|
||||
|
||||
if (kind == ENTRY_CREATE) {
|
||||
setFilePermission(PROPS_PATH);
|
||||
} else if (kind == ENTRY_MODIFY) {
|
||||
readTokens(PROPS_PATH);
|
||||
} else if (kind == ENTRY_DELETE) {
|
||||
synchronized (PROPS) {
|
||||
PROPS.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
key.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setupWatch() {
|
||||
try {
|
||||
WatchService watchService =
|
||||
FileSystems.getDefault().newWatchService();
|
||||
|
||||
PROPS_PATH
|
||||
.getParent()
|
||||
.register(watchService,
|
||||
ENTRY_CREATE,
|
||||
ENTRY_DELETE,
|
||||
ENTRY_MODIFY);
|
||||
|
||||
new WatcherThread(watchService).start();
|
||||
} catch (Exception e) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.printf("Token storage: failed to setup " +
|
||||
"file watch %s\n", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// called from native
|
||||
private static void storeTokenFromNative(String oldToken,
|
||||
String newToken,
|
||||
int[] allowedScreenBounds) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.printf("// storeToken old: |%s| new |%s| " +
|
||||
"allowed bounds %s\n",
|
||||
oldToken, newToken,
|
||||
Arrays.toString(allowedScreenBounds));
|
||||
}
|
||||
|
||||
if (allowedScreenBounds == null) return;
|
||||
|
||||
TokenItem tokenItem = new TokenItem(newToken, allowedScreenBounds);
|
||||
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.printf("// Storing TokenItem:\n%s\n", tokenItem);
|
||||
}
|
||||
|
||||
synchronized (PROPS) {
|
||||
String oldBoundsRecord = PROPS.getProperty(tokenItem.token, null);
|
||||
String newBoundsRecord = tokenItem.dump();
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
if (oldBoundsRecord == null
|
||||
|| !oldBoundsRecord.equals(newBoundsRecord)) {
|
||||
PROPS.setProperty(tokenItem.token, newBoundsRecord);
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.printf(
|
||||
"// Writing new TokenItem:\n%s\n", tokenItem);
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (oldToken != null && !oldToken.equals(newToken)) {
|
||||
// old token is no longer valid
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.printf(
|
||||
"// storeTokenFromNative old token |%s| is "
|
||||
+ "no longer valid, removing\n", oldToken);
|
||||
}
|
||||
|
||||
PROPS.remove(oldToken);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
store("save tokens");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean readTokens(Path path) {
|
||||
if (path == null) return false;
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(path)) {
|
||||
synchronized (PROPS) {
|
||||
PROPS.clear();
|
||||
PROPS.load(reader);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.printf("""
|
||||
Token storage: failed to load property file %s
|
||||
%s
|
||||
""", path, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static Set<TokenItem> getTokens(List<Rectangle> affectedScreenBounds) {
|
||||
// We need an ordered set to store tokens
|
||||
// with exact matches at the beginning.
|
||||
LinkedHashSet<TokenItem> result = new LinkedHashSet<>();
|
||||
|
||||
Set<String> malformed = new HashSet<>();
|
||||
List<TokenItem> allTokenItems;
|
||||
|
||||
synchronized (PROPS) {
|
||||
allTokenItems =
|
||||
PROPS.entrySet()
|
||||
.stream()
|
||||
.map(o -> {
|
||||
String token = String.valueOf(o.getKey());
|
||||
TokenItem tokenItem =
|
||||
TokenItem.parse(token, o.getValue());
|
||||
if (tokenItem == null) {
|
||||
malformed.add(token);
|
||||
}
|
||||
return tokenItem;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
}
|
||||
|
||||
removeMalformedRecords(malformed);
|
||||
|
||||
// 1. Try to find exact matches
|
||||
for (TokenItem tokenItem : allTokenItems) {
|
||||
if (tokenItem != null
|
||||
&& tokenItem.hasAllScreensWithExactMatch(affectedScreenBounds)) {
|
||||
|
||||
result.add(tokenItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.println("// getTokens exact matches 1. " + result);
|
||||
}
|
||||
|
||||
// 2. Try screens of the same size but in different locations,
|
||||
// screens may have been moved while the token is still valid
|
||||
List<Dimension> dimensions =
|
||||
affectedScreenBounds
|
||||
.stream()
|
||||
.map(rectangle -> new Dimension(
|
||||
rectangle.width,
|
||||
rectangle.height
|
||||
))
|
||||
.toList();
|
||||
|
||||
for (TokenItem tokenItem : allTokenItems) {
|
||||
if (tokenItem != null
|
||||
&& tokenItem.hasAllScreensOfSameSize(dimensions)) {
|
||||
|
||||
result.add(tokenItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.out.println("// getTokens same sizes 2. " + result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void removeMalformedRecords(Set<String> malformedRecords) {
|
||||
if (!isWritable()
|
||||
|| malformedRecords == null
|
||||
|| malformedRecords.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (PROPS) {
|
||||
for (String token : malformedRecords) {
|
||||
Object remove = PROPS.remove(token);
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.println("removing malformed record\n" + remove);
|
||||
}
|
||||
}
|
||||
|
||||
store("remove malformed records");
|
||||
}
|
||||
}
|
||||
|
||||
private static void store(String failMsg) {
|
||||
if (!isWritable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (PROPS) {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(PROPS_PATH)) {
|
||||
PROPS.store(writer, null);
|
||||
} catch (IOException e) {
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.printf(
|
||||
"Token storage: unable to %s\n%s\n", failMsg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isWritable() {
|
||||
if (PROPS_PATH == null
|
||||
|| (Files.exists(PROPS_PATH) && !Files.isWritable(PROPS_PATH))) {
|
||||
|
||||
if (SCREENCAST_DEBUG) {
|
||||
System.err.printf(
|
||||
"Token storage: %s is not writable\n", PROPS_PATH);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
41
src/java.desktop/unix/legal/pipewire.md
Normal file
41
src/java.desktop/unix/legal/pipewire.md
Normal file
@ -0,0 +1,41 @@
|
||||
## PipeWire 0.3.68
|
||||
|
||||
### PipeWire license:
|
||||
|
||||
All PipeWire header files are licensed under the MIT License:
|
||||
|
||||
|
||||
<pre>
|
||||
Copyright © 2018-2023 Wim Taymans
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
|
||||
The below copyright applies to the following files:
|
||||
|
||||
spa/include/spa/monitor/type-info.h
|
||||
```
|
||||
Copyright © 2021 Collabora Ltd.
|
||||
```
|
||||
|
||||
spa/include/spa/utils/string.h
|
||||
```
|
||||
Copyright © 2021 Red Hat, Inc.
|
||||
```
|
91
src/java.desktop/unix/native/libawt_xawt/awt/fp_pipewire.h
Normal file
91
src/java.desktop/unix/native/libawt_xawt/awt/fp_pipewire.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifdef HEADLESS
|
||||
#error This file should not be included in headless library
|
||||
#endif
|
||||
#ifndef _FP_PIPEWIRE_H
|
||||
#define _FP_PIPEWIRE_H
|
||||
|
||||
|
||||
struct pw_buffer *(*fp_pw_stream_dequeue_buffer)(struct pw_stream *stream);
|
||||
const char * (*fp_pw_stream_state_as_string)(enum pw_stream_state state);
|
||||
int (*fp_pw_stream_queue_buffer)(struct pw_stream *stream,
|
||||
struct pw_buffer *buffer);
|
||||
int (*fp_pw_stream_set_active)(struct pw_stream *stream, bool active);
|
||||
|
||||
int (*fp_pw_stream_connect)(
|
||||
struct pw_stream *stream,
|
||||
enum pw_direction direction,
|
||||
uint32_t target_id,
|
||||
enum pw_stream_flags flags,
|
||||
const struct spa_pod **params,
|
||||
uint32_t n_params);
|
||||
|
||||
struct pw_stream *(*fp_pw_stream_new)(
|
||||
struct pw_core *core,
|
||||
const char *name,
|
||||
struct pw_properties *props
|
||||
);
|
||||
void (*fp_pw_stream_add_listener)(struct pw_stream *stream,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_stream_events *events,
|
||||
void *data);
|
||||
int (*fp_pw_stream_disconnect)(struct pw_stream *stream);
|
||||
void (*fp_pw_stream_destroy)(struct pw_stream *stream);
|
||||
|
||||
|
||||
void (*fp_pw_init)(int *argc, char **argv[]);
|
||||
|
||||
|
||||
struct pw_core *
|
||||
(*fp_pw_context_connect_fd)(struct pw_context *context,
|
||||
int fd,
|
||||
struct pw_properties *properties,
|
||||
size_t user_data_size);
|
||||
|
||||
int (*fp_pw_core_disconnect)(struct pw_core *core);
|
||||
|
||||
struct pw_context * (*fp_pw_context_new)(struct pw_loop *main_loop,
|
||||
struct pw_properties *props,
|
||||
size_t user_data_size);
|
||||
|
||||
struct pw_thread_loop *
|
||||
(*fp_pw_thread_loop_new)(const char *name, const struct spa_dict *props);
|
||||
struct pw_loop * (*fp_pw_thread_loop_get_loop)(struct pw_thread_loop *loop);
|
||||
void (*fp_pw_thread_loop_signal)(struct pw_thread_loop *loop,
|
||||
bool wait_for_accept);
|
||||
void (*fp_pw_thread_loop_wait)(struct pw_thread_loop *loop);
|
||||
void (*fp_pw_thread_loop_accept)(struct pw_thread_loop *loop);
|
||||
int (*fp_pw_thread_loop_start)(struct pw_thread_loop *loop);
|
||||
void (*fp_pw_thread_loop_stop)(struct pw_thread_loop *loop);
|
||||
void (*fp_pw_thread_loop_destroy)(struct pw_thread_loop *loop);
|
||||
void (*fp_pw_thread_loop_lock)(struct pw_thread_loop *loop);
|
||||
void (*fp_pw_thread_loop_unlock)(struct pw_thread_loop *loop);
|
||||
|
||||
struct pw_properties * (*fp_pw_properties_new)(const char *key, ...);
|
||||
|
||||
|
||||
#endif //_FP_PIPEWIRE_H
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -86,13 +86,6 @@ typedef struct {
|
||||
gushort revents;
|
||||
} GPollFD;
|
||||
|
||||
typedef struct {
|
||||
gint x;
|
||||
gint y;
|
||||
gint width;
|
||||
gint height;
|
||||
} GdkRectangle;
|
||||
|
||||
typedef struct {
|
||||
gint x;
|
||||
gint y;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -44,6 +44,10 @@
|
||||
static void *gtk3_libhandle = NULL;
|
||||
static void *gthread_libhandle = NULL;
|
||||
|
||||
static void transform_detail_string (const gchar *detail,
|
||||
GtkStyleContext *context);
|
||||
static void gtk3_init(GtkApi* gtk);
|
||||
|
||||
static jmp_buf j;
|
||||
|
||||
/* Widgets */
|
||||
@ -246,6 +250,7 @@ static void empty() {}
|
||||
static gboolean gtk3_version_3_10 = TRUE;
|
||||
static gboolean gtk3_version_3_14 = FALSE;
|
||||
static gboolean gtk3_version_3_20 = FALSE;
|
||||
gboolean glib_version_2_68 = FALSE;
|
||||
|
||||
GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
|
||||
{
|
||||
@ -567,6 +572,50 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
|
||||
fp_g_list_append = dl_symbol("g_list_append");
|
||||
fp_g_list_free = dl_symbol("g_list_free");
|
||||
fp_g_list_free_full = dl_symbol("g_list_free_full");
|
||||
|
||||
/**
|
||||
* other
|
||||
*/
|
||||
|
||||
fp_g_bus_get_sync = dl_symbol("g_bus_get_sync");
|
||||
fp_g_dbus_proxy_call_sync = dl_symbol("g_dbus_proxy_call_sync");
|
||||
fp_g_dbus_proxy_new_sync = dl_symbol("g_dbus_proxy_new_sync");
|
||||
fp_g_dbus_connection_get_unique_name = dl_symbol("g_dbus_connection_get_unique_name");
|
||||
fp_g_dbus_connection_call_sync = dl_symbol("g_dbus_connection_call_sync");
|
||||
fp_g_dbus_connection_signal_subscribe = dl_symbol("g_dbus_connection_signal_subscribe");
|
||||
fp_g_dbus_connection_signal_unsubscribe = dl_symbol("g_dbus_connection_signal_unsubscribe");
|
||||
fp_g_dbus_proxy_call_with_unix_fd_list_sync = dl_symbol("g_dbus_proxy_call_with_unix_fd_list_sync");
|
||||
|
||||
fp_g_variant_builder_init = dl_symbol("g_variant_builder_init");
|
||||
fp_g_variant_builder_add = dl_symbol("g_variant_builder_add");
|
||||
fp_g_variant_new = dl_symbol("g_variant_new");
|
||||
fp_g_variant_new_string = dl_symbol("g_variant_new_string");
|
||||
fp_g_variant_new_uint32 = dl_symbol("g_variant_new_uint32");
|
||||
fp_g_variant_new_boolean = dl_symbol("g_variant_new_boolean");
|
||||
fp_g_variant_get = dl_symbol("g_variant_get");
|
||||
fp_g_variant_get_string = dl_symbol("g_variant_get_string");
|
||||
fp_g_variant_get_uint32 = dl_symbol("g_variant_get_uint32");
|
||||
fp_g_variant_iter_loop = dl_symbol("g_variant_iter_loop");
|
||||
fp_g_variant_unref = dl_symbol("g_variant_unref");
|
||||
fp_g_variant_lookup = dl_symbol("g_variant_lookup");
|
||||
fp_g_variant_lookup_value = dl_symbol("g_variant_lookup_value");
|
||||
fp_g_variant_iter_init = dl_symbol("g_variant_iter_init");
|
||||
fp_g_variant_iter_n_children = dl_symbol("g_variant_iter_n_children");
|
||||
|
||||
fp_g_string_new = dl_symbol("g_string_new");
|
||||
fp_g_string_erase = dl_symbol("g_string_erase");
|
||||
fp_g_string_free = dl_symbol("g_string_free");
|
||||
|
||||
glib_version_2_68 = !fp_glib_check_version(2, 68, 0);
|
||||
if (glib_version_2_68) {
|
||||
fp_g_string_replace = dl_symbol("g_string_replace"); //since: 2.68
|
||||
fp_g_uuid_string_is_valid = //since: 2.52
|
||||
dl_symbol("g_uuid_string_is_valid");
|
||||
}
|
||||
fp_g_string_printf = dl_symbol("g_string_printf");
|
||||
|
||||
fp_g_error_free = dl_symbol("g_error_free");
|
||||
fp_g_unix_fd_list_get = dl_symbol("g_unix_fd_list_get");
|
||||
}
|
||||
/* Now we have only one kind of exceptions: NO_SYMBOL_EXCEPTION
|
||||
* Otherwise we can check the return value of setjmp method.
|
||||
@ -3027,4 +3076,46 @@ static void gtk3_init(GtkApi* gtk) {
|
||||
gtk->g_list_append = fp_g_list_append;
|
||||
gtk->g_list_free = fp_g_list_free;
|
||||
gtk->g_list_free_full = fp_g_list_free_full;
|
||||
|
||||
gtk->g_bus_get_sync = fp_g_bus_get_sync;
|
||||
gtk->g_dbus_proxy_call_sync = fp_g_dbus_proxy_call_sync;
|
||||
gtk->g_dbus_proxy_new_sync = fp_g_dbus_proxy_new_sync;
|
||||
gtk->g_dbus_connection_get_unique_name = fp_g_dbus_connection_get_unique_name;
|
||||
gtk->g_dbus_connection_signal_subscribe = fp_g_dbus_connection_signal_subscribe;
|
||||
gtk->g_dbus_connection_signal_unsubscribe = fp_g_dbus_connection_signal_unsubscribe;
|
||||
gtk->g_dbus_proxy_call_with_unix_fd_list_sync = fp_g_dbus_proxy_call_with_unix_fd_list_sync;
|
||||
gtk->g_dbus_connection_call_sync = fp_g_dbus_connection_call_sync;
|
||||
|
||||
gtk->g_variant_new = fp_g_variant_new;
|
||||
gtk->g_variant_new_string = fp_g_variant_new_string;
|
||||
gtk->g_variant_new_boolean = fp_g_variant_new_boolean;
|
||||
gtk->g_variant_new_uint32 = fp_g_variant_new_uint32;
|
||||
|
||||
gtk->g_variant_get = fp_g_variant_get;
|
||||
gtk->g_variant_get_string = fp_g_variant_get_string;
|
||||
gtk->g_variant_get_uint32 = fp_g_variant_get_uint32;
|
||||
|
||||
gtk->g_variant_lookup = fp_g_variant_lookup;
|
||||
|
||||
gtk->g_variant_iter_loop = fp_g_variant_iter_loop;
|
||||
|
||||
gtk->g_variant_unref = fp_g_variant_unref;
|
||||
|
||||
gtk->g_variant_builder_init = fp_g_variant_builder_init;
|
||||
gtk->g_variant_builder_add = fp_g_variant_builder_add;
|
||||
|
||||
gtk->g_variant_lookup_value = fp_g_variant_lookup_value;
|
||||
gtk->g_variant_iter_init = fp_g_variant_iter_init;
|
||||
gtk->g_variant_iter_n_children = fp_g_variant_iter_n_children;
|
||||
|
||||
gtk->g_string_new = fp_g_string_new;
|
||||
gtk->g_string_erase = fp_g_string_erase;
|
||||
gtk->g_string_free = fp_g_string_free;
|
||||
gtk->g_string_replace = fp_g_string_replace;
|
||||
gtk->g_string_printf = fp_g_string_printf;
|
||||
gtk->g_uuid_string_is_valid = fp_g_uuid_string_is_valid;
|
||||
|
||||
gtk->g_main_context_iteration = fp_g_main_context_iteration;
|
||||
gtk->g_error_free = fp_g_error_free;
|
||||
gtk->g_unix_fd_list_get = fp_g_unix_fd_list_get;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -235,13 +235,6 @@ typedef struct {
|
||||
gushort revents;
|
||||
} GPollFD;
|
||||
|
||||
typedef struct {
|
||||
gint x;
|
||||
gint y;
|
||||
gint width;
|
||||
gint height;
|
||||
} GdkRectangle;
|
||||
|
||||
typedef struct {
|
||||
int x, y;
|
||||
int width, height;
|
||||
@ -375,7 +368,6 @@ static gboolean (*fp_gtk_show_uri)(GdkScreen *screen, const gchar *uri,
|
||||
guint32 timestamp, GError **error);
|
||||
|
||||
// Implementation functions prototypes
|
||||
static void gtk3_init(GtkApi* gtk);
|
||||
static GValue* (*fp_g_value_init)(GValue *value, GType g_type);
|
||||
static gboolean (*fp_g_type_is_a)(GType type, GType is_a_type);
|
||||
static gboolean (*fp_g_value_get_boolean)(const GValue *value);
|
||||
@ -494,16 +486,15 @@ static void (*fp_gtk_render_background)(GtkStyleContext *context, cairo_t *cr,
|
||||
gdouble x, gdouble y, gdouble width, gdouble height);
|
||||
static gboolean (*fp_gtk_style_context_has_class)(GtkStyleContext *context,
|
||||
const gchar *class_name);
|
||||
static void transform_detail_string (const gchar *detail,
|
||||
GtkStyleContext *context);
|
||||
void (*fp_gtk_style_context_set_junction_sides)(GtkStyleContext *context,
|
||||
|
||||
static void (*fp_gtk_style_context_set_junction_sides)(GtkStyleContext *context,
|
||||
GtkJunctionSides sides);
|
||||
void (*fp_gtk_style_context_add_region)(GtkStyleContext *context,
|
||||
static void (*fp_gtk_style_context_add_region)(GtkStyleContext *context,
|
||||
const gchar *region_name, GtkRegionFlags flags);
|
||||
void (*fp_gtk_render_arrow)(GtkStyleContext *context, cairo_t *cr,
|
||||
static void (*fp_gtk_render_arrow)(GtkStyleContext *context, cairo_t *cr,
|
||||
gdouble angle, gdouble x, gdouble y, gdouble size);
|
||||
void (*fp_gtk_bin_set_child)(GtkBin *bin, GtkWidget *widget);
|
||||
void (*fp_gtk_scrolled_window_set_shadow_type)(
|
||||
static void (*fp_gtk_bin_set_child)(GtkBin *bin, GtkWidget *widget);
|
||||
static void (*fp_gtk_scrolled_window_set_shadow_type)(
|
||||
GtkScrolledWindow *scrolled_window, GtkShadowType type);
|
||||
static void (*fp_gtk_render_slider)(GtkStyleContext *context, cairo_t *cr,
|
||||
gdouble x, gdouble y, gdouble width, gdouble height,
|
||||
@ -522,7 +513,7 @@ static GdkPixbuf* (*fp_gtk_icon_theme_load_icon)(GtkIconTheme *icon_theme,
|
||||
static void (*fp_gtk_adjustment_set_lower)(GtkAdjustment *adjustment,
|
||||
gdouble lower);
|
||||
static void (*fp_gtk_adjustment_set_page_increment)(GtkAdjustment *adjustment,
|
||||
gdouble page_increment);
|
||||
gdouble page_increment);
|
||||
static void (*fp_gtk_adjustment_set_page_size)(GtkAdjustment *adjustment,
|
||||
gdouble page_size);
|
||||
static void (*fp_gtk_adjustment_set_step_increment)(GtkAdjustment *adjustment,
|
||||
@ -637,4 +628,156 @@ static void (*fp_gtk_style_context_set_path)
|
||||
static void (*fp_gtk_widget_path_unref) (GtkWidgetPath *path);
|
||||
static GtkStyleContext* (*fp_gtk_style_context_new) (void);
|
||||
|
||||
|
||||
// ---------- fp_g_dbus_* ----------
|
||||
static GVariant *(*fp_g_dbus_proxy_call_sync)(
|
||||
GDBusProxy *proxy,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GCancellable *cancellable,
|
||||
GError **error
|
||||
);
|
||||
|
||||
static GDBusProxy *(*fp_g_dbus_proxy_new_sync)(
|
||||
GDBusConnection *connection,
|
||||
GDBusProxyFlags flags,
|
||||
GDBusInterfaceInfo *info,
|
||||
const gchar *name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
GCancellable *cancellable,
|
||||
GError **error
|
||||
);
|
||||
|
||||
static const gchar *(*fp_g_dbus_connection_get_unique_name)(
|
||||
GDBusConnection *connection
|
||||
);
|
||||
|
||||
static GDBusConnection *(*fp_g_bus_get_sync)(GBusType bus_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
static guint (*fp_g_dbus_connection_signal_subscribe)(
|
||||
GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *interface_name,
|
||||
const gchar *member,
|
||||
const gchar *object_path,
|
||||
const gchar *arg0,
|
||||
GDBusSignalFlags flags,
|
||||
GDBusSignalCallback callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func
|
||||
);
|
||||
|
||||
static void (*fp_g_dbus_connection_signal_unsubscribe)(
|
||||
GDBusConnection *connection,
|
||||
guint subscription_id
|
||||
);
|
||||
|
||||
static GVariant *(*fp_g_dbus_proxy_call_with_unix_fd_list_sync)(
|
||||
GDBusProxy *proxy,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GUnixFDList *fd_list,
|
||||
GUnixFDList **out_fd_list,
|
||||
GCancellable *cancellable,
|
||||
GError **error
|
||||
);
|
||||
|
||||
static GVariant *(*fp_g_dbus_connection_call_sync)(
|
||||
GDBusConnection *connection,
|
||||
const gchar *bus_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
const GVariantType *reply_type,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GCancellable *cancellable,
|
||||
GError **error
|
||||
);
|
||||
|
||||
// ---------- fp_g_variant_* ----------
|
||||
|
||||
static GVariant *(*fp_g_variant_new)(const gchar *format_string, ...);
|
||||
|
||||
static GVariant *(*fp_g_variant_new_string)(const gchar *string);
|
||||
|
||||
static GVariant *(*fp_g_variant_new_boolean)(gboolean value);
|
||||
|
||||
static GVariant *(*fp_g_variant_new_uint32)(guint32 value);
|
||||
|
||||
static void (*fp_g_variant_get)(GVariant *value,
|
||||
const gchar *format_string,
|
||||
...);
|
||||
|
||||
static const gchar *(*fp_g_variant_get_string)(GVariant *value,
|
||||
gsize *length);
|
||||
|
||||
static guint32 (*fp_g_variant_get_uint32)(GVariant *value);
|
||||
|
||||
static gboolean (*fp_g_variant_lookup)(GVariant *dictionary,
|
||||
const gchar *key,
|
||||
const gchar *format_string,
|
||||
...);
|
||||
|
||||
static gboolean (*fp_g_variant_iter_loop)(GVariantIter *iter,
|
||||
const gchar *format_string,
|
||||
...);
|
||||
|
||||
static void (*fp_g_variant_unref)(GVariant *value);
|
||||
|
||||
static void (*fp_g_variant_builder_init)(GVariantBuilder *builder,
|
||||
const GVariantType *type);
|
||||
|
||||
static void (*fp_g_variant_builder_add)(GVariantBuilder *builder,
|
||||
const gchar *format_string,
|
||||
...);
|
||||
|
||||
static GVariant *(*fp_g_variant_lookup_value)(GVariant *dictionary,
|
||||
const gchar *key,
|
||||
const GVariantType *expected_type);
|
||||
|
||||
static gsize (*fp_g_variant_iter_init)(GVariantIter *iter,
|
||||
GVariant *value);
|
||||
|
||||
static gsize (*fp_g_variant_iter_n_children)(GVariantIter *iter);
|
||||
|
||||
|
||||
// ---------- fp_g_string_* ----------
|
||||
|
||||
static GString *(*fp_g_string_new)(const gchar *init);
|
||||
|
||||
static GString *(*fp_g_string_erase)(GString *string,
|
||||
gssize pos,
|
||||
gssize len);
|
||||
|
||||
static gchar *(*fp_g_string_free)(GString *string,
|
||||
gboolean free_segment);
|
||||
|
||||
static guint (*fp_g_string_replace)(GString *string,
|
||||
const gchar *find,
|
||||
const gchar *replace,
|
||||
guint limit);
|
||||
|
||||
static void *(*fp_g_string_printf)(GString *string,
|
||||
const gchar *format,
|
||||
...);
|
||||
|
||||
static gboolean (*fp_g_uuid_string_is_valid)(const gchar *str);
|
||||
|
||||
|
||||
// ---------- * ----------
|
||||
static void (*fp_g_error_free)(GError *error);
|
||||
|
||||
static gint (*fp_g_unix_fd_list_get)(GUnixFDList *list,
|
||||
gint index_,
|
||||
GError **error);
|
||||
|
||||
#endif /* !_GTK3_INTERFACE_H */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -108,7 +108,7 @@ typedef unsigned short gushort;
|
||||
typedef unsigned short guint16;
|
||||
typedef unsigned int guint;
|
||||
typedef unsigned int guint32;
|
||||
typedef unsigned int gsize;
|
||||
typedef unsigned long gsize;
|
||||
typedef unsigned long gulong;
|
||||
typedef signed long long gint64;
|
||||
typedef unsigned long long guint64;
|
||||
@ -128,6 +128,93 @@ struct _GSList {
|
||||
GSList *next;
|
||||
};
|
||||
|
||||
typedef signed long gssize;
|
||||
typedef struct _GString GString;
|
||||
|
||||
struct _GString
|
||||
{
|
||||
gchar *str;
|
||||
gsize len;
|
||||
gsize allocated_len;
|
||||
};
|
||||
|
||||
typedef struct _GVariant GVariant;
|
||||
typedef struct _GVariantIter GVariantIter;
|
||||
struct _GVariantIter {
|
||||
/*< private >*/
|
||||
gsize x[16];
|
||||
};
|
||||
|
||||
typedef struct _GVariantType GVariantType;
|
||||
typedef struct _GVariantBuilder GVariantBuilder;
|
||||
|
||||
struct _GVariantBuilder {
|
||||
/*< private >*/
|
||||
union
|
||||
{
|
||||
struct {
|
||||
gsize partial_magic;
|
||||
const GVariantType *type;
|
||||
gsize y[14];
|
||||
} s;
|
||||
gsize x[16];
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
#define G_VARIANT_TYPE_VARDICT ((const GVariantType *) "a{sv}")
|
||||
#define G_VARIANT_TYPE_ARRAY ((const GVariantType *) "a*")
|
||||
#define G_VARIANT_TYPE_STRING ((const GVariantType *) "s")
|
||||
|
||||
typedef struct _GDBusProxy GDBusProxy;
|
||||
typedef enum {
|
||||
G_DBUS_CALL_FLAGS_NONE = 0,
|
||||
G_DBUS_CALL_FLAGS_NO_AUTO_START = (1<<0),
|
||||
G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION = (1<<1)
|
||||
} GDBusCallFlags;
|
||||
|
||||
typedef void GMainContext;
|
||||
typedef void GUnixFDList;
|
||||
|
||||
typedef void GDBusConnection;
|
||||
typedef enum /*< flags >*/
|
||||
{
|
||||
G_DBUS_SIGNAL_FLAGS_NONE = 0,
|
||||
G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE = (1<<0),
|
||||
G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE = (1<<1),
|
||||
G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH = (1<<2)
|
||||
} GDBusSignalFlags;
|
||||
|
||||
typedef void (*GDBusSignalCallback) (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data);
|
||||
|
||||
typedef struct _GCancellable GCancellable;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
G_BUS_TYPE_STARTER = -1,
|
||||
G_BUS_TYPE_NONE = 0,
|
||||
G_BUS_TYPE_SYSTEM = 1,
|
||||
G_BUS_TYPE_SESSION = 2
|
||||
} GBusType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
G_DBUS_PROXY_FLAGS_NONE = 0,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0),
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1),
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2),
|
||||
G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES = (1<<3),
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION = (1<<4)
|
||||
} GDBusProxyFlags;
|
||||
|
||||
typedef struct _GDBusInterfaceInfo GDBusInterfaceInfo;
|
||||
|
||||
typedef enum {
|
||||
BUTTON, /* GtkButton */
|
||||
CHECK_BOX, /* GtkCheckButton */
|
||||
@ -409,14 +496,29 @@ typedef enum {
|
||||
} GConnectFlags;
|
||||
//------------------------------
|
||||
|
||||
typedef guint32 GQuark;
|
||||
struct _GError
|
||||
{
|
||||
GQuark domain;
|
||||
gint code;
|
||||
gchar *message;
|
||||
};
|
||||
typedef struct _GError GError;
|
||||
|
||||
typedef void GError;
|
||||
typedef void GdkScreen;
|
||||
typedef void GtkWindow;
|
||||
typedef void GdkWindow;
|
||||
typedef void GClosure;
|
||||
typedef void GtkFileChooser;
|
||||
typedef void GtkFileFilter;
|
||||
|
||||
typedef struct {
|
||||
gint x;
|
||||
gint y;
|
||||
gint width;
|
||||
gint height;
|
||||
} GdkRectangle;
|
||||
|
||||
typedef struct {
|
||||
GtkFileFilterFlags contains;
|
||||
const gchar *filename;
|
||||
@ -513,7 +615,6 @@ typedef struct GtkApi {
|
||||
jint jwidth, int dx, int dy);
|
||||
void (*g_free)(gpointer mem);
|
||||
|
||||
|
||||
gchar* (*gtk_file_chooser_get_filename)(GtkFileChooser *chooser);
|
||||
void (*gtk_widget_hide)(void* widget);
|
||||
void (*gtk_main_quit)(void);
|
||||
@ -558,6 +659,141 @@ typedef struct GtkApi {
|
||||
GList* (*g_list_append) (GList *list, gpointer data);
|
||||
void (*g_list_free) (GList *list);
|
||||
void (*g_list_free_full) (GList *list, GDestroyNotify free_func);
|
||||
|
||||
|
||||
/* <for screencast, used only with GTK3> */
|
||||
GVariant *(*g_dbus_proxy_call_sync)(
|
||||
GDBusProxy *proxy,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
GVariant *(*g_variant_new)(const gchar *format_string, ...);
|
||||
GVariant *(*g_variant_new_string)(const gchar *string);
|
||||
GVariant *(*g_variant_new_boolean)(gboolean value);
|
||||
GVariant *(*g_variant_new_uint32)(guint32 value);
|
||||
|
||||
|
||||
void (*g_variant_get)(GVariant *value,
|
||||
const gchar *format_string,
|
||||
...);
|
||||
const gchar *(*g_variant_get_string)(GVariant *value, gsize *length);
|
||||
guint32 (*g_variant_get_uint32)(GVariant *value);
|
||||
|
||||
gboolean (*g_variant_lookup)(GVariant *dictionary,
|
||||
const gchar *key,
|
||||
const gchar *format_string,
|
||||
...);
|
||||
gboolean (*g_variant_iter_loop)(GVariantIter *iter,
|
||||
const gchar *format_string,
|
||||
...);
|
||||
|
||||
void (*g_variant_unref)(GVariant *value);
|
||||
|
||||
void (*g_variant_builder_init)(GVariantBuilder *builder, //+
|
||||
const GVariantType *type);
|
||||
|
||||
void (*g_variant_builder_add)(GVariantBuilder *builder, //+
|
||||
const gchar *format_string,
|
||||
...);
|
||||
|
||||
GVariant *(*g_variant_lookup_value)(GVariant *dictionary,
|
||||
const gchar *key,
|
||||
const GVariantType *expected_type);
|
||||
|
||||
gsize (*g_variant_iter_init)(GVariantIter *iter,
|
||||
GVariant *value);
|
||||
|
||||
gsize (*g_variant_iter_n_children)(GVariantIter *iter);
|
||||
|
||||
|
||||
GString *(*g_string_new)(const gchar *init);
|
||||
|
||||
GString *(*g_string_erase)(GString *string,
|
||||
gssize pos,
|
||||
gssize len);
|
||||
|
||||
gchar *(*g_string_free)(GString *string,
|
||||
gboolean free_segment);
|
||||
|
||||
guint (*g_string_replace)(GString *string,
|
||||
const gchar *find,
|
||||
const gchar *replace,
|
||||
guint limit);
|
||||
|
||||
void *(*g_string_printf)(GString *string,
|
||||
const gchar *format,
|
||||
...);
|
||||
|
||||
gboolean (*g_uuid_string_is_valid)(const gchar *str);
|
||||
|
||||
|
||||
GDBusConnection *(*g_bus_get_sync)(GBusType bus_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
GDBusProxy *(*g_dbus_proxy_new_sync)(GDBusConnection *connection,
|
||||
GDBusProxyFlags flags,
|
||||
GDBusInterfaceInfo *info,
|
||||
const gchar *name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
const gchar *(*g_dbus_connection_get_unique_name)(GDBusConnection *connection);
|
||||
|
||||
|
||||
|
||||
guint (*g_dbus_connection_signal_subscribe)(GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *interface_name,
|
||||
const gchar *member,
|
||||
const gchar *object_path,
|
||||
const gchar *arg0,
|
||||
GDBusSignalFlags flags,
|
||||
GDBusSignalCallback callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func);
|
||||
|
||||
void (*g_dbus_connection_signal_unsubscribe)(GDBusConnection *connection,
|
||||
guint subscription_id);
|
||||
|
||||
GVariant *(*g_dbus_proxy_call_with_unix_fd_list_sync)(GDBusProxy *proxy,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GUnixFDList *fd_list,
|
||||
GUnixFDList **out_fd_list,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
GVariant *(*g_dbus_connection_call_sync)(GDBusConnection *connection,
|
||||
const gchar *bus_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
const GVariantType *reply_type,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean (*g_main_context_iteration)(GMainContext *context,
|
||||
gboolean may_block);
|
||||
|
||||
void (*g_error_free)(GError *error);
|
||||
|
||||
gint (*g_unix_fd_list_get)(GUnixFDList *list,
|
||||
gint index_,
|
||||
GError **error);
|
||||
|
||||
/* </for screencast, used only with GTK3> */
|
||||
} GtkApi;
|
||||
|
||||
gboolean gtk_load(JNIEnv *env, GtkVersion version, gboolean verbose);
|
||||
|
@ -0,0 +1,897 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifdef HEADLESS
|
||||
#error This file should not be included in headless library
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "jni_util.h"
|
||||
#include "awt.h"
|
||||
#include "screencast_pipewire.h"
|
||||
#include "fp_pipewire.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gtk_interface.h"
|
||||
#include "gtk3_interface.h"
|
||||
|
||||
int DEBUG_SCREENCAST_ENABLED = FALSE;
|
||||
|
||||
#define EXCEPTION_CHECK_DESCRIBE() if ((*env)->ExceptionCheck(env)) { \
|
||||
(*env)->ExceptionDescribe(env); \
|
||||
}
|
||||
|
||||
struct ScreenSpace screenSpace = {0};
|
||||
static struct PwLoopData pw = {0};
|
||||
|
||||
jclass tokenStorageClass = NULL;
|
||||
jmethodID storeTokenMethodID = NULL;
|
||||
|
||||
inline void debug_screencast(
|
||||
const char *__restrict fmt,
|
||||
...
|
||||
) {
|
||||
if (DEBUG_SCREENCAST_ENABLED) {
|
||||
va_list myargs;
|
||||
va_start(myargs, fmt);
|
||||
vfprintf(stdout, fmt, myargs);
|
||||
va_end(myargs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TRUE on success
|
||||
*/
|
||||
static gboolean initScreenSpace() {
|
||||
screenSpace.screenCount = 0;
|
||||
screenSpace.allocated = SCREEN_SPACE_DEFAULT_ALLOCATED;
|
||||
screenSpace.screens = calloc(
|
||||
SCREEN_SPACE_DEFAULT_ALLOCATED,
|
||||
sizeof(struct ScreenProps)
|
||||
);
|
||||
|
||||
if (!screenSpace.screens) {
|
||||
ERR("failed to allocate memory\n");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void doCleanup() {
|
||||
for (int i = 0; i < screenSpace.screenCount; ++i) {
|
||||
struct ScreenProps *screenProps = &screenSpace.screens[i];
|
||||
if (screenProps->data) {
|
||||
if (screenProps->data->stream) {
|
||||
fp_pw_stream_disconnect(screenProps->data->stream);
|
||||
fp_pw_stream_destroy(screenProps->data->stream);
|
||||
screenProps->data->stream = NULL;
|
||||
}
|
||||
free(screenProps->data);
|
||||
screenProps->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pw.pwFd > 0) {
|
||||
close(pw.pwFd);
|
||||
pw.pwFd = -1;
|
||||
}
|
||||
|
||||
portalScreenCastCleanup();
|
||||
|
||||
if (pw.core) {
|
||||
fp_pw_core_disconnect(pw.core);
|
||||
pw.core = NULL;
|
||||
}
|
||||
|
||||
DEBUG_SCREENCAST("STOPPING loop\n", NULL)
|
||||
|
||||
if (pw.loop) {
|
||||
fp_pw_thread_loop_stop(pw.loop);
|
||||
fp_pw_thread_loop_destroy(pw.loop);
|
||||
pw.loop = NULL;
|
||||
}
|
||||
|
||||
if (screenSpace.screens) {
|
||||
free(screenSpace.screens);
|
||||
screenSpace.screens = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TRUE on success
|
||||
*/
|
||||
static gboolean initScreencast(const gchar *token,
|
||||
GdkRectangle *affectedBounds,
|
||||
gint affectedBoundsLength) {
|
||||
fp_pw_init(NULL, NULL);
|
||||
|
||||
pw.pwFd = RESULT_ERROR;
|
||||
|
||||
if (!initScreenSpace()
|
||||
|| !initXdgDesktopPortal()
|
||||
|| (pw.pwFd = getPipewireFd(token,
|
||||
affectedBounds,
|
||||
affectedBoundsLength)) < 0) {
|
||||
doCleanup();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void convertRGBxToBGRx(int* in) {
|
||||
char* o = (char*) in;
|
||||
char tmp = o[0];
|
||||
o[0] = o[2];
|
||||
o[2] = tmp;
|
||||
}
|
||||
|
||||
static gchar * cropTo(
|
||||
struct spa_data data,
|
||||
struct spa_video_info_raw raw,
|
||||
guint32 x,
|
||||
guint32 y,
|
||||
guint32 width,
|
||||
guint32 height
|
||||
) {
|
||||
int srcW = raw.size.width;
|
||||
if (data.chunk->stride / 4 != srcW) {
|
||||
fprintf(stderr, "%s:%i Unexpected stride / 4: %i srcW: %i\n",
|
||||
__func__, __LINE__, data.chunk->stride / 4, srcW);
|
||||
}
|
||||
|
||||
int* d = data.data;
|
||||
|
||||
int *outData = calloc(width * height, sizeof(int));
|
||||
if (!outData) {
|
||||
ERR("failed to allocate memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean needConversion = raw.format != SPA_VIDEO_FORMAT_BGRx;
|
||||
for (guint32 j = y; j < y + height; ++j) {
|
||||
for (guint32 i = x; i < x + width; ++i) {
|
||||
int color = *(d + (j * srcW) + i);
|
||||
if (needConversion) {
|
||||
convertRGBxToBGRx(&color);
|
||||
}
|
||||
*(outData + ((j - y) * width) + (i - x)) = color;
|
||||
}
|
||||
}
|
||||
|
||||
return (gchar*) outData;
|
||||
}
|
||||
|
||||
static void onStreamParamChanged(
|
||||
void *userdata,
|
||||
uint32_t id,
|
||||
const struct spa_pod *param
|
||||
) {
|
||||
struct PwStreamData *data = userdata;
|
||||
uint32_t mediaType;
|
||||
uint32_t mediaSubtype;
|
||||
|
||||
DEBUG_SCREEN_PREFIX(data->screenProps, "param event id %i\n", id);
|
||||
|
||||
if (param == NULL || id != SPA_PARAM_Format) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spa_format_parse(param,
|
||||
&mediaType,
|
||||
&mediaSubtype) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mediaType != SPA_MEDIA_TYPE_video ||
|
||||
mediaSubtype != SPA_MEDIA_SUBTYPE_raw) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spa_format_video_raw_parse(param, &data->rawFormat) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_SCREEN_PREFIX(data->screenProps, "stream format: %s (%d)\t%dx%d\n",
|
||||
spa_debug_type_find_name(
|
||||
spa_type_video_format,
|
||||
data->rawFormat.format
|
||||
),
|
||||
data->rawFormat.format,
|
||||
data->rawFormat.size.width,
|
||||
data->rawFormat.size.height);
|
||||
|
||||
data->hasFormat = TRUE;
|
||||
fp_pw_thread_loop_signal(pw.loop, TRUE);
|
||||
}
|
||||
|
||||
static void onStreamProcess(void *userdata) {
|
||||
struct PwStreamData *data = userdata;
|
||||
|
||||
struct ScreenProps *screen = data->screenProps;
|
||||
|
||||
DEBUG_SCREEN_PREFIX(screen,
|
||||
"hasFormat %i "
|
||||
"captureDataReady %i shouldCapture %i\n",
|
||||
data->hasFormat,
|
||||
screen->captureDataReady,
|
||||
screen->shouldCapture
|
||||
);
|
||||
if (
|
||||
!data->hasFormat
|
||||
|| !screen->shouldCapture
|
||||
|| screen->captureDataReady
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct pw_buffer *pwBuffer;
|
||||
struct spa_buffer *spaBuffer;
|
||||
|
||||
if (!data->stream
|
||||
|| (pwBuffer = fp_pw_stream_dequeue_buffer(data->stream)) == NULL) {
|
||||
DEBUG_SCREEN_PREFIX(screen, "!!! out of buffers\n", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
spaBuffer = pwBuffer->buffer;
|
||||
if (!spaBuffer
|
||||
|| spaBuffer->n_datas < 1
|
||||
|| spaBuffer->datas[0].data == NULL) {
|
||||
DEBUG_SCREEN_PREFIX(screen, "!!! no data, n_datas %d\n",
|
||||
spaBuffer->n_datas);
|
||||
return;
|
||||
}
|
||||
|
||||
struct spa_data spaData = spaBuffer->datas[0];
|
||||
|
||||
DEBUG_SCREEN(screen);
|
||||
DEBUG_SCREEN_PREFIX(screen,
|
||||
"got a frame of size %d offset %d stride %d "
|
||||
"flags %d FD %li captureDataReady %i\n",
|
||||
spaBuffer->datas[0].chunk->size,
|
||||
spaData.chunk->offset,
|
||||
spaData.chunk->stride,
|
||||
spaData.chunk->flags,
|
||||
spaData.fd,
|
||||
screen->captureDataReady
|
||||
);
|
||||
|
||||
data->screenProps->captureData = cropTo(
|
||||
spaData,
|
||||
data->rawFormat,
|
||||
screen->captureArea.x, screen->captureArea.y,
|
||||
screen->captureArea.width, screen->captureArea.height
|
||||
);
|
||||
|
||||
screen->captureDataReady = TRUE;
|
||||
|
||||
DEBUG_SCREEN_PREFIX(screen, "data ready\n", NULL);
|
||||
fp_pw_stream_queue_buffer(data->stream, pwBuffer);
|
||||
}
|
||||
|
||||
static void onStreamStateChanged(
|
||||
void *userdata,
|
||||
enum pw_stream_state old,
|
||||
enum pw_stream_state state,
|
||||
const char *error
|
||||
) {
|
||||
struct PwStreamData *data = userdata;
|
||||
DEBUG_SCREEN_PREFIX(data->screenProps, "state %i (%s) -> %i (%s) err %s\n",
|
||||
old, fp_pw_stream_state_as_string(old),
|
||||
state, fp_pw_stream_state_as_string(state),
|
||||
error);
|
||||
}
|
||||
|
||||
static const struct pw_stream_events streamEvents = {
|
||||
PW_VERSION_STREAM_EVENTS,
|
||||
.param_changed = onStreamParamChanged,
|
||||
.process = onStreamProcess,
|
||||
.state_changed = onStreamStateChanged,
|
||||
};
|
||||
|
||||
|
||||
static bool startStream(
|
||||
struct pw_stream *stream,
|
||||
uint32_t node
|
||||
) {
|
||||
char buffer[1024];
|
||||
struct spa_pod_builder builder =
|
||||
SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||
const struct spa_pod *param;
|
||||
|
||||
|
||||
param = spa_pod_builder_add_object(
|
||||
&builder,
|
||||
SPA_TYPE_OBJECT_Format,
|
||||
SPA_PARAM_EnumFormat,
|
||||
SPA_FORMAT_mediaType,
|
||||
SPA_POD_Id(SPA_MEDIA_TYPE_video),
|
||||
SPA_FORMAT_mediaSubtype,
|
||||
SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
|
||||
SPA_FORMAT_VIDEO_format,
|
||||
SPA_POD_CHOICE_ENUM_Id(
|
||||
2,
|
||||
SPA_VIDEO_FORMAT_RGBx,
|
||||
SPA_VIDEO_FORMAT_BGRx
|
||||
),
|
||||
SPA_FORMAT_VIDEO_size,
|
||||
SPA_POD_CHOICE_RANGE_Rectangle(
|
||||
&SPA_RECTANGLE(320, 240),
|
||||
&SPA_RECTANGLE(1, 1),
|
||||
&SPA_RECTANGLE(8192, 8192)
|
||||
),
|
||||
SPA_FORMAT_VIDEO_framerate,
|
||||
SPA_POD_CHOICE_RANGE_Fraction(
|
||||
&SPA_FRACTION(25, 1),
|
||||
&SPA_FRACTION(0, 1),
|
||||
&SPA_FRACTION(1000, 1)
|
||||
)
|
||||
);
|
||||
|
||||
DEBUG_SCREENCAST("screenId#%i: stream connecting %p\n", node, stream);
|
||||
|
||||
return fp_pw_stream_connect(
|
||||
stream,
|
||||
PW_DIRECTION_INPUT,
|
||||
node,
|
||||
PW_STREAM_FLAG_AUTOCONNECT
|
||||
| PW_STREAM_FLAG_MAP_BUFFERS,
|
||||
¶m,
|
||||
1
|
||||
) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index of a screen
|
||||
* @return TRUE on success
|
||||
*/
|
||||
static gboolean connectStream(int index) {
|
||||
DEBUG_SCREENCAST("@@@ using screen %i\n", index);
|
||||
if (index >= screenSpace.screenCount) {
|
||||
DEBUG_SCREENCAST("!!! Wrong index for screen\n", NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct PwStreamData *data = screenSpace.screens[index].data;
|
||||
|
||||
data->screenProps = &screenSpace.screens[index];
|
||||
|
||||
data->hasFormat = FALSE;
|
||||
|
||||
|
||||
data->stream = fp_pw_stream_new(
|
||||
pw.core,
|
||||
"AWT Screen Stream",
|
||||
fp_pw_properties_new(
|
||||
PW_KEY_MEDIA_TYPE, "Video",
|
||||
PW_KEY_MEDIA_CATEGORY, "Capture",
|
||||
PW_KEY_MEDIA_ROLE, "Screen",
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
if (!data->stream) {
|
||||
DEBUG_SCREEN_PREFIX(data->screenProps,
|
||||
"!!! Could not create a pipewire stream\n", NULL);
|
||||
fp_pw_thread_loop_unlock(pw.loop);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fp_pw_stream_add_listener(
|
||||
data->stream,
|
||||
&data->streamListener,
|
||||
&streamEvents,
|
||||
data
|
||||
);
|
||||
|
||||
DEBUG_SCREEN(data->screenProps);
|
||||
|
||||
if (!startStream(data->stream, screenSpace.screens[index].id)){
|
||||
DEBUG_SCREEN_PREFIX(data->screenProps,
|
||||
"!!! Could not start a pipewire stream\n", NULL);
|
||||
fp_pw_thread_loop_unlock(pw.loop);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (!data->hasFormat) {
|
||||
fp_pw_thread_loop_wait(pw.loop);
|
||||
}
|
||||
|
||||
DEBUG_SCREEN_PREFIX(data->screenProps,
|
||||
"frame size: %dx%d\n",
|
||||
data->rawFormat.size.width, data->rawFormat.size.height
|
||||
);
|
||||
|
||||
fp_pw_thread_loop_accept(pw.loop);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TRUE if requested screenshot area intersects with a screen
|
||||
*/
|
||||
static gboolean checkScreen(int index, GdkRectangle requestedArea) {
|
||||
if (index >= screenSpace.screenCount) {
|
||||
DEBUG_SCREENCAST("!!! Wrong index for screen %i >= %i\n",
|
||||
index, screenSpace.screenCount);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct ScreenProps * screen = &screenSpace.screens[index];
|
||||
|
||||
int x1 = MAX(requestedArea.x, screen->bounds.x);
|
||||
int y1 = MAX(requestedArea.y, screen->bounds.y);
|
||||
|
||||
int x2 = MIN(
|
||||
requestedArea.x + requestedArea.width,
|
||||
screen->bounds.x + screen->bounds.width
|
||||
);
|
||||
int y2 = MIN(
|
||||
requestedArea.y + requestedArea.height,
|
||||
screen->bounds.y + screen->bounds.height
|
||||
);
|
||||
|
||||
screen->shouldCapture = x2 > x1 && y2 > y1;
|
||||
|
||||
if (screen->shouldCapture) { //intersects
|
||||
//in screen coords:
|
||||
GdkRectangle * captureArea = &(screen->captureArea);
|
||||
|
||||
captureArea->x = x1 - screen->bounds.x;
|
||||
captureArea->y = y1 - screen->bounds.y;
|
||||
captureArea->width = x2 - x1;
|
||||
captureArea->height = y2 - y1;
|
||||
|
||||
screen->captureArea.x = x1 - screen->bounds.x;
|
||||
}
|
||||
|
||||
DEBUG_SCREEN(screen);
|
||||
return screen->shouldCapture;
|
||||
}
|
||||
|
||||
|
||||
static void onCoreError(
|
||||
void *data,
|
||||
uint32_t id,
|
||||
int seq,
|
||||
int res,
|
||||
const char *message
|
||||
) {
|
||||
DEBUG_SCREENCAST(
|
||||
"!!! pipewire error: id %u, seq: %d, res: %d (%s): %s\n",
|
||||
id, seq, res, strerror(res), message
|
||||
);
|
||||
fp_pw_thread_loop_unlock(pw.loop);
|
||||
}
|
||||
|
||||
static const struct pw_core_events coreEvents = {
|
||||
PW_VERSION_CORE_EVENTS,
|
||||
.error = onCoreError,
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param requestedArea requested screenshot area
|
||||
* @return TRUE on success
|
||||
*/
|
||||
static gboolean doLoop(GdkRectangle requestedArea) {
|
||||
pw.loop = fp_pw_thread_loop_new("AWT Pipewire Thread", NULL);
|
||||
|
||||
if (!pw.loop) {
|
||||
DEBUG_SCREENCAST("!!! Could not create a loop\n", NULL);
|
||||
doCleanup();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pw.context = fp_pw_context_new(
|
||||
fp_pw_thread_loop_get_loop(pw.loop),
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
if (!pw.context) {
|
||||
DEBUG_SCREENCAST("!!! Could not create a pipewire context\n", NULL);
|
||||
doCleanup();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (fp_pw_thread_loop_start(pw.loop) != 0) {
|
||||
DEBUG_SCREENCAST("!!! Could not start pipewire thread loop\n", NULL);
|
||||
doCleanup();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fp_pw_thread_loop_lock(pw.loop);
|
||||
|
||||
pw.core = fp_pw_context_connect_fd(
|
||||
pw.context,
|
||||
pw.pwFd,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
if (!pw.core) {
|
||||
DEBUG_SCREENCAST("!!! Could not create pipewire core\n", NULL);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pw_core_add_listener(pw.core, &pw.coreListener, &coreEvents, NULL);
|
||||
|
||||
for (int i = 0; i < screenSpace.screenCount; ++i) {
|
||||
struct PwStreamData *data =
|
||||
(struct PwStreamData*) malloc(sizeof (struct PwStreamData));
|
||||
if (!data) {
|
||||
ERR("failed to allocate memory\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memset(data, 0, sizeof (struct PwStreamData));
|
||||
|
||||
struct ScreenProps *screen = &screenSpace.screens[i];
|
||||
screen->data = data;
|
||||
|
||||
DEBUG_SCREEN_PREFIX(screen, "@@@ adding screen %i\n", i);
|
||||
if (checkScreen(i, requestedArea)) {
|
||||
if (!connectStream(i)){
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
DEBUG_SCREEN_PREFIX(screen, "@@@ screen processed %i\n", i);
|
||||
}
|
||||
|
||||
fp_pw_thread_loop_unlock(pw.loop);
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
fp_pw_thread_loop_unlock(pw.loop);
|
||||
doCleanup();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean isAllDataReady() {
|
||||
for (int i = 0; i < screenSpace.screenCount; ++i) {
|
||||
if (!screenSpace.screens[i].shouldCapture) {
|
||||
continue;
|
||||
}
|
||||
if (!screenSpace.screens[i].captureDataReady ) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void *pipewire_libhandle = NULL;
|
||||
//glib_version_2_68 false for gtk2, as it comes from gtk3_interface.c
|
||||
|
||||
extern gboolean glib_version_2_68;
|
||||
|
||||
#define LOAD_SYMBOL(fp_name, name) do { \
|
||||
(fp_name) = dlsym(pipewire_libhandle, name); \
|
||||
if (!(fp_name)) { \
|
||||
debug_screencast("!!! %s:%i error loading dl_symbol %s\n", \
|
||||
__func__, __LINE__, name); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
static gboolean loadSymbols() {
|
||||
if (!glib_version_2_68) {
|
||||
DEBUG_SCREENCAST("glib version 2.68+ required\n", NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pipewire_libhandle = dlopen(VERSIONED_JNI_LIB_NAME("pipewire-0.3", "0"),
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
|
||||
if (!pipewire_libhandle) {
|
||||
DEBUG_SCREENCAST("could not load pipewire library\n", NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LOAD_SYMBOL(fp_pw_stream_dequeue_buffer, "pw_stream_dequeue_buffer");
|
||||
LOAD_SYMBOL(fp_pw_stream_state_as_string, "pw_stream_state_as_string");
|
||||
LOAD_SYMBOL(fp_pw_stream_queue_buffer, "pw_stream_queue_buffer");
|
||||
LOAD_SYMBOL(fp_pw_stream_set_active, "pw_stream_set_active");
|
||||
LOAD_SYMBOL(fp_pw_stream_connect, "pw_stream_connect");
|
||||
LOAD_SYMBOL(fp_pw_stream_new, "pw_stream_new");
|
||||
LOAD_SYMBOL(fp_pw_stream_add_listener, "pw_stream_add_listener");
|
||||
LOAD_SYMBOL(fp_pw_stream_disconnect, "pw_stream_disconnect");
|
||||
LOAD_SYMBOL(fp_pw_stream_destroy, "pw_stream_destroy");
|
||||
LOAD_SYMBOL(fp_pw_init, "pw_init");
|
||||
LOAD_SYMBOL(fp_pw_context_connect_fd, "pw_context_connect_fd");
|
||||
LOAD_SYMBOL(fp_pw_core_disconnect, "pw_core_disconnect");
|
||||
LOAD_SYMBOL(fp_pw_context_new, "pw_context_new");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_new, "pw_thread_loop_new");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_get_loop, "pw_thread_loop_get_loop");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_signal, "pw_thread_loop_signal");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_wait, "pw_thread_loop_wait");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_accept, "pw_thread_loop_accept");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_start, "pw_thread_loop_start");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_stop, "pw_thread_loop_stop");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_destroy, "pw_thread_loop_destroy");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_lock, "pw_thread_loop_lock");
|
||||
LOAD_SYMBOL(fp_pw_thread_loop_unlock, "pw_thread_loop_unlock");
|
||||
LOAD_SYMBOL(fp_pw_properties_new, "pw_properties_new");
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
dlclose(pipewire_libhandle);
|
||||
pipewire_libhandle = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void storeRestoreToken(const gchar* oldToken, const gchar* newToken) {
|
||||
|
||||
JNIEnv* env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
DEBUG_SCREENCAST("saving token, old: |%s| > new: |%s|\n", oldToken, newToken);
|
||||
if (env) {
|
||||
jstring jOldToken = NULL;
|
||||
if (oldToken) {
|
||||
jOldToken = (*env)->NewStringUTF(env, oldToken);
|
||||
EXCEPTION_CHECK_DESCRIBE();
|
||||
if (!jOldToken) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
jstring jNewToken = (*env)->NewStringUTF(env, newToken);
|
||||
EXCEPTION_CHECK_DESCRIBE();
|
||||
if (!jNewToken) {
|
||||
(*env)->DeleteLocalRef(env, jOldToken);
|
||||
return;
|
||||
}
|
||||
|
||||
jintArray allowedBounds = NULL;
|
||||
if (screenSpace.screenCount > 0) {
|
||||
allowedBounds = (*env)->NewIntArray(env, screenSpace.screenCount*4);
|
||||
EXCEPTION_CHECK_DESCRIBE();
|
||||
if (!allowedBounds) {
|
||||
return;
|
||||
}
|
||||
jint* elements = (*env)->GetIntArrayElements(env, allowedBounds, NULL);
|
||||
EXCEPTION_CHECK_DESCRIBE();
|
||||
if (!elements) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < screenSpace.screenCount; ++i) {
|
||||
GdkRectangle bounds = screenSpace.screens[i].bounds;
|
||||
elements[4 * i] = bounds.x;
|
||||
elements[4 * i + 1] = bounds.y;
|
||||
elements[4 * i + 2] = bounds.width;
|
||||
elements[4 * i + 3] = bounds.height;
|
||||
}
|
||||
|
||||
(*env)->ReleaseIntArrayElements(env, allowedBounds, elements, 0);
|
||||
|
||||
(*env)->CallStaticVoidMethod(env, tokenStorageClass,
|
||||
storeTokenMethodID,
|
||||
jOldToken, jNewToken,
|
||||
allowedBounds);
|
||||
EXCEPTION_CHECK_DESCRIBE();
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, jOldToken);
|
||||
(*env)->DeleteLocalRef(env, jNewToken);
|
||||
} else {
|
||||
DEBUG_SCREENCAST("!!! Could not get env\n", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_UNIXToolkit
|
||||
* Method: load_gtk
|
||||
* Signature: (IZ)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_sun_awt_screencast_ScreencastHelper_loadPipewire(
|
||||
JNIEnv *env, jclass cls, jboolean screencastDebug
|
||||
) {
|
||||
DEBUG_SCREENCAST_ENABLED = screencastDebug;
|
||||
|
||||
if (!loadSymbols()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
tokenStorageClass = (*env)->FindClass(env, "sun/awt/screencast/TokenStorage");
|
||||
if (!tokenStorageClass) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
tokenStorageClass = (*env)->NewGlobalRef(env, tokenStorageClass);
|
||||
|
||||
if (tokenStorageClass) {
|
||||
storeTokenMethodID = (*env)->GetStaticMethodID(
|
||||
env,
|
||||
tokenStorageClass,
|
||||
"storeTokenFromNative",
|
||||
"(Ljava/lang/String;Ljava/lang/String;[I)V"
|
||||
);
|
||||
if (!storeTokenMethodID) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
} else {
|
||||
DEBUG_SCREENCAST("!!! @@@ tokenStorageClass %p\n",
|
||||
tokenStorageClass);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
gboolean usable = initXdgDesktopPortal();
|
||||
portalScreenCastCleanup();
|
||||
return usable;
|
||||
}
|
||||
|
||||
static void releaseToken(JNIEnv *env, jstring jtoken, const gchar *token) {
|
||||
if (token) {
|
||||
(*env)->ReleaseStringUTFChars(env, jtoken, token);
|
||||
}
|
||||
}
|
||||
|
||||
static void arrayToRectangles(JNIEnv *env,
|
||||
jintArray boundsArray,
|
||||
jint boundsLen,
|
||||
GdkRectangle *out
|
||||
) {
|
||||
if (!boundsArray) {
|
||||
return;
|
||||
}
|
||||
|
||||
jint * body = (*env)->GetIntArrayElements(env, boundsArray, 0);
|
||||
EXCEPTION_CHECK_DESCRIBE();
|
||||
if (!body) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < boundsLen; i += 4) {
|
||||
GdkRectangle screenBounds = {
|
||||
body[i], body[i + 1],
|
||||
body[i + 2], body[i + 3]
|
||||
};
|
||||
out[i / 4] = screenBounds;
|
||||
}
|
||||
|
||||
(*env)->ReleaseIntArrayElements(env, boundsArray, body, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_screencast_ScreencastHelper
|
||||
* Method: getRGBPixelsImpl
|
||||
* Signature: (IIII[I[ILjava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl(
|
||||
JNIEnv *env,
|
||||
jclass cls,
|
||||
jint jx,
|
||||
jint jy,
|
||||
jint jwidth,
|
||||
jint jheight,
|
||||
jintArray pixelArray,
|
||||
jintArray affectedScreensBoundsArray,
|
||||
jstring jtoken
|
||||
) {
|
||||
jsize boundsLen = 0;
|
||||
gint affectedBoundsLength = 0;
|
||||
if (affectedScreensBoundsArray) {
|
||||
boundsLen = (*env)->GetArrayLength(env, affectedScreensBoundsArray);
|
||||
EXCEPTION_CHECK_DESCRIBE();
|
||||
if (boundsLen % 4 != 0) {
|
||||
DEBUG_SCREENCAST("%s:%i incorrect array length\n", __FUNCTION__, __LINE__);
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
affectedBoundsLength = boundsLen / 4;
|
||||
}
|
||||
|
||||
GdkRectangle affectedScreenBounds[affectedBoundsLength];
|
||||
arrayToRectangles(env,
|
||||
affectedScreensBoundsArray,
|
||||
boundsLen,
|
||||
(GdkRectangle *) &affectedScreenBounds);
|
||||
|
||||
GdkRectangle requestedArea = { jx, jy, jwidth, jheight};
|
||||
|
||||
const gchar *token = jtoken
|
||||
? (*env)->GetStringUTFChars(env, jtoken, NULL)
|
||||
: NULL;
|
||||
|
||||
DEBUG_SCREENCAST(
|
||||
"taking screenshot at \n\tx: %5i y %5i w %5i h %5i with token |%s|\n",
|
||||
jx, jy, jwidth, jheight, token
|
||||
);
|
||||
|
||||
if (!initScreencast(token, affectedScreenBounds, affectedBoundsLength)) {
|
||||
releaseToken(env, jtoken, token);
|
||||
return pw.pwFd;
|
||||
}
|
||||
|
||||
if (!doLoop(requestedArea)) {
|
||||
releaseToken(env, jtoken, token);
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
|
||||
while (!isAllDataReady()) {
|
||||
fp_pw_thread_loop_wait(pw.loop);
|
||||
}
|
||||
|
||||
DEBUG_SCREENCAST("\nall data ready\n", NULL);
|
||||
|
||||
for (int i = 0; i < screenSpace.screenCount; ++i) {
|
||||
struct ScreenProps * screenProps = &screenSpace.screens[i];
|
||||
|
||||
if (screenProps->shouldCapture) {
|
||||
GdkRectangle bounds = screenProps->bounds;
|
||||
GdkRectangle captureArea = screenProps->captureArea;
|
||||
DEBUG_SCREEN_PREFIX(screenProps,
|
||||
"@@@ copying screen data %i, captureData %p\n"
|
||||
"\t||\tx %5i y %5i w %5i h %5i %s\n"
|
||||
"\t||\tx %5i y %5i w %5i h %5i %s\n"
|
||||
"\t||\tx %5i y %5i w %5i h %5i %s\n\n",
|
||||
i, screenProps->captureData,
|
||||
requestedArea.x, requestedArea.y,
|
||||
requestedArea.width, requestedArea.height,
|
||||
"requested area",
|
||||
|
||||
bounds.x, bounds.y,
|
||||
bounds.width, bounds.height,
|
||||
"screen bound",
|
||||
|
||||
captureArea.x, captureArea.y,
|
||||
captureArea.width, captureArea.height,
|
||||
"in-screen coords capture area"
|
||||
);
|
||||
|
||||
if (screenProps->captureData) {
|
||||
for (int y = 0; y < captureArea.height; y++) {
|
||||
jsize preY = (requestedArea.y > screenProps->bounds.y)
|
||||
? 0
|
||||
: screenProps->bounds.y - requestedArea.y;
|
||||
jsize preX = (requestedArea.x > screenProps->bounds.x)
|
||||
? 0
|
||||
: screenProps->bounds.x - requestedArea.x;
|
||||
jsize start = jwidth * (preY + y) + preX;
|
||||
|
||||
jsize len = captureArea.width;
|
||||
|
||||
(*env)->SetIntArrayRegion(
|
||||
env, pixelArray,
|
||||
start, len,
|
||||
((jint *) screenProps->captureData)
|
||||
+ (captureArea.width * y)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
free(screenProps->captureData);
|
||||
screenProps->captureData = NULL;
|
||||
screenProps->shouldCapture = FALSE;
|
||||
|
||||
fp_pw_stream_set_active(screenProps->data->stream, FALSE);
|
||||
fp_pw_stream_disconnect(screenProps->data->stream);
|
||||
}
|
||||
}
|
||||
doCleanup();
|
||||
releaseToken(env, jtoken, token);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifdef HEADLESS
|
||||
#error This file should not be included in headless library
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _SCREENCAST_PIPEWIRE_H
|
||||
#define _SCREENCAST_PIPEWIRE_H
|
||||
|
||||
#include "screencast_portal.h"
|
||||
|
||||
#include <pipewire/stream.h>
|
||||
#include <pipewire/keys.h>
|
||||
|
||||
#include <spa/param/video/format-utils.h>
|
||||
#include <spa/debug/types.h>
|
||||
|
||||
void storeRestoreToken(const gchar* oldToken, const gchar* newToken);
|
||||
|
||||
struct ScreenProps {
|
||||
guint32 id;
|
||||
GdkRectangle bounds;
|
||||
|
||||
GdkRectangle captureArea;
|
||||
struct PwStreamData *data;
|
||||
|
||||
gchar *captureData;
|
||||
volatile gboolean shouldCapture;
|
||||
volatile gboolean captureDataReady;
|
||||
};
|
||||
|
||||
|
||||
#define SCREEN_SPACE_DEFAULT_ALLOCATED 2
|
||||
struct ScreenSpace {
|
||||
struct ScreenProps *screens;
|
||||
int screenCount;
|
||||
int allocated;
|
||||
};
|
||||
|
||||
#define DEBUG_SCREENCAST(FORMAT, ...) debug_screencast("%s:%i " FORMAT, \
|
||||
__func__, __LINE__, __VA_ARGS__);
|
||||
|
||||
#define DEBUG_SCREEN(SCREEN) \
|
||||
DEBUG_SCREENCAST("screenId#%i\n" \
|
||||
"||\tbounds x %5i y %5i w %5i h %5i\n" \
|
||||
"||\tcapture area x %5i y %5i w %5i h %5i shouldCapture %i\n\n", \
|
||||
(SCREEN)->id, \
|
||||
(SCREEN)->bounds.x, (SCREEN)->bounds.y, \
|
||||
(SCREEN)->bounds.width, (SCREEN)->bounds.height, \
|
||||
(SCREEN)->captureArea.x, (SCREEN)->captureArea.y, \
|
||||
(SCREEN)->captureArea.width, (SCREEN)->captureArea.height, \
|
||||
(SCREEN)->shouldCapture);
|
||||
|
||||
#define DEBUG_SCREEN_PREFIX(SCREEN, FORMAT, ...) \
|
||||
DEBUG_SCREENCAST("screenId#%i[loc(%d,%d) size(%dx%d)] "FORMAT, \
|
||||
(SCREEN)->id, (SCREEN)->bounds.x, (SCREEN)->bounds.y, \
|
||||
(SCREEN)->bounds.width, (SCREEN)->bounds.height, __VA_ARGS__);
|
||||
|
||||
#define ERR(MSG) fprintf(stderr, "%s:%i " MSG, __func__, __LINE__);
|
||||
#define ERR_HANDLE(ERROR) errHandle((ERROR), __func__, __LINE__);
|
||||
|
||||
struct PwLoopData {
|
||||
struct pw_thread_loop *loop;
|
||||
struct pw_context *context;
|
||||
struct pw_core *core;
|
||||
struct spa_hook coreListener;
|
||||
int pwFd; //negative values can also be used to store a failure reason
|
||||
};
|
||||
|
||||
struct PwStreamData {
|
||||
struct pw_stream *stream;
|
||||
struct spa_hook streamListener;
|
||||
|
||||
struct spa_video_info_raw rawFormat;
|
||||
struct ScreenProps *screenProps;
|
||||
|
||||
gboolean hasFormat;
|
||||
};
|
||||
|
||||
#endif //_SCREENCAST_PIPEWIRE_H
|
905
src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c
Normal file
905
src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c
Normal file
@ -0,0 +1,905 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "stdlib.h"
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include "screencast_pipewire.h"
|
||||
#include "screencast_portal.h"
|
||||
|
||||
|
||||
extern struct ScreenSpace screenSpace;
|
||||
|
||||
struct XdgDesktopPortalApi *portal = NULL;
|
||||
|
||||
void errHandle(
|
||||
GError *error,
|
||||
const gchar *functionName,
|
||||
int lineNum
|
||||
) {
|
||||
if (error) {
|
||||
fprintf(stderr, "!!! %s:%i Error: domain %i code %i message: \"%s\"\n",
|
||||
functionName, lineNum,
|
||||
error->domain, error->code, error->message);
|
||||
}
|
||||
if (error) {
|
||||
gtk->g_error_free(error);
|
||||
}
|
||||
error = NULL;
|
||||
}
|
||||
|
||||
gboolean validateToken(const gchar *token) {
|
||||
if (!token) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean isValid = gtk->g_uuid_string_is_valid(token);
|
||||
if (!isValid) {
|
||||
DEBUG_SCREENCAST("!!! restore token "
|
||||
"is not a valid UUID string:\n\"%s\"\n",
|
||||
token);
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TRUE on success
|
||||
*/
|
||||
gboolean rebuildScreenData(GVariantIter *iterStreams, gboolean isTheOnlyMon) {
|
||||
guint32 nodeID;
|
||||
GVariant* prop = NULL;
|
||||
|
||||
int screenIndex = 0;
|
||||
|
||||
gboolean hasFailures = FALSE;
|
||||
|
||||
while (gtk->g_variant_iter_loop(
|
||||
iterStreams,
|
||||
"(u@a{sv})",
|
||||
&nodeID,
|
||||
&prop
|
||||
)) {
|
||||
DEBUG_SCREENCAST("\n==== screenId#%i\n", nodeID);
|
||||
|
||||
if (screenIndex >= screenSpace.allocated) {
|
||||
screenSpace.screens = realloc(
|
||||
screenSpace.screens,
|
||||
++screenSpace.allocated * sizeof(struct ScreenProps)
|
||||
);
|
||||
if (!screenSpace.screens) {
|
||||
ERR("failed to allocate memory\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
struct ScreenProps * screen = &screenSpace.screens[screenIndex];
|
||||
memset(screen, 0, sizeof(struct ScreenProps));
|
||||
|
||||
screenSpace.screenCount = screenIndex + 1;
|
||||
|
||||
screen->id = nodeID;
|
||||
|
||||
if (
|
||||
!gtk->g_variant_lookup(
|
||||
prop,
|
||||
"size",
|
||||
"(ii)",
|
||||
&screen->bounds.width,
|
||||
&screen->bounds.height
|
||||
)
|
||||
|| (
|
||||
!gtk->g_variant_lookup(
|
||||
prop,
|
||||
"position",
|
||||
"(ii)",
|
||||
&screen->bounds.x,
|
||||
&screen->bounds.y
|
||||
)
|
||||
//Screen position is not specified in some cases
|
||||
//(e.g. on Plasma).
|
||||
//In this case, proceed only if there is only one screen.
|
||||
&& !isTheOnlyMon
|
||||
)
|
||||
) {
|
||||
hasFailures = TRUE;
|
||||
}
|
||||
|
||||
DEBUG_SCREENCAST("-----------------------\n", NULL);
|
||||
DEBUG_SCREEN(screen);
|
||||
DEBUG_SCREENCAST("#---------------------#\n\n", NULL);
|
||||
|
||||
gtk->g_variant_unref(prop);
|
||||
screenIndex++;
|
||||
};
|
||||
|
||||
if (hasFailures) {
|
||||
DEBUG_SCREENCAST("screenId#%i hasFailures\n", nodeID);
|
||||
}
|
||||
|
||||
return !hasFailures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks screencast protocol version
|
||||
* @return FALSE if version < 4, or could not be determined
|
||||
*/
|
||||
gboolean checkVersion() {
|
||||
static guint32 version = 0;
|
||||
if (version == 0) {
|
||||
GError *error = NULL;
|
||||
GVariant *retVersion = gtk->g_dbus_proxy_call_sync(
|
||||
portal->screenCastProxy,
|
||||
"org.freedesktop.DBus.Properties.Get",
|
||||
gtk->g_variant_new("(ss)",
|
||||
"org.freedesktop.portal.ScreenCast",
|
||||
"version"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, NULL, NULL
|
||||
);
|
||||
|
||||
if (!retVersion) { //no backend on system
|
||||
DEBUG_SCREENCAST("!!! could not detect the screencast version\n",
|
||||
NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ERR_HANDLE(error);
|
||||
|
||||
GVariant *varVersion = NULL;
|
||||
gtk->g_variant_get(retVersion, "(v)", &varVersion);
|
||||
|
||||
if (!varVersion){
|
||||
gtk->g_variant_unref(retVersion);
|
||||
DEBUG_SCREENCAST("!!! could not get the screencast version\n",
|
||||
NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
version = gtk->g_variant_get_uint32(varVersion);
|
||||
|
||||
gtk->g_variant_unref(varVersion);
|
||||
gtk->g_variant_unref(retVersion);
|
||||
|
||||
}
|
||||
|
||||
DEBUG_SCREENCAST("ScreenCast protocol version %d\n", version);
|
||||
if (version < 4) {
|
||||
DEBUG_SCREENCAST("!!! ScreenCast protocol version %d < 4,"
|
||||
" session restore is not available\n",
|
||||
version);
|
||||
}
|
||||
|
||||
// restore_token was added in version 4, without it,
|
||||
// user confirmation is required for every screenshot.
|
||||
return version >= 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TRUE on success
|
||||
*/
|
||||
gboolean initXdgDesktopPortal() {
|
||||
portal = calloc(1, sizeof(*portal));
|
||||
|
||||
if (!portal) {
|
||||
ERR("failed to allocate memory\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GError* err = NULL;
|
||||
|
||||
portal->connection = gtk->g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err);
|
||||
|
||||
if (err) {
|
||||
ERR_HANDLE(err);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const gchar *name = gtk
|
||||
->g_dbus_connection_get_unique_name(portal->connection);
|
||||
if (!name) {
|
||||
ERR("Failed to get unique connection name\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GString * nameStr = gtk->g_string_new(name);
|
||||
gtk->g_string_erase(nameStr, 0, 1); //remove leading colon ":"
|
||||
gtk->g_string_replace(nameStr, ".", "_", 0);
|
||||
portal->senderName = nameStr->str;
|
||||
|
||||
gtk->g_string_free(nameStr, FALSE);
|
||||
|
||||
DEBUG_SCREENCAST("connection/sender name %s / %s\n",
|
||||
name,
|
||||
portal->senderName);
|
||||
|
||||
portal->screenCastProxy = gtk->g_dbus_proxy_new_sync(
|
||||
portal->connection,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
"org.freedesktop.portal.Desktop",
|
||||
"/org/freedesktop/portal/desktop",
|
||||
"org.freedesktop.portal.ScreenCast",
|
||||
NULL,
|
||||
&err
|
||||
);
|
||||
|
||||
if (err) {
|
||||
DEBUG_SCREENCAST("Failed to get ScreenCast portal: %s", err->message);
|
||||
ERR_HANDLE(err);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return checkVersion();
|
||||
}
|
||||
|
||||
static void updateRequestPath(
|
||||
gchar **path,
|
||||
gchar **token
|
||||
) {
|
||||
static uint64_t counter = 0;
|
||||
++counter;
|
||||
|
||||
GString *tokenStr = gtk->g_string_new(NULL);
|
||||
gtk->g_string_printf(
|
||||
tokenStr,
|
||||
PORTAL_TOKEN_TEMPLATE,
|
||||
counter
|
||||
);
|
||||
|
||||
*token = tokenStr->str;
|
||||
gtk->g_string_free(tokenStr, FALSE);
|
||||
|
||||
GString *pathStr = gtk->g_string_new(NULL);
|
||||
|
||||
gtk->g_string_printf(
|
||||
pathStr,
|
||||
PORTAL_REQUEST_TEMPLATE,
|
||||
portal->senderName,
|
||||
counter
|
||||
);
|
||||
|
||||
*path = pathStr->str;
|
||||
gtk->g_string_free(pathStr, FALSE);
|
||||
}
|
||||
|
||||
static void updateSessionToken(
|
||||
gchar **token
|
||||
) {
|
||||
static uint64_t counter = 0;
|
||||
counter++;
|
||||
|
||||
GString *tokenStr = gtk->g_string_new(NULL);
|
||||
|
||||
gtk->g_string_printf(
|
||||
tokenStr,
|
||||
PORTAL_TOKEN_TEMPLATE,
|
||||
counter
|
||||
);
|
||||
|
||||
*token = tokenStr->str;
|
||||
gtk->g_string_free(tokenStr, FALSE);
|
||||
}
|
||||
|
||||
static void registerScreenCastCallback(
|
||||
const char *path,
|
||||
struct DBusCallbackHelper *helper,
|
||||
GDBusSignalCallback callback
|
||||
) {
|
||||
helper->id = gtk->g_dbus_connection_signal_subscribe(
|
||||
portal->connection,
|
||||
"org.freedesktop.portal.Desktop",
|
||||
"org.freedesktop.portal.Request",
|
||||
"Response",
|
||||
path,
|
||||
NULL,
|
||||
G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
|
||||
callback,
|
||||
helper,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
static void unregisterScreenCastCallback(
|
||||
struct DBusCallbackHelper *helper
|
||||
) {
|
||||
if (helper->id) {
|
||||
gtk->g_dbus_connection_signal_unsubscribe(
|
||||
portal->connection,
|
||||
helper->id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void callbackScreenCastCreateSession(
|
||||
GDBusConnection *connection,
|
||||
const char *senderName,
|
||||
const char *objectPath,
|
||||
const char *interfaceName,
|
||||
const char *signalName,
|
||||
GVariant *parameters,
|
||||
void *data
|
||||
) {
|
||||
struct DBusCallbackHelper *helper = data;
|
||||
uint32_t status;
|
||||
GVariant *result = NULL;
|
||||
|
||||
gtk->g_variant_get(
|
||||
parameters,
|
||||
"(u@a{sv})",
|
||||
&status,
|
||||
&result
|
||||
);
|
||||
|
||||
if (status != 0) {
|
||||
DEBUG_SCREENCAST("Failed to create ScreenCast: %u\n", status);
|
||||
} else {
|
||||
gtk->g_variant_lookup(result, "session_handle", "s", helper->data);
|
||||
}
|
||||
|
||||
helper->isDone = TRUE;
|
||||
}
|
||||
|
||||
gboolean portalScreenCastCreateSession() {
|
||||
GError *err = NULL;
|
||||
|
||||
gchar *requestPath = NULL;
|
||||
gchar *requestToken = NULL;
|
||||
gchar *sessionToken = NULL;
|
||||
|
||||
struct DBusCallbackHelper helper = {
|
||||
.id = 0,
|
||||
.data = &portal->screenCastSessionHandle
|
||||
};
|
||||
|
||||
updateRequestPath(
|
||||
&requestPath,
|
||||
&requestToken
|
||||
);
|
||||
updateSessionToken(&sessionToken);
|
||||
|
||||
portal->screenCastSessionHandle = NULL;
|
||||
|
||||
registerScreenCastCallback(
|
||||
requestPath,
|
||||
&helper,
|
||||
callbackScreenCastCreateSession
|
||||
);
|
||||
|
||||
GVariantBuilder builder;
|
||||
|
||||
gtk->g_variant_builder_init(
|
||||
&builder,
|
||||
G_VARIANT_TYPE_VARDICT
|
||||
);
|
||||
|
||||
gtk->g_variant_builder_add(
|
||||
&builder,
|
||||
"{sv}",
|
||||
"handle_token",
|
||||
gtk->g_variant_new_string(requestToken)
|
||||
);
|
||||
|
||||
gtk->g_variant_builder_add(
|
||||
&builder,
|
||||
"{sv}",
|
||||
"session_handle_token",
|
||||
gtk->g_variant_new_string(sessionToken)
|
||||
);
|
||||
|
||||
GVariant *response = gtk->g_dbus_proxy_call_sync(
|
||||
portal->screenCastProxy,
|
||||
"CreateSession",
|
||||
gtk->g_variant_new("(a{sv})", &builder),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&err
|
||||
);
|
||||
|
||||
if (err) {
|
||||
DEBUG_SCREENCAST("Failed to create ScreenCast session: %s\n",
|
||||
err->message);
|
||||
ERR_HANDLE(err);
|
||||
} else {
|
||||
while (!helper.isDone) {
|
||||
gtk->g_main_context_iteration(NULL, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
unregisterScreenCastCallback(&helper);
|
||||
if (response) {
|
||||
gtk->g_variant_unref(response);
|
||||
}
|
||||
|
||||
free(sessionToken);
|
||||
free(requestPath);
|
||||
free(requestToken);
|
||||
|
||||
return portal->screenCastSessionHandle != NULL;
|
||||
}
|
||||
|
||||
static void callbackScreenCastSelectSources(
|
||||
GDBusConnection *connection,
|
||||
const char *senderName,
|
||||
const char *objectPath,
|
||||
const char *interfaceName,
|
||||
const char *signalName,
|
||||
GVariant *parameters,
|
||||
void *data
|
||||
) {
|
||||
struct DBusCallbackHelper *helper = data;
|
||||
|
||||
helper->data = (void *) 0;
|
||||
|
||||
uint32_t status;
|
||||
GVariant* result = NULL;
|
||||
|
||||
gtk->g_variant_get(parameters, "(u@a{sv})", &status, &result);
|
||||
|
||||
if (status != 0) {
|
||||
DEBUG_SCREENCAST("Failed select sources: %u\n", status);
|
||||
} else {
|
||||
helper->data = (void *) 1;
|
||||
}
|
||||
|
||||
helper->isDone = TRUE;
|
||||
|
||||
if (result) {
|
||||
gtk->g_variant_unref(result);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean portalScreenCastSelectSources(const gchar *token) {
|
||||
GError* err = NULL;
|
||||
|
||||
gchar *requestPath = NULL;
|
||||
gchar *requestToken = NULL;
|
||||
|
||||
struct DBusCallbackHelper helper = {0};
|
||||
|
||||
updateRequestPath(
|
||||
&requestPath,
|
||||
&requestToken
|
||||
);
|
||||
|
||||
registerScreenCastCallback(
|
||||
requestPath,
|
||||
&helper,
|
||||
callbackScreenCastSelectSources
|
||||
);
|
||||
|
||||
GVariantBuilder builder;
|
||||
|
||||
gtk->g_variant_builder_init(
|
||||
&builder,
|
||||
G_VARIANT_TYPE_VARDICT
|
||||
);
|
||||
|
||||
gtk->g_variant_builder_add(
|
||||
&builder,
|
||||
"{sv}", "handle_token",
|
||||
gtk->g_variant_new_string(requestToken)
|
||||
);
|
||||
|
||||
gtk->g_variant_builder_add(
|
||||
&builder,
|
||||
"{sv}", "multiple",
|
||||
gtk->g_variant_new_boolean(TRUE));
|
||||
|
||||
// 1: MONITOR
|
||||
// 2: WINDOW
|
||||
// 4: VIRTUAL
|
||||
gtk->g_variant_builder_add(
|
||||
&builder, "{sv}", "types",
|
||||
gtk->g_variant_new_uint32(1)
|
||||
);
|
||||
|
||||
// 0: Do not persist (default)
|
||||
// 1: Permissions persist as long as the application is running
|
||||
// 2: Permissions persist until explicitly revoked
|
||||
gtk->g_variant_builder_add(
|
||||
&builder,
|
||||
"{sv}",
|
||||
"persist_mode",
|
||||
gtk->g_variant_new_uint32(2)
|
||||
);
|
||||
|
||||
if (validateToken(token)) {
|
||||
gtk->g_variant_builder_add(
|
||||
&builder,
|
||||
"{sv}",
|
||||
"restore_token",
|
||||
gtk->g_variant_new_string(token)
|
||||
);
|
||||
}
|
||||
|
||||
GVariant *response = gtk->g_dbus_proxy_call_sync(
|
||||
portal->screenCastProxy,
|
||||
"SelectSources",
|
||||
gtk->g_variant_new("(oa{sv})", portal->screenCastSessionHandle, &builder),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&err
|
||||
);
|
||||
|
||||
if (err) {
|
||||
DEBUG_SCREENCAST("Failed to call SelectSources: %s\n", err->message);
|
||||
ERR_HANDLE(err);
|
||||
} else {
|
||||
while (!helper.isDone) {
|
||||
gtk->g_main_context_iteration(NULL, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
unregisterScreenCastCallback(&helper);
|
||||
if (response) {
|
||||
gtk->g_variant_unref(response);
|
||||
}
|
||||
|
||||
free(requestPath);
|
||||
free(requestToken);
|
||||
|
||||
return helper.data != NULL;
|
||||
}
|
||||
|
||||
static void callbackScreenCastStart(
|
||||
GDBusConnection *connection,
|
||||
const char *senderName,
|
||||
const char *objectPath,
|
||||
const char *interfaceName,
|
||||
const char *signalName,
|
||||
GVariant *parameters,
|
||||
void *data
|
||||
) {
|
||||
struct DBusCallbackHelper *helper = data;
|
||||
struct StartHelper *startHelper = helper->data;
|
||||
|
||||
uint32_t status;
|
||||
GVariant* result = NULL;
|
||||
const gchar *oldToken = startHelper->token;
|
||||
|
||||
gtk->g_variant_get(parameters, "(u@a{sv})", &status, &result);
|
||||
|
||||
if (status != 0) {
|
||||
// Cancel pressed on the system dialog
|
||||
DEBUG_SCREENCAST("Failed to start screencast: %u\n", status);
|
||||
startHelper->result = RESULT_DENIED;
|
||||
helper->isDone = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
GVariant *streams = gtk->g_variant_lookup_value(
|
||||
result,
|
||||
"streams",
|
||||
G_VARIANT_TYPE_ARRAY
|
||||
);
|
||||
|
||||
GVariantIter iter;
|
||||
gtk->g_variant_iter_init(
|
||||
&iter,
|
||||
streams
|
||||
);
|
||||
|
||||
size_t count = gtk->g_variant_iter_n_children(&iter);
|
||||
|
||||
DEBUG_SCREENCAST("available screen count %i\n", count);
|
||||
|
||||
startHelper->result = (rebuildScreenData(&iter, count == 1))
|
||||
? RESULT_OK
|
||||
: RESULT_ERROR;
|
||||
|
||||
DEBUG_SCREENCAST("rebuildScreenData result |%i|\n", startHelper->result);
|
||||
|
||||
if (startHelper->result == RESULT_OK) {
|
||||
GVariant *restoreTokenVar = gtk->g_variant_lookup_value(
|
||||
result,
|
||||
"restore_token",
|
||||
G_VARIANT_TYPE_STRING
|
||||
);
|
||||
|
||||
if (restoreTokenVar) {
|
||||
gsize len;
|
||||
const gchar *newToken = gtk->
|
||||
g_variant_get_string(restoreTokenVar, &len);
|
||||
DEBUG_SCREENCAST("restore_token |%s|\n", newToken);
|
||||
|
||||
storeRestoreToken(oldToken, newToken);
|
||||
|
||||
gtk->g_variant_unref(restoreTokenVar);
|
||||
}
|
||||
}
|
||||
|
||||
helper->isDone = TRUE;
|
||||
|
||||
if (streams) {
|
||||
gtk->g_variant_unref(streams);
|
||||
}
|
||||
}
|
||||
|
||||
ScreenCastResult portalScreenCastStart(const gchar *token) {
|
||||
GError *err = NULL;
|
||||
|
||||
gchar *requestPath = NULL;
|
||||
gchar *requestToken = NULL;
|
||||
|
||||
struct StartHelper startHelper = { 0 };
|
||||
startHelper.token = token;
|
||||
|
||||
struct DBusCallbackHelper helper = { 0 };
|
||||
helper.data = &startHelper;
|
||||
|
||||
updateRequestPath(
|
||||
&requestPath,
|
||||
&requestToken
|
||||
);
|
||||
|
||||
registerScreenCastCallback(
|
||||
requestPath,
|
||||
&helper,
|
||||
callbackScreenCastStart
|
||||
);
|
||||
|
||||
GVariantBuilder builder;
|
||||
|
||||
gtk->g_variant_builder_init(
|
||||
&builder,
|
||||
G_VARIANT_TYPE_VARDICT
|
||||
);
|
||||
|
||||
gtk->g_variant_builder_add(
|
||||
&builder,
|
||||
"{sv}",
|
||||
"handle_token",
|
||||
gtk->g_variant_new_string(requestToken)
|
||||
);
|
||||
|
||||
GVariant *response = gtk->g_dbus_proxy_call_sync(
|
||||
portal->screenCastProxy,
|
||||
"Start",
|
||||
gtk->g_variant_new("(osa{sv})", portal->screenCastSessionHandle, "", &builder),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&err
|
||||
);
|
||||
|
||||
if (err) {
|
||||
DEBUG_SCREENCAST("Failed to start session: %s\n", err->message);
|
||||
ERR_HANDLE(err);
|
||||
} else {
|
||||
while (!helper.isDone) {
|
||||
gtk->g_main_context_iteration(NULL, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
unregisterScreenCastCallback(&helper);
|
||||
if (response) {
|
||||
gtk->g_variant_unref(response);
|
||||
}
|
||||
|
||||
free(requestPath);
|
||||
free(requestToken);
|
||||
|
||||
DEBUG_SCREENCAST("ScreenCastResult |%i|\n", startHelper.result);
|
||||
|
||||
return startHelper.result;
|
||||
}
|
||||
|
||||
int portalScreenCastOpenPipewireRemote() {
|
||||
GError* err = NULL;
|
||||
GUnixFDList* fdList = NULL;
|
||||
|
||||
GVariantBuilder builder;
|
||||
|
||||
gtk->g_variant_builder_init(
|
||||
&builder, G_VARIANT_TYPE_VARDICT
|
||||
);
|
||||
|
||||
GVariant *response = gtk->g_dbus_proxy_call_with_unix_fd_list_sync(
|
||||
portal->screenCastProxy,
|
||||
"OpenPipeWireRemote",
|
||||
gtk->g_variant_new("(oa{sv})", portal->screenCastSessionHandle, &builder),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&fdList,
|
||||
NULL,
|
||||
&err
|
||||
);
|
||||
|
||||
if (err || !response) {
|
||||
DEBUG_SCREENCAST("Failed to call OpenPipeWireRemote on session: %s\n",
|
||||
err->message);
|
||||
ERR_HANDLE(err);
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
|
||||
gint32 index;
|
||||
gtk->g_variant_get(
|
||||
response,
|
||||
"(h)",
|
||||
&index,
|
||||
&err
|
||||
);
|
||||
|
||||
gtk->g_variant_unref(response);
|
||||
|
||||
if (err) {
|
||||
DEBUG_SCREENCAST("Failed to get pipewire fd index: %s\n",
|
||||
err->message);
|
||||
ERR_HANDLE(err);
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
|
||||
int fd = gtk->g_unix_fd_list_get(
|
||||
fdList,
|
||||
index,
|
||||
&err
|
||||
);
|
||||
|
||||
if (fdList) {
|
||||
gtk->g_object_unref(fdList);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
DEBUG_SCREENCAST("Failed to get pipewire fd: %s\n", err->message);
|
||||
ERR_HANDLE(err);
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void portalScreenCastCleanup() {
|
||||
if (portal->screenCastSessionHandle) {
|
||||
gtk->g_dbus_connection_call_sync(
|
||||
portal->connection,
|
||||
"org.freedesktop.portal.Desktop",
|
||||
portal->screenCastSessionHandle,
|
||||
"org.freedesktop.portal.Session",
|
||||
"Close",
|
||||
NULL,
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
gtk->g_free(portal->screenCastSessionHandle);
|
||||
portal->screenCastSessionHandle = NULL;
|
||||
}
|
||||
|
||||
if (!portal) {
|
||||
return;
|
||||
}
|
||||
if (portal->connection) {
|
||||
gtk->g_object_unref(portal->connection);
|
||||
portal->connection = NULL;
|
||||
}
|
||||
|
||||
if (portal->screenCastProxy) {
|
||||
gtk->g_object_unref(portal->screenCastProxy);
|
||||
portal->screenCastProxy = NULL;
|
||||
}
|
||||
|
||||
if (portal->senderName) {
|
||||
free(portal->senderName);
|
||||
portal->senderName = NULL;
|
||||
}
|
||||
|
||||
free(portal);
|
||||
portal = NULL;
|
||||
}
|
||||
|
||||
gboolean rectanglesEqual(GdkRectangle rect1, GdkRectangle rect2) {
|
||||
return rect1.x == rect2.x
|
||||
&& rect1.y == rect2.y
|
||||
&& rect1.width == rect2.width
|
||||
&& rect1.height == rect2.height;
|
||||
}
|
||||
|
||||
gboolean checkCanCaptureAllRequiredScreens(GdkRectangle *affectedBounds,
|
||||
gint affectedBoundsLength) {
|
||||
|
||||
|
||||
if (affectedBoundsLength > screenSpace.screenCount) {
|
||||
DEBUG_SCREENCAST("Requested screen count is greater "
|
||||
"than allowed with token (%i > %i)\n",
|
||||
affectedBoundsLength, screenSpace.screenCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < affectedBoundsLength; ++i) {
|
||||
gboolean found = false;
|
||||
GdkRectangle affBounds = affectedBounds[i];
|
||||
for (int j = 0; j < screenSpace.screenCount; ++j) {
|
||||
GdkRectangle allowedBounds = screenSpace.screens[j].bounds;
|
||||
|
||||
if (rectanglesEqual(allowedBounds, affBounds)) {
|
||||
DEBUG_SCREENCAST("Found allowed screen bounds in affected "
|
||||
"screen bounds %i %i %i %i\n",
|
||||
affBounds.x, affBounds.y,
|
||||
affBounds.width, affBounds.height);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
DEBUG_SCREENCAST("Could not find required screen %i %i %i %i "
|
||||
"in allowed bounds\n",
|
||||
affBounds.x, affBounds.y,
|
||||
affBounds.width, affBounds.height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int getPipewireFd(const gchar *token,
|
||||
GdkRectangle *affectedBounds,
|
||||
gint affectedBoundsLength) {
|
||||
if (!portalScreenCastCreateSession()) {
|
||||
DEBUG_SCREENCAST("Failed to create ScreenCast session\n", NULL);
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (!portalScreenCastSelectSources(token)) {
|
||||
DEBUG_SCREENCAST("Failed to select sources\n", NULL);
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
|
||||
ScreenCastResult startResult = portalScreenCastStart(token);
|
||||
DEBUG_SCREENCAST("portalScreenCastStart result |%i|\n", startResult);
|
||||
if (startResult != RESULT_OK) {
|
||||
DEBUG_SCREENCAST("Failed to start\n", NULL);
|
||||
return startResult;
|
||||
} else {
|
||||
if (!checkCanCaptureAllRequiredScreens(affectedBounds,
|
||||
affectedBoundsLength)) {
|
||||
DEBUG_SCREENCAST("The location of the screens has changed, "
|
||||
"the capture area is outside the allowed "
|
||||
"area.\n", NULL)
|
||||
return RESULT_OUT_OF_BOUNDS;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_SCREENCAST("--- portalScreenCastStart\n", NULL);
|
||||
|
||||
int pipewireFd = portalScreenCastOpenPipewireRemote();
|
||||
if (pipewireFd < 0) {
|
||||
DEBUG_SCREENCAST("!!! Failed to get pipewire fd\n", NULL);
|
||||
}
|
||||
|
||||
DEBUG_SCREENCAST("pwFd %i\n", pipewireFd);
|
||||
return pipewireFd;
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifdef HEADLESS
|
||||
#error This file should not be included in headless library
|
||||
#endif
|
||||
|
||||
#ifndef _SCREENCAST_PORTAL_H
|
||||
#define _SCREENCAST_PORTAL_H
|
||||
|
||||
#include "gtk_interface.h"
|
||||
|
||||
#define PORTAL_TOKEN_TEMPLATE "awtPipewire%lu"
|
||||
#define PORTAL_REQUEST_TEMPLATE "/org/freedesktop/portal/desktop/" \
|
||||
"request/%s/awtPipewire%lu"
|
||||
|
||||
void debug_screencast(const char *__restrict fmt, ...);
|
||||
|
||||
int getPipewireFd(const gchar *token,
|
||||
GdkRectangle *affectedBounds,
|
||||
gint affectedBoundsLength);
|
||||
|
||||
void portalScreenCastCleanup();
|
||||
|
||||
gboolean initXdgDesktopPortal();
|
||||
|
||||
void errHandle(GError *error, const gchar *functionName, int lineNum);
|
||||
|
||||
struct XdgDesktopPortalApi {
|
||||
GDBusConnection *connection;
|
||||
GDBusProxy *screenCastProxy;
|
||||
gchar *senderName;
|
||||
char *screenCastSessionHandle;
|
||||
};
|
||||
|
||||
struct DBusCallbackHelper {
|
||||
guint id;
|
||||
void *data;
|
||||
gboolean isDone;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
RESULT_OK = 0,
|
||||
RESULT_ERROR = -1,
|
||||
RESULT_DENIED = -11,
|
||||
RESULT_OUT_OF_BOUNDS = -12,
|
||||
} ScreenCastResult;
|
||||
|
||||
struct StartHelper {
|
||||
const gchar *token;
|
||||
ScreenCastResult result;
|
||||
};
|
||||
|
||||
#endif //_SCREENCAST_PORTAL_H
|
@ -0,0 +1,175 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_CONTEXT_H
|
||||
#define PIPEWIRE_CONTEXT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/hook.h>
|
||||
|
||||
/** \defgroup pw_context Context
|
||||
*
|
||||
* \brief The PipeWire context object manages all locally available
|
||||
* resources. It is used by both clients and servers.
|
||||
*
|
||||
* The context is used to:
|
||||
*
|
||||
* - Load modules and extend the functionality. This includes
|
||||
* extending the protocol with new object types or creating
|
||||
* any of the available objects.
|
||||
*
|
||||
* - Create implementations of various objects like nodes,
|
||||
* devices, factories, modules, etc.. This will usually also
|
||||
* create pw_global objects that can then be shared with
|
||||
* clients.
|
||||
*
|
||||
* - Connect to another PipeWire instance (the main daemon, for
|
||||
* example) and interact with it (See \ref page_core_api).
|
||||
*
|
||||
* - Export a local implementation of an object to another
|
||||
* instance.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_context
|
||||
* @{
|
||||
*/
|
||||
struct pw_context;
|
||||
|
||||
struct pw_global;
|
||||
struct pw_impl_client;
|
||||
|
||||
#include <pipewire/core.h>
|
||||
#include <pipewire/loop.h>
|
||||
#include <pipewire/properties.h>
|
||||
|
||||
/** context events emitted by the context object added with \ref pw_context_add_listener */
|
||||
struct pw_context_events {
|
||||
#define PW_VERSION_CONTEXT_EVENTS 0
|
||||
uint32_t version;
|
||||
|
||||
/** The context is being destroyed */
|
||||
void (*destroy) (void *data);
|
||||
/** The context is being freed */
|
||||
void (*free) (void *data);
|
||||
/** a new client object is added */
|
||||
void (*check_access) (void *data, struct pw_impl_client *client);
|
||||
/** a new global object was added */
|
||||
void (*global_added) (void *data, struct pw_global *global);
|
||||
/** a global object was removed */
|
||||
void (*global_removed) (void *data, struct pw_global *global);
|
||||
};
|
||||
|
||||
/** Make a new context object for a given main_loop. Ownership of the properties is taken */
|
||||
struct pw_context * pw_context_new(struct pw_loop *main_loop, /**< a main loop to run in */
|
||||
struct pw_properties *props, /**< extra properties */
|
||||
size_t user_data_size /**< extra user data size */);
|
||||
|
||||
/** destroy a context object, all resources except the main_loop will be destroyed */
|
||||
void pw_context_destroy(struct pw_context *context);
|
||||
|
||||
/** Get the context user data */
|
||||
void *pw_context_get_user_data(struct pw_context *context);
|
||||
|
||||
/** Add a new event listener to a context */
|
||||
void pw_context_add_listener(struct pw_context *context,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_context_events *events,
|
||||
void *data);
|
||||
|
||||
/** Get the context properties */
|
||||
const struct pw_properties *pw_context_get_properties(struct pw_context *context);
|
||||
|
||||
/** Update the context properties */
|
||||
int pw_context_update_properties(struct pw_context *context, const struct spa_dict *dict);
|
||||
|
||||
/** Get a config section for this context. Since 0.3.22, deprecated,
|
||||
* use pw_context_conf_section_for_each(). */
|
||||
const char *pw_context_get_conf_section(struct pw_context *context, const char *section);
|
||||
/** Parse a standard config section for this context. Since 0.3.22 */
|
||||
int pw_context_parse_conf_section(struct pw_context *context,
|
||||
struct pw_properties *conf, const char *section);
|
||||
|
||||
/** update properties from a section into props. Since 0.3.45 */
|
||||
int pw_context_conf_update_props(struct pw_context *context, const char *section,
|
||||
struct pw_properties *props);
|
||||
/** emit callback for all config sections. Since 0.3.45 */
|
||||
int pw_context_conf_section_for_each(struct pw_context *context, const char *section,
|
||||
int (*callback) (void *data, const char *location, const char *section,
|
||||
const char *str, size_t len),
|
||||
void *data);
|
||||
/** emit callback for all matched properties. Since 0.3.46 */
|
||||
int pw_context_conf_section_match_rules(struct pw_context *context, const char *section,
|
||||
const struct spa_dict *props,
|
||||
int (*callback) (void *data, const char *location, const char *action,
|
||||
const char *str, size_t len),
|
||||
void *data);
|
||||
|
||||
/** Get the context support objects */
|
||||
const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support);
|
||||
|
||||
/** get the context main loop */
|
||||
struct pw_loop *pw_context_get_main_loop(struct pw_context *context);
|
||||
|
||||
/** get the context data loop. Since 0.3.56 */
|
||||
struct pw_data_loop *pw_context_get_data_loop(struct pw_context *context);
|
||||
|
||||
/** Get the work queue from the context: Since 0.3.26 */
|
||||
struct pw_work_queue *pw_context_get_work_queue(struct pw_context *context);
|
||||
|
||||
/** Iterate the globals of the context. The callback should return
|
||||
* 0 to fetch the next item, any other value stops the iteration and returns
|
||||
* the value. When all callbacks return 0, this function returns 0 when all
|
||||
* globals are iterated. */
|
||||
int pw_context_for_each_global(struct pw_context *context,
|
||||
int (*callback) (void *data, struct pw_global *global),
|
||||
void *data);
|
||||
|
||||
/** Find a context global by id */
|
||||
struct pw_global *pw_context_find_global(struct pw_context *context, /**< the context */
|
||||
uint32_t id /**< the global id */);
|
||||
|
||||
/** add a spa library for the given factory_name regex */
|
||||
int pw_context_add_spa_lib(struct pw_context *context, const char *factory_regex, const char *lib);
|
||||
|
||||
/** find the library name for a spa factory */
|
||||
const char * pw_context_find_spa_lib(struct pw_context *context, const char *factory_name);
|
||||
|
||||
struct spa_handle *pw_context_load_spa_handle(struct pw_context *context,
|
||||
const char *factory_name,
|
||||
const struct spa_dict *info);
|
||||
|
||||
|
||||
/** data for registering export functions */
|
||||
struct pw_export_type {
|
||||
struct spa_list link;
|
||||
const char *type;
|
||||
struct pw_proxy * (*func) (struct pw_core *core,
|
||||
const char *type, const struct spa_dict *props, void *object,
|
||||
size_t user_data_size);
|
||||
};
|
||||
|
||||
/** register a type that can be exported on a context_proxy. This is usually used by
|
||||
* extension modules */
|
||||
int pw_context_register_export_type(struct pw_context *context, struct pw_export_type *type);
|
||||
/** find information about registered export type */
|
||||
const struct pw_export_type *pw_context_find_export_type(struct pw_context *context, const char *type);
|
||||
|
||||
/** add an object to the context */
|
||||
int pw_context_set_object(struct pw_context *context, const char *type, void *value);
|
||||
/** get an object from the context */
|
||||
void *pw_context_get_object(struct pw_context *context, const char *type);
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_CONTEXT_H */
|
612
src/java.desktop/unix/native/libpipewire/include/pipewire/core.h
Normal file
612
src/java.desktop/unix/native/libpipewire/include/pipewire/core.h
Normal file
@ -0,0 +1,612 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_CORE_H
|
||||
#define PIPEWIRE_CORE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <spa/utils/hook.h>
|
||||
|
||||
/** \defgroup pw_core Core
|
||||
*
|
||||
* \brief The core global object.
|
||||
*
|
||||
* This is a special singleton object. It is used for internal PipeWire
|
||||
* protocol features. Connecting to a PipeWire instance returns one core
|
||||
* object, the caller should then register event listeners
|
||||
* using \ref pw_core_add_listener.
|
||||
*
|
||||
* Updates to the core object are then provided through the \ref
|
||||
* pw_core_events interface. See \ref page_tutorial2 for an example.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_core
|
||||
* \{
|
||||
*/
|
||||
#define PW_TYPE_INTERFACE_Core PW_TYPE_INFO_INTERFACE_BASE "Core"
|
||||
#define PW_TYPE_INTERFACE_Registry PW_TYPE_INFO_INTERFACE_BASE "Registry"
|
||||
|
||||
#define PW_VERSION_CORE 4
|
||||
struct pw_core;
|
||||
#define PW_VERSION_REGISTRY 3
|
||||
struct pw_registry;
|
||||
|
||||
/** The default remote name to connect to */
|
||||
#define PW_DEFAULT_REMOTE "pipewire-0"
|
||||
|
||||
/** default ID for the core object after connect */
|
||||
#define PW_ID_CORE 0
|
||||
|
||||
/* invalid ID that matches any object when used for permissions */
|
||||
#define PW_ID_ANY (uint32_t)(0xffffffff)
|
||||
|
||||
/** The core information. Extra information may be added in later versions,
|
||||
* clients must not assume a constant struct size */
|
||||
struct pw_core_info {
|
||||
uint32_t id; /**< id of the global */
|
||||
uint32_t cookie; /**< a random cookie for identifying this instance of PipeWire */
|
||||
const char *user_name; /**< name of the user that started the core */
|
||||
const char *host_name; /**< name of the machine the core is running on */
|
||||
const char *version; /**< version of the core */
|
||||
const char *name; /**< name of the core */
|
||||
#define PW_CORE_CHANGE_MASK_PROPS (1 << 0)
|
||||
#define PW_CORE_CHANGE_MASK_ALL ((1 << 1)-1)
|
||||
uint64_t change_mask; /**< bitfield of changed fields since last call */
|
||||
struct spa_dict *props; /**< extra properties */
|
||||
};
|
||||
|
||||
#include <pipewire/context.h>
|
||||
#include <pipewire/properties.h>
|
||||
#include <pipewire/proxy.h>
|
||||
|
||||
/** Update an existing \ref pw_core_info with \a update with reset */
|
||||
struct pw_core_info *
|
||||
pw_core_info_update(struct pw_core_info *info,
|
||||
const struct pw_core_info *update);
|
||||
/** Update an existing \ref pw_core_info with \a update */
|
||||
struct pw_core_info *
|
||||
pw_core_info_merge(struct pw_core_info *info,
|
||||
const struct pw_core_info *update, bool reset);
|
||||
/** Free a \ref pw_core_info */
|
||||
void pw_core_info_free(struct pw_core_info *info);
|
||||
|
||||
/** Core */
|
||||
|
||||
#define PW_CORE_EVENT_INFO 0
|
||||
#define PW_CORE_EVENT_DONE 1
|
||||
#define PW_CORE_EVENT_PING 2
|
||||
#define PW_CORE_EVENT_ERROR 3
|
||||
#define PW_CORE_EVENT_REMOVE_ID 4
|
||||
#define PW_CORE_EVENT_BOUND_ID 5
|
||||
#define PW_CORE_EVENT_ADD_MEM 6
|
||||
#define PW_CORE_EVENT_REMOVE_MEM 7
|
||||
#define PW_CORE_EVENT_BOUND_PROPS 8
|
||||
#define PW_CORE_EVENT_NUM 9
|
||||
|
||||
/** \struct pw_core_events
|
||||
* \brief Core events
|
||||
*/
|
||||
struct pw_core_events {
|
||||
#define PW_VERSION_CORE_EVENTS 1
|
||||
uint32_t version;
|
||||
|
||||
/**
|
||||
* Notify new core info
|
||||
*
|
||||
* This event is emitted when first bound to the core or when the
|
||||
* hello method is called.
|
||||
*
|
||||
* \param info new core info
|
||||
*/
|
||||
void (*info) (void *data, const struct pw_core_info *info);
|
||||
/**
|
||||
* Emit a done event
|
||||
*
|
||||
* The done event is emitted as a result of a sync method with the
|
||||
* same seq number.
|
||||
*
|
||||
* \param seq the seq number passed to the sync method call
|
||||
*/
|
||||
void (*done) (void *data, uint32_t id, int seq);
|
||||
|
||||
/** Emit a ping event
|
||||
*
|
||||
* The client should reply with a pong reply with the same seq
|
||||
* number.
|
||||
*/
|
||||
void (*ping) (void *data, uint32_t id, int seq);
|
||||
|
||||
/**
|
||||
* Fatal error event
|
||||
*
|
||||
* The error event is sent out when a fatal (non-recoverable)
|
||||
* error has occurred. The id argument is the proxy object where
|
||||
* the error occurred, most often in response to a request to that
|
||||
* object. The message is a brief description of the error,
|
||||
* for (debugging) convenience.
|
||||
*
|
||||
* This event is usually also emitted on the proxy object with
|
||||
* \a id.
|
||||
*
|
||||
* \param id object where the error occurred
|
||||
* \param seq the sequence number that generated the error
|
||||
* \param res error code
|
||||
* \param message error description
|
||||
*/
|
||||
void (*error) (void *data, uint32_t id, int seq, int res, const char *message);
|
||||
/**
|
||||
* Remove an object ID
|
||||
*
|
||||
* This event is used internally by the object ID management
|
||||
* logic. When a client deletes an object, the server will send
|
||||
* this event to acknowledge that it has seen the delete request.
|
||||
* When the client receives this event, it will know that it can
|
||||
* safely reuse the object ID.
|
||||
*
|
||||
* \param id deleted object ID
|
||||
*/
|
||||
void (*remove_id) (void *data, uint32_t id);
|
||||
|
||||
/**
|
||||
* Notify an object binding
|
||||
*
|
||||
* This event is emitted when a local object ID is bound to a
|
||||
* global ID. It is emitted before the global becomes visible in the
|
||||
* registry.
|
||||
*
|
||||
* \param id bound object ID
|
||||
* \param global_id the global id bound to
|
||||
*/
|
||||
void (*bound_id) (void *data, uint32_t id, uint32_t global_id);
|
||||
|
||||
/**
|
||||
* Add memory for a client
|
||||
*
|
||||
* Memory is given to a client as \a fd of a certain
|
||||
* memory \a type.
|
||||
*
|
||||
* Further references to this fd will be made with the per memory
|
||||
* unique identifier \a id.
|
||||
*
|
||||
* \param id the unique id of the memory
|
||||
* \param type the memory type, one of enum spa_data_type
|
||||
* \param fd the file descriptor
|
||||
* \param flags extra flags
|
||||
*/
|
||||
void (*add_mem) (void *data, uint32_t id, uint32_t type, int fd, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Remove memory for a client
|
||||
*
|
||||
* \param id the memory id to remove
|
||||
*/
|
||||
void (*remove_mem) (void *data, uint32_t id);
|
||||
|
||||
void (*bound_props) (void *data, uint32_t id, uint32_t global_id, const struct spa_dict *props);
|
||||
};
|
||||
|
||||
#define PW_CORE_METHOD_ADD_LISTENER 0
|
||||
#define PW_CORE_METHOD_HELLO 1
|
||||
#define PW_CORE_METHOD_SYNC 2
|
||||
#define PW_CORE_METHOD_PONG 3
|
||||
#define PW_CORE_METHOD_ERROR 4
|
||||
#define PW_CORE_METHOD_GET_REGISTRY 5
|
||||
#define PW_CORE_METHOD_CREATE_OBJECT 6
|
||||
#define PW_CORE_METHOD_DESTROY 7
|
||||
#define PW_CORE_METHOD_NUM 8
|
||||
|
||||
/**
|
||||
* \struct pw_core_methods
|
||||
* \brief Core methods
|
||||
*
|
||||
* The core global object. This is a singleton object used for
|
||||
* creating new objects in the remote PipeWire instance. It is
|
||||
* also used for internal features.
|
||||
*/
|
||||
struct pw_core_methods {
|
||||
#define PW_VERSION_CORE_METHODS 0
|
||||
uint32_t version;
|
||||
|
||||
int (*add_listener) (void *object,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_core_events *events,
|
||||
void *data);
|
||||
/**
|
||||
* Start a conversation with the server. This will send
|
||||
* the core info and will destroy all resources for the client
|
||||
* (except the core and client resource).
|
||||
*/
|
||||
int (*hello) (void *object, uint32_t version);
|
||||
/**
|
||||
* Do server roundtrip
|
||||
*
|
||||
* Ask the server to emit the 'done' event with \a seq.
|
||||
*
|
||||
* Since methods are handled in-order and events are delivered
|
||||
* in-order, this can be used as a barrier to ensure all previous
|
||||
* methods and the resulting events have been handled.
|
||||
*
|
||||
* \param seq the seq number passed to the done event
|
||||
*/
|
||||
int (*sync) (void *object, uint32_t id, int seq);
|
||||
/**
|
||||
* Reply to a server ping event.
|
||||
*
|
||||
* Reply to the server ping event with the same seq.
|
||||
*
|
||||
* \param seq the seq number received in the ping event
|
||||
*/
|
||||
int (*pong) (void *object, uint32_t id, int seq);
|
||||
/**
|
||||
* Fatal error event
|
||||
*
|
||||
* The error method is sent out when a fatal (non-recoverable)
|
||||
* error has occurred. The id argument is the proxy object where
|
||||
* the error occurred, most often in response to an event on that
|
||||
* object. The message is a brief description of the error,
|
||||
* for (debugging) convenience.
|
||||
*
|
||||
* This method is usually also emitted on the resource object with
|
||||
* \a id.
|
||||
*
|
||||
* \param id object where the error occurred
|
||||
* \param res error code
|
||||
* \param message error description
|
||||
*/
|
||||
int (*error) (void *object, uint32_t id, int seq, int res, const char *message);
|
||||
/**
|
||||
* Get the registry object
|
||||
*
|
||||
* Create a registry object that allows the client to list and bind
|
||||
* the global objects available from the PipeWire server
|
||||
* \param version the client version
|
||||
* \param user_data_size extra size
|
||||
*/
|
||||
struct pw_registry * (*get_registry) (void *object, uint32_t version,
|
||||
size_t user_data_size);
|
||||
|
||||
/**
|
||||
* Create a new object on the PipeWire server from a factory.
|
||||
*
|
||||
* \param factory_name the factory name to use
|
||||
* \param type the interface to bind to
|
||||
* \param version the version of the interface
|
||||
* \param props extra properties
|
||||
* \param user_data_size extra size
|
||||
*/
|
||||
void * (*create_object) (void *object,
|
||||
const char *factory_name,
|
||||
const char *type,
|
||||
uint32_t version,
|
||||
const struct spa_dict *props,
|
||||
size_t user_data_size);
|
||||
/**
|
||||
* Destroy an resource
|
||||
*
|
||||
* Destroy the server resource for the given proxy.
|
||||
*
|
||||
* \param obj the proxy to destroy
|
||||
*/
|
||||
int (*destroy) (void *object, void *proxy);
|
||||
};
|
||||
|
||||
#define pw_core_method(o,method,version,...) \
|
||||
({ \
|
||||
int _res = -ENOTSUP; \
|
||||
spa_interface_call_res((struct spa_interface*)o, \
|
||||
struct pw_core_methods, _res, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
_res; \
|
||||
})
|
||||
|
||||
#define pw_core_add_listener(c,...) pw_core_method(c,add_listener,0,__VA_ARGS__)
|
||||
#define pw_core_hello(c,...) pw_core_method(c,hello,0,__VA_ARGS__)
|
||||
#define pw_core_sync(c,...) pw_core_method(c,sync,0,__VA_ARGS__)
|
||||
#define pw_core_pong(c,...) pw_core_method(c,pong,0,__VA_ARGS__)
|
||||
#define pw_core_error(c,...) pw_core_method(c,error,0,__VA_ARGS__)
|
||||
|
||||
|
||||
static inline
|
||||
SPA_PRINTF_FUNC(5, 0) int
|
||||
pw_core_errorv(struct pw_core *core, uint32_t id, int seq,
|
||||
int res, const char *message, va_list args)
|
||||
{
|
||||
char buffer[1024];
|
||||
vsnprintf(buffer, sizeof(buffer), message, args);
|
||||
buffer[1023] = '\0';
|
||||
return pw_core_error(core, id, seq, res, buffer);
|
||||
}
|
||||
|
||||
static inline
|
||||
SPA_PRINTF_FUNC(5, 6) int
|
||||
pw_core_errorf(struct pw_core *core, uint32_t id, int seq,
|
||||
int res, const char *message, ...)
|
||||
{
|
||||
va_list args;
|
||||
int r;
|
||||
va_start(args, message);
|
||||
r = pw_core_errorv(core, id, seq, res, message, args);
|
||||
va_end(args);
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline struct pw_registry *
|
||||
pw_core_get_registry(struct pw_core *core, uint32_t version, size_t user_data_size)
|
||||
{
|
||||
struct pw_registry *res = NULL;
|
||||
spa_interface_call_res((struct spa_interface*)core,
|
||||
struct pw_core_methods, res,
|
||||
get_registry, 0, version, user_data_size);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
pw_core_create_object(struct pw_core *core,
|
||||
const char *factory_name,
|
||||
const char *type,
|
||||
uint32_t version,
|
||||
const struct spa_dict *props,
|
||||
size_t user_data_size)
|
||||
{
|
||||
void *res = NULL;
|
||||
spa_interface_call_res((struct spa_interface*)core,
|
||||
struct pw_core_methods, res,
|
||||
create_object, 0, factory_name,
|
||||
type, version, props, user_data_size);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define pw_core_destroy(c,...) pw_core_method(c,destroy,0,__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
/** \defgroup pw_registry Registry
|
||||
*
|
||||
* The registry object is a singleton object that keeps track of
|
||||
* global objects on the PipeWire instance. See also \ref pw_global.
|
||||
*
|
||||
* Global objects typically represent an actual object in PipeWire
|
||||
* (for example, a module or node) or they are singleton
|
||||
* objects such as the core.
|
||||
*
|
||||
* When a client creates a registry object, the registry object
|
||||
* will emit a global event for each global currently in the
|
||||
* registry. Globals come and go as a result of device hotplugs or
|
||||
* reconfiguration or other events, and the registry will send out
|
||||
* global and global_remove events to keep the client up to date
|
||||
* with the changes. To mark the end of the initial burst of
|
||||
* events, the client can use the pw_core.sync methosd immediately
|
||||
* after calling pw_core.get_registry.
|
||||
*
|
||||
* A client can bind to a global object by using the bind
|
||||
* request. This creates a client-side proxy that lets the object
|
||||
* emit events to the client and lets the client invoke methods on
|
||||
* the object. See \ref page_proxy
|
||||
*
|
||||
* Clients can also change the permissions of the global objects that
|
||||
* it can see. This is interesting when you want to configure a
|
||||
* pipewire session before handing it to another application. You
|
||||
* can, for example, hide certain existing or new objects or limit
|
||||
* the access permissions on an object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_registry
|
||||
* \{
|
||||
*/
|
||||
|
||||
#define PW_REGISTRY_EVENT_GLOBAL 0
|
||||
#define PW_REGISTRY_EVENT_GLOBAL_REMOVE 1
|
||||
#define PW_REGISTRY_EVENT_NUM 2
|
||||
|
||||
/** Registry events */
|
||||
struct pw_registry_events {
|
||||
#define PW_VERSION_REGISTRY_EVENTS 0
|
||||
uint32_t version;
|
||||
/**
|
||||
* Notify of a new global object
|
||||
*
|
||||
* The registry emits this event when a new global object is
|
||||
* available.
|
||||
*
|
||||
* \param id the global object id
|
||||
* \param permissions the permissions of the object
|
||||
* \param type the type of the interface
|
||||
* \param version the version of the interface
|
||||
* \param props extra properties of the global
|
||||
*/
|
||||
void (*global) (void *data, uint32_t id,
|
||||
uint32_t permissions, const char *type, uint32_t version,
|
||||
const struct spa_dict *props);
|
||||
/**
|
||||
* Notify of a global object removal
|
||||
*
|
||||
* Emitted when a global object was removed from the registry.
|
||||
* If the client has any bindings to the global, it should destroy
|
||||
* those.
|
||||
*
|
||||
* \param id the id of the global that was removed
|
||||
*/
|
||||
void (*global_remove) (void *data, uint32_t id);
|
||||
};
|
||||
|
||||
#define PW_REGISTRY_METHOD_ADD_LISTENER 0
|
||||
#define PW_REGISTRY_METHOD_BIND 1
|
||||
#define PW_REGISTRY_METHOD_DESTROY 2
|
||||
#define PW_REGISTRY_METHOD_NUM 3
|
||||
|
||||
/** Registry methods */
|
||||
struct pw_registry_methods {
|
||||
#define PW_VERSION_REGISTRY_METHODS 0
|
||||
uint32_t version;
|
||||
|
||||
int (*add_listener) (void *object,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_registry_events *events,
|
||||
void *data);
|
||||
/**
|
||||
* Bind to a global object
|
||||
*
|
||||
* Bind to the global object with \a id and use the client proxy
|
||||
* with new_id as the proxy. After this call, methods can be
|
||||
* send to the remote global object and events can be received
|
||||
*
|
||||
* \param id the global id to bind to
|
||||
* \param type the interface type to bind to
|
||||
* \param version the interface version to use
|
||||
* \returns the new object
|
||||
*/
|
||||
void * (*bind) (void *object, uint32_t id, const char *type, uint32_t version,
|
||||
size_t use_data_size);
|
||||
|
||||
/**
|
||||
* Attempt to destroy a global object
|
||||
*
|
||||
* Try to destroy the global object.
|
||||
*
|
||||
* \param id the global id to destroy
|
||||
*/
|
||||
int (*destroy) (void *object, uint32_t id);
|
||||
};
|
||||
|
||||
#define pw_registry_method(o,method,version,...) \
|
||||
({ \
|
||||
int _res = -ENOTSUP; \
|
||||
spa_interface_call_res((struct spa_interface*)o, \
|
||||
struct pw_registry_methods, _res, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
_res; \
|
||||
})
|
||||
|
||||
/** Registry */
|
||||
#define pw_registry_add_listener(p,...) pw_registry_method(p,add_listener,0,__VA_ARGS__)
|
||||
|
||||
static inline void *
|
||||
pw_registry_bind(struct pw_registry *registry,
|
||||
uint32_t id, const char *type, uint32_t version,
|
||||
size_t user_data_size)
|
||||
{
|
||||
void *res = NULL;
|
||||
spa_interface_call_res((struct spa_interface*)registry,
|
||||
struct pw_registry_methods, res,
|
||||
bind, 0, id, type, version, user_data_size);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define pw_registry_destroy(p,...) pw_registry_method(p,destroy,0,__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_core
|
||||
* \{
|
||||
*/
|
||||
|
||||
/** Connect to a PipeWire instance
|
||||
*
|
||||
* \param context a \ref pw_context
|
||||
* \param properties optional properties, ownership of the properties is
|
||||
* taken.
|
||||
* \param user_data_size extra user data size
|
||||
*
|
||||
* \return a \ref pw_core on success or NULL with errno set on error. The core
|
||||
* will have an id of \ref PW_ID_CORE (0)
|
||||
*/
|
||||
struct pw_core *
|
||||
pw_context_connect(struct pw_context *context,
|
||||
struct pw_properties *properties,
|
||||
size_t user_data_size);
|
||||
|
||||
/** Connect to a PipeWire instance on the given socket
|
||||
*
|
||||
* \param context a \ref pw_context
|
||||
* \param fd the connected socket to use, the socket will be closed
|
||||
* automatically on disconnect or error.
|
||||
* \param properties optional properties, ownership of the properties is
|
||||
* taken.
|
||||
* \param user_data_size extra user data size
|
||||
*
|
||||
* \return a \ref pw_core on success or NULL with errno set on error */
|
||||
struct pw_core *
|
||||
pw_context_connect_fd(struct pw_context *context,
|
||||
int fd,
|
||||
struct pw_properties *properties,
|
||||
size_t user_data_size);
|
||||
|
||||
/** Connect to a given PipeWire instance
|
||||
*
|
||||
* \param context a \ref pw_context to connect to
|
||||
* \param properties optional properties, ownership of the properties is
|
||||
* taken.
|
||||
* \param user_data_size extra user data size
|
||||
*
|
||||
* \return a \ref pw_core on success or NULL with errno set on error */
|
||||
struct pw_core *
|
||||
pw_context_connect_self(struct pw_context *context,
|
||||
struct pw_properties *properties,
|
||||
size_t user_data_size);
|
||||
|
||||
/** Steal the fd of the core connection or < 0 on error. The core
|
||||
* will be disconnected after this call. */
|
||||
int pw_core_steal_fd(struct pw_core *core);
|
||||
|
||||
/** Pause or resume the core. When the core is paused, no new events
|
||||
* will be dispatched until the core is resumed again. */
|
||||
int pw_core_set_paused(struct pw_core *core, bool paused);
|
||||
|
||||
/** disconnect and destroy a core */
|
||||
int pw_core_disconnect(struct pw_core *core);
|
||||
|
||||
/** Get the user_data. It is of the size specified when this object was
|
||||
* constructed */
|
||||
void *pw_core_get_user_data(struct pw_core *core);
|
||||
|
||||
/** Get the client proxy of the connected core. This will have the id
|
||||
* of PW_ID_CLIENT (1) */
|
||||
struct pw_client * pw_core_get_client(struct pw_core *core);
|
||||
|
||||
/** Get the context object used to created this core */
|
||||
struct pw_context * pw_core_get_context(struct pw_core *core);
|
||||
|
||||
/** Get properties from the core */
|
||||
const struct pw_properties *pw_core_get_properties(struct pw_core *core);
|
||||
|
||||
/** Update the core properties. This updates the properties
|
||||
* of the associated client.
|
||||
* \return the number of properties that were updated */
|
||||
int pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict);
|
||||
|
||||
/** Get the core mempool object */
|
||||
struct pw_mempool * pw_core_get_mempool(struct pw_core *core);
|
||||
|
||||
/** Get the proxy with the given id */
|
||||
struct pw_proxy *pw_core_find_proxy(struct pw_core *core, uint32_t id);
|
||||
|
||||
/** Export an object into the PipeWire instance associated with core */
|
||||
struct pw_proxy *pw_core_export(struct pw_core *core, /**< the core */
|
||||
const char *type, /**< the type of object */
|
||||
const struct spa_dict *props, /**< extra properties */
|
||||
void *object, /**< object to export */
|
||||
size_t user_data_size /**< extra user data */);
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_CORE_H */
|
343
src/java.desktop/unix/native/libpipewire/include/pipewire/keys.h
Normal file
343
src/java.desktop/unix/native/libpipewire/include/pipewire/keys.h
Normal file
@ -0,0 +1,343 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_KEYS_H
|
||||
#define PIPEWIRE_KEYS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <pipewire/utils.h>
|
||||
/**
|
||||
* \defgroup pw_keys Key Names
|
||||
*
|
||||
* A collection of keys that are used to add extra information on objects.
|
||||
*
|
||||
* Keys that start with "pipewire." are in general set-once and then
|
||||
* read-only. They are usually used for security sensitive information that
|
||||
* needs to be fixed.
|
||||
*
|
||||
* Properties from other objects can also appear. This usually suggests some
|
||||
* sort of parent/child or owner/owned relationship.
|
||||
*
|
||||
* \addtogroup pw_keys
|
||||
* \{
|
||||
*/
|
||||
#define PW_KEY_PROTOCOL "pipewire.protocol" /**< protocol used for connection */
|
||||
#define PW_KEY_ACCESS "pipewire.access" /**< how the client access is controlled */
|
||||
#define PW_KEY_CLIENT_ACCESS "pipewire.client.access"/**< how the client wants to be access
|
||||
* controlled */
|
||||
|
||||
/** Various keys related to the identity of a client process and its security.
|
||||
* Must be obtained from trusted sources by the protocol and placed as
|
||||
* read-only properties. */
|
||||
#define PW_KEY_SEC_PID "pipewire.sec.pid" /**< Client pid, set by protocol */
|
||||
#define PW_KEY_SEC_UID "pipewire.sec.uid" /**< Client uid, set by protocol*/
|
||||
#define PW_KEY_SEC_GID "pipewire.sec.gid" /**< client gid, set by protocol*/
|
||||
#define PW_KEY_SEC_LABEL "pipewire.sec.label" /**< client security label, set by protocol*/
|
||||
|
||||
#define PW_KEY_LIBRARY_NAME_SYSTEM "library.name.system" /**< name of the system library to use */
|
||||
#define PW_KEY_LIBRARY_NAME_LOOP "library.name.loop" /**< name of the loop library to use */
|
||||
#define PW_KEY_LIBRARY_NAME_DBUS "library.name.dbus" /**< name of the dbus library to use */
|
||||
|
||||
/** object properties */
|
||||
#define PW_KEY_OBJECT_PATH "object.path" /**< unique path to construct the object */
|
||||
#define PW_KEY_OBJECT_ID "object.id" /**< a global object id */
|
||||
#define PW_KEY_OBJECT_SERIAL "object.serial" /**< a 64 bit object serial number. This is a number
|
||||
* incremented for each object that is created.
|
||||
* The lower 32 bits are guaranteed to never be
|
||||
* SPA_ID_INVALID. */
|
||||
#define PW_KEY_OBJECT_LINGER "object.linger" /**< the object lives on even after the client
|
||||
* that created it has been destroyed */
|
||||
#define PW_KEY_OBJECT_REGISTER "object.register" /**< If the object should be registered. */
|
||||
|
||||
|
||||
/* config */
|
||||
#define PW_KEY_CONFIG_PREFIX "config.prefix" /**< a config prefix directory */
|
||||
#define PW_KEY_CONFIG_NAME "config.name" /**< a config file name */
|
||||
#define PW_KEY_CONFIG_OVERRIDE_PREFIX "config.override.prefix" /**< a config override prefix directory */
|
||||
#define PW_KEY_CONFIG_OVERRIDE_NAME "config.override.name" /**< a config override file name */
|
||||
|
||||
/* context */
|
||||
#define PW_KEY_CONTEXT_PROFILE_MODULES "context.profile.modules" /**< a context profile for modules, deprecated */
|
||||
#define PW_KEY_USER_NAME "context.user-name" /**< The user name that runs pipewire */
|
||||
#define PW_KEY_HOST_NAME "context.host-name" /**< The host name of the machine */
|
||||
|
||||
/* core */
|
||||
#define PW_KEY_CORE_NAME "core.name" /**< The name of the core. Default is
|
||||
* `pipewire-<username>-<pid>`, overwritten
|
||||
* by env(PIPEWIRE_CORE) */
|
||||
#define PW_KEY_CORE_VERSION "core.version" /**< The version of the core. */
|
||||
#define PW_KEY_CORE_DAEMON "core.daemon" /**< If the core is listening for connections. */
|
||||
|
||||
#define PW_KEY_CORE_ID "core.id" /**< the core id */
|
||||
#define PW_KEY_CORE_MONITORS "core.monitors" /**< the apis monitored by core. */
|
||||
|
||||
/* cpu */
|
||||
#define PW_KEY_CPU_MAX_ALIGN "cpu.max-align" /**< maximum alignment needed to support
|
||||
* all CPU optimizations */
|
||||
#define PW_KEY_CPU_CORES "cpu.cores" /**< number of cores */
|
||||
|
||||
/* priorities */
|
||||
#define PW_KEY_PRIORITY_SESSION "priority.session" /**< priority in session manager */
|
||||
#define PW_KEY_PRIORITY_DRIVER "priority.driver" /**< priority to be a driver */
|
||||
|
||||
/* remote keys */
|
||||
#define PW_KEY_REMOTE_NAME "remote.name" /**< The name of the remote to connect to,
|
||||
* default pipewire-0, overwritten by
|
||||
* env(PIPEWIRE_REMOTE) */
|
||||
#define PW_KEY_REMOTE_INTENTION "remote.intention" /**< The intention of the remote connection,
|
||||
* "generic", "screencast" */
|
||||
|
||||
/** application keys */
|
||||
#define PW_KEY_APP_NAME "application.name" /**< application name. Ex: "Totem Music Player" */
|
||||
#define PW_KEY_APP_ID "application.id" /**< a textual id for identifying an
|
||||
* application logically. Ex: "org.gnome.Totem" */
|
||||
#define PW_KEY_APP_VERSION "application.version" /**< application version. Ex: "1.2.0" */
|
||||
#define PW_KEY_APP_ICON "application.icon" /**< aa base64 blob with PNG image data */
|
||||
#define PW_KEY_APP_ICON_NAME "application.icon-name" /**< an XDG icon name for the application.
|
||||
* Ex: "totem" */
|
||||
#define PW_KEY_APP_LANGUAGE "application.language" /**< application language if applicable, in
|
||||
* standard POSIX format. Ex: "en_GB" */
|
||||
|
||||
#define PW_KEY_APP_PROCESS_ID "application.process.id" /**< process id (pid)*/
|
||||
#define PW_KEY_APP_PROCESS_BINARY "application.process.binary" /**< binary name */
|
||||
#define PW_KEY_APP_PROCESS_USER "application.process.user" /**< user name */
|
||||
#define PW_KEY_APP_PROCESS_HOST "application.process.host" /**< host name */
|
||||
#define PW_KEY_APP_PROCESS_MACHINE_ID "application.process.machine-id" /**< the D-Bus host id the
|
||||
* application runs on */
|
||||
#define PW_KEY_APP_PROCESS_SESSION_ID "application.process.session-id" /**< login session of the
|
||||
* application, on Unix the
|
||||
* value of $XDG_SESSION_ID. */
|
||||
/** window system */
|
||||
#define PW_KEY_WINDOW_X11_DISPLAY "window.x11.display" /**< the X11 display string. Ex. ":0.0" */
|
||||
|
||||
/** Client properties */
|
||||
#define PW_KEY_CLIENT_ID "client.id" /**< a client id */
|
||||
#define PW_KEY_CLIENT_NAME "client.name" /**< the client name */
|
||||
#define PW_KEY_CLIENT_API "client.api" /**< the client api used to access
|
||||
* PipeWire */
|
||||
|
||||
/** Node keys */
|
||||
#define PW_KEY_NODE_ID "node.id" /**< node id */
|
||||
#define PW_KEY_NODE_NAME "node.name" /**< node name */
|
||||
#define PW_KEY_NODE_NICK "node.nick" /**< short node name */
|
||||
#define PW_KEY_NODE_DESCRIPTION "node.description" /**< localized human readable node one-line
|
||||
* description. Ex. "Foobar USB Headset" */
|
||||
#define PW_KEY_NODE_PLUGGED "node.plugged" /**< when the node was created. As a uint64 in
|
||||
* nanoseconds. */
|
||||
|
||||
#define PW_KEY_NODE_SESSION "node.session" /**< the session id this node is part of */
|
||||
#define PW_KEY_NODE_GROUP "node.group" /**< the group id this node is part of. Nodes
|
||||
* in the same group are always scheduled
|
||||
* with the same driver. */
|
||||
#define PW_KEY_NODE_EXCLUSIVE "node.exclusive" /**< node wants exclusive access to resources */
|
||||
#define PW_KEY_NODE_AUTOCONNECT "node.autoconnect" /**< node wants to be automatically connected
|
||||
* to a compatible node */
|
||||
#define PW_KEY_NODE_LATENCY "node.latency" /**< the requested latency of the node as
|
||||
* a fraction. Ex: 128/48000 */
|
||||
#define PW_KEY_NODE_MAX_LATENCY "node.max-latency" /**< the maximum supported latency of the
|
||||
* node as a fraction. Ex: 1024/48000 */
|
||||
#define PW_KEY_NODE_LOCK_QUANTUM "node.lock-quantum" /**< don't change quantum when this node
|
||||
* is active */
|
||||
#define PW_KEY_NODE_FORCE_QUANTUM "node.force-quantum" /**< force a quantum while the node is
|
||||
* active */
|
||||
#define PW_KEY_NODE_RATE "node.rate" /**< the requested rate of the graph as
|
||||
* a fraction. Ex: 1/48000 */
|
||||
#define PW_KEY_NODE_LOCK_RATE "node.lock-rate" /**< don't change rate when this node
|
||||
* is active */
|
||||
#define PW_KEY_NODE_FORCE_RATE "node.force-rate" /**< force a rate while the node is
|
||||
* active. A value of 0 takes the denominator
|
||||
* of node.rate */
|
||||
|
||||
#define PW_KEY_NODE_DONT_RECONNECT "node.dont-reconnect" /**< don't reconnect this node. The node is
|
||||
* initially linked to target.object or the
|
||||
* default node. If the target is removed,
|
||||
* the node is destroyed */
|
||||
#define PW_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< process even when unlinked */
|
||||
#define PW_KEY_NODE_WANT_DRIVER "node.want-driver" /**< the node wants to be grouped with a driver
|
||||
* node in order to schedule the graph. */
|
||||
#define PW_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< pause the node when idle */
|
||||
#define PW_KEY_NODE_SUSPEND_ON_IDLE "node.suspend-on-idle" /**< suspend the node when idle */
|
||||
#define PW_KEY_NODE_CACHE_PARAMS "node.cache-params" /**< cache the node params */
|
||||
#define PW_KEY_NODE_TRANSPORT_SYNC "node.transport.sync" /**< the node handles transport sync */
|
||||
#define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph */
|
||||
#define PW_KEY_NODE_STREAM "node.stream" /**< node is a stream, the server side should
|
||||
* add a converter */
|
||||
#define PW_KEY_NODE_VIRTUAL "node.virtual" /**< the node is some sort of virtual
|
||||
* object */
|
||||
#define PW_KEY_NODE_PASSIVE "node.passive" /**< indicate that a node wants passive links
|
||||
* on output/input/all ports when the value is
|
||||
* "out"/"in"/"true" respectively */
|
||||
#define PW_KEY_NODE_LINK_GROUP "node.link-group" /**< the node is internally linked to
|
||||
* nodes with the same link-group */
|
||||
#define PW_KEY_NODE_NETWORK "node.network" /**< the node is on a network */
|
||||
#define PW_KEY_NODE_TRIGGER "node.trigger" /**< the node is not scheduled automatically
|
||||
* based on the dependencies in the graph
|
||||
* but it will be triggered explicitly. */
|
||||
#define PW_KEY_NODE_CHANNELNAMES "node.channel-names" /**< names of node's
|
||||
* channels (unrelated to positions) */
|
||||
#define PW_KEY_NODE_DEVICE_PORT_NAME_PREFIX "node.device-port-name-prefix" /** override
|
||||
* port name prefix for device ports, like capture and playback
|
||||
* or disable the prefix completely if an empty string is provided */
|
||||
|
||||
/** Port keys */
|
||||
#define PW_KEY_PORT_ID "port.id" /**< port id */
|
||||
#define PW_KEY_PORT_NAME "port.name" /**< port name */
|
||||
#define PW_KEY_PORT_DIRECTION "port.direction" /**< the port direction, one of "in" or "out"
|
||||
* or "control" and "notify" for control ports */
|
||||
#define PW_KEY_PORT_ALIAS "port.alias" /**< port alias */
|
||||
#define PW_KEY_PORT_PHYSICAL "port.physical" /**< if this is a physical port */
|
||||
#define PW_KEY_PORT_TERMINAL "port.terminal" /**< if this port consumes the data */
|
||||
#define PW_KEY_PORT_CONTROL "port.control" /**< if this port is a control port */
|
||||
#define PW_KEY_PORT_MONITOR "port.monitor" /**< if this port is a monitor port */
|
||||
#define PW_KEY_PORT_CACHE_PARAMS "port.cache-params" /**< cache the node port params */
|
||||
#define PW_KEY_PORT_EXTRA "port.extra" /**< api specific extra port info, API name
|
||||
* should be prefixed. "jack:flags:56" */
|
||||
#define PW_KEY_PORT_PASSIVE "port.passive" /**< the ports wants passive links, since 0.3.67 */
|
||||
|
||||
/** link properties */
|
||||
#define PW_KEY_LINK_ID "link.id" /**< a link id */
|
||||
#define PW_KEY_LINK_INPUT_NODE "link.input.node" /**< input node id of a link */
|
||||
#define PW_KEY_LINK_INPUT_PORT "link.input.port" /**< input port id of a link */
|
||||
#define PW_KEY_LINK_OUTPUT_NODE "link.output.node" /**< output node id of a link */
|
||||
#define PW_KEY_LINK_OUTPUT_PORT "link.output.port" /**< output port id of a link */
|
||||
#define PW_KEY_LINK_PASSIVE "link.passive" /**< indicate that a link is passive and
|
||||
* does not cause the graph to be
|
||||
* runnable. */
|
||||
#define PW_KEY_LINK_FEEDBACK "link.feedback" /**< indicate that a link is a feedback
|
||||
* link and the target will receive data
|
||||
* in the next cycle */
|
||||
|
||||
/** device properties */
|
||||
#define PW_KEY_DEVICE_ID "device.id" /**< device id */
|
||||
#define PW_KEY_DEVICE_NAME "device.name" /**< device name */
|
||||
#define PW_KEY_DEVICE_PLUGGED "device.plugged" /**< when the device was created. As a uint64 in
|
||||
* nanoseconds. */
|
||||
#define PW_KEY_DEVICE_NICK "device.nick" /**< a short device nickname */
|
||||
#define PW_KEY_DEVICE_STRING "device.string" /**< device string in the underlying layer's
|
||||
* format. Ex. "surround51:0" */
|
||||
#define PW_KEY_DEVICE_API "device.api" /**< API this device is accessed with.
|
||||
* Ex. "alsa", "v4l2" */
|
||||
#define PW_KEY_DEVICE_DESCRIPTION "device.description" /**< localized human readable device one-line
|
||||
* description. Ex. "Foobar USB Headset" */
|
||||
#define PW_KEY_DEVICE_BUS_PATH "device.bus-path" /**< bus path to the device in the OS'
|
||||
* format. Ex. "pci-0000:00:14.0-usb-0:3.2:1.0" */
|
||||
#define PW_KEY_DEVICE_SERIAL "device.serial" /**< Serial number if applicable */
|
||||
#define PW_KEY_DEVICE_VENDOR_ID "device.vendor.id" /**< vendor ID if applicable */
|
||||
#define PW_KEY_DEVICE_VENDOR_NAME "device.vendor.name" /**< vendor name if applicable */
|
||||
#define PW_KEY_DEVICE_PRODUCT_ID "device.product.id" /**< product ID if applicable */
|
||||
#define PW_KEY_DEVICE_PRODUCT_NAME "device.product.name" /**< product name if applicable */
|
||||
#define PW_KEY_DEVICE_CLASS "device.class" /**< device class */
|
||||
#define PW_KEY_DEVICE_FORM_FACTOR "device.form-factor" /**< form factor if applicable. One of
|
||||
* "internal", "speaker", "handset", "tv",
|
||||
* "webcam", "microphone", "headset",
|
||||
* "headphone", "hands-free", "car", "hifi",
|
||||
* "computer", "portable" */
|
||||
#define PW_KEY_DEVICE_BUS "device.bus" /**< bus of the device if applicable. One of
|
||||
* "isa", "pci", "usb", "firewire",
|
||||
* "bluetooth" */
|
||||
#define PW_KEY_DEVICE_SUBSYSTEM "device.subsystem" /**< device subsystem */
|
||||
#define PW_KEY_DEVICE_SYSFS_PATH "device.sysfs.path" /**< device sysfs path */
|
||||
#define PW_KEY_DEVICE_ICON "device.icon" /**< icon for the device. A base64 blob
|
||||
* containing PNG image data */
|
||||
#define PW_KEY_DEVICE_ICON_NAME "device.icon-name" /**< an XDG icon name for the device.
|
||||
* Ex. "sound-card-speakers-usb" */
|
||||
#define PW_KEY_DEVICE_INTENDED_ROLES "device.intended-roles" /**< intended use. A space separated list of
|
||||
* roles (see PW_KEY_MEDIA_ROLE) this device
|
||||
* is particularly well suited for, due to
|
||||
* latency, quality or form factor. */
|
||||
#define PW_KEY_DEVICE_CACHE_PARAMS "device.cache-params" /**< cache the device spa params */
|
||||
|
||||
/** module properties */
|
||||
#define PW_KEY_MODULE_ID "module.id" /**< the module id */
|
||||
#define PW_KEY_MODULE_NAME "module.name" /**< the name of the module */
|
||||
#define PW_KEY_MODULE_AUTHOR "module.author" /**< the author's name */
|
||||
#define PW_KEY_MODULE_DESCRIPTION "module.description" /**< a human readable one-line description
|
||||
* of the module's purpose.*/
|
||||
#define PW_KEY_MODULE_USAGE "module.usage" /**< a human readable usage description of
|
||||
* the module's arguments. */
|
||||
#define PW_KEY_MODULE_VERSION "module.version" /**< a version string for the module. */
|
||||
|
||||
/** Factory properties */
|
||||
#define PW_KEY_FACTORY_ID "factory.id" /**< the factory id */
|
||||
#define PW_KEY_FACTORY_NAME "factory.name" /**< the name of the factory */
|
||||
#define PW_KEY_FACTORY_USAGE "factory.usage" /**< the usage of the factory */
|
||||
#define PW_KEY_FACTORY_TYPE_NAME "factory.type.name" /**< the name of the type created by a factory */
|
||||
#define PW_KEY_FACTORY_TYPE_VERSION "factory.type.version" /**< the version of the type created by a factory */
|
||||
|
||||
/** Stream properties */
|
||||
#define PW_KEY_STREAM_IS_LIVE "stream.is-live" /**< Indicates that the stream is live. */
|
||||
#define PW_KEY_STREAM_LATENCY_MIN "stream.latency.min" /**< The minimum latency of the stream. */
|
||||
#define PW_KEY_STREAM_LATENCY_MAX "stream.latency.max" /**< The maximum latency of the stream */
|
||||
#define PW_KEY_STREAM_MONITOR "stream.monitor" /**< Indicates that the stream is monitoring
|
||||
* and might select a less accurate but faster
|
||||
* conversion algorithm. */
|
||||
#define PW_KEY_STREAM_DONT_REMIX "stream.dont-remix" /**< don't remix channels */
|
||||
#define PW_KEY_STREAM_CAPTURE_SINK "stream.capture.sink" /**< Try to capture the sink output instead of
|
||||
* source output */
|
||||
|
||||
/** Media */
|
||||
#define PW_KEY_MEDIA_TYPE "media.type" /**< Media type, one of
|
||||
* Audio, Video, Midi */
|
||||
#define PW_KEY_MEDIA_CATEGORY "media.category" /**< Media Category:
|
||||
* Playback, Capture, Duplex, Monitor, Manager */
|
||||
#define PW_KEY_MEDIA_ROLE "media.role" /**< Role: Movie, Music, Camera,
|
||||
* Screen, Communication, Game,
|
||||
* Notification, DSP, Production,
|
||||
* Accessibility, Test */
|
||||
#define PW_KEY_MEDIA_CLASS "media.class" /**< class Ex: "Video/Source" */
|
||||
#define PW_KEY_MEDIA_NAME "media.name" /**< media name. Ex: "Pink Floyd: Time" */
|
||||
#define PW_KEY_MEDIA_TITLE "media.title" /**< title. Ex: "Time" */
|
||||
#define PW_KEY_MEDIA_ARTIST "media.artist" /**< artist. Ex: "Pink Floyd" */
|
||||
#define PW_KEY_MEDIA_COPYRIGHT "media.copyright" /**< copyright string */
|
||||
#define PW_KEY_MEDIA_SOFTWARE "media.software" /**< generator software */
|
||||
#define PW_KEY_MEDIA_LANGUAGE "media.language" /**< language in POSIX format. Ex: en_GB */
|
||||
#define PW_KEY_MEDIA_FILENAME "media.filename" /**< filename */
|
||||
#define PW_KEY_MEDIA_ICON "media.icon" /**< icon for the media, a base64 blob with
|
||||
* PNG image data */
|
||||
#define PW_KEY_MEDIA_ICON_NAME "media.icon-name" /**< an XDG icon name for the media.
|
||||
* Ex: "audio-x-mp3" */
|
||||
#define PW_KEY_MEDIA_COMMENT "media.comment" /**< extra comment */
|
||||
#define PW_KEY_MEDIA_DATE "media.date" /**< date of the media */
|
||||
#define PW_KEY_MEDIA_FORMAT "media.format" /**< format of the media */
|
||||
|
||||
/** format related properties */
|
||||
#define PW_KEY_FORMAT_DSP "format.dsp" /**< a dsp format.
|
||||
* Ex: "32 bit float mono audio" */
|
||||
/** audio related properties */
|
||||
#define PW_KEY_AUDIO_CHANNEL "audio.channel" /**< an audio channel. Ex: "FL" */
|
||||
#define PW_KEY_AUDIO_RATE "audio.rate" /**< an audio samplerate */
|
||||
#define PW_KEY_AUDIO_CHANNELS "audio.channels" /**< number of audio channels */
|
||||
#define PW_KEY_AUDIO_FORMAT "audio.format" /**< an audio format. Ex: "S16LE" */
|
||||
#define PW_KEY_AUDIO_ALLOWED_RATES "audio.allowed-rates" /**< a list of allowed samplerates
|
||||
* ex. "[ 44100 48000 ]" */
|
||||
|
||||
/** video related properties */
|
||||
#define PW_KEY_VIDEO_RATE "video.framerate" /**< a video framerate */
|
||||
#define PW_KEY_VIDEO_FORMAT "video.format" /**< a video format */
|
||||
#define PW_KEY_VIDEO_SIZE "video.size" /**< a video size as "<width>x<height" */
|
||||
|
||||
#define PW_KEY_TARGET_OBJECT "target.object" /**< a target object to link to. This can be
|
||||
* and object name or object.serial */
|
||||
|
||||
#ifndef PW_REMOVE_DEPRECATED
|
||||
# ifdef PW_ENABLE_DEPRECATED
|
||||
# define PW_KEY_PRIORITY_MASTER "priority.master" /**< deprecated, use priority.driver */
|
||||
# define PW_KEY_NODE_TARGET "node.target" /**< deprecated since 0.3.64, use target.object. */
|
||||
# else
|
||||
# define PW_KEY_PRIORITY_MASTER PW_DEPRECATED("priority.master")
|
||||
# define PW_KEY_NODE_TARGET PW_DEPRECATED("node.target")
|
||||
# endif /* PW_ENABLE_DEPRECATED */
|
||||
#endif /* PW_REMOVE_DEPRECATED */
|
||||
|
||||
/** \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_KEYS_H */
|
@ -0,0 +1,70 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_LOOP_H
|
||||
#define PIPEWIRE_LOOP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/support/loop.h>
|
||||
#include <spa/utils/dict.h>
|
||||
|
||||
/** \defgroup pw_loop Loop
|
||||
*
|
||||
* PipeWire loop object provides an implementation of
|
||||
* the spa loop interfaces. It can be used to implement various
|
||||
* event loops.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_loop
|
||||
* \{
|
||||
*/
|
||||
|
||||
struct pw_loop {
|
||||
struct spa_system *system; /**< system utils */
|
||||
struct spa_loop *loop; /**< wrapped loop */
|
||||
struct spa_loop_control *control; /**< loop control */
|
||||
struct spa_loop_utils *utils; /**< loop utils */
|
||||
};
|
||||
|
||||
struct pw_loop *
|
||||
pw_loop_new(const struct spa_dict *props);
|
||||
|
||||
void
|
||||
pw_loop_destroy(struct pw_loop *loop);
|
||||
|
||||
#define pw_loop_add_source(l,...) spa_loop_add_source((l)->loop,__VA_ARGS__)
|
||||
#define pw_loop_update_source(l,...) spa_loop_update_source((l)->loop,__VA_ARGS__)
|
||||
#define pw_loop_remove_source(l,...) spa_loop_remove_source((l)->loop,__VA_ARGS__)
|
||||
#define pw_loop_invoke(l,...) spa_loop_invoke((l)->loop,__VA_ARGS__)
|
||||
|
||||
#define pw_loop_get_fd(l) spa_loop_control_get_fd((l)->control)
|
||||
#define pw_loop_add_hook(l,...) spa_loop_control_add_hook((l)->control,__VA_ARGS__)
|
||||
#define pw_loop_enter(l) spa_loop_control_enter((l)->control)
|
||||
#define pw_loop_iterate(l,...) spa_loop_control_iterate((l)->control,__VA_ARGS__)
|
||||
#define pw_loop_leave(l) spa_loop_control_leave((l)->control)
|
||||
|
||||
#define pw_loop_add_io(l,...) spa_loop_utils_add_io((l)->utils,__VA_ARGS__)
|
||||
#define pw_loop_update_io(l,...) spa_loop_utils_update_io((l)->utils,__VA_ARGS__)
|
||||
#define pw_loop_add_idle(l,...) spa_loop_utils_add_idle((l)->utils,__VA_ARGS__)
|
||||
#define pw_loop_enable_idle(l,...) spa_loop_utils_enable_idle((l)->utils,__VA_ARGS__)
|
||||
#define pw_loop_add_event(l,...) spa_loop_utils_add_event((l)->utils,__VA_ARGS__)
|
||||
#define pw_loop_signal_event(l,...) spa_loop_utils_signal_event((l)->utils,__VA_ARGS__)
|
||||
#define pw_loop_add_timer(l,...) spa_loop_utils_add_timer((l)->utils,__VA_ARGS__)
|
||||
#define pw_loop_update_timer(l,...) spa_loop_utils_update_timer((l)->utils,__VA_ARGS__)
|
||||
#define pw_loop_add_signal(l,...) spa_loop_utils_add_signal((l)->utils,__VA_ARGS__)
|
||||
#define pw_loop_destroy_source(l,...) spa_loop_utils_destroy_source((l)->utils,__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_LOOP_H */
|
159
src/java.desktop/unix/native/libpipewire/include/pipewire/port.h
Normal file
159
src/java.desktop/unix/native/libpipewire/include/pipewire/port.h
Normal file
@ -0,0 +1,159 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_PORT_H
|
||||
#define PIPEWIRE_PORT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/hook.h>
|
||||
#include <spa/param/param.h>
|
||||
|
||||
#include <pipewire/proxy.h>
|
||||
|
||||
/** \defgroup pw_port Port
|
||||
* Port interface
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_port
|
||||
* \{
|
||||
*/
|
||||
|
||||
#define PW_TYPE_INTERFACE_Port PW_TYPE_INFO_INTERFACE_BASE "Port"
|
||||
|
||||
#define PW_VERSION_PORT 3
|
||||
struct pw_port;
|
||||
|
||||
/** The direction of a port */
|
||||
#define pw_direction spa_direction
|
||||
#define PW_DIRECTION_INPUT SPA_DIRECTION_INPUT
|
||||
#define PW_DIRECTION_OUTPUT SPA_DIRECTION_OUTPUT
|
||||
|
||||
/** Convert a \ref pw_direction to a readable string */
|
||||
const char * pw_direction_as_string(enum pw_direction direction);
|
||||
|
||||
struct pw_port_info {
|
||||
uint32_t id; /**< id of the global */
|
||||
enum pw_direction direction; /**< port direction */
|
||||
#define PW_PORT_CHANGE_MASK_PROPS (1 << 0)
|
||||
#define PW_PORT_CHANGE_MASK_PARAMS (1 << 1)
|
||||
#define PW_PORT_CHANGE_MASK_ALL ((1 << 2)-1)
|
||||
uint64_t change_mask; /**< bitfield of changed fields since last call */
|
||||
struct spa_dict *props; /**< the properties of the port */
|
||||
struct spa_param_info *params; /**< parameters */
|
||||
uint32_t n_params; /**< number of items in \a params */
|
||||
};
|
||||
|
||||
struct pw_port_info *
|
||||
pw_port_info_update(struct pw_port_info *info,
|
||||
const struct pw_port_info *update);
|
||||
|
||||
struct pw_port_info *
|
||||
pw_port_info_merge(struct pw_port_info *info,
|
||||
const struct pw_port_info *update, bool reset);
|
||||
|
||||
void
|
||||
pw_port_info_free(struct pw_port_info *info);
|
||||
|
||||
#define PW_PORT_EVENT_INFO 0
|
||||
#define PW_PORT_EVENT_PARAM 1
|
||||
#define PW_PORT_EVENT_NUM 2
|
||||
|
||||
/** Port events */
|
||||
struct pw_port_events {
|
||||
#define PW_VERSION_PORT_EVENTS 0
|
||||
uint32_t version;
|
||||
/**
|
||||
* Notify port info
|
||||
*
|
||||
* \param info info about the port
|
||||
*/
|
||||
void (*info) (void *data, const struct pw_port_info *info);
|
||||
/**
|
||||
* Notify a port param
|
||||
*
|
||||
* Event emitted as a result of the enum_params method.
|
||||
*
|
||||
* \param seq the sequence number of the request
|
||||
* \param id the param id
|
||||
* \param index the param index
|
||||
* \param next the param index of the next param
|
||||
* \param param the parameter
|
||||
*/
|
||||
void (*param) (void *data, int seq,
|
||||
uint32_t id, uint32_t index, uint32_t next,
|
||||
const struct spa_pod *param);
|
||||
};
|
||||
|
||||
#define PW_PORT_METHOD_ADD_LISTENER 0
|
||||
#define PW_PORT_METHOD_SUBSCRIBE_PARAMS 1
|
||||
#define PW_PORT_METHOD_ENUM_PARAMS 2
|
||||
#define PW_PORT_METHOD_NUM 3
|
||||
|
||||
/** Port methods */
|
||||
struct pw_port_methods {
|
||||
#define PW_VERSION_PORT_METHODS 0
|
||||
uint32_t version;
|
||||
|
||||
int (*add_listener) (void *object,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_port_events *events,
|
||||
void *data);
|
||||
/**
|
||||
* Subscribe to parameter changes
|
||||
*
|
||||
* Automatically emit param events for the given ids when
|
||||
* they are changed.
|
||||
*
|
||||
* \param ids an array of param ids
|
||||
* \param n_ids the number of ids in \a ids
|
||||
*/
|
||||
int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
|
||||
|
||||
/**
|
||||
* Enumerate port parameters
|
||||
*
|
||||
* Start enumeration of port parameters. For each param, a
|
||||
* param event will be emitted.
|
||||
*
|
||||
* \param seq a sequence number returned in the reply
|
||||
* \param id the parameter id to enumerate
|
||||
* \param start the start index or 0 for the first param
|
||||
* \param num the maximum number of params to retrieve
|
||||
* \param filter a param filter or NULL
|
||||
*/
|
||||
int (*enum_params) (void *object, int seq,
|
||||
uint32_t id, uint32_t start, uint32_t num,
|
||||
const struct spa_pod *filter);
|
||||
};
|
||||
|
||||
#define pw_port_method(o,method,version,...) \
|
||||
({ \
|
||||
int _res = -ENOTSUP; \
|
||||
spa_interface_call_res((struct spa_interface*)o, \
|
||||
struct pw_port_methods, _res, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
_res; \
|
||||
})
|
||||
|
||||
#define pw_port_add_listener(c,...) pw_port_method(c,add_listener,0,__VA_ARGS__)
|
||||
#define pw_port_subscribe_params(c,...) pw_port_method(c,subscribe_params,0,__VA_ARGS__)
|
||||
#define pw_port_enum_params(c,...) pw_port_method(c,enum_params,0,__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_PORT_H */
|
@ -0,0 +1,179 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_PROPERTIES_H
|
||||
#define PIPEWIRE_PROPERTIES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <spa/utils/dict.h>
|
||||
#include <spa/utils/string.h>
|
||||
|
||||
/** \defgroup pw_properties Properties
|
||||
*
|
||||
* Properties are used to pass around arbitrary key/value pairs.
|
||||
* Both keys and values are strings which keeps things simple.
|
||||
* Encoding of arbitrary values should be done by using a string
|
||||
* serialization such as base64 for binary blobs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_properties
|
||||
* \{
|
||||
*/
|
||||
struct pw_properties {
|
||||
struct spa_dict dict; /**< dictionary of key/values */
|
||||
uint32_t flags; /**< extra flags */
|
||||
};
|
||||
|
||||
struct pw_properties *
|
||||
pw_properties_new(const char *key, ...) SPA_SENTINEL;
|
||||
|
||||
struct pw_properties *
|
||||
pw_properties_new_dict(const struct spa_dict *dict);
|
||||
|
||||
struct pw_properties *
|
||||
pw_properties_new_string(const char *args);
|
||||
|
||||
struct pw_properties *
|
||||
pw_properties_copy(const struct pw_properties *properties);
|
||||
|
||||
int pw_properties_update_keys(struct pw_properties *props,
|
||||
const struct spa_dict *dict, const char * const keys[]);
|
||||
int pw_properties_update_ignore(struct pw_properties *props,
|
||||
const struct spa_dict *dict, const char * const ignore[]);
|
||||
|
||||
/* Update props with all key/value pairs from dict */
|
||||
int pw_properties_update(struct pw_properties *props,
|
||||
const struct spa_dict *dict);
|
||||
/* Update props with all key/value pairs from str */
|
||||
int pw_properties_update_string(struct pw_properties *props,
|
||||
const char *str, size_t size);
|
||||
|
||||
int pw_properties_add(struct pw_properties *oldprops,
|
||||
const struct spa_dict *dict);
|
||||
int pw_properties_add_keys(struct pw_properties *oldprops,
|
||||
const struct spa_dict *dict, const char * const keys[]);
|
||||
|
||||
void pw_properties_clear(struct pw_properties *properties);
|
||||
|
||||
void
|
||||
pw_properties_free(struct pw_properties *properties);
|
||||
|
||||
int
|
||||
pw_properties_set(struct pw_properties *properties, const char *key, const char *value);
|
||||
|
||||
int
|
||||
pw_properties_setf(struct pw_properties *properties,
|
||||
const char *key, const char *format, ...) SPA_PRINTF_FUNC(3, 4);
|
||||
int
|
||||
pw_properties_setva(struct pw_properties *properties,
|
||||
const char *key, const char *format, va_list args) SPA_PRINTF_FUNC(3,0);
|
||||
const char *
|
||||
pw_properties_get(const struct pw_properties *properties, const char *key);
|
||||
|
||||
int
|
||||
pw_properties_fetch_uint32(const struct pw_properties *properties, const char *key, uint32_t *value);
|
||||
|
||||
int
|
||||
pw_properties_fetch_int32(const struct pw_properties *properties, const char *key, int32_t *value);
|
||||
|
||||
int
|
||||
pw_properties_fetch_uint64(const struct pw_properties *properties, const char *key, uint64_t *value);
|
||||
|
||||
int
|
||||
pw_properties_fetch_int64(const struct pw_properties *properties, const char *key, int64_t *value);
|
||||
|
||||
int
|
||||
pw_properties_fetch_bool(const struct pw_properties *properties, const char *key, bool *value);
|
||||
|
||||
static inline uint32_t
|
||||
pw_properties_get_uint32(const struct pw_properties *properties, const char *key, uint32_t deflt)
|
||||
{
|
||||
uint32_t val = deflt;
|
||||
pw_properties_fetch_uint32(properties, key, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
pw_properties_get_int32(const struct pw_properties *properties, const char *key, int32_t deflt)
|
||||
{
|
||||
int32_t val = deflt;
|
||||
pw_properties_fetch_int32(properties, key, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
pw_properties_get_uint64(const struct pw_properties *properties, const char *key, uint64_t deflt)
|
||||
{
|
||||
uint64_t val = deflt;
|
||||
pw_properties_fetch_uint64(properties, key, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline int64_t
|
||||
pw_properties_get_int64(const struct pw_properties *properties, const char *key, int64_t deflt)
|
||||
{
|
||||
int64_t val = deflt;
|
||||
pw_properties_fetch_int64(properties, key, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static inline bool
|
||||
pw_properties_get_bool(const struct pw_properties *properties, const char *key, bool deflt)
|
||||
{
|
||||
bool val = deflt;
|
||||
pw_properties_fetch_bool(properties, key, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
const char *
|
||||
pw_properties_iterate(const struct pw_properties *properties, void **state);
|
||||
|
||||
#define PW_PROPERTIES_FLAG_NL (1<<0)
|
||||
int pw_properties_serialize_dict(FILE *f, const struct spa_dict *dict, uint32_t flags);
|
||||
|
||||
static inline bool pw_properties_parse_bool(const char *value) {
|
||||
return spa_atob(value);
|
||||
}
|
||||
|
||||
static inline int pw_properties_parse_int(const char *value) {
|
||||
int v;
|
||||
return spa_atoi32(value, &v, 0) ? v: 0;
|
||||
}
|
||||
|
||||
static inline int64_t pw_properties_parse_int64(const char *value) {
|
||||
int64_t v;
|
||||
return spa_atoi64(value, &v, 0) ? v : 0;
|
||||
}
|
||||
|
||||
static inline uint64_t pw_properties_parse_uint64(const char *value) {
|
||||
uint64_t v;
|
||||
return spa_atou64(value, &v, 0) ? v : 0;
|
||||
}
|
||||
|
||||
static inline float pw_properties_parse_float(const char *value) {
|
||||
float v;
|
||||
return spa_atof(value, &v) ? v : 0.0f;
|
||||
}
|
||||
|
||||
static inline double pw_properties_parse_double(const char *value) {
|
||||
double v;
|
||||
return spa_atod(value, &v) ? v : 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_PROPERTIES_H */
|
@ -0,0 +1,142 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_PROTOCOL_H
|
||||
#define PIPEWIRE_PROTOCOL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/list.h>
|
||||
|
||||
/** \defgroup pw_protocol Protocol
|
||||
*
|
||||
* \brief Manages protocols and their implementation
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_protocol
|
||||
* \{
|
||||
*/
|
||||
|
||||
struct pw_protocol;
|
||||
|
||||
#include <pipewire/context.h>
|
||||
#include <pipewire/properties.h>
|
||||
#include <pipewire/utils.h>
|
||||
|
||||
#define PW_TYPE_INFO_Protocol "PipeWire:Protocol"
|
||||
#define PW_TYPE_INFO_PROTOCOL_BASE PW_TYPE_INFO_Protocol ":"
|
||||
|
||||
struct pw_protocol_client {
|
||||
struct spa_list link; /**< link in protocol client_list */
|
||||
struct pw_protocol *protocol; /**< the owner protocol */
|
||||
|
||||
struct pw_core *core;
|
||||
|
||||
int (*connect) (struct pw_protocol_client *client,
|
||||
const struct spa_dict *props,
|
||||
void (*done_callback) (void *data, int result),
|
||||
void *data);
|
||||
int (*connect_fd) (struct pw_protocol_client *client, int fd, bool close);
|
||||
int (*steal_fd) (struct pw_protocol_client *client);
|
||||
void (*disconnect) (struct pw_protocol_client *client);
|
||||
void (*destroy) (struct pw_protocol_client *client);
|
||||
int (*set_paused) (struct pw_protocol_client *client, bool paused);
|
||||
};
|
||||
|
||||
#define pw_protocol_client_connect(c,p,cb,d) ((c)->connect(c,p,cb,d))
|
||||
#define pw_protocol_client_connect_fd(c,fd,cl) ((c)->connect_fd(c,fd,cl))
|
||||
#define pw_protocol_client_steal_fd(c) ((c)->steal_fd(c))
|
||||
#define pw_protocol_client_disconnect(c) ((c)->disconnect(c))
|
||||
#define pw_protocol_client_destroy(c) ((c)->destroy(c))
|
||||
#define pw_protocol_client_set_paused(c,p) ((c)->set_paused(c,p))
|
||||
|
||||
struct pw_protocol_server {
|
||||
struct spa_list link; /**< link in protocol server_list */
|
||||
struct pw_protocol *protocol; /**< the owner protocol */
|
||||
|
||||
struct pw_impl_core *core;
|
||||
|
||||
struct spa_list client_list; /**< list of clients of this protocol */
|
||||
|
||||
void (*destroy) (struct pw_protocol_server *listen);
|
||||
};
|
||||
|
||||
#define pw_protocol_server_destroy(l) ((l)->destroy(l))
|
||||
|
||||
struct pw_protocol_marshal {
|
||||
const char *type; /**< interface type */
|
||||
uint32_t version; /**< version */
|
||||
#define PW_PROTOCOL_MARSHAL_FLAG_IMPL (1 << 0) /**< marshal for implementations */
|
||||
uint32_t flags; /**< version */
|
||||
uint32_t n_client_methods; /**< number of client methods */
|
||||
uint32_t n_server_methods; /**< number of server methods */
|
||||
const void *client_marshal;
|
||||
const void *server_demarshal;
|
||||
const void *server_marshal;
|
||||
const void *client_demarshal;
|
||||
};
|
||||
|
||||
struct pw_protocol_implementation {
|
||||
#define PW_VERSION_PROTOCOL_IMPLEMENTATION 0
|
||||
uint32_t version;
|
||||
|
||||
struct pw_protocol_client * (*new_client) (struct pw_protocol *protocol,
|
||||
struct pw_core *core,
|
||||
const struct spa_dict *props);
|
||||
struct pw_protocol_server * (*add_server) (struct pw_protocol *protocol,
|
||||
struct pw_impl_core *core,
|
||||
const struct spa_dict *props);
|
||||
};
|
||||
|
||||
struct pw_protocol_events {
|
||||
#define PW_VERSION_PROTOCOL_EVENTS 0
|
||||
uint32_t version;
|
||||
|
||||
void (*destroy) (void *data);
|
||||
};
|
||||
|
||||
#define pw_protocol_new_client(p,...) (pw_protocol_get_implementation(p)->new_client(p,__VA_ARGS__))
|
||||
#define pw_protocol_add_server(p,...) (pw_protocol_get_implementation(p)->add_server(p,__VA_ARGS__))
|
||||
#define pw_protocol_ext(p,type,method,...) (((type*)pw_protocol_get_extension(p))->method( __VA_ARGS__))
|
||||
|
||||
struct pw_protocol *pw_protocol_new(struct pw_context *context, const char *name, size_t user_data_size);
|
||||
|
||||
void pw_protocol_destroy(struct pw_protocol *protocol);
|
||||
|
||||
struct pw_context *pw_protocol_get_context(struct pw_protocol *protocol);
|
||||
|
||||
void *pw_protocol_get_user_data(struct pw_protocol *protocol);
|
||||
|
||||
const struct pw_protocol_implementation *
|
||||
pw_protocol_get_implementation(struct pw_protocol *protocol);
|
||||
|
||||
const void *
|
||||
pw_protocol_get_extension(struct pw_protocol *protocol);
|
||||
|
||||
|
||||
void pw_protocol_add_listener(struct pw_protocol *protocol,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_protocol_events *events,
|
||||
void *data);
|
||||
|
||||
int pw_protocol_add_marshal(struct pw_protocol *protocol,
|
||||
const struct pw_protocol_marshal *marshal);
|
||||
|
||||
const struct pw_protocol_marshal *
|
||||
pw_protocol_get_marshal(struct pw_protocol *protocol, const char *type, uint32_t version, uint32_t flags);
|
||||
|
||||
struct pw_protocol * pw_context_find_protocol(struct pw_context *context, const char *name);
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_PROTOCOL_H */
|
@ -0,0 +1,201 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_PROXY_H
|
||||
#define PIPEWIRE_PROXY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/hook.h>
|
||||
|
||||
/** \page page_proxy Proxy
|
||||
*
|
||||
* \section sec_page_proxy_overview Overview
|
||||
*
|
||||
* The proxy object is a client side representation of a resource
|
||||
* that lives on a remote PipeWire instance.
|
||||
*
|
||||
* It is used to communicate with the remote object.
|
||||
*
|
||||
* \section sec_page_proxy_core Core proxy
|
||||
*
|
||||
* A proxy for a remote core object can be obtained by making
|
||||
* a remote connection with \ref pw_context_connect.
|
||||
* See \ref pw_proxy
|
||||
*
|
||||
* Some methods on proxy object allow creation of more proxy objects or
|
||||
* create a binding between a local proxy and global resource.
|
||||
*
|
||||
* \section sec_page_proxy_create Create
|
||||
*
|
||||
* A client first creates a new proxy object with pw_proxy_new(). A
|
||||
* type must be provided for this object.
|
||||
*
|
||||
* The protocol of the context will usually install an interface to
|
||||
* translate method calls and events to the wire format.
|
||||
*
|
||||
* The creator of the proxy will usually also install an event
|
||||
* implementation of the particular object type.
|
||||
*
|
||||
* \section sec_page_proxy_bind Bind
|
||||
*
|
||||
* To actually use the proxy object, one needs to create a server
|
||||
* side resource for it. This can be done by, for example, binding
|
||||
* to a global object or by calling a method that creates and binds
|
||||
* to a new remote object. In all cases, the local id is passed to
|
||||
* the server and is used to create a resource with the same id.
|
||||
*
|
||||
* \section sec_page_proxy_methods Methods
|
||||
*
|
||||
* To call a method on the proxy use the interface methods. Calling
|
||||
* any interface method will result in a request to the server to
|
||||
* perform the requested action on the corresponding resource.
|
||||
*
|
||||
* \section sec_page_proxy_events Events
|
||||
*
|
||||
* Events send from the server to the proxy will be demarshalled by
|
||||
* the protocol and will then result in a call to the installed
|
||||
* implementation of the proxy.
|
||||
*
|
||||
* \section sec_page_proxy_destroy Destroy
|
||||
*
|
||||
* Use pw_proxy_destroy() to destroy the client side object. This
|
||||
* is usually done automatically when the server removes the resource
|
||||
* associated to the proxy.
|
||||
*/
|
||||
|
||||
/** \defgroup pw_proxy Proxy
|
||||
*
|
||||
* \brief Represents an object on the client side.
|
||||
*
|
||||
* A pw_proxy acts as a client side proxy to an object existing in a remote
|
||||
* pipewire instance. The proxy is responsible for converting interface functions
|
||||
* invoked by the client to PipeWire messages. Events will call the handlers
|
||||
* set in listener.
|
||||
*
|
||||
* See \ref page_proxy
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_proxy
|
||||
* \{
|
||||
*/
|
||||
struct pw_proxy;
|
||||
|
||||
#include <pipewire/protocol.h>
|
||||
|
||||
/** Proxy events, use \ref pw_proxy_add_listener */
|
||||
struct pw_proxy_events {
|
||||
#define PW_VERSION_PROXY_EVENTS 1
|
||||
uint32_t version;
|
||||
|
||||
/** The proxy is destroyed */
|
||||
void (*destroy) (void *data);
|
||||
|
||||
/** a proxy is bound to a global id */
|
||||
void (*bound) (void *data, uint32_t global_id);
|
||||
|
||||
/** a proxy is removed from the server. Use pw_proxy_destroy to
|
||||
* free the proxy. */
|
||||
void (*removed) (void *data);
|
||||
|
||||
/** a reply to a sync method completed */
|
||||
void (*done) (void *data, int seq);
|
||||
|
||||
/** an error occurred on the proxy */
|
||||
void (*error) (void *data, int seq, int res, const char *message);
|
||||
|
||||
void (*bound_props) (void *data, uint32_t global_id, const struct spa_dict *props);
|
||||
};
|
||||
|
||||
/* Make a new proxy object. The id can be used to bind to a remote object and
|
||||
* can be retrieved with \ref pw_proxy_get_id . */
|
||||
struct pw_proxy *
|
||||
pw_proxy_new(struct pw_proxy *factory,
|
||||
const char *type, /* interface type */
|
||||
uint32_t version, /* interface version */
|
||||
size_t user_data_size /* size of user data */);
|
||||
|
||||
/** Add an event listener to proxy */
|
||||
void pw_proxy_add_listener(struct pw_proxy *proxy,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_proxy_events *events,
|
||||
void *data);
|
||||
|
||||
/** Add a listener for the events received from the remote object. The
|
||||
* events depend on the type of the remote object type. */
|
||||
void pw_proxy_add_object_listener(struct pw_proxy *proxy, /**< the proxy */
|
||||
struct spa_hook *listener, /**< listener */
|
||||
const void *funcs, /**< proxied functions */
|
||||
void *data /**< data passed to events */);
|
||||
|
||||
/** destroy a proxy */
|
||||
void pw_proxy_destroy(struct pw_proxy *proxy);
|
||||
|
||||
void pw_proxy_ref(struct pw_proxy *proxy);
|
||||
void pw_proxy_unref(struct pw_proxy *proxy);
|
||||
|
||||
/** Get the user_data. The size was given in \ref pw_proxy_new */
|
||||
void *pw_proxy_get_user_data(struct pw_proxy *proxy);
|
||||
|
||||
/** Get the local id of the proxy */
|
||||
uint32_t pw_proxy_get_id(struct pw_proxy *proxy);
|
||||
|
||||
/** Get the type and version of the proxy */
|
||||
const char *pw_proxy_get_type(struct pw_proxy *proxy, uint32_t *version);
|
||||
|
||||
/** Get the protocol used for the proxy */
|
||||
struct pw_protocol *pw_proxy_get_protocol(struct pw_proxy *proxy);
|
||||
|
||||
/** Generate an sync method for a proxy. This will generate a done event
|
||||
* with the same seq number of the reply. */
|
||||
int pw_proxy_sync(struct pw_proxy *proxy, int seq);
|
||||
|
||||
/** Set the global id this proxy is bound to. This is usually used internally
|
||||
* and will also emit the bound event */
|
||||
int pw_proxy_set_bound_id(struct pw_proxy *proxy, uint32_t global_id);
|
||||
/** Get the global id bound to this proxy of SPA_ID_INVALID when not bound
|
||||
* to a global */
|
||||
uint32_t pw_proxy_get_bound_id(struct pw_proxy *proxy);
|
||||
|
||||
/** Generate an error for a proxy */
|
||||
int pw_proxy_error(struct pw_proxy *proxy, int res, const char *error);
|
||||
int pw_proxy_errorf(struct pw_proxy *proxy, int res, const char *error, ...) SPA_PRINTF_FUNC(3, 4);
|
||||
|
||||
/** Get the listener of proxy */
|
||||
struct spa_hook_list *pw_proxy_get_object_listeners(struct pw_proxy *proxy);
|
||||
|
||||
/** Get the marshal functions for the proxy */
|
||||
const struct pw_protocol_marshal *pw_proxy_get_marshal(struct pw_proxy *proxy);
|
||||
|
||||
/** Install a marshal function on a proxy */
|
||||
int pw_proxy_install_marshal(struct pw_proxy *proxy, bool implementor);
|
||||
|
||||
#define pw_proxy_notify(p,type,event,version,...) \
|
||||
spa_hook_list_call(pw_proxy_get_object_listeners(p), \
|
||||
type, event, version, ## __VA_ARGS__)
|
||||
|
||||
#define pw_proxy_call(p,type,method,version,...) \
|
||||
spa_interface_call((struct spa_interface*)p, \
|
||||
type, method, version, ##__VA_ARGS__)
|
||||
|
||||
#define pw_proxy_call_res(p,type,method,version,...) \
|
||||
({ \
|
||||
int _res = -ENOTSUP; \
|
||||
spa_interface_call_res((struct spa_interface*)p, \
|
||||
type, _res, method, version, ##__VA_ARGS__); \
|
||||
_res; \
|
||||
})
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_PROXY_H */
|
@ -0,0 +1,509 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_STREAM_H
|
||||
#define PIPEWIRE_STREAM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \page page_streams Streams
|
||||
*
|
||||
* \section sec_overview Overview
|
||||
*
|
||||
* \ref pw_stream "Streams" are used to exchange data with the
|
||||
* PipeWire server. A stream is a wrapper around a proxy for a pw_client_node
|
||||
* with an adapter. This means the stream will automatically do conversion
|
||||
* to the type required by the server.
|
||||
*
|
||||
* Streams can be used to:
|
||||
*
|
||||
* \li Consume a stream from PipeWire. This is a PW_DIRECTION_INPUT stream.
|
||||
* \li Produce a stream to PipeWire. This is a PW_DIRECTION_OUTPUT stream
|
||||
*
|
||||
* You can connect the stream port to a specific server port or let PipeWire
|
||||
* choose a port for you.
|
||||
*
|
||||
* For more complicated nodes such as filters or ports with multiple
|
||||
* inputs and/or outputs you will need to use the pw_filter or make
|
||||
* a pw_node yourself and export it with \ref pw_core_export.
|
||||
*
|
||||
* Streams can also be used to:
|
||||
*
|
||||
* \li Implement a Sink in PipeWire. This is a PW_DIRECTION_INPUT stream.
|
||||
* \li Implement a Source in PipeWire. This is a PW_DIRECTION_OUTPUT stream
|
||||
*
|
||||
* In this case, the PW_KEY_MEDIA_CLASS property needs to be set to
|
||||
* "Audio/Sink" or "Audio/Source" respectively.
|
||||
*
|
||||
* \section sec_create Create
|
||||
*
|
||||
* Make a new stream with \ref pw_stream_new(). You will need to specify
|
||||
* a name for the stream and extra properties. The basic set of properties
|
||||
* each stream must provide is filled in automatically.
|
||||
*
|
||||
* Once the stream is created, the state_changed event should be used to
|
||||
* track the state of the stream.
|
||||
*
|
||||
* \section sec_connect Connect
|
||||
*
|
||||
* The stream is initially unconnected. To connect the stream, use
|
||||
* \ref pw_stream_connect(). Pass the desired direction as an argument.
|
||||
*
|
||||
* The direction is:
|
||||
|
||||
* \li PW_DIRECTION_INPUT for a stream that *consumes* data. This can be a
|
||||
* stream that captures from a Source or a when the stream is used to
|
||||
* implement a Sink.
|
||||
*
|
||||
* \li PW_DIRECTION_OUTPUT for a stream that *produces* data. This can be a
|
||||
* stream that plays to a Sink or when the stream is used to implement
|
||||
* a Source.
|
||||
*
|
||||
* \subsection ssec_stream_target Stream target
|
||||
*
|
||||
* To make the newly connected stream automatically connect to an existing
|
||||
* PipeWire node, use the \ref PW_STREAM_FLAG_AUTOCONNECT and set the
|
||||
* PW_KEY_OBJECT_SERIAL or the PW_KEY_NODE_NAME value of the target node
|
||||
* in the PW_KEY_TARGET_OBJECT property before connecting.
|
||||
*
|
||||
* \subsection ssec_stream_formats Stream formats
|
||||
*
|
||||
* An array of possible formats that this stream can consume or provide
|
||||
* must be specified.
|
||||
*
|
||||
* \section sec_format Format negotiation
|
||||
*
|
||||
* After connecting the stream, the server will want to configure some
|
||||
* parameters on the stream. You will be notified of these changes
|
||||
* with the param_changed event.
|
||||
*
|
||||
* When a format param change is emitted, the client should now prepare
|
||||
* itself to deal with the format and complete the negotiation procedure
|
||||
* with a call to \ref pw_stream_update_params().
|
||||
*
|
||||
* As arguments to \ref pw_stream_update_params() an array of spa_param
|
||||
* structures must be given. They contain parameters such as buffer size,
|
||||
* number of buffers, required metadata and other parameters for the
|
||||
* media buffers.
|
||||
*
|
||||
* \section sec_buffers Buffer negotiation
|
||||
*
|
||||
* After completing the format negotiation, PipeWire will allocate and
|
||||
* notify the stream of the buffers that will be used to exchange data
|
||||
* between client and server.
|
||||
*
|
||||
* With the add_buffer event, a stream will be notified of a new buffer
|
||||
* that can be used for data transport. You can attach user_data to these
|
||||
* buffers. The buffers can only be used with the stream that emitted
|
||||
* the add_buffer event.
|
||||
*
|
||||
* After the buffers are negotiated, the stream will transition to the
|
||||
* \ref PW_STREAM_STATE_PAUSED state.
|
||||
*
|
||||
* \section sec_streaming Streaming
|
||||
*
|
||||
* From the \ref PW_STREAM_STATE_PAUSED state, the stream can be set to
|
||||
* the \ref PW_STREAM_STATE_STREAMING state by the PipeWire server when
|
||||
* data transport is started.
|
||||
*
|
||||
* Depending on how the stream was connected it will need to Produce or
|
||||
* Consume data for/from PipeWire as explained in the following
|
||||
* subsections.
|
||||
*
|
||||
* \subsection ssec_consume Consume data
|
||||
*
|
||||
* The process event is emitted for each new buffer that can be
|
||||
* consumed.
|
||||
*
|
||||
* \ref pw_stream_dequeue_buffer() should be used to get the data and
|
||||
* metadata of the buffer.
|
||||
*
|
||||
* The buffer is owned by the stream and stays alive until the
|
||||
* remove_buffer callback has returned or the stream is destroyed.
|
||||
*
|
||||
* When the buffer has been processed, call \ref pw_stream_queue_buffer()
|
||||
* to let PipeWire reuse the buffer.
|
||||
*
|
||||
* \subsection ssec_produce Produce data
|
||||
*
|
||||
* \ref pw_stream_dequeue_buffer() gives an empty buffer that can be filled.
|
||||
*
|
||||
* The buffer is owned by the stream and stays alive until the
|
||||
* remove_buffer event is emitted or the stream is destroyed.
|
||||
*
|
||||
* Filled buffers should be queued with \ref pw_stream_queue_buffer().
|
||||
*
|
||||
* The process event is emitted when PipeWire has emptied a buffer that
|
||||
* can now be refilled.
|
||||
*
|
||||
* \section sec_stream_disconnect Disconnect
|
||||
*
|
||||
* Use \ref pw_stream_disconnect() to disconnect a stream after use.
|
||||
*
|
||||
* \section sec_stream_configuration Configuration
|
||||
*
|
||||
* \subsection ssec_config_properties Stream Properties
|
||||
*
|
||||
* \subsection ssec_config_rules Stream Rules
|
||||
*
|
||||
* \section sec_stream_environment Environment Variables
|
||||
*
|
||||
*/
|
||||
/** \defgroup pw_stream Stream
|
||||
*
|
||||
* \brief PipeWire stream objects
|
||||
*
|
||||
* The stream object provides a convenient way to send and
|
||||
* receive data streams from/to PipeWire.
|
||||
*
|
||||
* See also \ref page_streams and \ref api_pw_core
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_stream
|
||||
* \{
|
||||
*/
|
||||
struct pw_stream;
|
||||
|
||||
#include <spa/buffer/buffer.h>
|
||||
#include <spa/param/param.h>
|
||||
#include <spa/pod/command.h>
|
||||
|
||||
/** \enum pw_stream_state The state of a stream */
|
||||
enum pw_stream_state {
|
||||
PW_STREAM_STATE_ERROR = -1, /**< the stream is in error */
|
||||
PW_STREAM_STATE_UNCONNECTED = 0, /**< unconnected */
|
||||
PW_STREAM_STATE_CONNECTING = 1, /**< connection is in progress */
|
||||
PW_STREAM_STATE_PAUSED = 2, /**< paused */
|
||||
PW_STREAM_STATE_STREAMING = 3 /**< streaming */
|
||||
};
|
||||
|
||||
/** a buffer structure obtained from pw_stream_dequeue_buffer(). The size of this
|
||||
* structure can grow as more field are added in the future */
|
||||
struct pw_buffer {
|
||||
struct spa_buffer *buffer; /**< the spa buffer */
|
||||
void *user_data; /**< user data attached to the buffer */
|
||||
uint64_t size; /**< This field is set by the user and the sum of
|
||||
* all queued buffer is returned in the time info.
|
||||
* For audio, it is advised to use the number of
|
||||
* samples in the buffer for this field. */
|
||||
uint64_t requested; /**< For playback streams, this field contains the
|
||||
* suggested amount of data to provide. For audio
|
||||
* streams this will be the amount of samples
|
||||
* required by the resampler. This field is 0
|
||||
* when no suggestion is provided. Since 0.3.49 */
|
||||
};
|
||||
|
||||
struct pw_stream_control {
|
||||
const char *name; /**< name of the control */
|
||||
uint32_t flags; /**< extra flags (unused) */
|
||||
float def; /**< default value */
|
||||
float min; /**< min value */
|
||||
float max; /**< max value */
|
||||
float *values; /**< array of values */
|
||||
uint32_t n_values; /**< number of values in array */
|
||||
uint32_t max_values; /**< max values that can be set on this control */
|
||||
};
|
||||
|
||||
/** A time structure.
|
||||
*
|
||||
* Use pw_stream_get_time_n() to get an updated time snapshot of the stream.
|
||||
* The time snapshot can give information about the time in the driver of the
|
||||
* graph, the delay to the edge of the graph and the internal queuing in the
|
||||
* stream.
|
||||
*
|
||||
* pw_time.ticks gives a monotonic increasing counter of the time in the graph
|
||||
* driver. I can be used to generate a timetime to schedule samples as well
|
||||
* as detect discontinuities in the timeline caused by xruns.
|
||||
*
|
||||
* pw_time.delay is expressed as pw_time.rate, the time domain of the graph. This
|
||||
* value, and pw_time.ticks, were captured at pw_time.now and can be extrapolated
|
||||
* to the current time like this:
|
||||
*
|
||||
* struct timespec ts;
|
||||
* clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
* int64_t diff = SPA_TIMESPEC_TO_NSEC(&ts) - pw_time.now;
|
||||
* int64_t elapsed = (pw_time.rate.denom * diff) / (pw_time.rate.num * SPA_NSEC_PER_SEC);
|
||||
*
|
||||
* pw_time.delay contains the total delay that a signal will travel through the
|
||||
* graph. This includes the delay caused by filters in the graph as well as delays
|
||||
* caused by the hardware. The delay is usually quite stable and should only change when
|
||||
* the topology, quantum or samplerate of the graph changes.
|
||||
*
|
||||
* pw_time.queued and pw_time.buffered is expressed in the time domain of the stream,
|
||||
* or the format that is used for the buffers of this stream.
|
||||
*
|
||||
* pw_time.queued is the sum of all the pw_buffer.size fields of the buffers that are
|
||||
* currently queued in the stream but not yet processed. The application can choose
|
||||
* the units of this value, for example, time, samples or bytes (below expressed
|
||||
* as app.rate).
|
||||
*
|
||||
* pw_time.buffered is format dependent, for audio/raw it contains the number of samples
|
||||
* that are buffered inside the resampler/converter.
|
||||
*
|
||||
* The total delay of data in a stream is the sum of the queued and buffered data
|
||||
* (not yet processed data) and the delay to the edge of the graph, usually a
|
||||
* playback or capture device.
|
||||
*
|
||||
* For an audio playback stream, if you were to queue a buffer, the total delay
|
||||
* in milliseconds for the first sample in the newly queued buffer to be played
|
||||
* by the hardware can be calculated as:
|
||||
*
|
||||
* (pw_time.buffered * 1000 / stream.samplerate) +
|
||||
* (pw_time.queued * 1000 / app.rate) +
|
||||
* ((pw_time.delay - elapsed) * 1000 * pw_time.rate.num / pw_time.rate.denom)
|
||||
*
|
||||
* The current extrapolated time (in ms) in the source or sink can be calculated as:
|
||||
*
|
||||
* (pw_time.ticks + elapsed) * 1000 * pw_time.rate.num / pw_time.rate.denom
|
||||
*
|
||||
*
|
||||
* stream time domain graph time domain
|
||||
* /-----------------------\/-----------------------------\
|
||||
*
|
||||
* queue +-+ +-+ +-----------+ +--------+
|
||||
* ----> | | | |->| converter | -> graph -> | kernel | -> speaker
|
||||
* <---- +-+ +-+ +-----------+ +--------+
|
||||
* dequeue buffers \-------------------/\--------/
|
||||
* graph internal
|
||||
* latency latency
|
||||
* \--------/\-------------/\-----------------------------/
|
||||
* queued buffered delay
|
||||
*/
|
||||
struct pw_time {
|
||||
int64_t now; /**< the monotonic time in nanoseconds. This is the time
|
||||
* when this time report was updated. It is usually
|
||||
* updated every graph cycle. You can use the current
|
||||
* monotonic time to calculate the elapsed time between
|
||||
* this report and the current state and calculate
|
||||
* updated ticks and delay values. */
|
||||
struct spa_fraction rate; /**< the rate of \a ticks and delay. This is usually
|
||||
* expressed in 1/<samplerate>. */
|
||||
uint64_t ticks; /**< the ticks at \a now. This is the current time that
|
||||
* the remote end is reading/writing. This is monotonicaly
|
||||
* increasing. */
|
||||
int64_t delay; /**< delay to device. This is the time it will take for
|
||||
* the next output sample of the stream to be presented by
|
||||
* the playback device or the time a sample traveled
|
||||
* from the capture device. This delay includes the
|
||||
* delay introduced by all filters on the path between
|
||||
* the stream and the device. The delay is normally
|
||||
* constant in a graph and can change when the topology
|
||||
* of the graph or the quantum changes. This delay does
|
||||
* not include the delay caused by queued buffers. */
|
||||
uint64_t queued; /**< data queued in the stream, this is the sum
|
||||
* of the size fields in the pw_buffer that are
|
||||
* currently queued */
|
||||
uint64_t buffered; /**< for audio/raw streams, this contains the extra
|
||||
* number of samples buffered in the resampler.
|
||||
* Since 0.3.50. */
|
||||
uint32_t queued_buffers; /**< The number of buffers that are queued. Since 0.3.50 */
|
||||
uint32_t avail_buffers; /**< The number of buffers that can be dequeued. Since 0.3.50 */
|
||||
};
|
||||
|
||||
#include <pipewire/port.h>
|
||||
|
||||
/** Events for a stream. These events are always called from the mainloop
|
||||
* unless explicitly documented otherwise. */
|
||||
struct pw_stream_events {
|
||||
#define PW_VERSION_STREAM_EVENTS 2
|
||||
uint32_t version;
|
||||
|
||||
void (*destroy) (void *data);
|
||||
/** when the stream state changes */
|
||||
void (*state_changed) (void *data, enum pw_stream_state old,
|
||||
enum pw_stream_state state, const char *error);
|
||||
|
||||
/** Notify information about a control. */
|
||||
void (*control_info) (void *data, uint32_t id, const struct pw_stream_control *control);
|
||||
|
||||
/** when io changed on the stream. */
|
||||
void (*io_changed) (void *data, uint32_t id, void *area, uint32_t size);
|
||||
/** when a parameter changed */
|
||||
void (*param_changed) (void *data, uint32_t id, const struct spa_pod *param);
|
||||
|
||||
/** when a new buffer was created for this stream */
|
||||
void (*add_buffer) (void *data, struct pw_buffer *buffer);
|
||||
/** when a buffer was destroyed for this stream */
|
||||
void (*remove_buffer) (void *data, struct pw_buffer *buffer);
|
||||
|
||||
/** when a buffer can be queued (for playback streams) or
|
||||
* dequeued (for capture streams). This is normally called from the
|
||||
* mainloop but can also be called directly from the realtime data
|
||||
* thread if the user is prepared to deal with this. */
|
||||
void (*process) (void *data);
|
||||
|
||||
/** The stream is drained */
|
||||
void (*drained) (void *data);
|
||||
|
||||
/** A command notify, Since 0.3.39:1 */
|
||||
void (*command) (void *data, const struct spa_command *command);
|
||||
|
||||
/** a trigger_process completed. Since version 0.3.40:2 */
|
||||
void (*trigger_done) (void *data);
|
||||
};
|
||||
|
||||
/** Convert a stream state to a readable string */
|
||||
const char * pw_stream_state_as_string(enum pw_stream_state state);
|
||||
|
||||
/** \enum pw_stream_flags Extra flags that can be used in \ref pw_stream_connect() */
|
||||
enum pw_stream_flags {
|
||||
PW_STREAM_FLAG_NONE = 0, /**< no flags */
|
||||
PW_STREAM_FLAG_AUTOCONNECT = (1 << 0), /**< try to automatically connect
|
||||
* this stream */
|
||||
PW_STREAM_FLAG_INACTIVE = (1 << 1), /**< start the stream inactive,
|
||||
* pw_stream_set_active() needs to be
|
||||
* called explicitly */
|
||||
PW_STREAM_FLAG_MAP_BUFFERS = (1 << 2), /**< mmap the buffers except DmaBuf */
|
||||
PW_STREAM_FLAG_DRIVER = (1 << 3), /**< be a driver */
|
||||
PW_STREAM_FLAG_RT_PROCESS = (1 << 4), /**< call process from the realtime
|
||||
* thread. You MUST use RT safe functions
|
||||
* in the process callback. */
|
||||
PW_STREAM_FLAG_NO_CONVERT = (1 << 5), /**< don't convert format */
|
||||
PW_STREAM_FLAG_EXCLUSIVE = (1 << 6), /**< require exclusive access to the
|
||||
* device */
|
||||
PW_STREAM_FLAG_DONT_RECONNECT = (1 << 7), /**< don't try to reconnect this stream
|
||||
* when the sink/source is removed */
|
||||
PW_STREAM_FLAG_ALLOC_BUFFERS = (1 << 8), /**< the application will allocate buffer
|
||||
* memory. In the add_buffer event, the
|
||||
* data of the buffer should be set */
|
||||
PW_STREAM_FLAG_TRIGGER = (1 << 9), /**< the output stream will not be scheduled
|
||||
* automatically but _trigger_process()
|
||||
* needs to be called. This can be used
|
||||
* when the output of the stream depends
|
||||
* on input from other streams. */
|
||||
};
|
||||
|
||||
/** Create a new unconneced \ref pw_stream
|
||||
* \return a newly allocated \ref pw_stream */
|
||||
struct pw_stream *
|
||||
pw_stream_new(struct pw_core *core, /**< a \ref pw_core */
|
||||
const char *name, /**< a stream media name */
|
||||
struct pw_properties *props /**< stream properties, ownership is taken */);
|
||||
|
||||
struct pw_stream *
|
||||
pw_stream_new_simple(struct pw_loop *loop, /**< a \ref pw_loop to use */
|
||||
const char *name, /**< a stream media name */
|
||||
struct pw_properties *props,/**< stream properties, ownership is taken */
|
||||
const struct pw_stream_events *events, /**< stream events */
|
||||
void *data /**< data passed to events */);
|
||||
|
||||
/** Destroy a stream */
|
||||
void pw_stream_destroy(struct pw_stream *stream);
|
||||
|
||||
void pw_stream_add_listener(struct pw_stream *stream,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_stream_events *events,
|
||||
void *data);
|
||||
|
||||
enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char **error);
|
||||
|
||||
const char *pw_stream_get_name(struct pw_stream *stream);
|
||||
|
||||
struct pw_core *pw_stream_get_core(struct pw_stream *stream);
|
||||
|
||||
const struct pw_properties *pw_stream_get_properties(struct pw_stream *stream);
|
||||
|
||||
int pw_stream_update_properties(struct pw_stream *stream, const struct spa_dict *dict);
|
||||
|
||||
/** Connect a stream for input or output on \a port_path.
|
||||
* \return 0 on success < 0 on error.
|
||||
*
|
||||
* You should connect to the process event and use pw_stream_dequeue_buffer()
|
||||
* to get the latest metadata and data. */
|
||||
int
|
||||
pw_stream_connect(struct pw_stream *stream, /**< a \ref pw_stream */
|
||||
enum pw_direction direction, /**< the stream direction */
|
||||
uint32_t target_id, /**< should have the value PW_ID_ANY.
|
||||
* To select a specific target
|
||||
* node, specify the
|
||||
* PW_KEY_OBJECT_SERIAL or the
|
||||
* PW_KEY_NODE_NAME value of the target
|
||||
* node in the PW_KEY_TARGET_OBJECT
|
||||
* property of the stream.
|
||||
* Specifying target nodes by
|
||||
* their id is deprecated.
|
||||
*/
|
||||
enum pw_stream_flags flags, /**< stream flags */
|
||||
const struct spa_pod **params, /**< an array with params. The params
|
||||
* should ideally contain supported
|
||||
* formats. */
|
||||
uint32_t n_params /**< number of items in \a params */);
|
||||
|
||||
/** Get the node ID of the stream.
|
||||
* \return node ID. */
|
||||
uint32_t
|
||||
pw_stream_get_node_id(struct pw_stream *stream);
|
||||
|
||||
/** Disconnect \a stream */
|
||||
int pw_stream_disconnect(struct pw_stream *stream);
|
||||
|
||||
/** Set the stream in error state */
|
||||
int pw_stream_set_error(struct pw_stream *stream, /**< a \ref pw_stream */
|
||||
int res, /**< a result code */
|
||||
const char *error, /**< an error message */
|
||||
...) SPA_PRINTF_FUNC(3, 4);
|
||||
|
||||
/** Complete the negotiation process with result code \a res
|
||||
*
|
||||
* This function should be called after notification of the format.
|
||||
|
||||
* When \a res indicates success, \a params contain the parameters for the
|
||||
* allocation state. */
|
||||
int
|
||||
pw_stream_update_params(struct pw_stream *stream, /**< a \ref pw_stream */
|
||||
const struct spa_pod **params, /**< an array of params. The params should
|
||||
* ideally contain parameters for doing
|
||||
* buffer allocation. */
|
||||
uint32_t n_params /**< number of elements in \a params */);
|
||||
|
||||
/** Get control values */
|
||||
const struct pw_stream_control *pw_stream_get_control(struct pw_stream *stream, uint32_t id);
|
||||
|
||||
/** Set control values */
|
||||
int pw_stream_set_control(struct pw_stream *stream, uint32_t id, uint32_t n_values, float *values, ...);
|
||||
|
||||
/** Query the time on the stream */
|
||||
int pw_stream_get_time_n(struct pw_stream *stream, struct pw_time *time, size_t size);
|
||||
|
||||
/** Query the time on the stream, deprecated since 0.3.50,
|
||||
* use pw_stream_get_time_n() to get the fields added since 0.3.50. */
|
||||
SPA_DEPRECATED
|
||||
int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time);
|
||||
|
||||
/** Get a buffer that can be filled for playback streams or consumed
|
||||
* for capture streams. */
|
||||
struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream);
|
||||
|
||||
/** Submit a buffer for playback or recycle a buffer for capture. */
|
||||
int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer);
|
||||
|
||||
/** Activate or deactivate the stream */
|
||||
int pw_stream_set_active(struct pw_stream *stream, bool active);
|
||||
|
||||
/** Flush a stream. When \a drain is true, the drained callback will
|
||||
* be called when all data is played or recorded */
|
||||
int pw_stream_flush(struct pw_stream *stream, bool drain);
|
||||
|
||||
/** Check if the stream is driving. The stream needs to have the
|
||||
* PW_STREAM_FLAG_DRIVER set. When the stream is driving,
|
||||
* pw_stream_trigger_process() needs to be called when data is
|
||||
* available (output) or needed (input). Since 0.3.34 */
|
||||
bool pw_stream_is_driving(struct pw_stream *stream);
|
||||
|
||||
/** Trigger a push/pull on the stream. One iteration of the graph will
|
||||
* scheduled and process() will be called. Since 0.3.34 */
|
||||
int pw_stream_trigger_process(struct pw_stream *stream);
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_STREAM_H */
|
@ -0,0 +1,99 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_UTILS_H
|
||||
#define PIPEWIRE_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/un.h>
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
# include <sys/mount.h>
|
||||
#endif
|
||||
|
||||
#ifndef ENODATA
|
||||
#define ENODATA 9919
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
/** \defgroup pw_utils Utilities
|
||||
*
|
||||
* Various utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup pw_utils
|
||||
* \{
|
||||
*/
|
||||
|
||||
/** a function to destroy an item */
|
||||
typedef void (*pw_destroy_t) (void *object);
|
||||
|
||||
const char *
|
||||
pw_split_walk(const char *str, const char *delimiter, size_t *len, const char **state);
|
||||
|
||||
char **
|
||||
pw_split_strv(const char *str, const char *delimiter, int max_tokens, int *n_tokens);
|
||||
|
||||
int
|
||||
pw_split_ip(char *str, const char *delimiter, int max_tokens, char *tokens[]);
|
||||
|
||||
void
|
||||
pw_free_strv(char **str);
|
||||
|
||||
char *
|
||||
pw_strip(char *str, const char *whitespace);
|
||||
|
||||
#if !defined(strndupa)
|
||||
# define strndupa(s, n) \
|
||||
({ \
|
||||
const char *__old = (s); \
|
||||
size_t __len = strnlen(__old, (n)); \
|
||||
char *__new = (char *) __builtin_alloca(__len + 1); \
|
||||
memcpy(__new, __old, __len); \
|
||||
__new[__len] = '\0'; \
|
||||
__new; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#if !defined(strdupa)
|
||||
# define strdupa(s) \
|
||||
({ \
|
||||
const char *__old = (s); \
|
||||
size_t __len = strlen(__old) + 1; \
|
||||
char *__new = (char *) alloca(__len); \
|
||||
(char *) memcpy(__new, __old, __len); \
|
||||
})
|
||||
#endif
|
||||
|
||||
SPA_WARN_UNUSED_RESULT
|
||||
ssize_t pw_getrandom(void *buf, size_t buflen, unsigned int flags);
|
||||
|
||||
void pw_random(void *buf, size_t buflen);
|
||||
|
||||
#define pw_rand32() ({ uint32_t val; pw_random(&val, sizeof(val)); val; })
|
||||
|
||||
void* pw_reallocarray(void *ptr, size_t nmemb, size_t size);
|
||||
|
||||
#ifdef PW_ENABLE_DEPRECATED
|
||||
#define PW_DEPRECATED(v) (v)
|
||||
#else
|
||||
#define PW_DEPRECATED(v) ({ __typeof__(v) _v SPA_DEPRECATED = (v); (void)_v; (v); })
|
||||
#endif /* PW_ENABLE_DEPRECATED */
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_UTILS_H */
|
@ -0,0 +1,112 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_BUFFER_H
|
||||
#define SPA_BUFFER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/buffer/meta.h>
|
||||
|
||||
/** \defgroup spa_buffer Buffers
|
||||
*
|
||||
* Buffers describe the data and metadata that is exchanged between
|
||||
* ports of a node.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup spa_buffer
|
||||
* \{
|
||||
*/
|
||||
|
||||
enum spa_data_type {
|
||||
SPA_DATA_Invalid,
|
||||
SPA_DATA_MemPtr, /**< pointer to memory, the data field in
|
||||
* struct spa_data is set. */
|
||||
SPA_DATA_MemFd, /**< generic fd, mmap to get to memory */
|
||||
SPA_DATA_DmaBuf, /**< fd to dmabuf memory */
|
||||
SPA_DATA_MemId, /**< memory is identified with an id */
|
||||
|
||||
_SPA_DATA_LAST, /**< not part of ABI */
|
||||
};
|
||||
|
||||
/** Chunk of memory, can change for each buffer */
|
||||
struct spa_chunk {
|
||||
uint32_t offset; /**< offset of valid data. Should be taken
|
||||
* modulo the data maxsize to get the offset
|
||||
* in the data memory. */
|
||||
uint32_t size; /**< size of valid data. Should be clamped to
|
||||
* maxsize. */
|
||||
int32_t stride; /**< stride of valid data */
|
||||
#define SPA_CHUNK_FLAG_NONE 0
|
||||
#define SPA_CHUNK_FLAG_CORRUPTED (1u<<0) /**< chunk data is corrupted in some way */
|
||||
#define SPA_CHUNK_FLAG_EMPTY (1u<<1) /**< chunk data is empty with media specific
|
||||
* neutral data such as silence or black. This
|
||||
* could be used to optimize processing. */
|
||||
int32_t flags; /**< chunk flags */
|
||||
};
|
||||
|
||||
/** Data for a buffer this stays constant for a buffer */
|
||||
struct spa_data {
|
||||
uint32_t type; /**< memory type, one of enum spa_data_type, when
|
||||
* allocating memory, the type contains a bitmask
|
||||
* of allowed types. SPA_ID_INVALID is a special
|
||||
* value for the allocator to indicate that the
|
||||
* other side did not explicitly specify any
|
||||
* supported data types. It should probably use
|
||||
* a memory type that does not require special
|
||||
* handling in addition to simple mmap/munmap. */
|
||||
#define SPA_DATA_FLAG_NONE 0
|
||||
#define SPA_DATA_FLAG_READABLE (1u<<0) /**< data is readable */
|
||||
#define SPA_DATA_FLAG_WRITABLE (1u<<1) /**< data is writable */
|
||||
#define SPA_DATA_FLAG_DYNAMIC (1u<<2) /**< data pointer can be changed */
|
||||
#define SPA_DATA_FLAG_READWRITE (SPA_DATA_FLAG_READABLE|SPA_DATA_FLAG_WRITABLE)
|
||||
uint32_t flags; /**< data flags */
|
||||
int64_t fd; /**< optional fd for data */
|
||||
uint32_t mapoffset; /**< offset to map fd at */
|
||||
uint32_t maxsize; /**< max size of data */
|
||||
void *data; /**< optional data pointer */
|
||||
struct spa_chunk *chunk; /**< valid chunk of memory */
|
||||
};
|
||||
|
||||
/** A Buffer */
|
||||
struct spa_buffer {
|
||||
uint32_t n_metas; /**< number of metadata */
|
||||
uint32_t n_datas; /**< number of data members */
|
||||
struct spa_meta *metas; /**< array of metadata */
|
||||
struct spa_data *datas; /**< array of data members */
|
||||
};
|
||||
|
||||
/** Find metadata in a buffer */
|
||||
static inline struct spa_meta *spa_buffer_find_meta(const struct spa_buffer *b, uint32_t type)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < b->n_metas; i++)
|
||||
if (b->metas[i].type == type)
|
||||
return &b->metas[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void *spa_buffer_find_meta_data(const struct spa_buffer *b, uint32_t type, size_t size)
|
||||
{
|
||||
struct spa_meta *m;
|
||||
if ((m = spa_buffer_find_meta(b, type)) && m->size >= size)
|
||||
return m->data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_BUFFER_H */
|
@ -0,0 +1,172 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_META_H
|
||||
#define SPA_META_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
/**
|
||||
* \addtogroup spa_buffer
|
||||
* \{
|
||||
*/
|
||||
|
||||
enum spa_meta_type {
|
||||
SPA_META_Invalid,
|
||||
SPA_META_Header, /**< struct spa_meta_header */
|
||||
SPA_META_VideoCrop, /**< struct spa_meta_region with cropping data */
|
||||
SPA_META_VideoDamage, /**< array of struct spa_meta_region with damage, where an invalid entry or end-of-array marks the end. */
|
||||
SPA_META_Bitmap, /**< struct spa_meta_bitmap */
|
||||
SPA_META_Cursor, /**< struct spa_meta_cursor */
|
||||
SPA_META_Control, /**< metadata contains a spa_meta_control
|
||||
* associated with the data */
|
||||
SPA_META_Busy, /**< don't write to buffer when count > 0 */
|
||||
SPA_META_VideoTransform, /**< struct spa_meta_transform */
|
||||
|
||||
_SPA_META_LAST, /**< not part of ABI/API */
|
||||
};
|
||||
|
||||
/**
|
||||
* A metadata element.
|
||||
*
|
||||
* This structure is available on the buffer structure and contains
|
||||
* the type of the metadata and a pointer/size to the actual metadata
|
||||
* itself.
|
||||
*/
|
||||
struct spa_meta {
|
||||
uint32_t type; /**< metadata type, one of enum spa_meta_type */
|
||||
uint32_t size; /**< size of metadata */
|
||||
void *data; /**< pointer to metadata */
|
||||
};
|
||||
|
||||
static inline void *spa_meta_first(const struct spa_meta *m) {
|
||||
return m->data;
|
||||
}
|
||||
#define spa_meta_first spa_meta_first
|
||||
static inline void *spa_meta_end(const struct spa_meta *m) {
|
||||
return SPA_PTROFF(m->data,m->size,void);
|
||||
}
|
||||
#define spa_meta_end spa_meta_end
|
||||
#define spa_meta_check(p,m) (SPA_PTROFF(p,sizeof(*(p)),void) <= spa_meta_end(m))
|
||||
|
||||
/**
|
||||
* Describes essential buffer header metadata such as flags and
|
||||
* timestamps.
|
||||
*/
|
||||
struct spa_meta_header {
|
||||
#define SPA_META_HEADER_FLAG_DISCONT (1 << 0) /**< data is not continuous with previous buffer */
|
||||
#define SPA_META_HEADER_FLAG_CORRUPTED (1 << 1) /**< data might be corrupted */
|
||||
#define SPA_META_HEADER_FLAG_MARKER (1 << 2) /**< media specific marker */
|
||||
#define SPA_META_HEADER_FLAG_HEADER (1 << 3) /**< data contains a codec specific header */
|
||||
#define SPA_META_HEADER_FLAG_GAP (1 << 4) /**< data contains media neutral data */
|
||||
#define SPA_META_HEADER_FLAG_DELTA_UNIT (1 << 5) /**< cannot be decoded independently */
|
||||
uint32_t flags; /**< flags */
|
||||
uint32_t offset; /**< offset in current cycle */
|
||||
int64_t pts; /**< presentation timestamp in nanoseconds */
|
||||
int64_t dts_offset; /**< decoding timestamp as a difference with pts */
|
||||
uint64_t seq; /**< sequence number, increments with a
|
||||
* media specific frequency */
|
||||
};
|
||||
|
||||
/** metadata structure for Region or an array of these for RegionArray */
|
||||
struct spa_meta_region {
|
||||
struct spa_region region;
|
||||
};
|
||||
|
||||
static inline bool spa_meta_region_is_valid(const struct spa_meta_region *m) {
|
||||
return m->region.size.width != 0 && m->region.size.height != 0;
|
||||
}
|
||||
#define spa_meta_region_is_valid spa_meta_region_is_valid
|
||||
|
||||
/** iterate all the items in a metadata */
|
||||
#define spa_meta_for_each(pos,meta) \
|
||||
for ((pos) = (__typeof(pos))spa_meta_first(meta); \
|
||||
spa_meta_check(pos, meta); \
|
||||
(pos)++)
|
||||
|
||||
#define spa_meta_bitmap_is_valid(m) ((m)->format != 0)
|
||||
|
||||
/**
|
||||
* Bitmap information
|
||||
*
|
||||
* This metadata contains a bitmap image in the given format and size.
|
||||
* It is typically used for cursor images or other small images that are
|
||||
* better transferred inline.
|
||||
*/
|
||||
struct spa_meta_bitmap {
|
||||
uint32_t format; /**< bitmap video format, one of enum spa_video_format. 0 is
|
||||
* and invalid format and should be handled as if there is
|
||||
* no new bitmap information. */
|
||||
struct spa_rectangle size; /**< width and height of bitmap */
|
||||
int32_t stride; /**< stride of bitmap data */
|
||||
uint32_t offset; /**< offset of bitmap data in this structure. An offset of
|
||||
* 0 means no image data (invisible), an offset >=
|
||||
* sizeof(struct spa_meta_bitmap) contains valid bitmap
|
||||
* info. */
|
||||
};
|
||||
|
||||
#define spa_meta_cursor_is_valid(m) ((m)->id != 0)
|
||||
|
||||
/**
|
||||
* Cursor information
|
||||
*
|
||||
* Metadata to describe the position and appearance of a pointing device.
|
||||
*/
|
||||
struct spa_meta_cursor {
|
||||
uint32_t id; /**< cursor id. an id of 0 is an invalid id and means that
|
||||
* there is no new cursor data */
|
||||
uint32_t flags; /**< extra flags */
|
||||
struct spa_point position; /**< position on screen */
|
||||
struct spa_point hotspot; /**< offsets for hotspot in bitmap, this field has no meaning
|
||||
* when there is no valid bitmap (see below) */
|
||||
uint32_t bitmap_offset; /**< offset of bitmap meta in this structure. When the offset
|
||||
* is 0, there is no new bitmap information. When the offset is
|
||||
* >= sizeof(struct spa_meta_cursor) there is a
|
||||
* struct spa_meta_bitmap at the offset. */
|
||||
};
|
||||
|
||||
/** a timed set of events associated with the buffer */
|
||||
struct spa_meta_control {
|
||||
struct spa_pod_sequence sequence;
|
||||
};
|
||||
|
||||
/** a busy counter for the buffer */
|
||||
struct spa_meta_busy {
|
||||
uint32_t flags;
|
||||
uint32_t count; /**< number of users busy with the buffer */
|
||||
};
|
||||
|
||||
enum spa_meta_videotransform_value {
|
||||
SPA_META_TRANSFORMATION_None = 0, /**< no transform */
|
||||
SPA_META_TRANSFORMATION_90, /**< 90 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_180, /**< 180 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_270, /**< 270 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_Flipped, /**< 180 degree flipped around the vertical axis. Equivalent
|
||||
* to a reflexion through the vertical line splitting the
|
||||
* bufffer in two equal sized parts */
|
||||
SPA_META_TRANSFORMATION_Flipped90, /**< flip then rotate around 90 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_Flipped180, /**< flip then rotate around 180 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_Flipped270, /**< flip then rotate around 270 degree counter-clockwise */
|
||||
};
|
||||
|
||||
/** a transformation of the buffer */
|
||||
struct spa_meta_videotransform {
|
||||
uint32_t transform; /**< orientation transformation that was applied to the buffer,
|
||||
* one of enum spa_meta_videotransform_value */
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_META_H */
|
@ -0,0 +1,74 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_BUFFER_TYPES_H
|
||||
#define SPA_BUFFER_TYPES_H
|
||||
|
||||
/**
|
||||
* \addtogroup spa_buffer
|
||||
* \{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/buffer/buffer.h>
|
||||
#include <spa/buffer/meta.h>
|
||||
#include <spa/utils/type.h>
|
||||
|
||||
#define SPA_TYPE_INFO_Buffer SPA_TYPE_INFO_POINTER_BASE "Buffer"
|
||||
#define SPA_TYPE_INFO_BUFFER_BASE SPA_TYPE_INFO_Buffer ":"
|
||||
|
||||
/** Buffers contain data of a certain type */
|
||||
#define SPA_TYPE_INFO_Data SPA_TYPE_INFO_ENUM_BASE "Data"
|
||||
#define SPA_TYPE_INFO_DATA_BASE SPA_TYPE_INFO_Data ":"
|
||||
|
||||
/** base type for fd based memory */
|
||||
#define SPA_TYPE_INFO_DATA_Fd SPA_TYPE_INFO_DATA_BASE "Fd"
|
||||
#define SPA_TYPE_INFO_DATA_FD_BASE SPA_TYPE_INFO_DATA_Fd ":"
|
||||
|
||||
static const struct spa_type_info spa_type_data_type[] = {
|
||||
{ SPA_DATA_Invalid, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_BASE "Invalid", NULL },
|
||||
{ SPA_DATA_MemPtr, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_BASE "MemPtr", NULL },
|
||||
{ SPA_DATA_MemFd, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_FD_BASE "MemFd", NULL },
|
||||
{ SPA_DATA_DmaBuf, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_FD_BASE "DmaBuf", NULL },
|
||||
{ SPA_DATA_MemId, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_BASE "MemId", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_Meta SPA_TYPE_INFO_POINTER_BASE "Meta"
|
||||
#define SPA_TYPE_INFO_META_BASE SPA_TYPE_INFO_Meta ":"
|
||||
|
||||
#define SPA_TYPE_INFO_META_Array SPA_TYPE_INFO_META_BASE "Array"
|
||||
#define SPA_TYPE_INFO_META_ARRAY_BASE SPA_TYPE_INFO_META_Array ":"
|
||||
|
||||
#define SPA_TYPE_INFO_META_Region SPA_TYPE_INFO_META_BASE "Region"
|
||||
#define SPA_TYPE_INFO_META_REGION_BASE SPA_TYPE_INFO_META_Region ":"
|
||||
|
||||
#define SPA_TYPE_INFO_META_ARRAY_Region SPA_TYPE_INFO_META_ARRAY_BASE "Region"
|
||||
#define SPA_TYPE_INFO_META_ARRAY_REGION_BASE SPA_TYPE_INFO_META_ARRAY_Region ":"
|
||||
|
||||
static const struct spa_type_info spa_type_meta_type[] = {
|
||||
{ SPA_META_Invalid, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Invalid", NULL },
|
||||
{ SPA_META_Header, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Header", NULL },
|
||||
{ SPA_META_VideoCrop, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_REGION_BASE "VideoCrop", NULL },
|
||||
{ SPA_META_VideoDamage, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_ARRAY_REGION_BASE "VideoDamage", NULL },
|
||||
{ SPA_META_Bitmap, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Bitmap", NULL },
|
||||
{ SPA_META_Cursor, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Cursor", NULL },
|
||||
{ SPA_META_Control, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Control", NULL },
|
||||
{ SPA_META_Busy, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Busy", NULL },
|
||||
{ SPA_META_VideoTransform, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "VideoTransform", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_BUFFER_TYPES_H */
|
@ -0,0 +1,42 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_CONTROL_H
|
||||
#define SPA_CONTROL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
/** \defgroup spa_control Control
|
||||
* Control type declarations
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup spa_control
|
||||
* \{
|
||||
*/
|
||||
|
||||
/** Different Control types */
|
||||
enum spa_control_type {
|
||||
SPA_CONTROL_Invalid,
|
||||
SPA_CONTROL_Properties, /**< data contains a SPA_TYPE_OBJECT_Props */
|
||||
SPA_CONTROL_Midi, /**< data contains a spa_pod_bytes with raw midi data */
|
||||
SPA_CONTROL_OSC, /**< data contains a spa_pod_bytes with an OSC packet */
|
||||
|
||||
_SPA_CONTROL_LAST, /**< not part of ABI */
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_CONTROL_H */
|
@ -0,0 +1,41 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_CONTROL_TYPES_H
|
||||
#define SPA_CONTROL_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_control
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/type-info.h>
|
||||
#include <spa/control/control.h>
|
||||
|
||||
/* base for parameter object enumerations */
|
||||
#define SPA_TYPE_INFO_Control SPA_TYPE_INFO_ENUM_BASE "Control"
|
||||
#define SPA_TYPE_INFO_CONTROL_BASE SPA_TYPE_INFO_Control ":"
|
||||
|
||||
static const struct spa_type_info spa_type_control[] = {
|
||||
{ SPA_CONTROL_Invalid, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "Invalid", NULL },
|
||||
{ SPA_CONTROL_Properties, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "Properties", NULL },
|
||||
{ SPA_CONTROL_Midi, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "Midi", NULL },
|
||||
{ SPA_CONTROL_OSC, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "OSC", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_CONTROL_TYPES_H */
|
@ -0,0 +1,107 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_DEBUG_TYPES_H
|
||||
#define SPA_DEBUG_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_debug
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/utils/type-info.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static inline const struct spa_type_info *spa_debug_type_find(const struct spa_type_info *info, uint32_t type)
|
||||
{
|
||||
const struct spa_type_info *res;
|
||||
|
||||
if (info == NULL)
|
||||
info = SPA_TYPE_ROOT;
|
||||
|
||||
while (info && info->name) {
|
||||
if (info->type == SPA_ID_INVALID) {
|
||||
if (info->values && (res = spa_debug_type_find(info->values, type)))
|
||||
return res;
|
||||
}
|
||||
else if (info->type == type)
|
||||
return info;
|
||||
info++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const char *spa_debug_type_short_name(const char *name)
|
||||
{
|
||||
const char *h;
|
||||
if ((h = strrchr(name, ':')) != NULL)
|
||||
name = h + 1;
|
||||
return name;
|
||||
}
|
||||
|
||||
static inline const char *spa_debug_type_find_name(const struct spa_type_info *info, uint32_t type)
|
||||
{
|
||||
if ((info = spa_debug_type_find(info, type)) == NULL)
|
||||
return NULL;
|
||||
return info->name;
|
||||
}
|
||||
|
||||
static inline const char *spa_debug_type_find_short_name(const struct spa_type_info *info, uint32_t type)
|
||||
{
|
||||
const char *str;
|
||||
if ((str = spa_debug_type_find_name(info, type)) == NULL)
|
||||
return NULL;
|
||||
return spa_debug_type_short_name(str);
|
||||
}
|
||||
|
||||
static inline uint32_t spa_debug_type_find_type(const struct spa_type_info *info, const char *name)
|
||||
{
|
||||
if (info == NULL)
|
||||
info = SPA_TYPE_ROOT;
|
||||
|
||||
while (info && info->name) {
|
||||
uint32_t res;
|
||||
if (strcmp(info->name, name) == 0)
|
||||
return info->type;
|
||||
if (info->values && (res = spa_debug_type_find_type(info->values, name)) != SPA_ID_INVALID)
|
||||
return res;
|
||||
info++;
|
||||
}
|
||||
return SPA_ID_INVALID;
|
||||
}
|
||||
|
||||
static inline const struct spa_type_info *spa_debug_type_find_short(const struct spa_type_info *info, const char *name)
|
||||
{
|
||||
while (info && info->name) {
|
||||
if (strcmp(spa_debug_type_short_name(info->name), name) == 0)
|
||||
return info;
|
||||
if (strcmp(info->name, name) == 0)
|
||||
return info;
|
||||
if (info->type != 0 && info->type == (uint32_t)atoi(name))
|
||||
return info;
|
||||
info++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline uint32_t spa_debug_type_find_type_short(const struct spa_type_info *info, const char *name)
|
||||
{
|
||||
if ((info = spa_debug_type_find_short(info, name)) == NULL)
|
||||
return SPA_ID_INVALID;
|
||||
return info->type;
|
||||
}
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_DEBUG_NODE_H */
|
@ -0,0 +1,43 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2020 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_EVENT_DEVICE_H
|
||||
#define SPA_EVENT_DEVICE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/pod/event.h>
|
||||
|
||||
/**
|
||||
* \addtogroup spa_device
|
||||
* \{
|
||||
*/
|
||||
|
||||
/* object id of SPA_TYPE_EVENT_Device */
|
||||
enum spa_device_event {
|
||||
SPA_DEVICE_EVENT_ObjectConfig,
|
||||
};
|
||||
|
||||
#define SPA_DEVICE_EVENT_ID(ev) SPA_EVENT_ID(ev, SPA_TYPE_EVENT_Device)
|
||||
#define SPA_DEVICE_EVENT_INIT(id) SPA_EVENT_INIT(SPA_TYPE_EVENT_Device, id)
|
||||
|
||||
/* properties for SPA_TYPE_EVENT_Device */
|
||||
enum spa_event_device {
|
||||
SPA_EVENT_DEVICE_START,
|
||||
|
||||
SPA_EVENT_DEVICE_Object, /* an object id (Int) */
|
||||
SPA_EVENT_DEVICE_Props, /* properties for an object (SPA_TYPE_OBJECT_Props) */
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_EVENT_DEVICE */
|
@ -0,0 +1,47 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2021 Collabora Ltd. */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_DEVICE_TYPE_INFO_H
|
||||
#define SPA_DEVICE_TYPE_INFO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/type-info.h>
|
||||
|
||||
#include <spa/monitor/event.h>
|
||||
|
||||
/**
|
||||
* \addtogroup spa_device
|
||||
* \{
|
||||
*/
|
||||
|
||||
#define SPA_TYPE_INFO_DeviceEvent SPA_TYPE_INFO_EVENT_BASE "Device"
|
||||
#define SPA_TYPE_INFO_DEVICE_EVENT_BASE SPA_TYPE_INFO_DeviceEvent ":"
|
||||
|
||||
#define SPA_TYPE_INFO_DeviceEventId SPA_TYPE_INFO_ENUM_BASE "DeviceEventId"
|
||||
#define SPA_TYPE_INFO_DEVICE_EVENT_ID_BASE SPA_TYPE_INFO_DeviceEventId ":"
|
||||
|
||||
static const struct spa_type_info spa_type_device_event_id[] = {
|
||||
{ SPA_DEVICE_EVENT_ObjectConfig, SPA_TYPE_EVENT_Device, SPA_TYPE_INFO_DEVICE_EVENT_ID_BASE "ObjectConfig", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
static const struct spa_type_info spa_type_device_event[] = {
|
||||
{ SPA_EVENT_DEVICE_START, SPA_TYPE_Id, SPA_TYPE_INFO_DEVICE_EVENT_BASE, spa_type_device_event_id },
|
||||
{ SPA_EVENT_DEVICE_Object, SPA_TYPE_Int, SPA_TYPE_INFO_DEVICE_EVENT_BASE "Object", NULL },
|
||||
{ SPA_EVENT_DEVICE_Props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_DEVICE_EVENT_BASE "Props", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_DEVICE_TYPE_INFO_H */
|
@ -0,0 +1,53 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_COMMAND_NODE_H
|
||||
#define SPA_COMMAND_NODE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_node
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/pod/command.h>
|
||||
|
||||
/* object id of SPA_TYPE_COMMAND_Node */
|
||||
enum spa_node_command {
|
||||
SPA_NODE_COMMAND_Suspend, /**< suspend a node, this removes all configured
|
||||
* formats and closes any devices */
|
||||
SPA_NODE_COMMAND_Pause, /**< pause a node. this makes it stop emitting
|
||||
* scheduling events */
|
||||
SPA_NODE_COMMAND_Start, /**< start a node, this makes it start emitting
|
||||
* scheduling events */
|
||||
SPA_NODE_COMMAND_Enable,
|
||||
SPA_NODE_COMMAND_Disable,
|
||||
SPA_NODE_COMMAND_Flush,
|
||||
SPA_NODE_COMMAND_Drain,
|
||||
SPA_NODE_COMMAND_Marker,
|
||||
SPA_NODE_COMMAND_ParamBegin, /**< begin a set of parameter enumerations or
|
||||
* configuration that require the device to
|
||||
* remain opened, like query formats and then
|
||||
* set a format */
|
||||
SPA_NODE_COMMAND_ParamEnd, /**< end a transaction */
|
||||
SPA_NODE_COMMAND_RequestProcess,/**< Sent to a driver when some other node emitted
|
||||
* the RequestProcess event. */
|
||||
};
|
||||
|
||||
#define SPA_NODE_COMMAND_ID(cmd) SPA_COMMAND_ID(cmd, SPA_TYPE_COMMAND_Node)
|
||||
#define SPA_NODE_COMMAND_INIT(id) SPA_COMMAND_INIT(SPA_TYPE_COMMAND_Node, id)
|
||||
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_COMMAND_NODE_H */
|
@ -0,0 +1,44 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_EVENT_NODE_H
|
||||
#define SPA_EVENT_NODE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_node
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/pod/event.h>
|
||||
|
||||
/* object id of SPA_TYPE_EVENT_Node */
|
||||
enum spa_node_event {
|
||||
SPA_NODE_EVENT_Error,
|
||||
SPA_NODE_EVENT_Buffering,
|
||||
SPA_NODE_EVENT_RequestRefresh,
|
||||
SPA_NODE_EVENT_RequestProcess, /*< Ask the driver to start processing
|
||||
* the graph */
|
||||
};
|
||||
|
||||
#define SPA_NODE_EVENT_ID(ev) SPA_EVENT_ID(ev, SPA_TYPE_EVENT_Node)
|
||||
#define SPA_NODE_EVENT_INIT(id) SPA_EVENT_INIT(SPA_TYPE_EVENT_Node, id)
|
||||
|
||||
/* properties for SPA_TYPE_EVENT_Node */
|
||||
enum spa_event_node {
|
||||
SPA_EVENT_NODE_START,
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_EVENT_NODE_H */
|
290
src/java.desktop/unix/native/libpipewire/include/spa/node/io.h
Normal file
290
src/java.desktop/unix/native/libpipewire/include/spa/node/io.h
Normal file
@ -0,0 +1,290 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_IO_H
|
||||
#define SPA_IO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_node
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
/** IO areas
|
||||
*
|
||||
* IO information for a port on a node. This is allocated
|
||||
* by the host and configured on a node or all ports for which
|
||||
* IO is requested.
|
||||
*
|
||||
* The plugin will communicate with the host through the IO
|
||||
* areas.
|
||||
*/
|
||||
|
||||
/** Different IO area types */
|
||||
enum spa_io_type {
|
||||
SPA_IO_Invalid,
|
||||
SPA_IO_Buffers, /**< area to exchange buffers, struct spa_io_buffers */
|
||||
SPA_IO_Range, /**< expected byte range, struct spa_io_range */
|
||||
SPA_IO_Clock, /**< area to update clock information, struct spa_io_clock */
|
||||
SPA_IO_Latency, /**< latency reporting, struct spa_io_latency */
|
||||
SPA_IO_Control, /**< area for control messages, struct spa_io_sequence */
|
||||
SPA_IO_Notify, /**< area for notify messages, struct spa_io_sequence */
|
||||
SPA_IO_Position, /**< position information in the graph, struct spa_io_position */
|
||||
SPA_IO_RateMatch, /**< rate matching between nodes, struct spa_io_rate_match */
|
||||
SPA_IO_Memory, /**< memory pointer, struct spa_io_memory */
|
||||
};
|
||||
|
||||
/**
|
||||
* IO area to exchange buffers.
|
||||
*
|
||||
* A set of buffers should first be configured on the node/port.
|
||||
* Further references to those buffers will be made by using the
|
||||
* id of the buffer.
|
||||
*
|
||||
* If status is SPA_STATUS_OK, the host should ignore
|
||||
* the io area.
|
||||
*
|
||||
* If status is SPA_STATUS_NEED_DATA, the host should:
|
||||
* 1) recycle the buffer in buffer_id, if possible
|
||||
* 2) prepare a new buffer and place the id in buffer_id.
|
||||
*
|
||||
* If status is SPA_STATUS_HAVE_DATA, the host should consume
|
||||
* the buffer in buffer_id and set the state to
|
||||
* SPA_STATUS_NEED_DATA when new data is requested.
|
||||
*
|
||||
* If status is SPA_STATUS_STOPPED, some error occurred on the
|
||||
* port.
|
||||
*
|
||||
* If status is SPA_STATUS_DRAINED, data from the io area was
|
||||
* used to drain.
|
||||
*
|
||||
* Status can also be a negative errno value to indicate errors.
|
||||
* such as:
|
||||
* -EINVAL: buffer_id is invalid
|
||||
* -EPIPE: no more buffers available
|
||||
*/
|
||||
struct spa_io_buffers {
|
||||
#define SPA_STATUS_OK 0
|
||||
#define SPA_STATUS_NEED_DATA (1<<0)
|
||||
#define SPA_STATUS_HAVE_DATA (1<<1)
|
||||
#define SPA_STATUS_STOPPED (1<<2)
|
||||
#define SPA_STATUS_DRAINED (1<<3)
|
||||
int32_t status; /**< the status code */
|
||||
uint32_t buffer_id; /**< a buffer id */
|
||||
};
|
||||
|
||||
#define SPA_IO_BUFFERS_INIT ((struct spa_io_buffers) { SPA_STATUS_OK, SPA_ID_INVALID, })
|
||||
|
||||
/**
|
||||
* IO area to exchange a memory region
|
||||
*/
|
||||
struct spa_io_memory {
|
||||
int32_t status; /**< the status code */
|
||||
uint32_t size; /**< the size of \a data */
|
||||
void *data; /**< a memory pointer */
|
||||
};
|
||||
#define SPA_IO_MEMORY_INIT ((struct spa_io_memory) { SPA_STATUS_OK, 0, NULL, })
|
||||
|
||||
/** A range, suitable for input ports that can suggest a range to output ports */
|
||||
struct spa_io_range {
|
||||
uint64_t offset; /**< offset in range */
|
||||
uint32_t min_size; /**< minimum size of data */
|
||||
uint32_t max_size; /**< maximum size of data */
|
||||
};
|
||||
|
||||
/**
|
||||
* Absolute time reporting.
|
||||
*
|
||||
* Nodes that can report clocking information will receive this io block.
|
||||
* The application sets the id. This is usually set as part of the
|
||||
* position information but can also be set separately.
|
||||
*
|
||||
* The clock counts the elapsed time according to the clock provider
|
||||
* since the provider was last started.
|
||||
*/
|
||||
struct spa_io_clock {
|
||||
#define SPA_IO_CLOCK_FLAG_FREEWHEEL (1u<<0)
|
||||
uint32_t flags; /**< clock flags */
|
||||
uint32_t id; /**< unique clock id, set by application */
|
||||
char name[64]; /**< clock name prefixed with API, set by node. The clock name
|
||||
* is unique per clock and can be used to check if nodes
|
||||
* share the same clock. */
|
||||
uint64_t nsec; /**< time in nanoseconds against monotonic clock */
|
||||
struct spa_fraction rate; /**< rate for position/duration/delay */
|
||||
uint64_t position; /**< current position */
|
||||
uint64_t duration; /**< duration of current cycle */
|
||||
int64_t delay; /**< delay between position and hardware,
|
||||
* positive for capture, negative for playback */
|
||||
double rate_diff; /**< rate difference between clock and monotonic time */
|
||||
uint64_t next_nsec; /**< estimated next wakeup time in nanoseconds */
|
||||
|
||||
struct spa_fraction target_rate; /**< target rate of next cycle */
|
||||
uint64_t target_duration; /**< target duration of next cycle */
|
||||
uint32_t target_seq; /**< seq counter. must be equal at start and
|
||||
* end of read and lower bit must be 0 */
|
||||
|
||||
uint32_t padding[3];
|
||||
};
|
||||
|
||||
/* the size of the video in this cycle */
|
||||
struct spa_io_video_size {
|
||||
#define SPA_IO_VIDEO_SIZE_VALID (1<<0)
|
||||
uint32_t flags; /**< optional flags */
|
||||
uint32_t stride; /**< video stride in bytes */
|
||||
struct spa_rectangle size; /**< the video size */
|
||||
struct spa_fraction framerate; /**< the minimum framerate, the cycle duration is
|
||||
* always smaller to ensure there is only one
|
||||
* video frame per cycle. */
|
||||
uint32_t padding[4];
|
||||
};
|
||||
|
||||
/** latency reporting */
|
||||
struct spa_io_latency {
|
||||
struct spa_fraction rate; /**< rate for min/max */
|
||||
uint64_t min; /**< min latency */
|
||||
uint64_t max; /**< max latency */
|
||||
};
|
||||
|
||||
/** control stream, io area for SPA_IO_Control and SPA_IO_Notify */
|
||||
struct spa_io_sequence {
|
||||
struct spa_pod_sequence sequence; /**< sequence of timed events */
|
||||
};
|
||||
|
||||
/** bar and beat segment */
|
||||
struct spa_io_segment_bar {
|
||||
#define SPA_IO_SEGMENT_BAR_FLAG_VALID (1<<0)
|
||||
uint32_t flags; /**< extra flags */
|
||||
uint32_t offset; /**< offset in segment of this beat */
|
||||
float signature_num; /**< time signature numerator */
|
||||
float signature_denom; /**< time signature denominator */
|
||||
double bpm; /**< beats per minute */
|
||||
double beat; /**< current beat in segment */
|
||||
uint32_t padding[8];
|
||||
};
|
||||
|
||||
/** video frame segment */
|
||||
struct spa_io_segment_video {
|
||||
#define SPA_IO_SEGMENT_VIDEO_FLAG_VALID (1<<0)
|
||||
#define SPA_IO_SEGMENT_VIDEO_FLAG_DROP_FRAME (1<<1)
|
||||
#define SPA_IO_SEGMENT_VIDEO_FLAG_PULL_DOWN (1<<2)
|
||||
#define SPA_IO_SEGMENT_VIDEO_FLAG_INTERLACED (1<<3)
|
||||
uint32_t flags; /**< flags */
|
||||
uint32_t offset; /**< offset in segment */
|
||||
struct spa_fraction framerate;
|
||||
uint32_t hours;
|
||||
uint32_t minutes;
|
||||
uint32_t seconds;
|
||||
uint32_t frames;
|
||||
uint32_t field_count; /**< 0 for progressive, 1 and 2 for interlaced */
|
||||
uint32_t padding[11];
|
||||
};
|
||||
|
||||
/**
|
||||
* A segment converts a running time to a segment (stream) position.
|
||||
*
|
||||
* The segment position is valid when the current running time is between
|
||||
* start and start + duration. The position is then
|
||||
* calculated as:
|
||||
*
|
||||
* (running time - start) * rate + position;
|
||||
*
|
||||
* Support for looping is done by specifying the LOOPING flags with a
|
||||
* non-zero duration. When the running time reaches start + duration,
|
||||
* duration is added to start and the loop repeats.
|
||||
*
|
||||
* Care has to be taken when the running time + clock.duration extends
|
||||
* past the start + duration from the segment; the user should correctly
|
||||
* wrap around and partially repeat the loop in the current cycle.
|
||||
*
|
||||
* Extra information can be placed in the segment by setting the valid flags
|
||||
* and filling up the corresponding structures.
|
||||
*/
|
||||
struct spa_io_segment {
|
||||
uint32_t version;
|
||||
#define SPA_IO_SEGMENT_FLAG_LOOPING (1<<0) /**< after the duration, the segment repeats */
|
||||
#define SPA_IO_SEGMENT_FLAG_NO_POSITION (1<<1) /**< position is invalid. The position can be invalid
|
||||
* after a seek, for example, when the exact mapping
|
||||
* of the extra segment info (bar, video, ...) to
|
||||
* position has not been determined yet */
|
||||
uint32_t flags; /**< extra flags */
|
||||
uint64_t start; /**< value of running time when this
|
||||
* info is active. Can be in the future for
|
||||
* pending changes. It does not have to be in
|
||||
* exact multiples of the clock duration. */
|
||||
uint64_t duration; /**< duration when this info becomes invalid expressed
|
||||
* in running time. If the duration is 0, this
|
||||
* segment extends to the next segment. If the
|
||||
* segment becomes invalid and the looping flag is
|
||||
* set, the segment repeats. */
|
||||
double rate; /**< overall rate of the segment, can be negative for
|
||||
* backwards time reporting. */
|
||||
uint64_t position; /**< The position when the running time == start.
|
||||
* can be invalid when the owner of the extra segment
|
||||
* information has not yet made the mapping. */
|
||||
|
||||
struct spa_io_segment_bar bar;
|
||||
struct spa_io_segment_video video;
|
||||
};
|
||||
|
||||
enum spa_io_position_state {
|
||||
SPA_IO_POSITION_STATE_STOPPED,
|
||||
SPA_IO_POSITION_STATE_STARTING,
|
||||
SPA_IO_POSITION_STATE_RUNNING,
|
||||
};
|
||||
|
||||
/** the maximum number of segments visible in the future */
|
||||
#define SPA_IO_POSITION_MAX_SEGMENTS 8
|
||||
|
||||
/**
|
||||
* The position information adds extra meaning to the raw clock times.
|
||||
*
|
||||
* It is set on all nodes and the clock id will contain the clock of the
|
||||
* driving node in the graph.
|
||||
*
|
||||
* The position information contains 1 or more segments that convert the
|
||||
* raw clock times to a stream time. They are sorted based on their
|
||||
* start times, and thus the order in which they will activate in
|
||||
* the future. This makes it possible to look ahead in the scheduled
|
||||
* segments and anticipate the changes in the timeline.
|
||||
*/
|
||||
struct spa_io_position {
|
||||
struct spa_io_clock clock; /**< clock position of driver, always valid and
|
||||
* read only */
|
||||
struct spa_io_video_size video; /**< size of the video in the current cycle */
|
||||
int64_t offset; /**< an offset to subtract from the clock position
|
||||
* to get a running time. This is the time that
|
||||
* the state has been in the RUNNING state and the
|
||||
* time that should be used to compare the segment
|
||||
* start values against. */
|
||||
uint32_t state; /**< one of enum spa_io_position_state */
|
||||
|
||||
uint32_t n_segments; /**< number of segments */
|
||||
struct spa_io_segment segments[SPA_IO_POSITION_MAX_SEGMENTS]; /**< segments */
|
||||
};
|
||||
|
||||
/** rate matching */
|
||||
struct spa_io_rate_match {
|
||||
uint32_t delay; /**< extra delay in samples for resampler */
|
||||
uint32_t size; /**< requested input size for resampler */
|
||||
double rate; /**< rate for resampler */
|
||||
#define SPA_IO_RATE_MATCH_FLAG_ACTIVE (1 << 0)
|
||||
uint32_t flags; /**< extra flags */
|
||||
uint32_t padding[7];
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_IO_H */
|
@ -0,0 +1,87 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_NODE_TYPES_H
|
||||
#define SPA_NODE_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_node
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/utils/type.h>
|
||||
|
||||
#include <spa/node/command.h>
|
||||
#include <spa/node/event.h>
|
||||
#include <spa/node/io.h>
|
||||
|
||||
#define SPA_TYPE_INFO_IO SPA_TYPE_INFO_ENUM_BASE "IO"
|
||||
#define SPA_TYPE_INFO_IO_BASE SPA_TYPE_INFO_IO ":"
|
||||
|
||||
static const struct spa_type_info spa_type_io[] = {
|
||||
{ SPA_IO_Invalid, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Invalid", NULL },
|
||||
{ SPA_IO_Buffers, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Buffers", NULL },
|
||||
{ SPA_IO_Range, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Range", NULL },
|
||||
{ SPA_IO_Clock, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Clock", NULL },
|
||||
{ SPA_IO_Latency, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Latency", NULL },
|
||||
{ SPA_IO_Control, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Control", NULL },
|
||||
{ SPA_IO_Notify, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Notify", NULL },
|
||||
{ SPA_IO_Position, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Position", NULL },
|
||||
{ SPA_IO_RateMatch, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "RateMatch", NULL },
|
||||
{ SPA_IO_Memory, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Memory", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_NodeEvent SPA_TYPE_INFO_EVENT_BASE "Node"
|
||||
#define SPA_TYPE_INFO_NODE_EVENT_BASE SPA_TYPE_INFO_NodeEvent ":"
|
||||
|
||||
static const struct spa_type_info spa_type_node_event_id[] = {
|
||||
{ SPA_NODE_EVENT_Error, SPA_TYPE_EVENT_Node, SPA_TYPE_INFO_NODE_EVENT_BASE "Error", NULL },
|
||||
{ SPA_NODE_EVENT_Buffering, SPA_TYPE_EVENT_Node, SPA_TYPE_INFO_NODE_EVENT_BASE "Buffering", NULL },
|
||||
{ SPA_NODE_EVENT_RequestRefresh, SPA_TYPE_EVENT_Node, SPA_TYPE_INFO_NODE_EVENT_BASE "RequestRefresh", NULL },
|
||||
{ SPA_NODE_EVENT_RequestProcess, SPA_TYPE_EVENT_Node, SPA_TYPE_INFO_NODE_EVENT_BASE "RequestProcess", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
static const struct spa_type_info spa_type_node_event[] = {
|
||||
{ SPA_EVENT_NODE_START, SPA_TYPE_Id, SPA_TYPE_INFO_NODE_EVENT_BASE, spa_type_node_event_id },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_NodeCommand SPA_TYPE_INFO_COMMAND_BASE "Node"
|
||||
#define SPA_TYPE_INFO_NODE_COMMAND_BASE SPA_TYPE_INFO_NodeCommand ":"
|
||||
|
||||
static const struct spa_type_info spa_type_node_command_id[] = {
|
||||
{ SPA_NODE_COMMAND_Suspend, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Suspend", NULL },
|
||||
{ SPA_NODE_COMMAND_Pause, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Pause", NULL },
|
||||
{ SPA_NODE_COMMAND_Start, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Start", NULL },
|
||||
{ SPA_NODE_COMMAND_Enable, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Enable", NULL },
|
||||
{ SPA_NODE_COMMAND_Disable, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Disable", NULL },
|
||||
{ SPA_NODE_COMMAND_Flush, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Flush", NULL },
|
||||
{ SPA_NODE_COMMAND_Drain, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Drain", NULL },
|
||||
{ SPA_NODE_COMMAND_Marker, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Marker", NULL },
|
||||
{ SPA_NODE_COMMAND_ParamBegin, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "ParamBegin", NULL },
|
||||
{ SPA_NODE_COMMAND_ParamEnd, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "ParamEnd", NULL },
|
||||
{ SPA_NODE_COMMAND_RequestProcess, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "RequestProcess", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
static const struct spa_type_info spa_type_node_command[] = {
|
||||
{ 0, SPA_TYPE_Id, SPA_TYPE_INFO_NODE_COMMAND_BASE, spa_type_node_command_id },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_NODE_TYPES_H */
|
@ -0,0 +1,38 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_AAC_TYPES_H
|
||||
#define SPA_AUDIO_AAC_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/type.h>
|
||||
#include <spa/param/audio/aac.h>
|
||||
|
||||
#define SPA_TYPE_INFO_AudioAACStreamFormat SPA_TYPE_INFO_ENUM_BASE "AudioAACStreamFormat"
|
||||
#define SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE SPA_TYPE_INFO_AudioAACStreamFormat ":"
|
||||
|
||||
static const struct spa_type_info spa_type_audio_aac_stream_format[] = {
|
||||
{ SPA_AUDIO_AAC_STREAM_FORMAT_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "UNKNOWN", NULL },
|
||||
{ SPA_AUDIO_AAC_STREAM_FORMAT_RAW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "RAW", NULL },
|
||||
{ SPA_AUDIO_AAC_STREAM_FORMAT_MP2ADTS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP2ADTS", NULL },
|
||||
{ SPA_AUDIO_AAC_STREAM_FORMAT_MP4ADTS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP4ADTS", NULL },
|
||||
{ SPA_AUDIO_AAC_STREAM_FORMAT_MP4LOAS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP4LOAS", NULL },
|
||||
{ SPA_AUDIO_AAC_STREAM_FORMAT_MP4LATM, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP4LATM", NULL },
|
||||
{ SPA_AUDIO_AAC_STREAM_FORMAT_ADIF, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "ADIF", NULL },
|
||||
{ SPA_AUDIO_AAC_STREAM_FORMAT_MP4FF, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP4FF", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_AAC_TYPES_H */
|
@ -0,0 +1,51 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_AAC_H
|
||||
#define SPA_AUDIO_AAC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/param/audio/raw.h>
|
||||
|
||||
enum spa_audio_aac_stream_format {
|
||||
SPA_AUDIO_AAC_STREAM_FORMAT_UNKNOWN,
|
||||
/* Raw AAC frames */
|
||||
SPA_AUDIO_AAC_STREAM_FORMAT_RAW,
|
||||
/* ISO/IEC 13818-7 MPEG-2 Audio Data Transport Stream (ADTS) */
|
||||
SPA_AUDIO_AAC_STREAM_FORMAT_MP2ADTS,
|
||||
/* ISO/IEC 14496-3 MPEG-4 Audio Data Transport Stream (ADTS) */
|
||||
SPA_AUDIO_AAC_STREAM_FORMAT_MP4ADTS,
|
||||
/* ISO/IEC 14496-3 Low Overhead Audio Stream (LOAS) */
|
||||
SPA_AUDIO_AAC_STREAM_FORMAT_MP4LOAS,
|
||||
/* ISO/IEC 14496-3 Low Overhead Audio Transport Multiplex (LATM) */
|
||||
SPA_AUDIO_AAC_STREAM_FORMAT_MP4LATM,
|
||||
/* ISO/IEC 14496-3 Audio Data Interchange Format (ADIF) */
|
||||
SPA_AUDIO_AAC_STREAM_FORMAT_ADIF,
|
||||
/* ISO/IEC 14496-12 MPEG-4 file format */
|
||||
SPA_AUDIO_AAC_STREAM_FORMAT_MP4FF,
|
||||
|
||||
SPA_AUDIO_AAC_STREAM_FORMAT_CUSTOM = 0x10000,
|
||||
};
|
||||
|
||||
struct spa_audio_info_aac {
|
||||
uint32_t rate; /*< sample rate */
|
||||
uint32_t channels; /*< number of channels */
|
||||
uint32_t bitrate; /*< stream bitrate */
|
||||
enum spa_audio_aac_stream_format stream_format; /*< AAC audio stream format */
|
||||
};
|
||||
|
||||
#define SPA_AUDIO_INFO_AAC_INIT(...) ((struct spa_audio_info_aac) { __VA_ARGS__ })
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_AAC_H */
|
@ -0,0 +1,32 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_AMR_TYPES_H
|
||||
#define SPA_AUDIO_AMR_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/type.h>
|
||||
#include <spa/param/audio/amr.h>
|
||||
|
||||
#define SPA_TYPE_INFO_AudioAMRBandMode SPA_TYPE_INFO_ENUM_BASE "AudioAMRBandMode"
|
||||
#define SPA_TYPE_INFO_AUDIO_AMR_BAND_MODE_BASE SPA_TYPE_INFO_AudioAMRBandMode ":"
|
||||
|
||||
static const struct spa_type_info spa_type_audio_amr_band_mode[] = {
|
||||
{ SPA_AUDIO_AMR_BAND_MODE_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AMR_BAND_MODE_BASE "UNKNOWN", NULL },
|
||||
{ SPA_AUDIO_AMR_BAND_MODE_NB, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AMR_BAND_MODE_BASE "NB", NULL },
|
||||
{ SPA_AUDIO_AMR_BAND_MODE_WB, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AMR_BAND_MODE_BASE "WB", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_AMR_TYPES_H */
|
@ -0,0 +1,36 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_AMR_H
|
||||
#define SPA_AUDIO_AMR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/param/audio/raw.h>
|
||||
|
||||
enum spa_audio_amr_band_mode {
|
||||
SPA_AUDIO_AMR_BAND_MODE_UNKNOWN,
|
||||
SPA_AUDIO_AMR_BAND_MODE_NB,
|
||||
SPA_AUDIO_AMR_BAND_MODE_WB,
|
||||
};
|
||||
|
||||
struct spa_audio_info_amr {
|
||||
uint32_t rate; /*< sample rate */
|
||||
uint32_t channels; /*< number of channels */
|
||||
enum spa_audio_amr_band_mode band_mode;
|
||||
};
|
||||
|
||||
#define SPA_AUDIO_INFO_AMR_INIT(...) ((struct spa_audio_info_amr) { __VA_ARGS__ })
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_AMR_H */
|
@ -0,0 +1,39 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_IEC958_TYPES_H
|
||||
#define SPA_AUDIO_IEC958_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/type.h>
|
||||
#include <spa/param/audio/iec958.h>
|
||||
|
||||
#define SPA_TYPE_INFO_AudioIEC958Codec SPA_TYPE_INFO_ENUM_BASE "AudioIEC958Codec"
|
||||
#define SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE SPA_TYPE_INFO_AudioIEC958Codec ":"
|
||||
|
||||
static const struct spa_type_info spa_type_audio_iec958_codec[] = {
|
||||
{ SPA_AUDIO_IEC958_CODEC_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "UNKNOWN", NULL },
|
||||
{ SPA_AUDIO_IEC958_CODEC_PCM, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "PCM", NULL },
|
||||
{ SPA_AUDIO_IEC958_CODEC_DTS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "DTS", NULL },
|
||||
{ SPA_AUDIO_IEC958_CODEC_AC3, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "AC3", NULL },
|
||||
{ SPA_AUDIO_IEC958_CODEC_MPEG, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "MPEG", NULL },
|
||||
{ SPA_AUDIO_IEC958_CODEC_MPEG2_AAC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "MPEG2-AAC", NULL },
|
||||
{ SPA_AUDIO_IEC958_CODEC_EAC3, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "EAC3", NULL },
|
||||
{ SPA_AUDIO_IEC958_CODEC_TRUEHD, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "TrueHD", NULL },
|
||||
{ SPA_AUDIO_IEC958_CODEC_DTSHD, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "DTS-HD", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_RAW_IEC958_TYPES_H */
|
@ -0,0 +1,49 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_IEC958_H
|
||||
#define SPA_AUDIO_IEC958_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
enum spa_audio_iec958_codec {
|
||||
SPA_AUDIO_IEC958_CODEC_UNKNOWN,
|
||||
|
||||
SPA_AUDIO_IEC958_CODEC_PCM,
|
||||
SPA_AUDIO_IEC958_CODEC_DTS,
|
||||
SPA_AUDIO_IEC958_CODEC_AC3,
|
||||
SPA_AUDIO_IEC958_CODEC_MPEG, /**< MPEG-1 or MPEG-2 (Part 3, not AAC) */
|
||||
SPA_AUDIO_IEC958_CODEC_MPEG2_AAC, /**< MPEG-2 AAC */
|
||||
|
||||
SPA_AUDIO_IEC958_CODEC_EAC3,
|
||||
|
||||
SPA_AUDIO_IEC958_CODEC_TRUEHD, /**< Dolby TrueHD */
|
||||
SPA_AUDIO_IEC958_CODEC_DTSHD, /**< DTS-HD Master Audio */
|
||||
};
|
||||
|
||||
struct spa_audio_info_iec958 {
|
||||
enum spa_audio_iec958_codec codec; /*< format, one of the DSP formats in enum spa_audio_format_dsp */
|
||||
uint32_t flags; /*< extra flags */
|
||||
uint32_t rate; /*< sample rate */
|
||||
};
|
||||
|
||||
#define SPA_AUDIO_INFO_IEC958_INIT(...) ((struct spa_audio_info_iec958) { __VA_ARGS__ })
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_IEC958_H */
|
@ -0,0 +1,34 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_MP3_TYPES_H
|
||||
#define SPA_AUDIO_MP3_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/type.h>
|
||||
#include <spa/param/audio/mp3.h>
|
||||
|
||||
#define SPA_TYPE_INFO_AudioMP3ChannelMode SPA_TYPE_INFO_ENUM_BASE "AudioMP3ChannelMode"
|
||||
#define SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE SPA_TYPE_INFO_AudioMP3ChannelMode ":"
|
||||
|
||||
static const struct spa_type_info spa_type_audio_mp3_channel_mode[] = {
|
||||
{ SPA_AUDIO_MP3_CHANNEL_MODE_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "UNKNOWN", NULL },
|
||||
{ SPA_AUDIO_MP3_CHANNEL_MODE_MONO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "Mono", NULL },
|
||||
{ SPA_AUDIO_MP3_CHANNEL_MODE_STEREO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "Stereo", NULL },
|
||||
{ SPA_AUDIO_MP3_CHANNEL_MODE_JOINTSTEREO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "Joint-stereo", NULL },
|
||||
{ SPA_AUDIO_MP3_CHANNEL_MODE_DUAL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "Dual", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_MP3_TYPES_H */
|
@ -0,0 +1,37 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_MP3_H
|
||||
#define SPA_AUDIO_MP3_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/param/audio/raw.h>
|
||||
|
||||
enum spa_audio_mp3_channel_mode {
|
||||
SPA_AUDIO_MP3_CHANNEL_MODE_UNKNOWN,
|
||||
SPA_AUDIO_MP3_CHANNEL_MODE_MONO,
|
||||
SPA_AUDIO_MP3_CHANNEL_MODE_STEREO,
|
||||
SPA_AUDIO_MP3_CHANNEL_MODE_JOINTSTEREO,
|
||||
SPA_AUDIO_MP3_CHANNEL_MODE_DUAL,
|
||||
};
|
||||
|
||||
struct spa_audio_info_mp3 {
|
||||
uint32_t rate; /*< sample rate */
|
||||
uint32_t channels; /*< number of channels */
|
||||
};
|
||||
|
||||
#define SPA_AUDIO_INFO_MP3_INIT(...) ((struct spa_audio_info_mp3) { __VA_ARGS__ })
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_MP3_H */
|
@ -0,0 +1,258 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_RAW_TYPES_H
|
||||
#define SPA_AUDIO_RAW_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/utils/type.h>
|
||||
#include <spa/param/audio/raw.h>
|
||||
|
||||
#define SPA_TYPE_INFO_AudioFormat SPA_TYPE_INFO_ENUM_BASE "AudioFormat"
|
||||
#define SPA_TYPE_INFO_AUDIO_FORMAT_BASE SPA_TYPE_INFO_AudioFormat ":"
|
||||
|
||||
static const struct spa_type_info spa_type_audio_format[] = {
|
||||
{ SPA_AUDIO_FORMAT_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "UNKNOWN", NULL },
|
||||
{ SPA_AUDIO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ENCODED", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S8", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U8", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S20_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S20_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U20_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U20_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S18_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S18_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U18_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U18_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32BE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F64_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64LE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F64_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64BE", NULL },
|
||||
|
||||
{ SPA_AUDIO_FORMAT_ULAW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ULAW", NULL },
|
||||
{ SPA_AUDIO_FORMAT_ALAW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ALAW", NULL },
|
||||
|
||||
{ SPA_AUDIO_FORMAT_U8P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U8P", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S16P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16P", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32P", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32P", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24P", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32P", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F64P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64P", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S8P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S8P", NULL },
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
{ SPA_AUDIO_FORMAT_S16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F64_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F64, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64", NULL },
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
{ SPA_AUDIO_FORMAT_S16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18", NULL },
|
||||
{ SPA_AUDIO_FORMAT_S18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18", NULL },
|
||||
{ SPA_AUDIO_FORMAT_U18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32OE", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F64, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64", NULL },
|
||||
{ SPA_AUDIO_FORMAT_F64_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64OE", NULL },
|
||||
#endif
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_AudioFlags SPA_TYPE_INFO_FLAGS_BASE "AudioFlags"
|
||||
#define SPA_TYPE_INFO_AUDIO_FLAGS_BASE SPA_TYPE_INFO_AudioFlags ":"
|
||||
|
||||
static const struct spa_type_info spa_type_audio_flags[] = {
|
||||
{ SPA_AUDIO_FLAG_NONE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FLAGS_BASE "none", NULL },
|
||||
{ SPA_AUDIO_FLAG_UNPOSITIONED, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FLAGS_BASE "unpositioned", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_AudioChannel SPA_TYPE_INFO_ENUM_BASE "AudioChannel"
|
||||
#define SPA_TYPE_INFO_AUDIO_CHANNEL_BASE SPA_TYPE_INFO_AudioChannel ":"
|
||||
|
||||
static const struct spa_type_info spa_type_audio_channel[] = {
|
||||
{ SPA_AUDIO_CHANNEL_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "UNK", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_NA, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "NA", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_MONO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "MONO", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FL", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FR", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_LFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LFE", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_SL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "SL", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_SR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "SR", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_RC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_RL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RL", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_RR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RR", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TFL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFL", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TFC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TFR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFR", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TRL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRL", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TRR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRR", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_RLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RLC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_RRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RRC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FLW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLW", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FRW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRW", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_LFE2, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LFE2", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FLH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLH", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FCH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FCH", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_FRH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRH", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TFLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFLC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TFRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFRC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TSL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSL", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_TSR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSR", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_LLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LLFR", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_RLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RLFE", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_BC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_BLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BLC", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_BRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BRC", NULL },
|
||||
|
||||
{ SPA_AUDIO_CHANNEL_AUX0, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX0", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX1, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX1", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX2, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX2", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX3, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX3", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX4, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX4", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX5, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX5", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX6, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX6", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX7, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX7", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX8", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX9, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX9", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX10, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX10", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX11, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX11", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX12, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX12", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX13, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX13", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX14, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX14", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX15, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX15", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX16", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX17, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX17", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX18", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX19, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX19", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX20", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX21, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX21", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX22, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX22", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX23, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX23", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX24", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX25, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX25", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX26, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX26", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX27, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX27", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX28, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX28", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX29, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX29", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX30, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX30", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX31, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX31", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX32", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX33, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX33", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX34, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX34", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX35, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX35", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX36, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX36", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX37, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX37", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX38, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX38", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX39, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX39", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX40, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX40", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX41, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX41", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX42, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX42", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX43, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX43", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX44, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX44", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX45, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX45", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX46, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX46", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX47, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX47", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX48, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX48", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX49, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX49", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX50, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX50", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX51, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX51", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX52, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX52", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX53, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX53", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX54, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX54", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX55, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX55", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX56, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX56", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX57, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX57", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX58, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX58", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX59, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX59", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX60, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX60", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX61, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX61", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX62, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX62", NULL },
|
||||
{ SPA_AUDIO_CHANNEL_AUX63, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX63", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_RAW_RAW_TYPES_H */
|
@ -0,0 +1,303 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_RAW_H
|
||||
#define SPA_AUDIO_RAW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#define SPA_AUDIO_MAX_CHANNELS 64u
|
||||
|
||||
enum spa_audio_format {
|
||||
SPA_AUDIO_FORMAT_UNKNOWN,
|
||||
SPA_AUDIO_FORMAT_ENCODED,
|
||||
|
||||
/* interleaved formats */
|
||||
SPA_AUDIO_FORMAT_START_Interleaved = 0x100,
|
||||
SPA_AUDIO_FORMAT_S8,
|
||||
SPA_AUDIO_FORMAT_U8,
|
||||
SPA_AUDIO_FORMAT_S16_LE,
|
||||
SPA_AUDIO_FORMAT_S16_BE,
|
||||
SPA_AUDIO_FORMAT_U16_LE,
|
||||
SPA_AUDIO_FORMAT_U16_BE,
|
||||
SPA_AUDIO_FORMAT_S24_32_LE,
|
||||
SPA_AUDIO_FORMAT_S24_32_BE,
|
||||
SPA_AUDIO_FORMAT_U24_32_LE,
|
||||
SPA_AUDIO_FORMAT_U24_32_BE,
|
||||
SPA_AUDIO_FORMAT_S32_LE,
|
||||
SPA_AUDIO_FORMAT_S32_BE,
|
||||
SPA_AUDIO_FORMAT_U32_LE,
|
||||
SPA_AUDIO_FORMAT_U32_BE,
|
||||
SPA_AUDIO_FORMAT_S24_LE,
|
||||
SPA_AUDIO_FORMAT_S24_BE,
|
||||
SPA_AUDIO_FORMAT_U24_LE,
|
||||
SPA_AUDIO_FORMAT_U24_BE,
|
||||
SPA_AUDIO_FORMAT_S20_LE,
|
||||
SPA_AUDIO_FORMAT_S20_BE,
|
||||
SPA_AUDIO_FORMAT_U20_LE,
|
||||
SPA_AUDIO_FORMAT_U20_BE,
|
||||
SPA_AUDIO_FORMAT_S18_LE,
|
||||
SPA_AUDIO_FORMAT_S18_BE,
|
||||
SPA_AUDIO_FORMAT_U18_LE,
|
||||
SPA_AUDIO_FORMAT_U18_BE,
|
||||
SPA_AUDIO_FORMAT_F32_LE,
|
||||
SPA_AUDIO_FORMAT_F32_BE,
|
||||
SPA_AUDIO_FORMAT_F64_LE,
|
||||
SPA_AUDIO_FORMAT_F64_BE,
|
||||
|
||||
SPA_AUDIO_FORMAT_ULAW,
|
||||
SPA_AUDIO_FORMAT_ALAW,
|
||||
|
||||
/* planar formats */
|
||||
SPA_AUDIO_FORMAT_START_Planar = 0x200,
|
||||
SPA_AUDIO_FORMAT_U8P,
|
||||
SPA_AUDIO_FORMAT_S16P,
|
||||
SPA_AUDIO_FORMAT_S24_32P,
|
||||
SPA_AUDIO_FORMAT_S32P,
|
||||
SPA_AUDIO_FORMAT_S24P,
|
||||
SPA_AUDIO_FORMAT_F32P,
|
||||
SPA_AUDIO_FORMAT_F64P,
|
||||
SPA_AUDIO_FORMAT_S8P,
|
||||
|
||||
/* other formats start here */
|
||||
SPA_AUDIO_FORMAT_START_Other = 0x400,
|
||||
|
||||
/* Aliases */
|
||||
|
||||
/* DSP formats */
|
||||
SPA_AUDIO_FORMAT_DSP_S32 = SPA_AUDIO_FORMAT_S24_32P,
|
||||
SPA_AUDIO_FORMAT_DSP_F32 = SPA_AUDIO_FORMAT_F32P,
|
||||
SPA_AUDIO_FORMAT_DSP_F64 = SPA_AUDIO_FORMAT_F64P,
|
||||
|
||||
/* native endian */
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
SPA_AUDIO_FORMAT_S16 = SPA_AUDIO_FORMAT_S16_BE,
|
||||
SPA_AUDIO_FORMAT_U16 = SPA_AUDIO_FORMAT_U16_BE,
|
||||
SPA_AUDIO_FORMAT_S24_32 = SPA_AUDIO_FORMAT_S24_32_BE,
|
||||
SPA_AUDIO_FORMAT_U24_32 = SPA_AUDIO_FORMAT_U24_32_BE,
|
||||
SPA_AUDIO_FORMAT_S32 = SPA_AUDIO_FORMAT_S32_BE,
|
||||
SPA_AUDIO_FORMAT_U32 = SPA_AUDIO_FORMAT_U32_BE,
|
||||
SPA_AUDIO_FORMAT_S24 = SPA_AUDIO_FORMAT_S24_BE,
|
||||
SPA_AUDIO_FORMAT_U24 = SPA_AUDIO_FORMAT_U24_BE,
|
||||
SPA_AUDIO_FORMAT_S20 = SPA_AUDIO_FORMAT_S20_BE,
|
||||
SPA_AUDIO_FORMAT_U20 = SPA_AUDIO_FORMAT_U20_BE,
|
||||
SPA_AUDIO_FORMAT_S18 = SPA_AUDIO_FORMAT_S18_BE,
|
||||
SPA_AUDIO_FORMAT_U18 = SPA_AUDIO_FORMAT_U18_BE,
|
||||
SPA_AUDIO_FORMAT_F32 = SPA_AUDIO_FORMAT_F32_BE,
|
||||
SPA_AUDIO_FORMAT_F64 = SPA_AUDIO_FORMAT_F64_BE,
|
||||
SPA_AUDIO_FORMAT_S16_OE = SPA_AUDIO_FORMAT_S16_LE,
|
||||
SPA_AUDIO_FORMAT_U16_OE = SPA_AUDIO_FORMAT_U16_LE,
|
||||
SPA_AUDIO_FORMAT_S24_32_OE = SPA_AUDIO_FORMAT_S24_32_LE,
|
||||
SPA_AUDIO_FORMAT_U24_32_OE = SPA_AUDIO_FORMAT_U24_32_LE,
|
||||
SPA_AUDIO_FORMAT_S32_OE = SPA_AUDIO_FORMAT_S32_LE,
|
||||
SPA_AUDIO_FORMAT_U32_OE = SPA_AUDIO_FORMAT_U32_LE,
|
||||
SPA_AUDIO_FORMAT_S24_OE = SPA_AUDIO_FORMAT_S24_LE,
|
||||
SPA_AUDIO_FORMAT_U24_OE = SPA_AUDIO_FORMAT_U24_LE,
|
||||
SPA_AUDIO_FORMAT_S20_OE = SPA_AUDIO_FORMAT_S20_LE,
|
||||
SPA_AUDIO_FORMAT_U20_OE = SPA_AUDIO_FORMAT_U20_LE,
|
||||
SPA_AUDIO_FORMAT_S18_OE = SPA_AUDIO_FORMAT_S18_LE,
|
||||
SPA_AUDIO_FORMAT_U18_OE = SPA_AUDIO_FORMAT_U18_LE,
|
||||
SPA_AUDIO_FORMAT_F32_OE = SPA_AUDIO_FORMAT_F32_LE,
|
||||
SPA_AUDIO_FORMAT_F64_OE = SPA_AUDIO_FORMAT_F64_LE,
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
SPA_AUDIO_FORMAT_S16 = SPA_AUDIO_FORMAT_S16_LE,
|
||||
SPA_AUDIO_FORMAT_U16 = SPA_AUDIO_FORMAT_U16_LE,
|
||||
SPA_AUDIO_FORMAT_S24_32 = SPA_AUDIO_FORMAT_S24_32_LE,
|
||||
SPA_AUDIO_FORMAT_U24_32 = SPA_AUDIO_FORMAT_U24_32_LE,
|
||||
SPA_AUDIO_FORMAT_S32 = SPA_AUDIO_FORMAT_S32_LE,
|
||||
SPA_AUDIO_FORMAT_U32 = SPA_AUDIO_FORMAT_U32_LE,
|
||||
SPA_AUDIO_FORMAT_S24 = SPA_AUDIO_FORMAT_S24_LE,
|
||||
SPA_AUDIO_FORMAT_U24 = SPA_AUDIO_FORMAT_U24_LE,
|
||||
SPA_AUDIO_FORMAT_S20 = SPA_AUDIO_FORMAT_S20_LE,
|
||||
SPA_AUDIO_FORMAT_U20 = SPA_AUDIO_FORMAT_U20_LE,
|
||||
SPA_AUDIO_FORMAT_S18 = SPA_AUDIO_FORMAT_S18_LE,
|
||||
SPA_AUDIO_FORMAT_U18 = SPA_AUDIO_FORMAT_U18_LE,
|
||||
SPA_AUDIO_FORMAT_F32 = SPA_AUDIO_FORMAT_F32_LE,
|
||||
SPA_AUDIO_FORMAT_F64 = SPA_AUDIO_FORMAT_F64_LE,
|
||||
SPA_AUDIO_FORMAT_S16_OE = SPA_AUDIO_FORMAT_S16_BE,
|
||||
SPA_AUDIO_FORMAT_U16_OE = SPA_AUDIO_FORMAT_U16_BE,
|
||||
SPA_AUDIO_FORMAT_S24_32_OE = SPA_AUDIO_FORMAT_S24_32_BE,
|
||||
SPA_AUDIO_FORMAT_U24_32_OE = SPA_AUDIO_FORMAT_U24_32_BE,
|
||||
SPA_AUDIO_FORMAT_S32_OE = SPA_AUDIO_FORMAT_S32_BE,
|
||||
SPA_AUDIO_FORMAT_U32_OE = SPA_AUDIO_FORMAT_U32_BE,
|
||||
SPA_AUDIO_FORMAT_S24_OE = SPA_AUDIO_FORMAT_S24_BE,
|
||||
SPA_AUDIO_FORMAT_U24_OE = SPA_AUDIO_FORMAT_U24_BE,
|
||||
SPA_AUDIO_FORMAT_S20_OE = SPA_AUDIO_FORMAT_S20_BE,
|
||||
SPA_AUDIO_FORMAT_U20_OE = SPA_AUDIO_FORMAT_U20_BE,
|
||||
SPA_AUDIO_FORMAT_S18_OE = SPA_AUDIO_FORMAT_S18_BE,
|
||||
SPA_AUDIO_FORMAT_U18_OE = SPA_AUDIO_FORMAT_U18_BE,
|
||||
SPA_AUDIO_FORMAT_F32_OE = SPA_AUDIO_FORMAT_F32_BE,
|
||||
SPA_AUDIO_FORMAT_F64_OE = SPA_AUDIO_FORMAT_F64_BE,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SPA_AUDIO_FORMAT_IS_INTERLEAVED(fmt) ((fmt) > SPA_AUDIO_FORMAT_START_Interleaved && (fmt) < SPA_AUDIO_FORMAT_START_Planar)
|
||||
#define SPA_AUDIO_FORMAT_IS_PLANAR(fmt) ((fmt) > SPA_AUDIO_FORMAT_START_Planar && (fmt) < SPA_AUDIO_FORMAT_START_Other)
|
||||
|
||||
enum spa_audio_channel {
|
||||
SPA_AUDIO_CHANNEL_UNKNOWN, /**< unspecified */
|
||||
SPA_AUDIO_CHANNEL_NA, /**< N/A, silent */
|
||||
|
||||
SPA_AUDIO_CHANNEL_MONO, /**< mono stream */
|
||||
|
||||
SPA_AUDIO_CHANNEL_FL, /**< front left */
|
||||
SPA_AUDIO_CHANNEL_FR, /**< front right */
|
||||
SPA_AUDIO_CHANNEL_FC, /**< front center */
|
||||
SPA_AUDIO_CHANNEL_LFE, /**< LFE */
|
||||
SPA_AUDIO_CHANNEL_SL, /**< side left */
|
||||
SPA_AUDIO_CHANNEL_SR, /**< side right */
|
||||
SPA_AUDIO_CHANNEL_FLC, /**< front left center */
|
||||
SPA_AUDIO_CHANNEL_FRC, /**< front right center */
|
||||
SPA_AUDIO_CHANNEL_RC, /**< rear center */
|
||||
SPA_AUDIO_CHANNEL_RL, /**< rear left */
|
||||
SPA_AUDIO_CHANNEL_RR, /**< rear right */
|
||||
SPA_AUDIO_CHANNEL_TC, /**< top center */
|
||||
SPA_AUDIO_CHANNEL_TFL, /**< top front left */
|
||||
SPA_AUDIO_CHANNEL_TFC, /**< top front center */
|
||||
SPA_AUDIO_CHANNEL_TFR, /**< top front right */
|
||||
SPA_AUDIO_CHANNEL_TRL, /**< top rear left */
|
||||
SPA_AUDIO_CHANNEL_TRC, /**< top rear center */
|
||||
SPA_AUDIO_CHANNEL_TRR, /**< top rear right */
|
||||
SPA_AUDIO_CHANNEL_RLC, /**< rear left center */
|
||||
SPA_AUDIO_CHANNEL_RRC, /**< rear right center */
|
||||
SPA_AUDIO_CHANNEL_FLW, /**< front left wide */
|
||||
SPA_AUDIO_CHANNEL_FRW, /**< front right wide */
|
||||
SPA_AUDIO_CHANNEL_LFE2, /**< LFE 2 */
|
||||
SPA_AUDIO_CHANNEL_FLH, /**< front left high */
|
||||
SPA_AUDIO_CHANNEL_FCH, /**< front center high */
|
||||
SPA_AUDIO_CHANNEL_FRH, /**< front right high */
|
||||
SPA_AUDIO_CHANNEL_TFLC, /**< top front left center */
|
||||
SPA_AUDIO_CHANNEL_TFRC, /**< top front right center */
|
||||
SPA_AUDIO_CHANNEL_TSL, /**< top side left */
|
||||
SPA_AUDIO_CHANNEL_TSR, /**< top side right */
|
||||
SPA_AUDIO_CHANNEL_LLFE, /**< left LFE */
|
||||
SPA_AUDIO_CHANNEL_RLFE, /**< right LFE */
|
||||
SPA_AUDIO_CHANNEL_BC, /**< bottom center */
|
||||
SPA_AUDIO_CHANNEL_BLC, /**< bottom left center */
|
||||
SPA_AUDIO_CHANNEL_BRC, /**< bottom right center */
|
||||
|
||||
SPA_AUDIO_CHANNEL_START_Aux = 0x1000, /**< aux channels */
|
||||
SPA_AUDIO_CHANNEL_AUX0 = SPA_AUDIO_CHANNEL_START_Aux,
|
||||
SPA_AUDIO_CHANNEL_AUX1,
|
||||
SPA_AUDIO_CHANNEL_AUX2,
|
||||
SPA_AUDIO_CHANNEL_AUX3,
|
||||
SPA_AUDIO_CHANNEL_AUX4,
|
||||
SPA_AUDIO_CHANNEL_AUX5,
|
||||
SPA_AUDIO_CHANNEL_AUX6,
|
||||
SPA_AUDIO_CHANNEL_AUX7,
|
||||
SPA_AUDIO_CHANNEL_AUX8,
|
||||
SPA_AUDIO_CHANNEL_AUX9,
|
||||
SPA_AUDIO_CHANNEL_AUX10,
|
||||
SPA_AUDIO_CHANNEL_AUX11,
|
||||
SPA_AUDIO_CHANNEL_AUX12,
|
||||
SPA_AUDIO_CHANNEL_AUX13,
|
||||
SPA_AUDIO_CHANNEL_AUX14,
|
||||
SPA_AUDIO_CHANNEL_AUX15,
|
||||
SPA_AUDIO_CHANNEL_AUX16,
|
||||
SPA_AUDIO_CHANNEL_AUX17,
|
||||
SPA_AUDIO_CHANNEL_AUX18,
|
||||
SPA_AUDIO_CHANNEL_AUX19,
|
||||
SPA_AUDIO_CHANNEL_AUX20,
|
||||
SPA_AUDIO_CHANNEL_AUX21,
|
||||
SPA_AUDIO_CHANNEL_AUX22,
|
||||
SPA_AUDIO_CHANNEL_AUX23,
|
||||
SPA_AUDIO_CHANNEL_AUX24,
|
||||
SPA_AUDIO_CHANNEL_AUX25,
|
||||
SPA_AUDIO_CHANNEL_AUX26,
|
||||
SPA_AUDIO_CHANNEL_AUX27,
|
||||
SPA_AUDIO_CHANNEL_AUX28,
|
||||
SPA_AUDIO_CHANNEL_AUX29,
|
||||
SPA_AUDIO_CHANNEL_AUX30,
|
||||
SPA_AUDIO_CHANNEL_AUX31,
|
||||
SPA_AUDIO_CHANNEL_AUX32,
|
||||
SPA_AUDIO_CHANNEL_AUX33,
|
||||
SPA_AUDIO_CHANNEL_AUX34,
|
||||
SPA_AUDIO_CHANNEL_AUX35,
|
||||
SPA_AUDIO_CHANNEL_AUX36,
|
||||
SPA_AUDIO_CHANNEL_AUX37,
|
||||
SPA_AUDIO_CHANNEL_AUX38,
|
||||
SPA_AUDIO_CHANNEL_AUX39,
|
||||
SPA_AUDIO_CHANNEL_AUX40,
|
||||
SPA_AUDIO_CHANNEL_AUX41,
|
||||
SPA_AUDIO_CHANNEL_AUX42,
|
||||
SPA_AUDIO_CHANNEL_AUX43,
|
||||
SPA_AUDIO_CHANNEL_AUX44,
|
||||
SPA_AUDIO_CHANNEL_AUX45,
|
||||
SPA_AUDIO_CHANNEL_AUX46,
|
||||
SPA_AUDIO_CHANNEL_AUX47,
|
||||
SPA_AUDIO_CHANNEL_AUX48,
|
||||
SPA_AUDIO_CHANNEL_AUX49,
|
||||
SPA_AUDIO_CHANNEL_AUX50,
|
||||
SPA_AUDIO_CHANNEL_AUX51,
|
||||
SPA_AUDIO_CHANNEL_AUX52,
|
||||
SPA_AUDIO_CHANNEL_AUX53,
|
||||
SPA_AUDIO_CHANNEL_AUX54,
|
||||
SPA_AUDIO_CHANNEL_AUX55,
|
||||
SPA_AUDIO_CHANNEL_AUX56,
|
||||
SPA_AUDIO_CHANNEL_AUX57,
|
||||
SPA_AUDIO_CHANNEL_AUX58,
|
||||
SPA_AUDIO_CHANNEL_AUX59,
|
||||
SPA_AUDIO_CHANNEL_AUX60,
|
||||
SPA_AUDIO_CHANNEL_AUX61,
|
||||
SPA_AUDIO_CHANNEL_AUX62,
|
||||
SPA_AUDIO_CHANNEL_AUX63,
|
||||
|
||||
SPA_AUDIO_CHANNEL_LAST_Aux = 0x1fff, /**< aux channels */
|
||||
|
||||
SPA_AUDIO_CHANNEL_START_Custom = 0x10000,
|
||||
};
|
||||
|
||||
enum spa_audio_volume_ramp_scale {
|
||||
SPA_AUDIO_VOLUME_RAMP_INVALID,
|
||||
SPA_AUDIO_VOLUME_RAMP_LINEAR,
|
||||
SPA_AUDIO_VOLUME_RAMP_CUBIC,
|
||||
};
|
||||
|
||||
/** Extra audio flags */
|
||||
#define SPA_AUDIO_FLAG_NONE (0) /*< no valid flag */
|
||||
#define SPA_AUDIO_FLAG_UNPOSITIONED (1 << 0) /*< the position array explicitly
|
||||
* contains unpositioned channels. */
|
||||
/** Audio information description */
|
||||
struct spa_audio_info_raw {
|
||||
enum spa_audio_format format; /*< format, one of enum spa_audio_format */
|
||||
uint32_t flags; /*< extra flags */
|
||||
uint32_t rate; /*< sample rate */
|
||||
uint32_t channels; /*< number of channels */
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS]; /*< channel position from enum spa_audio_channel */
|
||||
};
|
||||
|
||||
#define SPA_AUDIO_INFO_RAW_INIT(...) ((struct spa_audio_info_raw) { __VA_ARGS__ })
|
||||
|
||||
#define SPA_KEY_AUDIO_FORMAT "audio.format" /**< an audio format as string,
|
||||
* Ex. "S16LE" */
|
||||
#define SPA_KEY_AUDIO_CHANNEL "audio.channel" /**< an audio channel as string,
|
||||
* Ex. "FL" */
|
||||
#define SPA_KEY_AUDIO_CHANNELS "audio.channels" /**< an audio channel count as int */
|
||||
#define SPA_KEY_AUDIO_RATE "audio.rate" /**< an audio sample rate as int */
|
||||
#define SPA_KEY_AUDIO_POSITION "audio.position" /**< channel positions as comma separated list
|
||||
* of channels ex. "FL,FR" */
|
||||
#define SPA_KEY_AUDIO_ALLOWED_RATES "audio.allowed-rates" /**< a list of allowed samplerates
|
||||
* ex. "[ 44100 48000 ]" */
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_RAW_H */
|
@ -0,0 +1,15 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_TYPES_H
|
||||
#define SPA_AUDIO_TYPES_H
|
||||
|
||||
#include <spa/param/audio/raw-types.h>
|
||||
#include <spa/param/audio/iec958-types.h>
|
||||
#include <spa/param/audio/mp3-types.h>
|
||||
#include <spa/param/audio/aac-types.h>
|
||||
#include <spa/param/audio/wma-types.h>
|
||||
#include <spa/param/audio/amr-types.h>
|
||||
|
||||
#endif /* SPA_AUDIO_TYPES_H */
|
@ -0,0 +1,37 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_WMA_TYPES_H
|
||||
#define SPA_AUDIO_WMA_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/type.h>
|
||||
#include <spa/param/audio/wma.h>
|
||||
|
||||
#define SPA_TYPE_INFO_AudioWMAProfile SPA_TYPE_INFO_ENUM_BASE "AudioWMAProfile"
|
||||
#define SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE SPA_TYPE_INFO_AudioWMAProfile ":"
|
||||
|
||||
static const struct spa_type_info spa_type_audio_wma_profile[] = {
|
||||
{ SPA_AUDIO_WMA_PROFILE_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "UNKNOWN", NULL },
|
||||
{ SPA_AUDIO_WMA_PROFILE_WMA7, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA7", NULL },
|
||||
{ SPA_AUDIO_WMA_PROFILE_WMA8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA8", NULL },
|
||||
{ SPA_AUDIO_WMA_PROFILE_WMA9, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA9", NULL },
|
||||
{ SPA_AUDIO_WMA_PROFILE_WMA10, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA10", NULL },
|
||||
{ SPA_AUDIO_WMA_PROFILE_WMA9_PRO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA9-Pro", NULL },
|
||||
{ SPA_AUDIO_WMA_PROFILE_WMA9_LOSSLESS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA9-Lossless", NULL },
|
||||
{ SPA_AUDIO_WMA_PROFILE_WMA10_LOSSLESS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA10-Lossless", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_WMA_TYPES_H */
|
@ -0,0 +1,47 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_AUDIO_WMA_H
|
||||
#define SPA_AUDIO_WMA_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/param/audio/raw.h>
|
||||
|
||||
enum spa_audio_wma_profile {
|
||||
SPA_AUDIO_WMA_PROFILE_UNKNOWN,
|
||||
|
||||
SPA_AUDIO_WMA_PROFILE_WMA7,
|
||||
SPA_AUDIO_WMA_PROFILE_WMA8,
|
||||
SPA_AUDIO_WMA_PROFILE_WMA9,
|
||||
SPA_AUDIO_WMA_PROFILE_WMA10,
|
||||
SPA_AUDIO_WMA_PROFILE_WMA9_PRO,
|
||||
SPA_AUDIO_WMA_PROFILE_WMA9_LOSSLESS,
|
||||
SPA_AUDIO_WMA_PROFILE_WMA10_LOSSLESS,
|
||||
|
||||
SPA_AUDIO_WMA_PROFILE_CUSTOM = 0x10000,
|
||||
};
|
||||
|
||||
struct spa_audio_info_wma {
|
||||
uint32_t rate; /*< sample rate */
|
||||
uint32_t channels; /*< number of channels */
|
||||
uint32_t bitrate; /*< stream bitrate */
|
||||
uint32_t block_align; /*< block alignment */
|
||||
enum spa_audio_wma_profile profile; /*< WMA profile */
|
||||
|
||||
};
|
||||
|
||||
#define SPA_AUDIO_INFO_WMA_INIT(...) ((struct spa_audio_info_wma) { __VA_ARGS__ })
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_AUDIO_WMA_H */
|
@ -0,0 +1,54 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2020 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_BLUETOOTH_AUDIO_H
|
||||
#define SPA_BLUETOOTH_AUDIO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
enum spa_bluetooth_audio_codec {
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_START,
|
||||
|
||||
/* A2DP */
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_SBC,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_MPEG,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_AAC,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_APTX,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_APTX_HD,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_LDAC,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL_DUPLEX,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM_DUPLEX,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_LC3PLUS_HR,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_51,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO,
|
||||
|
||||
/* HFP */
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_CVSD = 0x100,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_MSBC,
|
||||
|
||||
/* BAP */
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_LC3 = 0x200,
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_BLUETOOTH_AUDIO_H */
|
@ -0,0 +1,58 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_BLUETOOTH_TYPES_H
|
||||
#define SPA_BLUETOOTH_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/bluetooth/audio.h>
|
||||
|
||||
#define SPA_TYPE_INFO_BluetoothAudioCodec SPA_TYPE_INFO_ENUM_BASE "BluetoothAudioCodec"
|
||||
#define SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE SPA_TYPE_INFO_BluetoothAudioCodec ":"
|
||||
|
||||
static const struct spa_type_info spa_type_bluetooth_audio_codec[] = {
|
||||
/* A2DP */
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_SBC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "sbc", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "sbc_xq", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_MPEG, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "mpeg", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_AAC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aac", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_APTX, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aptx", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_APTX_HD, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aptx_hd", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_LDAC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "ldac", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aptx_ll", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL_DUPLEX, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aptx_ll_duplex", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "faststream", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM_DUPLEX, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "faststream_duplex", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_LC3PLUS_HR, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "lc3plus_hr", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_51, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_51", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_71", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_duplex", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_pro", NULL },
|
||||
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_CVSD, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "cvsd", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_MSBC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "msbc", NULL },
|
||||
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_LC3, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "lc3", NULL },
|
||||
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_BLUETOOTH_TYPES_H */
|
@ -0,0 +1,70 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_BUFFERS_TYPES_H
|
||||
#define SPA_PARAM_BUFFERS_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param-types.h>
|
||||
#include <spa/node/type-info.h>
|
||||
|
||||
#include <spa/param/buffers.h>
|
||||
|
||||
#define SPA_TYPE_INFO_PARAM_Meta SPA_TYPE_INFO_PARAM_BASE "Meta"
|
||||
#define SPA_TYPE_INFO_PARAM_META_BASE SPA_TYPE_INFO_PARAM_Meta ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_meta[] = {
|
||||
{ SPA_PARAM_META_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_META_BASE, spa_type_param },
|
||||
{ SPA_PARAM_META_type, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_META_BASE "type", spa_type_meta_type },
|
||||
{ SPA_PARAM_META_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_META_BASE "size", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/** Base for parameters that describe IO areas to exchange data,
|
||||
* control and properties with a node.
|
||||
*/
|
||||
#define SPA_TYPE_INFO_PARAM_IO SPA_TYPE_INFO_PARAM_BASE "IO"
|
||||
#define SPA_TYPE_INFO_PARAM_IO_BASE SPA_TYPE_INFO_PARAM_IO ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_io[] = {
|
||||
{ SPA_PARAM_IO_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_IO_BASE, spa_type_param, },
|
||||
{ SPA_PARAM_IO_id, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_IO_BASE "id", spa_type_io },
|
||||
{ SPA_PARAM_IO_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_IO_BASE "size", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_PARAM_Buffers SPA_TYPE_INFO_PARAM_BASE "Buffers"
|
||||
#define SPA_TYPE_INFO_PARAM_BUFFERS_BASE SPA_TYPE_INFO_PARAM_Buffers ":"
|
||||
|
||||
#define SPA_TYPE_INFO_PARAM_BlockInfo SPA_TYPE_INFO_PARAM_BUFFERS_BASE "BlockInfo"
|
||||
#define SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE SPA_TYPE_INFO_PARAM_BlockInfo ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_buffers[] = {
|
||||
{ SPA_PARAM_BUFFERS_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_BUFFERS_BASE, spa_type_param, },
|
||||
{ SPA_PARAM_BUFFERS_buffers, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BUFFERS_BASE "buffers", NULL },
|
||||
{ SPA_PARAM_BUFFERS_blocks, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BUFFERS_BASE "blocks", NULL },
|
||||
{ SPA_PARAM_BUFFERS_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "size", NULL },
|
||||
{ SPA_PARAM_BUFFERS_stride, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "stride", NULL },
|
||||
{ SPA_PARAM_BUFFERS_align, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "align", NULL },
|
||||
{ SPA_PARAM_BUFFERS_dataType, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "dataType", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_BUFFERS_TYPES_H */
|
@ -0,0 +1,52 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_BUFFERS_H
|
||||
#define SPA_PARAM_BUFFERS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param.h>
|
||||
|
||||
/** properties for SPA_TYPE_OBJECT_ParamBuffers */
|
||||
enum spa_param_buffers {
|
||||
SPA_PARAM_BUFFERS_START,
|
||||
SPA_PARAM_BUFFERS_buffers, /**< number of buffers (Int) */
|
||||
SPA_PARAM_BUFFERS_blocks, /**< number of data blocks per buffer (Int) */
|
||||
SPA_PARAM_BUFFERS_size, /**< size of a data block memory (Int)*/
|
||||
SPA_PARAM_BUFFERS_stride, /**< stride of data block memory (Int) */
|
||||
SPA_PARAM_BUFFERS_align, /**< alignment of data block memory (Int) */
|
||||
SPA_PARAM_BUFFERS_dataType, /**< possible memory types (Int, mask of enum spa_data_type) */
|
||||
};
|
||||
|
||||
/** properties for SPA_TYPE_OBJECT_ParamMeta */
|
||||
enum spa_param_meta {
|
||||
SPA_PARAM_META_START,
|
||||
SPA_PARAM_META_type, /**< the metadata, one of enum spa_meta_type (Id enum spa_meta_type) */
|
||||
SPA_PARAM_META_size, /**< the expected maximum size the meta (Int) */
|
||||
};
|
||||
|
||||
/** properties for SPA_TYPE_OBJECT_ParamIO */
|
||||
enum spa_param_io {
|
||||
SPA_PARAM_IO_START,
|
||||
SPA_PARAM_IO_id, /**< type ID, uniquely identifies the io area (Id enum spa_io_type) */
|
||||
SPA_PARAM_IO_size, /**< size of the io area (Int) */
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_BUFFERS_H */
|
@ -0,0 +1,172 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_FORMAT_TYPES_H
|
||||
#define SPA_PARAM_FORMAT_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/format.h>
|
||||
#include <spa/param/param-types.h>
|
||||
|
||||
#include <spa/param/audio/type-info.h>
|
||||
#include <spa/param/video/type-info.h>
|
||||
|
||||
#define SPA_TYPE_INFO_Format SPA_TYPE_INFO_PARAM_BASE "Format"
|
||||
#define SPA_TYPE_INFO_FORMAT_BASE SPA_TYPE_INFO_Format ":"
|
||||
|
||||
#define SPA_TYPE_INFO_MediaType SPA_TYPE_INFO_ENUM_BASE "MediaType"
|
||||
#define SPA_TYPE_INFO_MEDIA_TYPE_BASE SPA_TYPE_INFO_MediaType ":"
|
||||
|
||||
static const struct spa_type_info spa_type_media_type[] = {
|
||||
{ SPA_MEDIA_TYPE_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "unknown", NULL },
|
||||
{ SPA_MEDIA_TYPE_audio, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "audio", NULL },
|
||||
{ SPA_MEDIA_TYPE_video, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "video", NULL },
|
||||
{ SPA_MEDIA_TYPE_image, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "image", NULL },
|
||||
{ SPA_MEDIA_TYPE_binary, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "binary", NULL },
|
||||
{ SPA_MEDIA_TYPE_stream, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "stream", NULL },
|
||||
{ SPA_MEDIA_TYPE_application, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "application", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_MediaSubtype SPA_TYPE_INFO_ENUM_BASE "MediaSubtype"
|
||||
#define SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE SPA_TYPE_INFO_MediaSubtype ":"
|
||||
|
||||
static const struct spa_type_info spa_type_media_subtype[] = {
|
||||
{ SPA_MEDIA_SUBTYPE_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "unknown", NULL },
|
||||
/* generic subtypes */
|
||||
{ SPA_MEDIA_SUBTYPE_raw, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "raw", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_dsp, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dsp", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_iec958, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "iec958", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_dsd, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dsd", NULL },
|
||||
/* audio subtypes */
|
||||
{ SPA_MEDIA_SUBTYPE_mp3, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mp3", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_aac, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "aac", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_vorbis, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vorbis", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_wma, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "wma", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_ra, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "ra", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_sbc, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "sbc", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_adpcm, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "adpcm", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_g723, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g723", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_g726, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g726", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_g729, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g729", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_amr, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "amr", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_gsm, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "gsm", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_alac, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "alac", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_flac, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "flac", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_ape, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "ape", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_opus, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "opus", NULL },
|
||||
/* video subtypes */
|
||||
{ SPA_MEDIA_SUBTYPE_h264, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "h264", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_mjpg, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mjpg", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_dv, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dv", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_mpegts, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpegts", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_h263, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "h263", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_mpeg1, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg1", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_mpeg2, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg2", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_mpeg4, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg4", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_xvid, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "xvid", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_vc1, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vc1", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_vp8, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vp8", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_vp9, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vp9", NULL },
|
||||
{ SPA_MEDIA_SUBTYPE_bayer, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "bayer", NULL },
|
||||
/* image subtypes */
|
||||
{ SPA_MEDIA_SUBTYPE_jpeg, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "jpeg", NULL },
|
||||
/* stream subtypes */
|
||||
{ SPA_MEDIA_SUBTYPE_midi, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "midi", NULL },
|
||||
/* application subtypes */
|
||||
{ SPA_MEDIA_SUBTYPE_control, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "control", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_FormatAudio SPA_TYPE_INFO_FORMAT_BASE "Audio"
|
||||
#define SPA_TYPE_INFO_FORMAT_AUDIO_BASE SPA_TYPE_INFO_FormatAudio ":"
|
||||
|
||||
#define SPA_TYPE_INFO_FORMAT_AUDIO_AAC SPA_TYPE_INFO_FORMAT_AUDIO_BASE "AAC"
|
||||
#define SPA_TYPE_INFO_FORMAT_AUDIO_AAC_BASE SPA_TYPE_INFO_FORMAT_AUDIO_AAC ":"
|
||||
#define SPA_TYPE_INFO_FORMAT_AUDIO_WMA SPA_TYPE_INFO_FORMAT_AUDIO_BASE "WMA"
|
||||
#define SPA_TYPE_INFO_FORMAT_AUDIO_WMA_BASE SPA_TYPE_INFO_FORMAT_AUDIO_WMA ":"
|
||||
#define SPA_TYPE_INFO_FORMAT_AUDIO_AMR SPA_TYPE_INFO_FORMAT_AUDIO_BASE "AMR"
|
||||
#define SPA_TYPE_INFO_FORMAT_AUDIO_AMR_BASE SPA_TYPE_INFO_FORMAT_AUDIO_AMR ":"
|
||||
|
||||
#define SPA_TYPE_INFO_FormatVideo SPA_TYPE_INFO_FORMAT_BASE "Video"
|
||||
#define SPA_TYPE_INFO_FORMAT_VIDEO_BASE SPA_TYPE_INFO_FormatVideo ":"
|
||||
|
||||
#define SPA_TYPE_INFO_FORMAT_VIDEO_H264 SPA_TYPE_INFO_FORMAT_VIDEO_BASE "H264"
|
||||
#define SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE SPA_TYPE_INFO_FORMAT_VIDEO_H264 ":"
|
||||
|
||||
static const struct spa_type_info spa_type_format[] = {
|
||||
{ SPA_FORMAT_START, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE, spa_type_param, },
|
||||
|
||||
{ SPA_FORMAT_mediaType, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE "mediaType",
|
||||
spa_type_media_type, },
|
||||
{ SPA_FORMAT_mediaSubtype, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE "mediaSubtype",
|
||||
spa_type_media_subtype, },
|
||||
|
||||
{ SPA_FORMAT_AUDIO_format, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "format",
|
||||
spa_type_audio_format },
|
||||
{ SPA_FORMAT_AUDIO_flags, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "flags",
|
||||
spa_type_audio_flags },
|
||||
{ SPA_FORMAT_AUDIO_rate, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "rate", NULL },
|
||||
{ SPA_FORMAT_AUDIO_channels, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "channels", NULL },
|
||||
{ SPA_FORMAT_AUDIO_position, SPA_TYPE_Array, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "position",
|
||||
spa_type_prop_channel_map },
|
||||
|
||||
{ SPA_FORMAT_AUDIO_iec958Codec, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "iec958Codec",
|
||||
spa_type_audio_iec958_codec },
|
||||
|
||||
{ SPA_FORMAT_AUDIO_bitorder, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "bitorder",
|
||||
spa_type_param_bitorder },
|
||||
{ SPA_FORMAT_AUDIO_interleave, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "interleave", NULL },
|
||||
{ SPA_FORMAT_AUDIO_bitrate, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "bitrate", NULL },
|
||||
{ SPA_FORMAT_AUDIO_blockAlign, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "blockAlign", NULL },
|
||||
|
||||
{ SPA_FORMAT_AUDIO_AAC_streamFormat, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_AAC_BASE "streamFormat",
|
||||
spa_type_audio_aac_stream_format },
|
||||
{ SPA_FORMAT_AUDIO_WMA_profile, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_WMA_BASE "profile",
|
||||
spa_type_audio_wma_profile },
|
||||
{ SPA_FORMAT_AUDIO_AMR_bandMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_AMR_BASE "bandMode",
|
||||
spa_type_audio_amr_band_mode },
|
||||
|
||||
{ SPA_FORMAT_VIDEO_format, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "format",
|
||||
spa_type_video_format, },
|
||||
{ SPA_FORMAT_VIDEO_modifier, SPA_TYPE_Long, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "modifier", NULL },
|
||||
{ SPA_FORMAT_VIDEO_size, SPA_TYPE_Rectangle, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "size", NULL },
|
||||
{ SPA_FORMAT_VIDEO_framerate, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "framerate", NULL },
|
||||
{ SPA_FORMAT_VIDEO_maxFramerate, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "maxFramerate", NULL },
|
||||
{ SPA_FORMAT_VIDEO_views, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "views", NULL },
|
||||
{ SPA_FORMAT_VIDEO_interlaceMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "interlaceMode",
|
||||
spa_type_video_interlace_mode, },
|
||||
{ SPA_FORMAT_VIDEO_pixelAspectRatio, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "pixelAspectRatio", NULL },
|
||||
{ SPA_FORMAT_VIDEO_multiviewMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "multiviewMode", NULL },
|
||||
{ SPA_FORMAT_VIDEO_multiviewFlags, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "multiviewFlags", NULL },
|
||||
{ SPA_FORMAT_VIDEO_chromaSite, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "chromaSite", NULL },
|
||||
{ SPA_FORMAT_VIDEO_colorRange, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorRange", NULL },
|
||||
{ SPA_FORMAT_VIDEO_colorMatrix, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorMatrix", NULL },
|
||||
{ SPA_FORMAT_VIDEO_transferFunction, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "transferFunction", NULL },
|
||||
{ SPA_FORMAT_VIDEO_colorPrimaries, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorPrimaries", NULL },
|
||||
{ SPA_FORMAT_VIDEO_profile, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "profile", NULL },
|
||||
{ SPA_FORMAT_VIDEO_level, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "level", NULL },
|
||||
|
||||
{ SPA_FORMAT_VIDEO_H264_streamFormat, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE "streamFormat", NULL },
|
||||
{ SPA_FORMAT_VIDEO_H264_alignment, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE "alignment", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_FORMAT_TYPES_H */
|
@ -0,0 +1,38 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_FORMAT_UTILS_H
|
||||
#define SPA_PARAM_FORMAT_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/pod/parser.h>
|
||||
#include <spa/param/format.h>
|
||||
|
||||
static inline int
|
||||
spa_format_parse(const struct spa_pod *format, uint32_t *media_type, uint32_t *media_subtype)
|
||||
{
|
||||
return spa_pod_parse_object(format,
|
||||
SPA_TYPE_OBJECT_Format, NULL,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(media_type),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(media_subtype));
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_FORMAT_UTILS_H */
|
@ -0,0 +1,157 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_FORMAT_H
|
||||
#define SPA_PARAM_FORMAT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param.h>
|
||||
|
||||
/** media type for SPA_TYPE_OBJECT_Format */
|
||||
enum spa_media_type {
|
||||
SPA_MEDIA_TYPE_unknown,
|
||||
SPA_MEDIA_TYPE_audio,
|
||||
SPA_MEDIA_TYPE_video,
|
||||
SPA_MEDIA_TYPE_image,
|
||||
SPA_MEDIA_TYPE_binary,
|
||||
SPA_MEDIA_TYPE_stream,
|
||||
SPA_MEDIA_TYPE_application,
|
||||
};
|
||||
|
||||
/** media subtype for SPA_TYPE_OBJECT_Format */
|
||||
enum spa_media_subtype {
|
||||
SPA_MEDIA_SUBTYPE_unknown,
|
||||
SPA_MEDIA_SUBTYPE_raw,
|
||||
SPA_MEDIA_SUBTYPE_dsp,
|
||||
SPA_MEDIA_SUBTYPE_iec958, /** S/PDIF */
|
||||
SPA_MEDIA_SUBTYPE_dsd,
|
||||
|
||||
SPA_MEDIA_SUBTYPE_START_Audio = 0x10000,
|
||||
SPA_MEDIA_SUBTYPE_mp3,
|
||||
SPA_MEDIA_SUBTYPE_aac,
|
||||
SPA_MEDIA_SUBTYPE_vorbis,
|
||||
SPA_MEDIA_SUBTYPE_wma,
|
||||
SPA_MEDIA_SUBTYPE_ra,
|
||||
SPA_MEDIA_SUBTYPE_sbc,
|
||||
SPA_MEDIA_SUBTYPE_adpcm,
|
||||
SPA_MEDIA_SUBTYPE_g723,
|
||||
SPA_MEDIA_SUBTYPE_g726,
|
||||
SPA_MEDIA_SUBTYPE_g729,
|
||||
SPA_MEDIA_SUBTYPE_amr,
|
||||
SPA_MEDIA_SUBTYPE_gsm,
|
||||
SPA_MEDIA_SUBTYPE_alac, /** since 0.3.65 */
|
||||
SPA_MEDIA_SUBTYPE_flac, /** since 0.3.65 */
|
||||
SPA_MEDIA_SUBTYPE_ape, /** since 0.3.65 */
|
||||
SPA_MEDIA_SUBTYPE_opus, /** since 0.3.68 */
|
||||
|
||||
SPA_MEDIA_SUBTYPE_START_Video = 0x20000,
|
||||
SPA_MEDIA_SUBTYPE_h264,
|
||||
SPA_MEDIA_SUBTYPE_mjpg,
|
||||
SPA_MEDIA_SUBTYPE_dv,
|
||||
SPA_MEDIA_SUBTYPE_mpegts,
|
||||
SPA_MEDIA_SUBTYPE_h263,
|
||||
SPA_MEDIA_SUBTYPE_mpeg1,
|
||||
SPA_MEDIA_SUBTYPE_mpeg2,
|
||||
SPA_MEDIA_SUBTYPE_mpeg4,
|
||||
SPA_MEDIA_SUBTYPE_xvid,
|
||||
SPA_MEDIA_SUBTYPE_vc1,
|
||||
SPA_MEDIA_SUBTYPE_vp8,
|
||||
SPA_MEDIA_SUBTYPE_vp9,
|
||||
SPA_MEDIA_SUBTYPE_bayer,
|
||||
|
||||
SPA_MEDIA_SUBTYPE_START_Image = 0x30000,
|
||||
SPA_MEDIA_SUBTYPE_jpeg,
|
||||
|
||||
SPA_MEDIA_SUBTYPE_START_Binary = 0x40000,
|
||||
|
||||
SPA_MEDIA_SUBTYPE_START_Stream = 0x50000,
|
||||
SPA_MEDIA_SUBTYPE_midi,
|
||||
|
||||
SPA_MEDIA_SUBTYPE_START_Application = 0x60000,
|
||||
SPA_MEDIA_SUBTYPE_control, /**< control stream, data contains
|
||||
* spa_pod_sequence with control info. */
|
||||
};
|
||||
|
||||
/** properties for audio SPA_TYPE_OBJECT_Format */
|
||||
enum spa_format {
|
||||
SPA_FORMAT_START,
|
||||
|
||||
SPA_FORMAT_mediaType, /**< media type (Id enum spa_media_type) */
|
||||
SPA_FORMAT_mediaSubtype, /**< media subtype (Id enum spa_media_subtype) */
|
||||
|
||||
/* Audio format keys */
|
||||
SPA_FORMAT_START_Audio = 0x10000,
|
||||
SPA_FORMAT_AUDIO_format, /**< audio format, (Id enum spa_audio_format) */
|
||||
SPA_FORMAT_AUDIO_flags, /**< optional flags (Int) */
|
||||
SPA_FORMAT_AUDIO_rate, /**< sample rate (Int) */
|
||||
SPA_FORMAT_AUDIO_channels, /**< number of audio channels (Int) */
|
||||
SPA_FORMAT_AUDIO_position, /**< channel positions (Id enum spa_audio_position) */
|
||||
|
||||
SPA_FORMAT_AUDIO_iec958Codec, /**< codec used (IEC958) (Id enum spa_audio_iec958_codec) */
|
||||
|
||||
SPA_FORMAT_AUDIO_bitorder, /**< bit order (Id enum spa_param_bitorder) */
|
||||
SPA_FORMAT_AUDIO_interleave, /**< Interleave bytes (Int) */
|
||||
SPA_FORMAT_AUDIO_bitrate, /**< bit rate (Int) */
|
||||
SPA_FORMAT_AUDIO_blockAlign, /**< audio data block alignment (Int) */
|
||||
|
||||
SPA_FORMAT_AUDIO_AAC_streamFormat, /**< AAC stream format, (Id enum spa_audio_aac_stream_format) */
|
||||
|
||||
SPA_FORMAT_AUDIO_WMA_profile, /**< WMA profile (Id enum spa_audio_wma_profile) */
|
||||
|
||||
SPA_FORMAT_AUDIO_AMR_bandMode, /**< AMR band mode (Id enum spa_audio_amr_band_mode) */
|
||||
|
||||
|
||||
/* Video Format keys */
|
||||
SPA_FORMAT_START_Video = 0x20000,
|
||||
SPA_FORMAT_VIDEO_format, /**< video format (Id enum spa_video_format) */
|
||||
SPA_FORMAT_VIDEO_modifier, /**< format modifier (Long)
|
||||
* use only with DMA-BUF and omit for other buffer types */
|
||||
SPA_FORMAT_VIDEO_size, /**< size (Rectangle) */
|
||||
SPA_FORMAT_VIDEO_framerate, /**< frame rate (Fraction) */
|
||||
SPA_FORMAT_VIDEO_maxFramerate, /**< maximum frame rate (Fraction) */
|
||||
SPA_FORMAT_VIDEO_views, /**< number of views (Int) */
|
||||
SPA_FORMAT_VIDEO_interlaceMode, /**< (Id enum spa_video_interlace_mode) */
|
||||
SPA_FORMAT_VIDEO_pixelAspectRatio, /**< (Rectangle) */
|
||||
SPA_FORMAT_VIDEO_multiviewMode, /**< (Id enum spa_video_multiview_mode) */
|
||||
SPA_FORMAT_VIDEO_multiviewFlags, /**< (Id enum spa_video_multiview_flags) */
|
||||
SPA_FORMAT_VIDEO_chromaSite, /**< /Id enum spa_video_chroma_site) */
|
||||
SPA_FORMAT_VIDEO_colorRange, /**< /Id enum spa_video_color_range) */
|
||||
SPA_FORMAT_VIDEO_colorMatrix, /**< /Id enum spa_video_color_matrix) */
|
||||
SPA_FORMAT_VIDEO_transferFunction, /**< /Id enum spa_video_transfer_function) */
|
||||
SPA_FORMAT_VIDEO_colorPrimaries, /**< /Id enum spa_video_color_primaries) */
|
||||
SPA_FORMAT_VIDEO_profile, /**< (Int) */
|
||||
SPA_FORMAT_VIDEO_level, /**< (Int) */
|
||||
SPA_FORMAT_VIDEO_H264_streamFormat, /**< (Id enum spa_h264_stream_format) */
|
||||
SPA_FORMAT_VIDEO_H264_alignment, /**< (Id enum spa_h264_alignment) */
|
||||
|
||||
/* Image Format keys */
|
||||
SPA_FORMAT_START_Image = 0x30000,
|
||||
/* Binary Format keys */
|
||||
SPA_FORMAT_START_Binary = 0x40000,
|
||||
/* Stream Format keys */
|
||||
SPA_FORMAT_START_Stream = 0x50000,
|
||||
/* Application Format keys */
|
||||
SPA_FORMAT_START_Application = 0x60000,
|
||||
};
|
||||
|
||||
#define SPA_KEY_FORMAT_DSP "format.dsp" /**< a predefined DSP format,
|
||||
* Ex. "32 bit float mono audio" */
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_FORMAT_H */
|
@ -0,0 +1,55 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_LATENCY_TYPES_H
|
||||
#define SPA_PARAM_LATENCY_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/utils/enum-types.h>
|
||||
#include <spa/param/param-types.h>
|
||||
#include <spa/param/latency.h>
|
||||
|
||||
#define SPA_TYPE_INFO_PARAM_Latency SPA_TYPE_INFO_PARAM_BASE "Latency"
|
||||
#define SPA_TYPE_INFO_PARAM_LATENCY_BASE SPA_TYPE_INFO_PARAM_Latency ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_latency[] = {
|
||||
{ SPA_PARAM_LATENCY_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LATENCY_BASE, spa_type_param, },
|
||||
{ SPA_PARAM_LATENCY_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LATENCY_BASE "direction", spa_type_direction, },
|
||||
{ SPA_PARAM_LATENCY_minQuantum, SPA_TYPE_Float, SPA_TYPE_INFO_PARAM_LATENCY_BASE "minQuantum", NULL, },
|
||||
{ SPA_PARAM_LATENCY_maxQuantum, SPA_TYPE_Float, SPA_TYPE_INFO_PARAM_LATENCY_BASE "maxQuantum", NULL, },
|
||||
{ SPA_PARAM_LATENCY_minRate, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_LATENCY_BASE "minRate", NULL, },
|
||||
{ SPA_PARAM_LATENCY_maxRate, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_LATENCY_BASE "maxRate", NULL, },
|
||||
{ SPA_PARAM_LATENCY_minNs, SPA_TYPE_Long, SPA_TYPE_INFO_PARAM_LATENCY_BASE "minNs", NULL, },
|
||||
{ SPA_PARAM_LATENCY_maxNs, SPA_TYPE_Long, SPA_TYPE_INFO_PARAM_LATENCY_BASE "maxNs", NULL, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_PARAM_ProcessLatency SPA_TYPE_INFO_PARAM_BASE "ProcessLatency"
|
||||
#define SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE SPA_TYPE_INFO_PARAM_ProcessLatency ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_process_latency[] = {
|
||||
{ SPA_PARAM_PROCESS_LATENCY_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LATENCY_BASE, spa_type_param, },
|
||||
{ SPA_PARAM_PROCESS_LATENCY_quantum, SPA_TYPE_Float, SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE "quantum", NULL, },
|
||||
{ SPA_PARAM_PROCESS_LATENCY_rate, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE "rate", NULL, },
|
||||
{ SPA_PARAM_PROCESS_LATENCY_ns, SPA_TYPE_Long, SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE "ns", NULL, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_LATENCY_TYPES_H */
|
@ -0,0 +1,69 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_LATENY_H
|
||||
#define SPA_PARAM_LATENY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param.h>
|
||||
|
||||
/** properties for SPA_TYPE_OBJECT_ParamLatency */
|
||||
enum spa_param_latency {
|
||||
SPA_PARAM_LATENCY_START,
|
||||
SPA_PARAM_LATENCY_direction, /**< direction, input/output (Id enum spa_direction) */
|
||||
SPA_PARAM_LATENCY_minQuantum, /**< min latency relative to quantum (Float) */
|
||||
SPA_PARAM_LATENCY_maxQuantum, /**< max latency relative to quantum (Float) */
|
||||
SPA_PARAM_LATENCY_minRate, /**< min latency (Int) relative to rate */
|
||||
SPA_PARAM_LATENCY_maxRate, /**< max latency (Int) relative to rate */
|
||||
SPA_PARAM_LATENCY_minNs, /**< min latency (Long) in nanoseconds */
|
||||
SPA_PARAM_LATENCY_maxNs, /**< max latency (Long) in nanoseconds */
|
||||
};
|
||||
|
||||
/** helper structure for managing latency objects */
|
||||
struct spa_latency_info {
|
||||
enum spa_direction direction;
|
||||
float min_quantum;
|
||||
float max_quantum;
|
||||
uint32_t min_rate;
|
||||
uint32_t max_rate;
|
||||
uint64_t min_ns;
|
||||
uint64_t max_ns;
|
||||
};
|
||||
|
||||
#define SPA_LATENCY_INFO(dir,...) ((struct spa_latency_info) { .direction = (dir), ## __VA_ARGS__ })
|
||||
|
||||
/** properties for SPA_TYPE_OBJECT_ParamProcessLatency */
|
||||
enum spa_param_process_latency {
|
||||
SPA_PARAM_PROCESS_LATENCY_START,
|
||||
SPA_PARAM_PROCESS_LATENCY_quantum, /**< latency relative to quantum (Float) */
|
||||
SPA_PARAM_PROCESS_LATENCY_rate, /**< latency (Int) relative to rate */
|
||||
SPA_PARAM_PROCESS_LATENCY_ns, /**< latency (Long) in nanoseconds */
|
||||
};
|
||||
|
||||
/** Helper structure for managing process latency objects */
|
||||
struct spa_process_latency_info {
|
||||
float quantum;
|
||||
uint32_t rate;
|
||||
uint64_t ns;
|
||||
};
|
||||
|
||||
#define SPA_PROCESS_LATENCY_INFO_INIT(...) ((struct spa_process_latency_info) { __VA_ARGS__ })
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_LATENY_H */
|
@ -0,0 +1,95 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_TYPES_H
|
||||
#define SPA_PARAM_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/props.h>
|
||||
#include <spa/param/format.h>
|
||||
#include <spa/buffer/type-info.h>
|
||||
|
||||
/* base for parameter object enumerations */
|
||||
#define SPA_TYPE_INFO_ParamId SPA_TYPE_INFO_ENUM_BASE "ParamId"
|
||||
#define SPA_TYPE_INFO_PARAM_ID_BASE SPA_TYPE_INFO_ParamId ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param[] = {
|
||||
{ SPA_PARAM_Invalid, SPA_TYPE_None, SPA_TYPE_INFO_PARAM_ID_BASE "Invalid", NULL },
|
||||
{ SPA_PARAM_PropInfo, SPA_TYPE_OBJECT_PropInfo, SPA_TYPE_INFO_PARAM_ID_BASE "PropInfo", NULL },
|
||||
{ SPA_PARAM_Props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ID_BASE "Props", NULL },
|
||||
{ SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_ID_BASE "EnumFormat", NULL },
|
||||
{ SPA_PARAM_Format, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_ID_BASE "Format", NULL },
|
||||
{ SPA_PARAM_Buffers, SPA_TYPE_OBJECT_ParamBuffers, SPA_TYPE_INFO_PARAM_ID_BASE "Buffers", NULL },
|
||||
{ SPA_PARAM_Meta, SPA_TYPE_OBJECT_ParamMeta, SPA_TYPE_INFO_PARAM_ID_BASE "Meta", NULL },
|
||||
{ SPA_PARAM_IO, SPA_TYPE_OBJECT_ParamIO, SPA_TYPE_INFO_PARAM_ID_BASE "IO", NULL },
|
||||
{ SPA_PARAM_EnumProfile, SPA_TYPE_OBJECT_ParamProfile, SPA_TYPE_INFO_PARAM_ID_BASE "EnumProfile", NULL },
|
||||
{ SPA_PARAM_Profile, SPA_TYPE_OBJECT_ParamProfile, SPA_TYPE_INFO_PARAM_ID_BASE "Profile", NULL },
|
||||
{ SPA_PARAM_EnumPortConfig, SPA_TYPE_OBJECT_ParamPortConfig, SPA_TYPE_INFO_PARAM_ID_BASE "EnumPortConfig", NULL },
|
||||
{ SPA_PARAM_PortConfig, SPA_TYPE_OBJECT_ParamPortConfig, SPA_TYPE_INFO_PARAM_ID_BASE "PortConfig", NULL },
|
||||
{ SPA_PARAM_EnumRoute, SPA_TYPE_OBJECT_ParamRoute, SPA_TYPE_INFO_PARAM_ID_BASE "EnumRoute", NULL },
|
||||
{ SPA_PARAM_Route, SPA_TYPE_OBJECT_ParamRoute, SPA_TYPE_INFO_PARAM_ID_BASE "Route", NULL },
|
||||
{ SPA_PARAM_Control, SPA_TYPE_Sequence, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL },
|
||||
{ SPA_PARAM_Latency, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_INFO_PARAM_ID_BASE "Latency", NULL },
|
||||
{ SPA_PARAM_ProcessLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_INFO_PARAM_ID_BASE "ProcessLatency", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/* base for parameter objects */
|
||||
#define SPA_TYPE_INFO_Param SPA_TYPE_INFO_OBJECT_BASE "Param"
|
||||
#define SPA_TYPE_INFO_PARAM_BASE SPA_TYPE_INFO_Param ":"
|
||||
|
||||
#include <spa/param/audio/type-info.h>
|
||||
|
||||
static const struct spa_type_info spa_type_prop_float_array[] = {
|
||||
{ SPA_PROP_START, SPA_TYPE_Float, SPA_TYPE_INFO_BASE "floatArray", NULL, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
static const struct spa_type_info spa_type_prop_channel_map[] = {
|
||||
{ SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_BASE "channelMap", spa_type_audio_channel, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
static const struct spa_type_info spa_type_prop_iec958_codec[] = {
|
||||
{ SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_BASE "iec958Codec", spa_type_audio_iec958_codec, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_ParamBitorder SPA_TYPE_INFO_ENUM_BASE "ParamBitorder"
|
||||
#define SPA_TYPE_INFO_PARAM_BITORDER_BASE SPA_TYPE_INFO_ParamBitorder ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_bitorder[] = {
|
||||
{ SPA_PARAM_BITORDER_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BITORDER_BASE "unknown", NULL },
|
||||
{ SPA_PARAM_BITORDER_msb, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BITORDER_BASE "msb", NULL },
|
||||
{ SPA_PARAM_BITORDER_lsb, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BITORDER_BASE "lsb", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_ParamAvailability SPA_TYPE_INFO_ENUM_BASE "ParamAvailability"
|
||||
#define SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE SPA_TYPE_INFO_ParamAvailability ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_availability[] = {
|
||||
{ SPA_PARAM_AVAILABILITY_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "unknown", NULL },
|
||||
{ SPA_PARAM_AVAILABILITY_no, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "no", NULL },
|
||||
{ SPA_PARAM_AVAILABILITY_yes, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "yes", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_TYPES_H */
|
@ -0,0 +1,87 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_H
|
||||
#define SPA_PARAM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup spa_param Parameters
|
||||
* Parameter value enumerations and type information
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
|
||||
/** different parameter types that can be queried */
|
||||
enum spa_param_type {
|
||||
SPA_PARAM_Invalid, /**< invalid */
|
||||
SPA_PARAM_PropInfo, /**< property information as SPA_TYPE_OBJECT_PropInfo */
|
||||
SPA_PARAM_Props, /**< properties as SPA_TYPE_OBJECT_Props */
|
||||
SPA_PARAM_EnumFormat, /**< available formats as SPA_TYPE_OBJECT_Format */
|
||||
SPA_PARAM_Format, /**< configured format as SPA_TYPE_OBJECT_Format */
|
||||
SPA_PARAM_Buffers, /**< buffer configurations as SPA_TYPE_OBJECT_ParamBuffers*/
|
||||
SPA_PARAM_Meta, /**< allowed metadata for buffers as SPA_TYPE_OBJECT_ParamMeta*/
|
||||
SPA_PARAM_IO, /**< configurable IO areas as SPA_TYPE_OBJECT_ParamIO */
|
||||
SPA_PARAM_EnumProfile, /**< profile enumeration as SPA_TYPE_OBJECT_ParamProfile */
|
||||
SPA_PARAM_Profile, /**< profile configuration as SPA_TYPE_OBJECT_ParamProfile */
|
||||
SPA_PARAM_EnumPortConfig, /**< port configuration enumeration as SPA_TYPE_OBJECT_ParamPortConfig */
|
||||
SPA_PARAM_PortConfig, /**< port configuration as SPA_TYPE_OBJECT_ParamPortConfig */
|
||||
SPA_PARAM_EnumRoute, /**< routing enumeration as SPA_TYPE_OBJECT_ParamRoute */
|
||||
SPA_PARAM_Route, /**< routing configuration as SPA_TYPE_OBJECT_ParamRoute */
|
||||
SPA_PARAM_Control, /**< Control parameter, a SPA_TYPE_Sequence */
|
||||
SPA_PARAM_Latency, /**< latency reporting, a SPA_TYPE_OBJECT_ParamLatency */
|
||||
SPA_PARAM_ProcessLatency, /**< processing latency, a SPA_TYPE_OBJECT_ParamProcessLatency */
|
||||
};
|
||||
|
||||
/** information about a parameter */
|
||||
struct spa_param_info {
|
||||
uint32_t id; /**< enum spa_param_type */
|
||||
#define SPA_PARAM_INFO_SERIAL (1<<0) /**< bit to signal update even when the
|
||||
* read/write flags don't change */
|
||||
#define SPA_PARAM_INFO_READ (1<<1)
|
||||
#define SPA_PARAM_INFO_WRITE (1<<2)
|
||||
#define SPA_PARAM_INFO_READWRITE (SPA_PARAM_INFO_WRITE|SPA_PARAM_INFO_READ)
|
||||
uint32_t flags;
|
||||
uint32_t user; /**< private user field. You can use this to keep
|
||||
* state. */
|
||||
int32_t seq; /**< private seq field. You can use this to keep
|
||||
* state of a pending update. */
|
||||
uint32_t padding[4];
|
||||
};
|
||||
|
||||
#define SPA_PARAM_INFO(id,flags) ((struct spa_param_info){ (id), (flags) })
|
||||
|
||||
enum spa_param_bitorder {
|
||||
SPA_PARAM_BITORDER_unknown, /**< unknown bitorder */
|
||||
SPA_PARAM_BITORDER_msb, /**< most significant bit */
|
||||
SPA_PARAM_BITORDER_lsb, /**< least significant bit */
|
||||
};
|
||||
|
||||
enum spa_param_availability {
|
||||
SPA_PARAM_AVAILABILITY_unknown, /**< unknown availability */
|
||||
SPA_PARAM_AVAILABILITY_no, /**< not available */
|
||||
SPA_PARAM_AVAILABILITY_yes, /**< available */
|
||||
};
|
||||
|
||||
#include <spa/param/buffers.h>
|
||||
#include <spa/param/profile.h>
|
||||
#include <spa/param/port-config.h>
|
||||
#include <spa/param/route.h>
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_H */
|
@ -0,0 +1,53 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_PORT_CONFIG_TYPES_H
|
||||
#define SPA_PARAM_PORT_CONFIG_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/utils/enum-types.h>
|
||||
#include <spa/param/param-types.h>
|
||||
#include <spa/param/port-config.h>
|
||||
|
||||
#define SPA_TYPE_INFO_ParamPortConfigMode SPA_TYPE_INFO_ENUM_BASE "ParamPortConfigMode"
|
||||
#define SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE SPA_TYPE_INFO_ParamPortConfigMode ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_port_config_mode[] = {
|
||||
{ SPA_PARAM_PORT_CONFIG_MODE_none, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "none", NULL },
|
||||
{ SPA_PARAM_PORT_CONFIG_MODE_passthrough, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "passthrough", NULL },
|
||||
{ SPA_PARAM_PORT_CONFIG_MODE_convert, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "convert", NULL },
|
||||
{ SPA_PARAM_PORT_CONFIG_MODE_dsp, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "dsp", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_PARAM_PortConfig SPA_TYPE_INFO_PARAM_BASE "PortConfig"
|
||||
#define SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE SPA_TYPE_INFO_PARAM_PortConfig ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_port_config[] = {
|
||||
{ SPA_PARAM_PORT_CONFIG_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE, spa_type_param, },
|
||||
{ SPA_PARAM_PORT_CONFIG_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "direction", spa_type_direction, },
|
||||
{ SPA_PARAM_PORT_CONFIG_mode, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "mode", spa_type_param_port_config_mode },
|
||||
{ SPA_PARAM_PORT_CONFIG_monitor, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "monitor", NULL },
|
||||
{ SPA_PARAM_PORT_CONFIG_control, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "control", NULL },
|
||||
{ SPA_PARAM_PORT_CONFIG_format, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "format", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_PORT_CONFIG_TYPES_H */
|
@ -0,0 +1,46 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_PORT_CONFIG_H
|
||||
#define SPA_PARAM_PORT_CONFIG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param.h>
|
||||
|
||||
enum spa_param_port_config_mode {
|
||||
SPA_PARAM_PORT_CONFIG_MODE_none, /**< no configuration */
|
||||
SPA_PARAM_PORT_CONFIG_MODE_passthrough, /**< passthrough configuration */
|
||||
SPA_PARAM_PORT_CONFIG_MODE_convert, /**< convert configuration */
|
||||
SPA_PARAM_PORT_CONFIG_MODE_dsp, /**< dsp configuration, depending on the external
|
||||
* format. For audio, ports will be configured for
|
||||
* the given number of channels with F32 format. */
|
||||
};
|
||||
|
||||
/** properties for SPA_TYPE_OBJECT_ParamPortConfig */
|
||||
enum spa_param_port_config {
|
||||
SPA_PARAM_PORT_CONFIG_START,
|
||||
SPA_PARAM_PORT_CONFIG_direction, /**< (Id enum spa_direction) direction */
|
||||
SPA_PARAM_PORT_CONFIG_mode, /**< (Id enum spa_param_port_config_mode) mode */
|
||||
SPA_PARAM_PORT_CONFIG_monitor, /**< (Bool) enable monitor output ports on input ports */
|
||||
SPA_PARAM_PORT_CONFIG_control, /**< (Bool) enable control ports */
|
||||
SPA_PARAM_PORT_CONFIG_format, /**< (Object) format filter */
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_PORT_CONFIG_H */
|
@ -0,0 +1,45 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_PROFILE_TYPES_H
|
||||
#define SPA_PARAM_PROFILE_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param-types.h>
|
||||
|
||||
#include <spa/param/profile.h>
|
||||
|
||||
#define SPA_TYPE_INFO_PARAM_Profile SPA_TYPE_INFO_PARAM_BASE "Profile"
|
||||
#define SPA_TYPE_INFO_PARAM_PROFILE_BASE SPA_TYPE_INFO_PARAM_Profile ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_profile[] = {
|
||||
{ SPA_PARAM_PROFILE_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PROFILE_BASE, spa_type_param, },
|
||||
{ SPA_PARAM_PROFILE_index, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROFILE_BASE "index", NULL },
|
||||
{ SPA_PARAM_PROFILE_name, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_PROFILE_BASE "name", NULL },
|
||||
{ SPA_PARAM_PROFILE_description, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_PROFILE_BASE "description", NULL },
|
||||
{ SPA_PARAM_PROFILE_priority, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROFILE_BASE "priority", NULL },
|
||||
{ SPA_PARAM_PROFILE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PROFILE_BASE "available", spa_type_param_availability, },
|
||||
{ SPA_PARAM_PROFILE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "info", NULL, },
|
||||
{ SPA_PARAM_PROFILE_classes, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "classes", NULL, },
|
||||
{ SPA_PARAM_PROFILE_save, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PROFILE_BASE "save", NULL, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_PROFILE_TYPES_H */
|
@ -0,0 +1,52 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_PROFILE_H
|
||||
#define SPA_PARAM_PROFILE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param.h>
|
||||
|
||||
/** properties for SPA_TYPE_OBJECT_ParamProfile */
|
||||
enum spa_param_profile {
|
||||
SPA_PARAM_PROFILE_START,
|
||||
SPA_PARAM_PROFILE_index, /**< profile index (Int) */
|
||||
SPA_PARAM_PROFILE_name, /**< profile name (String) */
|
||||
SPA_PARAM_PROFILE_description, /**< profile description (String) */
|
||||
SPA_PARAM_PROFILE_priority, /**< profile priority (Int) */
|
||||
SPA_PARAM_PROFILE_available, /**< availability of the profile
|
||||
* (Id enum spa_param_availability) */
|
||||
SPA_PARAM_PROFILE_info, /**< info (Struct(
|
||||
* Int : n_items,
|
||||
* (String : key,
|
||||
* String : value)*)) */
|
||||
SPA_PARAM_PROFILE_classes, /**< node classes provided by this profile
|
||||
* (Struct(
|
||||
* Int : number of items following
|
||||
* Struct(
|
||||
* String : class name (eg. "Audio/Source"),
|
||||
* Int : number of nodes
|
||||
* String : property (eg. "card.profile.devices"),
|
||||
* Array of Int: device indexes
|
||||
* )*)) */
|
||||
SPA_PARAM_PROFILE_save, /**< If profile should be saved (Bool) */
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_PROFILE_H */
|
@ -0,0 +1,40 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_PROFILER_TYPES_H
|
||||
#define SPA_PARAM_PROFILER_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param-types.h>
|
||||
#include <spa/param/profiler.h>
|
||||
|
||||
#define SPA_TYPE_INFO_Profiler SPA_TYPE_INFO_OBJECT_BASE "Profiler"
|
||||
#define SPA_TYPE_INFO_PROFILER_BASE SPA_TYPE_INFO_Profiler ":"
|
||||
|
||||
static const struct spa_type_info spa_type_profiler[] = {
|
||||
{ SPA_PROFILER_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROFILER_BASE, spa_type_param, },
|
||||
{ SPA_PROFILER_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "info", NULL, },
|
||||
{ SPA_PROFILER_clock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "clock", NULL, },
|
||||
{ SPA_PROFILER_driverBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "driverBlock", NULL, },
|
||||
{ SPA_PROFILER_followerBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "followerBlock", NULL, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_PROFILER_TYPES_H */
|
@ -0,0 +1,77 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2020 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_PROFILER_H
|
||||
#define SPA_PARAM_PROFILER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param.h>
|
||||
|
||||
/** properties for SPA_TYPE_OBJECT_Profiler */
|
||||
enum spa_profiler {
|
||||
SPA_PROFILER_START,
|
||||
|
||||
SPA_PROFILER_START_Driver = 0x10000, /**< driver related profiler properties */
|
||||
SPA_PROFILER_info, /**< Generic info, counter and CPU load,
|
||||
* (Struct(
|
||||
* Long : counter,
|
||||
* Float : cpu_load fast,
|
||||
* Float : cpu_load medium,
|
||||
* Float : cpu_load slow),
|
||||
* Int : xrun-count)) */
|
||||
SPA_PROFILER_clock, /**< clock information
|
||||
* (Struct(
|
||||
* Int : clock flags,
|
||||
* Int : clock id,
|
||||
* String: clock name,
|
||||
* Long : clock nsec,
|
||||
* Fraction : clock rate,
|
||||
* Long : clock position,
|
||||
* Long : clock duration,
|
||||
* Long : clock delay,
|
||||
* Double : clock rate_diff,
|
||||
* Long : clock next_nsec)) */
|
||||
SPA_PROFILER_driverBlock, /**< generic driver info block
|
||||
* (Struct(
|
||||
* Int : driver_id,
|
||||
* String : name,
|
||||
* Long : driver prev_signal,
|
||||
* Long : driver signal,
|
||||
* Long : driver awake,
|
||||
* Long : driver finish,
|
||||
* Int : driver status),
|
||||
* Fraction : latency)) */
|
||||
|
||||
SPA_PROFILER_START_Follower = 0x20000, /**< follower related profiler properties */
|
||||
SPA_PROFILER_followerBlock, /**< generic follower info block
|
||||
* (Struct(
|
||||
* Int : id,
|
||||
* String : name,
|
||||
* Long : prev_signal,
|
||||
* Long : signal,
|
||||
* Long : awake,
|
||||
* Long : finish,
|
||||
* Int : status,
|
||||
* Fraction : latency)) */
|
||||
|
||||
SPA_PROFILER_START_CUSTOM = 0x1000000,
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_PROFILER_H */
|
@ -0,0 +1,104 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_PROPS_TYPES_H
|
||||
#define SPA_PARAM_PROPS_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param-types.h>
|
||||
|
||||
#include <spa/param/bluetooth/type-info.h>
|
||||
|
||||
/** Props Param */
|
||||
#define SPA_TYPE_INFO_Props SPA_TYPE_INFO_PARAM_BASE "Props"
|
||||
#define SPA_TYPE_INFO_PROPS_BASE SPA_TYPE_INFO_Props ":"
|
||||
|
||||
static const struct spa_type_info spa_type_props[] = {
|
||||
{ SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE, spa_type_param, },
|
||||
{ SPA_PROP_unknown, SPA_TYPE_None, SPA_TYPE_INFO_PROPS_BASE "unknown", NULL },
|
||||
{ SPA_PROP_device, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "device", NULL },
|
||||
{ SPA_PROP_deviceName, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "deviceName", NULL },
|
||||
{ SPA_PROP_deviceFd, SPA_TYPE_Fd, SPA_TYPE_INFO_PROPS_BASE "deviceFd", NULL },
|
||||
{ SPA_PROP_card, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "card", NULL },
|
||||
{ SPA_PROP_cardName, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "cardName", NULL },
|
||||
{ SPA_PROP_minLatency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "minLatency", NULL },
|
||||
{ SPA_PROP_maxLatency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "maxLatency", NULL },
|
||||
{ SPA_PROP_periods, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "periods", NULL },
|
||||
{ SPA_PROP_periodSize, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "periodSize", NULL },
|
||||
{ SPA_PROP_periodEvent, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "periodEvent", NULL },
|
||||
{ SPA_PROP_live, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "live", NULL },
|
||||
{ SPA_PROP_rate, SPA_TYPE_Double, SPA_TYPE_INFO_PROPS_BASE "rate", NULL },
|
||||
{ SPA_PROP_quality, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "quality", NULL },
|
||||
{ SPA_PROP_bluetoothAudioCodec, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "bluetoothAudioCodec", spa_type_bluetooth_audio_codec },
|
||||
{ SPA_PROP_bluetoothOffloadActive, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "bluetoothOffloadActive", NULL },
|
||||
|
||||
{ SPA_PROP_waveType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "waveType", NULL },
|
||||
{ SPA_PROP_frequency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "frequency", NULL },
|
||||
{ SPA_PROP_volume, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volume", NULL },
|
||||
{ SPA_PROP_mute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "mute", NULL },
|
||||
{ SPA_PROP_patternType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "patternType", NULL },
|
||||
{ SPA_PROP_ditherType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "ditherType", NULL },
|
||||
{ SPA_PROP_truncate, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "truncate", NULL },
|
||||
{ SPA_PROP_channelVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "channelVolumes", spa_type_prop_float_array },
|
||||
{ SPA_PROP_volumeBase, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeBase", NULL },
|
||||
{ SPA_PROP_volumeStep, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeStep", NULL },
|
||||
{ SPA_PROP_channelMap, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "channelMap", spa_type_prop_channel_map },
|
||||
{ SPA_PROP_monitorMute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "monitorMute", NULL },
|
||||
{ SPA_PROP_monitorVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "monitorVolumes", spa_type_prop_float_array },
|
||||
{ SPA_PROP_latencyOffsetNsec, SPA_TYPE_Long, SPA_TYPE_INFO_PROPS_BASE "latencyOffsetNsec", NULL },
|
||||
{ SPA_PROP_softMute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "softMute", NULL },
|
||||
{ SPA_PROP_softVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "softVolumes", spa_type_prop_float_array },
|
||||
{ SPA_PROP_iec958Codecs, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "iec958Codecs", spa_type_prop_iec958_codec },
|
||||
{ SPA_PROP_volumeRampSamples, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeRampSamples", NULL },
|
||||
{ SPA_PROP_volumeRampStepSamples, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeRampStepSamples", NULL },
|
||||
{ SPA_PROP_volumeRampTime, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeRampTime", NULL },
|
||||
{ SPA_PROP_volumeRampStepTime, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeRampStepTime", NULL },
|
||||
{ SPA_PROP_volumeRampScale, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "volumeRampScale", NULL },
|
||||
|
||||
{ SPA_PROP_brightness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "brightness", NULL },
|
||||
{ SPA_PROP_contrast, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "contrast", NULL },
|
||||
{ SPA_PROP_saturation, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "saturation", NULL },
|
||||
{ SPA_PROP_hue, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "hue", NULL },
|
||||
{ SPA_PROP_gamma, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gamma", NULL },
|
||||
{ SPA_PROP_exposure, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "exposure", NULL },
|
||||
{ SPA_PROP_gain, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gain", NULL },
|
||||
{ SPA_PROP_sharpness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "sharpness", NULL },
|
||||
|
||||
{ SPA_PROP_params, SPA_TYPE_Struct, SPA_TYPE_INFO_PROPS_BASE "params", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/** Enum Property info */
|
||||
#define SPA_TYPE_INFO_PropInfo SPA_TYPE_INFO_PARAM_BASE "PropInfo"
|
||||
#define SPA_TYPE_INFO_PROP_INFO_BASE SPA_TYPE_INFO_PropInfo ":"
|
||||
|
||||
static const struct spa_type_info spa_type_prop_info[] = {
|
||||
{ SPA_PROP_INFO_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE, spa_type_param, },
|
||||
{ SPA_PROP_INFO_id, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE "id", spa_type_props },
|
||||
{ SPA_PROP_INFO_name, SPA_TYPE_String, SPA_TYPE_INFO_PROP_INFO_BASE "name", NULL },
|
||||
{ SPA_PROP_INFO_type, SPA_TYPE_Pod, SPA_TYPE_INFO_PROP_INFO_BASE "type", NULL },
|
||||
{ SPA_PROP_INFO_labels, SPA_TYPE_Struct, SPA_TYPE_INFO_PROP_INFO_BASE "labels", NULL },
|
||||
{ SPA_PROP_INFO_container, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE "container", NULL },
|
||||
{ SPA_PROP_INFO_params, SPA_TYPE_Bool, SPA_TYPE_INFO_PROP_INFO_BASE "params", NULL },
|
||||
{ SPA_PROP_INFO_description, SPA_TYPE_String, SPA_TYPE_INFO_PROP_INFO_BASE "description", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_PROPS_TYPES_H */
|
@ -0,0 +1,120 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_PROPS_H
|
||||
#define SPA_PARAM_PROPS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param.h>
|
||||
|
||||
/** properties of SPA_TYPE_OBJECT_PropInfo */
|
||||
enum spa_prop_info {
|
||||
SPA_PROP_INFO_START,
|
||||
SPA_PROP_INFO_id, /**< associated id of the property */
|
||||
SPA_PROP_INFO_name, /**< name of the property */
|
||||
SPA_PROP_INFO_type, /**< type and range/enums of property */
|
||||
SPA_PROP_INFO_labels, /**< labels of property if any, this is a
|
||||
* struct with pairs of values, the first one
|
||||
* is of the type of the property, the second
|
||||
* one is a string with a user readable label
|
||||
* for the value. */
|
||||
SPA_PROP_INFO_container, /**< type of container if any (Id) */
|
||||
SPA_PROP_INFO_params, /**< is part of params property (Bool) */
|
||||
SPA_PROP_INFO_description, /**< User readable description */
|
||||
};
|
||||
|
||||
/** predefined properties for SPA_TYPE_OBJECT_Props */
|
||||
enum spa_prop {
|
||||
SPA_PROP_START,
|
||||
|
||||
SPA_PROP_unknown, /**< an unknown property */
|
||||
|
||||
SPA_PROP_START_Device = 0x100, /**< device related properties */
|
||||
SPA_PROP_device,
|
||||
SPA_PROP_deviceName,
|
||||
SPA_PROP_deviceFd,
|
||||
SPA_PROP_card,
|
||||
SPA_PROP_cardName,
|
||||
|
||||
SPA_PROP_minLatency,
|
||||
SPA_PROP_maxLatency,
|
||||
SPA_PROP_periods,
|
||||
SPA_PROP_periodSize,
|
||||
SPA_PROP_periodEvent,
|
||||
SPA_PROP_live,
|
||||
SPA_PROP_rate,
|
||||
SPA_PROP_quality,
|
||||
SPA_PROP_bluetoothAudioCodec,
|
||||
SPA_PROP_bluetoothOffloadActive,
|
||||
|
||||
SPA_PROP_START_Audio = 0x10000, /**< audio related properties */
|
||||
SPA_PROP_waveType,
|
||||
SPA_PROP_frequency,
|
||||
SPA_PROP_volume, /**< a volume (Float), 0.0 silence, 1.0 normal */
|
||||
SPA_PROP_mute, /**< mute (Bool) */
|
||||
SPA_PROP_patternType,
|
||||
SPA_PROP_ditherType,
|
||||
SPA_PROP_truncate,
|
||||
SPA_PROP_channelVolumes, /**< a volume array, one volume per
|
||||
* channel (Array of Float) */
|
||||
SPA_PROP_volumeBase, /**< a volume base (Float) */
|
||||
SPA_PROP_volumeStep, /**< a volume step (Float) */
|
||||
SPA_PROP_channelMap, /**< a channelmap array
|
||||
* (Array (Id enum spa_audio_channel)) */
|
||||
SPA_PROP_monitorMute, /**< mute (Bool) */
|
||||
SPA_PROP_monitorVolumes, /**< a volume array, one volume per
|
||||
* channel (Array of Float) */
|
||||
SPA_PROP_latencyOffsetNsec, /**< delay adjustment */
|
||||
SPA_PROP_softMute, /**< mute (Bool) */
|
||||
SPA_PROP_softVolumes, /**< a volume array, one volume per
|
||||
* channel (Array of Float) */
|
||||
|
||||
SPA_PROP_iec958Codecs, /**< enabled IEC958 (S/PDIF) codecs,
|
||||
* (Array (Id enum spa_audio_iec958_codec) */
|
||||
SPA_PROP_volumeRampSamples, /**< Samples to ramp the volume over */
|
||||
SPA_PROP_volumeRampStepSamples, /**< Step or incremental Samples to ramp
|
||||
* the volume over */
|
||||
SPA_PROP_volumeRampTime, /**< Time in millisec to ramp the volume over */
|
||||
SPA_PROP_volumeRampStepTime, /**< Step or incremental Time in nano seconds
|
||||
* to ramp the */
|
||||
SPA_PROP_volumeRampScale, /**< the scale or graph to used to ramp the
|
||||
* volume */
|
||||
|
||||
SPA_PROP_START_Video = 0x20000, /**< video related properties */
|
||||
SPA_PROP_brightness,
|
||||
SPA_PROP_contrast,
|
||||
SPA_PROP_saturation,
|
||||
SPA_PROP_hue,
|
||||
SPA_PROP_gamma,
|
||||
SPA_PROP_exposure,
|
||||
SPA_PROP_gain,
|
||||
SPA_PROP_sharpness,
|
||||
|
||||
SPA_PROP_START_Other = 0x80000, /**< other properties */
|
||||
SPA_PROP_params, /**< simple control params
|
||||
* (Struct(
|
||||
* (String : key,
|
||||
* Pod : value)*)) */
|
||||
|
||||
|
||||
SPA_PROP_START_CUSTOM = 0x1000000,
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_PROPS_H */
|
@ -0,0 +1,51 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_ROUTE_TYPES_H
|
||||
#define SPA_PARAM_ROUTE_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/utils/enum-types.h>
|
||||
#include <spa/param/param-types.h>
|
||||
|
||||
#include <spa/param/route.h>
|
||||
|
||||
#define SPA_TYPE_INFO_PARAM_Route SPA_TYPE_INFO_PARAM_BASE "Route"
|
||||
#define SPA_TYPE_INFO_PARAM_ROUTE_BASE SPA_TYPE_INFO_PARAM_Route ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_route[] = {
|
||||
{ SPA_PARAM_ROUTE_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE, spa_type_param, },
|
||||
{ SPA_PARAM_ROUTE_index, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "index", NULL, },
|
||||
{ SPA_PARAM_ROUTE_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE "direction", spa_type_direction, },
|
||||
{ SPA_PARAM_ROUTE_device, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "device", NULL, },
|
||||
{ SPA_PARAM_ROUTE_name, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_ROUTE_BASE "name", NULL, },
|
||||
{ SPA_PARAM_ROUTE_description, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_ROUTE_BASE "description", NULL, },
|
||||
{ SPA_PARAM_ROUTE_priority, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "priority", NULL, },
|
||||
{ SPA_PARAM_ROUTE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE "available", spa_type_param_availability, },
|
||||
{ SPA_PARAM_ROUTE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_ROUTE_BASE "info", NULL, },
|
||||
{ SPA_PARAM_ROUTE_profiles, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profiles", NULL, },
|
||||
{ SPA_PARAM_ROUTE_props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ROUTE_BASE "props", NULL, },
|
||||
{ SPA_PARAM_ROUTE_devices, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "devices", NULL, },
|
||||
{ SPA_PARAM_ROUTE_profile, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profile", NULL, },
|
||||
{ SPA_PARAM_ROUTE_save, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_ROUTE_BASE "save", NULL, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_ROUTE_TYPES_H */
|
@ -0,0 +1,49 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_ROUTE_H
|
||||
#define SPA_PARAM_ROUTE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/param.h>
|
||||
|
||||
/** properties for SPA_TYPE_OBJECT_ParamRoute */
|
||||
enum spa_param_route {
|
||||
SPA_PARAM_ROUTE_START,
|
||||
SPA_PARAM_ROUTE_index, /**< index of the routing destination (Int) */
|
||||
SPA_PARAM_ROUTE_direction, /**< direction, input/output (Id enum spa_direction) */
|
||||
SPA_PARAM_ROUTE_device, /**< device id (Int) */
|
||||
SPA_PARAM_ROUTE_name, /**< name of the routing destination (String) */
|
||||
SPA_PARAM_ROUTE_description, /**< description of the destination (String) */
|
||||
SPA_PARAM_ROUTE_priority, /**< priority of the destination (Int) */
|
||||
SPA_PARAM_ROUTE_available, /**< availability of the destination
|
||||
* (Id enum spa_param_availability) */
|
||||
SPA_PARAM_ROUTE_info, /**< info (Struct(
|
||||
* Int : n_items,
|
||||
* (String : key,
|
||||
* String : value)*)) */
|
||||
SPA_PARAM_ROUTE_profiles, /**< associated profile indexes (Array of Int) */
|
||||
SPA_PARAM_ROUTE_props, /**< properties SPA_TYPE_OBJECT_Props */
|
||||
SPA_PARAM_ROUTE_devices, /**< associated device indexes (Array of Int) */
|
||||
SPA_PARAM_ROUTE_profile, /**< profile id (Int) */
|
||||
SPA_PARAM_ROUTE_save, /**< If route should be saved (Bool) */
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_ROUTE_H */
|
@ -0,0 +1,18 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_TYPE_INFO_H
|
||||
#define SPA_PARAM_TYPE_INFO_H
|
||||
|
||||
#include <spa/param/param-types.h>
|
||||
#include <spa/param/buffers-types.h>
|
||||
#include <spa/param/props-types.h>
|
||||
#include <spa/param/format-types.h>
|
||||
#include <spa/param/latency-types.h>
|
||||
#include <spa/param/port-config-types.h>
|
||||
#include <spa/param/profiler-types.h>
|
||||
#include <spa/param/profile-types.h>
|
||||
#include <spa/param/route-types.h>
|
||||
|
||||
#endif /* SPA_PARAM_TYPE_INFO_H */
|
@ -0,0 +1,44 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_CHROMA_H
|
||||
#define SPA_VIDEO_CHROMA_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
/** Various Chroma settings.
|
||||
*/
|
||||
enum spa_video_chroma_site {
|
||||
SPA_VIDEO_CHROMA_SITE_UNKNOWN = 0, /**< unknown cositing */
|
||||
SPA_VIDEO_CHROMA_SITE_NONE = (1 << 0), /**< no cositing */
|
||||
SPA_VIDEO_CHROMA_SITE_H_COSITED = (1 << 1), /**< chroma is horizontally cosited */
|
||||
SPA_VIDEO_CHROMA_SITE_V_COSITED = (1 << 2), /**< chroma is vertically cosited */
|
||||
SPA_VIDEO_CHROMA_SITE_ALT_LINE = (1 << 3), /**< chroma samples are sited on alternate lines */
|
||||
/* some common chroma cositing */
|
||||
/** chroma samples cosited with luma samples */
|
||||
SPA_VIDEO_CHROMA_SITE_COSITED = (SPA_VIDEO_CHROMA_SITE_H_COSITED | SPA_VIDEO_CHROMA_SITE_V_COSITED),
|
||||
/** jpeg style cositing, also for mpeg1 and mjpeg */
|
||||
SPA_VIDEO_CHROMA_SITE_JPEG = (SPA_VIDEO_CHROMA_SITE_NONE),
|
||||
/** mpeg2 style cositing */
|
||||
SPA_VIDEO_CHROMA_SITE_MPEG2 = (SPA_VIDEO_CHROMA_SITE_H_COSITED),
|
||||
/**< DV style cositing */
|
||||
SPA_VIDEO_CHROMA_SITE_DV = (SPA_VIDEO_CHROMA_SITE_COSITED | SPA_VIDEO_CHROMA_SITE_ALT_LINE),
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_CHROMA_H */
|
@ -0,0 +1,105 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_COLOR_H
|
||||
#define SPA_VIDEO_COLOR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Possible color range values. These constants are defined for 8 bit color
|
||||
* values and can be scaled for other bit depths.
|
||||
*/
|
||||
enum spa_video_color_range {
|
||||
SPA_VIDEO_COLOR_RANGE_UNKNOWN = 0, /**< unknown range */
|
||||
SPA_VIDEO_COLOR_RANGE_0_255, /**< [0..255] for 8 bit components */
|
||||
SPA_VIDEO_COLOR_RANGE_16_235 /**< [16..235] for 8 bit components. Chroma has
|
||||
[16..240] range. */
|
||||
};
|
||||
|
||||
/**
|
||||
* The color matrix is used to convert between Y'PbPr and
|
||||
* non-linear RGB (R'G'B')
|
||||
*/
|
||||
enum spa_video_color_matrix {
|
||||
SPA_VIDEO_COLOR_MATRIX_UNKNOWN = 0, /**< unknown matrix */
|
||||
SPA_VIDEO_COLOR_MATRIX_RGB, /**< identity matrix */
|
||||
SPA_VIDEO_COLOR_MATRIX_FCC, /**< FCC color matrix */
|
||||
SPA_VIDEO_COLOR_MATRIX_BT709, /**< ITU BT.709 color matrix */
|
||||
SPA_VIDEO_COLOR_MATRIX_BT601, /**< ITU BT.601 color matrix */
|
||||
SPA_VIDEO_COLOR_MATRIX_SMPTE240M, /**< SMTPE 240M color matrix */
|
||||
SPA_VIDEO_COLOR_MATRIX_BT2020, /**< ITU-R BT.2020 color matrix. since 1.6. */
|
||||
};
|
||||
|
||||
/**
|
||||
* The video transfer function defines the formula for converting between
|
||||
* non-linear RGB (R'G'B') and linear RGB
|
||||
*/
|
||||
enum spa_video_transfer_function {
|
||||
SPA_VIDEO_TRANSFER_UNKNOWN = 0, /**< unknown transfer function */
|
||||
SPA_VIDEO_TRANSFER_GAMMA10, /**< linear RGB, gamma 1.0 curve */
|
||||
SPA_VIDEO_TRANSFER_GAMMA18, /**< Gamma 1.8 curve */
|
||||
SPA_VIDEO_TRANSFER_GAMMA20, /**< Gamma 2.0 curve */
|
||||
SPA_VIDEO_TRANSFER_GAMMA22, /**< Gamma 2.2 curve */
|
||||
SPA_VIDEO_TRANSFER_BT709, /**< Gamma 2.2 curve with a linear segment in the lower range */
|
||||
SPA_VIDEO_TRANSFER_SMPTE240M, /**< Gamma 2.2 curve with a linear segment in the lower range */
|
||||
SPA_VIDEO_TRANSFER_SRGB, /**< Gamma 2.4 curve with a linear segment in the lower range */
|
||||
SPA_VIDEO_TRANSFER_GAMMA28, /**< Gamma 2.8 curve */
|
||||
SPA_VIDEO_TRANSFER_LOG100, /**< Logarithmic transfer characteristic 100:1 range */
|
||||
SPA_VIDEO_TRANSFER_LOG316, /**< Logarithmic transfer characteristic 316.22777:1 range */
|
||||
SPA_VIDEO_TRANSFER_BT2020_12, /**< Gamma 2.2 curve with a linear segment in the lower
|
||||
* range. Used for BT.2020 with 12 bits per
|
||||
* component. \since 1.6. */
|
||||
SPA_VIDEO_TRANSFER_ADOBERGB, /**< Gamma 2.19921875. \since 1.8 */
|
||||
};
|
||||
|
||||
/**
|
||||
* The color primaries define the how to transform linear RGB values to and from
|
||||
* the CIE XYZ colorspace.
|
||||
*/
|
||||
enum spa_video_color_primaries {
|
||||
SPA_VIDEO_COLOR_PRIMARIES_UNKNOWN = 0, /**< unknown color primaries */
|
||||
SPA_VIDEO_COLOR_PRIMARIES_BT709, /**< BT709 primaries */
|
||||
SPA_VIDEO_COLOR_PRIMARIES_BT470M, /**< BT470M primaries */
|
||||
SPA_VIDEO_COLOR_PRIMARIES_BT470BG, /**< BT470BG primaries */
|
||||
SPA_VIDEO_COLOR_PRIMARIES_SMPTE170M, /**< SMPTE170M primaries */
|
||||
SPA_VIDEO_COLOR_PRIMARIES_SMPTE240M, /**< SMPTE240M primaries */
|
||||
SPA_VIDEO_COLOR_PRIMARIES_FILM, /**< Generic film */
|
||||
SPA_VIDEO_COLOR_PRIMARIES_BT2020, /**< BT2020 primaries. \since 1.6. */
|
||||
SPA_VIDEO_COLOR_PRIMARIES_ADOBERGB, /**< Adobe RGB primaries. \since 1.8 */
|
||||
};
|
||||
|
||||
/**
|
||||
* spa_video_colorimetry:
|
||||
*
|
||||
* Structure describing the color info.
|
||||
*/
|
||||
struct spa_video_colorimetry {
|
||||
enum spa_video_color_range range; /**< The color range. This is the valid range for the
|
||||
* samples. It is used to convert the samples to Y'PbPr
|
||||
* values. */
|
||||
enum spa_video_color_matrix matrix; /**< the color matrix. Used to convert between Y'PbPr and
|
||||
* non-linear RGB (R'G'B') */
|
||||
enum spa_video_transfer_function transfer; /**< The transfer function. Used to convert between
|
||||
* R'G'B' and RGB */
|
||||
enum spa_video_color_primaries primaries; /**< Color primaries. Used to convert between R'G'B'
|
||||
* and CIE XYZ */
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_COLOR_H */
|
@ -0,0 +1,63 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_DSP_UTILS_H
|
||||
#define SPA_VIDEO_DSP_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/pod/parser.h>
|
||||
#include <spa/pod/builder.h>
|
||||
#include <spa/param/video/dsp.h>
|
||||
|
||||
static inline int
|
||||
spa_format_video_dsp_parse(const struct spa_pod *format,
|
||||
struct spa_video_info_dsp *info)
|
||||
{
|
||||
info->flags = SPA_VIDEO_FLAG_NONE;
|
||||
if (spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier)) {
|
||||
info->flags |= SPA_VIDEO_FLAG_MODIFIER;
|
||||
}
|
||||
|
||||
return spa_pod_parse_object(format,
|
||||
SPA_TYPE_OBJECT_Format, NULL,
|
||||
SPA_FORMAT_VIDEO_format, SPA_POD_OPT_Id(&info->format),
|
||||
SPA_FORMAT_VIDEO_modifier, SPA_POD_OPT_Long(&info->modifier));
|
||||
}
|
||||
|
||||
static inline struct spa_pod *
|
||||
spa_format_video_dsp_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
struct spa_video_info_dsp *info)
|
||||
{
|
||||
struct spa_pod_frame f;
|
||||
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp),
|
||||
0);
|
||||
if (info->format != SPA_VIDEO_FORMAT_UNKNOWN)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_format, SPA_POD_Id(info->format), 0);
|
||||
if (info->modifier != 0 || info->flags & SPA_VIDEO_FLAG_MODIFIER)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0);
|
||||
return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_DSP_UTILS_H */
|
@ -0,0 +1,35 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_DSP_H
|
||||
#define SPA_VIDEO_DSP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/video/raw.h>
|
||||
|
||||
struct spa_video_info_dsp {
|
||||
enum spa_video_format format;
|
||||
uint32_t flags;
|
||||
uint64_t modifier;
|
||||
};
|
||||
|
||||
#define SPA_VIDEO_INFO_DSP_INIT(...) ((struct spa_video_info_dsp) { __VA_ARGS__ })
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_DSP_H */
|
@ -0,0 +1,11 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_ENCODED_H
|
||||
#define SPA_VIDEO_ENCODED_H
|
||||
|
||||
#include <spa/param/video/h264.h>
|
||||
#include <spa/param/video/mjpg.h>
|
||||
|
||||
#endif /* SPA_VIDEO_ENCODED_H */
|
@ -0,0 +1,64 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_VIDEO_FORMAT_UTILS_H
|
||||
#define SPA_PARAM_VIDEO_FORMAT_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/param/format-utils.h>
|
||||
#include <spa/param/video/format.h>
|
||||
#include <spa/param/video/raw-utils.h>
|
||||
#include <spa/param/video/dsp-utils.h>
|
||||
#include <spa/param/video/h264-utils.h>
|
||||
#include <spa/param/video/mjpg-utils.h>
|
||||
|
||||
static inline int
|
||||
spa_format_video_parse(const struct spa_pod *format, struct spa_video_info *info)
|
||||
{
|
||||
int res;
|
||||
|
||||
if ((res = spa_format_parse(format, &info->media_type, &info->media_subtype)) < 0)
|
||||
return res;
|
||||
|
||||
if (info->media_type != SPA_MEDIA_TYPE_video)
|
||||
return -EINVAL;
|
||||
|
||||
switch (info->media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
return spa_format_video_raw_parse(format, &info->info.raw);
|
||||
case SPA_MEDIA_SUBTYPE_dsp:
|
||||
return spa_format_video_dsp_parse(format, &info->info.dsp);
|
||||
case SPA_MEDIA_SUBTYPE_h264:
|
||||
return spa_format_video_h264_parse(format, &info->info.h264);
|
||||
case SPA_MEDIA_SUBTYPE_mjpg:
|
||||
return spa_format_video_mjpg_parse(format, &info->info.mjpg);
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static inline struct spa_pod *
|
||||
spa_format_video_build(struct spa_pod_builder *builder, uint32_t id, struct spa_video_info *info)
|
||||
{
|
||||
switch (info->media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
return spa_format_video_raw_build(builder, id, &info->info.raw);
|
||||
case SPA_MEDIA_SUBTYPE_dsp:
|
||||
return spa_format_video_dsp_build(builder, id, &info->info.dsp);
|
||||
case SPA_MEDIA_SUBTYPE_h264:
|
||||
return spa_format_video_h264_build(builder, id, &info->info.h264);
|
||||
case SPA_MEDIA_SUBTYPE_mjpg:
|
||||
return spa_format_video_mjpg_build(builder, id, &info->info.mjpg);
|
||||
}
|
||||
errno = ENOTSUP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_VIDEO_FORMAT_UTILS_H */
|
@ -0,0 +1,41 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_PARAM_VIDEO_FORMAT_H
|
||||
#define SPA_PARAM_VIDEO_FORMAT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/format.h>
|
||||
#include <spa/param/video/raw.h>
|
||||
#include <spa/param/video/dsp.h>
|
||||
#include <spa/param/video/encoded.h>
|
||||
|
||||
struct spa_video_info {
|
||||
uint32_t media_type;
|
||||
uint32_t media_subtype;
|
||||
union {
|
||||
struct spa_video_info_raw raw;
|
||||
struct spa_video_info_dsp dsp;
|
||||
struct spa_video_info_h264 h264;
|
||||
struct spa_video_info_mjpg mjpg;
|
||||
} info;
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_PARAM_VIDEO_FORMAT_H */
|
@ -0,0 +1,70 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_H264_UTILS_H
|
||||
#define SPA_VIDEO_H264_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/pod/parser.h>
|
||||
#include <spa/pod/builder.h>
|
||||
#include <spa/param/video/h264.h>
|
||||
|
||||
static inline int
|
||||
spa_format_video_h264_parse(const struct spa_pod *format,
|
||||
struct spa_video_info_h264 *info)
|
||||
{
|
||||
return spa_pod_parse_object(format,
|
||||
SPA_TYPE_OBJECT_Format, NULL,
|
||||
SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size),
|
||||
SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate),
|
||||
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate),
|
||||
SPA_FORMAT_VIDEO_H264_streamFormat, SPA_POD_OPT_Id(&info->stream_format),
|
||||
SPA_FORMAT_VIDEO_H264_alignment, SPA_POD_OPT_Id(&info->alignment));
|
||||
}
|
||||
|
||||
static inline struct spa_pod *
|
||||
spa_format_video_h264_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
struct spa_video_info_h264 *info)
|
||||
{
|
||||
struct spa_pod_frame f;
|
||||
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_h264),
|
||||
0);
|
||||
if (info->size.width != 0 && info->size.height != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size), 0);
|
||||
if (info->framerate.denom != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0);
|
||||
if (info->max_framerate.denom != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0);
|
||||
if (info->stream_format != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_H264_streamFormat, SPA_POD_Id(info->stream_format), 0);
|
||||
if (info->alignment != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_H264_alignment, SPA_POD_Id(info->alignment), 0);
|
||||
return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_H264_UTILS_H */
|
@ -0,0 +1,48 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_H264_H
|
||||
#define SPA_VIDEO_H264_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/format.h>
|
||||
|
||||
enum spa_h264_stream_format {
|
||||
SPA_H264_STREAM_FORMAT_UNKNOWN = 0,
|
||||
SPA_H264_STREAM_FORMAT_AVC,
|
||||
SPA_H264_STREAM_FORMAT_AVC3,
|
||||
SPA_H264_STREAM_FORMAT_BYTESTREAM
|
||||
};
|
||||
|
||||
enum spa_h264_alignment {
|
||||
SPA_H264_ALIGNMENT_UNKNOWN = 0,
|
||||
SPA_H264_ALIGNMENT_AU,
|
||||
SPA_H264_ALIGNMENT_NAL
|
||||
};
|
||||
|
||||
struct spa_video_info_h264 {
|
||||
struct spa_rectangle size;
|
||||
struct spa_fraction framerate;
|
||||
struct spa_fraction max_framerate;
|
||||
enum spa_h264_stream_format stream_format;
|
||||
enum spa_h264_alignment alignment;
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_H264_H */
|
@ -0,0 +1,62 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_MJPG_UTILS_H
|
||||
#define SPA_VIDEO_MJPG_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/pod/parser.h>
|
||||
#include <spa/pod/builder.h>
|
||||
#include <spa/param/video/mjpg.h>
|
||||
|
||||
static inline int
|
||||
spa_format_video_mjpg_parse(const struct spa_pod *format,
|
||||
struct spa_video_info_mjpg *info)
|
||||
{
|
||||
return spa_pod_parse_object(format,
|
||||
SPA_TYPE_OBJECT_Format, NULL,
|
||||
SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size),
|
||||
SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate),
|
||||
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate));
|
||||
}
|
||||
|
||||
static inline struct spa_pod *
|
||||
spa_format_video_mjpg_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
struct spa_video_info_mjpg *info)
|
||||
{
|
||||
struct spa_pod_frame f;
|
||||
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_mjpg),
|
||||
0);
|
||||
if (info->size.width != 0 && info->size.height != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size), 0);
|
||||
if (info->framerate.denom != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0);
|
||||
if (info->max_framerate.denom != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0);
|
||||
return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_MJPG_UTILS_H */
|
@ -0,0 +1,33 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_MJPG_H
|
||||
#define SPA_VIDEO_MJPG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/format.h>
|
||||
|
||||
struct spa_video_info_mjpg {
|
||||
struct spa_rectangle size;
|
||||
struct spa_fraction framerate;
|
||||
struct spa_fraction max_framerate;
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_MJPG_H */
|
@ -0,0 +1,114 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_MULTIVIEW_H
|
||||
#define SPA_VIDEO_MULTIVIEW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* All possible stereoscopic 3D and multiview representations.
|
||||
* In conjunction with \ref spa_video_multiview_flags, describes how
|
||||
* multiview content is being transported in the stream.
|
||||
*/
|
||||
enum spa_video_multiview_mode {
|
||||
/** A special value indicating no multiview information. Used in spa_video_info and other
|
||||
* places to indicate that no specific multiview handling has been requested or provided.
|
||||
* This value is never carried on caps. */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_NONE = -1,
|
||||
SPA_VIDEO_MULTIVIEW_MODE_MONO = 0, /**< All frames are monoscopic */
|
||||
/* Single view modes */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_LEFT, /**< All frames represent a left-eye view */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_RIGHT, /**< All frames represent a right-eye view */
|
||||
/* Stereo view modes */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE, /**< Left and right eye views are provided
|
||||
* in the left and right half of the frame
|
||||
* respectively. */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX, /**< Left and right eye views are provided
|
||||
* in the left and right half of the
|
||||
* frame, but have been sampled using
|
||||
* quincunx method, with half-pixel offset
|
||||
* between the 2 views. */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED, /**< Alternating vertical columns of pixels
|
||||
* represent the left and right eye view
|
||||
* respectively. */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED, /**< Alternating horizontal rows of pixels
|
||||
* represent the left and right eye view
|
||||
* respectively. */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM, /**< The top half of the frame contains the
|
||||
* left eye, and the bottom half the right
|
||||
* eye. */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_CHECKERBOARD, /**< Pixels are arranged with alternating
|
||||
* pixels representing left and right eye
|
||||
* views in a checkerboard fashion. */
|
||||
/* Padding for new frame packing modes */
|
||||
|
||||
SPA_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME = 32, /**< Left and right eye views are provided
|
||||
* in separate frames alternately. */
|
||||
/* Multiview mode(s) */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME, /**< Multipleindependent views are
|
||||
* provided in separate frames in
|
||||
* sequence. This method only applies to
|
||||
* raw video buffers at the moment.
|
||||
* Specific view identification is via
|
||||
* \ref spa_video_multiview_meta on raw
|
||||
* video buffers. */
|
||||
SPA_VIDEO_MULTIVIEW_MODE_SEPARATED, /**< Multiple views are provided as separate
|
||||
* \ref spa_data framebuffers attached
|
||||
* to each \ref spa_buffer, described
|
||||
* by the \ref spa_video_multiview_meta */
|
||||
/* future expansion for annotated modes */
|
||||
};
|
||||
|
||||
/**
|
||||
* spa_video_multiview_flags are used to indicate extra properties of a
|
||||
* stereo/multiview stream beyond the frame layout and buffer mapping
|
||||
* that is conveyed in the \ref spa_video_multiview_mode.
|
||||
*/
|
||||
enum spa_video_multiview_flags {
|
||||
SPA_VIDEO_MULTIVIEW_FLAGS_NONE = 0, /**< No flags */
|
||||
SPA_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST = (1 << 0), /**< For stereo streams, the normal arrangement
|
||||
* of left and right views is reversed */
|
||||
SPA_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED = (1 << 1), /**< The left view is vertically mirrored */
|
||||
SPA_VIDEO_MULTIVIEW_FLAGS_LEFT_FLOPPED = (1 << 2), /**< The left view is horizontally mirrored */
|
||||
SPA_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLIPPED = (1 << 3), /**< The right view is vertically mirrored */
|
||||
SPA_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLOPPED = (1 << 4), /**< The right view is horizontally mirrored */
|
||||
SPA_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT = (1 << 14), /**< For frame-packed multiview
|
||||
* modes, indicates that the individual
|
||||
* views have been encoded with half the true
|
||||
* width or height and should be scaled back
|
||||
* up for display. This flag is used for
|
||||
* overriding input layout interpretation
|
||||
* by adjusting pixel-aspect-ratio.
|
||||
* For side-by-side, column interleaved or
|
||||
* checkerboard packings, the
|
||||
* pixel width will be doubled.
|
||||
* For row interleaved and
|
||||
* top-bottom encodings, pixel height will
|
||||
* be doubled */
|
||||
SPA_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO = (1 << 15), /**< The video stream contains both
|
||||
* mono and multiview portions,
|
||||
* signalled on each buffer by the
|
||||
* absence or presence of the
|
||||
* \ref SPA_VIDEO_BUFFER_FLAG_MULTIPLE_VIEW
|
||||
* buffer flag. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_MULTIVIEW_H */
|
@ -0,0 +1,144 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_RAW_TYPES_H
|
||||
#define SPA_VIDEO_RAW_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
#include <spa/utils/type.h>
|
||||
#include <spa/param/video/raw.h>
|
||||
|
||||
#define SPA_TYPE_INFO_VideoFormat SPA_TYPE_INFO_ENUM_BASE "VideoFormat"
|
||||
#define SPA_TYPE_INFO_VIDEO_FORMAT_BASE SPA_TYPE_INFO_VideoFormat ":"
|
||||
|
||||
static const struct spa_type_info spa_type_video_format[] = {
|
||||
{ SPA_VIDEO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "encoded", NULL },
|
||||
{ SPA_VIDEO_FORMAT_I420, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420", NULL },
|
||||
{ SPA_VIDEO_FORMAT_YV12, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YV12", NULL },
|
||||
{ SPA_VIDEO_FORMAT_YUY2, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YUY2", NULL },
|
||||
{ SPA_VIDEO_FORMAT_UYVY, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "UYVY", NULL },
|
||||
{ SPA_VIDEO_FORMAT_AYUV, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "AYUV", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGBx, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBx", NULL },
|
||||
{ SPA_VIDEO_FORMAT_BGRx, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRx", NULL },
|
||||
{ SPA_VIDEO_FORMAT_xRGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xRGB", NULL },
|
||||
{ SPA_VIDEO_FORMAT_xBGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xBGR", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGBA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA", NULL },
|
||||
{ SPA_VIDEO_FORMAT_BGRA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRA", NULL },
|
||||
{ SPA_VIDEO_FORMAT_ARGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB", NULL },
|
||||
{ SPA_VIDEO_FORMAT_ABGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ABGR", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB", NULL },
|
||||
{ SPA_VIDEO_FORMAT_BGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR", NULL },
|
||||
{ SPA_VIDEO_FORMAT_Y41B, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y41B", NULL },
|
||||
{ SPA_VIDEO_FORMAT_Y42B, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y42B", NULL },
|
||||
{ SPA_VIDEO_FORMAT_YVYU, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YVYU", NULL },
|
||||
{ SPA_VIDEO_FORMAT_Y444, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444", NULL },
|
||||
{ SPA_VIDEO_FORMAT_v210, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v210", NULL },
|
||||
{ SPA_VIDEO_FORMAT_v216, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v216", NULL },
|
||||
{ SPA_VIDEO_FORMAT_NV12, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV12", NULL },
|
||||
{ SPA_VIDEO_FORMAT_NV21, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV21", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GRAY8, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY8", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GRAY16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY16_BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GRAY16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY16_LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_v308, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v308", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGB16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB16", NULL },
|
||||
{ SPA_VIDEO_FORMAT_BGR16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR16", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGB15, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB15", NULL },
|
||||
{ SPA_VIDEO_FORMAT_BGR15, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR15", NULL },
|
||||
{ SPA_VIDEO_FORMAT_UYVP, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "UYVP", NULL },
|
||||
{ SPA_VIDEO_FORMAT_A420, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGB8P, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB8P", NULL },
|
||||
{ SPA_VIDEO_FORMAT_YUV9, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YUV9", NULL },
|
||||
{ SPA_VIDEO_FORMAT_YVU9, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YVU9", NULL },
|
||||
{ SPA_VIDEO_FORMAT_IYU1, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "IYU1", NULL },
|
||||
{ SPA_VIDEO_FORMAT_ARGB64, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB64", NULL },
|
||||
{ SPA_VIDEO_FORMAT_AYUV64, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "AYUV64", NULL },
|
||||
{ SPA_VIDEO_FORMAT_r210, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "r210", NULL },
|
||||
{ SPA_VIDEO_FORMAT_I420_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_10BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_I420_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_10LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_I422_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_10BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_I422_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_10LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_Y444_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_10BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_Y444_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_10LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBR_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_10BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBR_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_10LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_NV16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV16", NULL },
|
||||
{ SPA_VIDEO_FORMAT_NV24, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV24", NULL },
|
||||
{ SPA_VIDEO_FORMAT_NV12_64Z32, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV12_64Z32", NULL },
|
||||
{ SPA_VIDEO_FORMAT_A420_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420_10BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_A420_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420_10LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_A422_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A422_10BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_A422_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A422_10LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_A444_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A444_10BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_A444_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A444_10LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_NV61, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV61", NULL },
|
||||
{ SPA_VIDEO_FORMAT_P010_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "P010_10BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_P010_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "P010_10LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_IYU2, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "IYU2", NULL },
|
||||
{ SPA_VIDEO_FORMAT_VYUY, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "VYUY", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBRA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBRA_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_10BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBRA_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_10LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBR_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_12BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBR_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_12LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBRA_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_12BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_GBRA_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_12LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_I420_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_12BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_I420_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_12LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_I422_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_12BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_I422_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_12LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_Y444_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_12BE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_Y444_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_12LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGBA_F16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_F16", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGBA_F32, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_F32", NULL },
|
||||
{ SPA_VIDEO_FORMAT_xRGB_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xRGB_210LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_xBGR_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xBGR_210LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGBx_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBx_102LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_BGRx_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRx_102LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_ARGB_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB_210LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_ABGR_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ABGR_210LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_RGBA_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_102LE", NULL },
|
||||
{ SPA_VIDEO_FORMAT_BGRA_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRA_102LE", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_VideoFlags SPA_TYPE_INFO_FLAGS_BASE "VideoFlags"
|
||||
#define SPA_TYPE_INFO_VIDEO_FLAGS_BASE SPA_TYPE_INFO_VideoFlags ":"
|
||||
|
||||
static const struct spa_type_info spa_type_video_flags[] = {
|
||||
|
||||
{ SPA_VIDEO_FLAG_NONE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FLAGS_BASE "none", NULL },
|
||||
{ SPA_VIDEO_FLAG_VARIABLE_FPS, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FLAGS_BASE "variable-fps", NULL },
|
||||
{ SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FLAGS_BASE "premultiplied-alpha", NULL },
|
||||
{ SPA_VIDEO_FLAG_MODIFIER, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FLAGS_BASE "modifier", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_VideoInterlaceMode SPA_TYPE_INFO_ENUM_BASE "VideoInterlaceMode"
|
||||
#define SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE SPA_TYPE_INFO_VideoInterlaceMode ":"
|
||||
|
||||
static const struct spa_type_info spa_type_video_interlace_mode[] = {
|
||||
{ SPA_VIDEO_INTERLACE_MODE_PROGRESSIVE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE "progressive", NULL },
|
||||
{ SPA_VIDEO_INTERLACE_MODE_INTERLEAVED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE "interleaved", NULL },
|
||||
{ SPA_VIDEO_INTERLACE_MODE_MIXED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE "mixed", NULL },
|
||||
{ SPA_VIDEO_INTERLACE_MODE_FIELDS, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE "fields", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_RAW_TYPES_H */
|
@ -0,0 +1,115 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_RAW_UTILS_H
|
||||
#define SPA_VIDEO_RAW_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/pod/parser.h>
|
||||
#include <spa/pod/builder.h>
|
||||
#include <spa/param/video/raw.h>
|
||||
|
||||
static inline int
|
||||
spa_format_video_raw_parse(const struct spa_pod *format,
|
||||
struct spa_video_info_raw *info)
|
||||
{
|
||||
info->flags = SPA_VIDEO_FLAG_NONE;
|
||||
if (spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier)) {
|
||||
info->flags |= SPA_VIDEO_FLAG_MODIFIER;
|
||||
}
|
||||
|
||||
return spa_pod_parse_object(format,
|
||||
SPA_TYPE_OBJECT_Format, NULL,
|
||||
SPA_FORMAT_VIDEO_format, SPA_POD_OPT_Id(&info->format),
|
||||
SPA_FORMAT_VIDEO_modifier, SPA_POD_OPT_Long(&info->modifier),
|
||||
SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size),
|
||||
SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate),
|
||||
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate),
|
||||
SPA_FORMAT_VIDEO_views, SPA_POD_OPT_Int(&info->views),
|
||||
SPA_FORMAT_VIDEO_interlaceMode, SPA_POD_OPT_Id(&info->interlace_mode),
|
||||
SPA_FORMAT_VIDEO_pixelAspectRatio, SPA_POD_OPT_Fraction(&info->pixel_aspect_ratio),
|
||||
SPA_FORMAT_VIDEO_multiviewMode, SPA_POD_OPT_Id(&info->multiview_mode),
|
||||
SPA_FORMAT_VIDEO_multiviewFlags, SPA_POD_OPT_Id(&info->multiview_flags),
|
||||
SPA_FORMAT_VIDEO_chromaSite, SPA_POD_OPT_Id(&info->chroma_site),
|
||||
SPA_FORMAT_VIDEO_colorRange, SPA_POD_OPT_Id(&info->color_range),
|
||||
SPA_FORMAT_VIDEO_colorMatrix, SPA_POD_OPT_Id(&info->color_matrix),
|
||||
SPA_FORMAT_VIDEO_transferFunction, SPA_POD_OPT_Id(&info->transfer_function),
|
||||
SPA_FORMAT_VIDEO_colorPrimaries, SPA_POD_OPT_Id(&info->color_primaries));
|
||||
}
|
||||
|
||||
static inline struct spa_pod *
|
||||
spa_format_video_raw_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
struct spa_video_info_raw *info)
|
||||
{
|
||||
struct spa_pod_frame f;
|
||||
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
|
||||
0);
|
||||
if (info->format != SPA_VIDEO_FORMAT_UNKNOWN)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_format, SPA_POD_Id(info->format), 0);
|
||||
if (info->size.width != 0 && info->size.height != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size), 0);
|
||||
if (info->framerate.denom != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0);
|
||||
if (info->modifier != 0 || info->flags & SPA_VIDEO_FLAG_MODIFIER)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0);
|
||||
if (info->max_framerate.denom != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0);
|
||||
if (info->views != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_views, SPA_POD_Int(info->views), 0);
|
||||
if (info->interlace_mode != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_interlaceMode, SPA_POD_Id(info->interlace_mode), 0);
|
||||
if (info->pixel_aspect_ratio.denom != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_pixelAspectRatio,SPA_POD_Fraction(info->pixel_aspect_ratio), 0);
|
||||
if (info->multiview_mode != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_multiviewMode, SPA_POD_Id(info->multiview_mode), 0);
|
||||
if (info->multiview_flags != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_multiviewFlags,SPA_POD_Id(info->multiview_flags), 0);
|
||||
if (info->chroma_site != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_chromaSite, SPA_POD_Id(info->chroma_site), 0);
|
||||
if (info->color_range != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_colorRange, SPA_POD_Id(info->color_range), 0);
|
||||
if (info->color_matrix != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_colorMatrix, SPA_POD_Id(info->color_matrix), 0);
|
||||
if (info->transfer_function != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_transferFunction,SPA_POD_Id(info->transfer_function), 0);
|
||||
if (info->color_primaries != 0)
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_VIDEO_colorPrimaries,SPA_POD_Id(info->color_primaries), 0);
|
||||
return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_RAW_UTILS_H */
|
@ -0,0 +1,201 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_RAW_H
|
||||
#define SPA_VIDEO_RAW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_param
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <spa/param/format.h>
|
||||
#include <spa/param/video/chroma.h>
|
||||
#include <spa/param/video/color.h>
|
||||
#include <spa/param/video/multiview.h>
|
||||
|
||||
#define SPA_VIDEO_MAX_PLANES 4
|
||||
#define SPA_VIDEO_MAX_COMPONENTS 4
|
||||
|
||||
/**
|
||||
* Video formats
|
||||
*
|
||||
* The components are in general described in big-endian order. There are some
|
||||
* exceptions (e.g. RGB15 and RGB16) which use the host endianness.
|
||||
*
|
||||
* Most of the formats are identical to their GStreamer equivalent. See the
|
||||
* GStreamer video formats documentation for more details:
|
||||
*
|
||||
* https://gstreamer.freedesktop.org/documentation/additional/design/mediatype-video-raw.html#formats
|
||||
*/
|
||||
enum spa_video_format {
|
||||
SPA_VIDEO_FORMAT_UNKNOWN,
|
||||
SPA_VIDEO_FORMAT_ENCODED,
|
||||
|
||||
SPA_VIDEO_FORMAT_I420,
|
||||
SPA_VIDEO_FORMAT_YV12,
|
||||
SPA_VIDEO_FORMAT_YUY2,
|
||||
SPA_VIDEO_FORMAT_UYVY,
|
||||
SPA_VIDEO_FORMAT_AYUV,
|
||||
SPA_VIDEO_FORMAT_RGBx,
|
||||
SPA_VIDEO_FORMAT_BGRx,
|
||||
SPA_VIDEO_FORMAT_xRGB,
|
||||
SPA_VIDEO_FORMAT_xBGR,
|
||||
SPA_VIDEO_FORMAT_RGBA,
|
||||
SPA_VIDEO_FORMAT_BGRA,
|
||||
SPA_VIDEO_FORMAT_ARGB,
|
||||
SPA_VIDEO_FORMAT_ABGR,
|
||||
SPA_VIDEO_FORMAT_RGB,
|
||||
SPA_VIDEO_FORMAT_BGR,
|
||||
SPA_VIDEO_FORMAT_Y41B,
|
||||
SPA_VIDEO_FORMAT_Y42B,
|
||||
SPA_VIDEO_FORMAT_YVYU,
|
||||
SPA_VIDEO_FORMAT_Y444,
|
||||
SPA_VIDEO_FORMAT_v210,
|
||||
SPA_VIDEO_FORMAT_v216,
|
||||
SPA_VIDEO_FORMAT_NV12,
|
||||
SPA_VIDEO_FORMAT_NV21,
|
||||
SPA_VIDEO_FORMAT_GRAY8,
|
||||
SPA_VIDEO_FORMAT_GRAY16_BE,
|
||||
SPA_VIDEO_FORMAT_GRAY16_LE,
|
||||
SPA_VIDEO_FORMAT_v308,
|
||||
SPA_VIDEO_FORMAT_RGB16,
|
||||
SPA_VIDEO_FORMAT_BGR16,
|
||||
SPA_VIDEO_FORMAT_RGB15,
|
||||
SPA_VIDEO_FORMAT_BGR15,
|
||||
SPA_VIDEO_FORMAT_UYVP,
|
||||
SPA_VIDEO_FORMAT_A420,
|
||||
SPA_VIDEO_FORMAT_RGB8P,
|
||||
SPA_VIDEO_FORMAT_YUV9,
|
||||
SPA_VIDEO_FORMAT_YVU9,
|
||||
SPA_VIDEO_FORMAT_IYU1,
|
||||
SPA_VIDEO_FORMAT_ARGB64,
|
||||
SPA_VIDEO_FORMAT_AYUV64,
|
||||
SPA_VIDEO_FORMAT_r210,
|
||||
SPA_VIDEO_FORMAT_I420_10BE,
|
||||
SPA_VIDEO_FORMAT_I420_10LE,
|
||||
SPA_VIDEO_FORMAT_I422_10BE,
|
||||
SPA_VIDEO_FORMAT_I422_10LE,
|
||||
SPA_VIDEO_FORMAT_Y444_10BE,
|
||||
SPA_VIDEO_FORMAT_Y444_10LE,
|
||||
SPA_VIDEO_FORMAT_GBR,
|
||||
SPA_VIDEO_FORMAT_GBR_10BE,
|
||||
SPA_VIDEO_FORMAT_GBR_10LE,
|
||||
SPA_VIDEO_FORMAT_NV16,
|
||||
SPA_VIDEO_FORMAT_NV24,
|
||||
SPA_VIDEO_FORMAT_NV12_64Z32,
|
||||
SPA_VIDEO_FORMAT_A420_10BE,
|
||||
SPA_VIDEO_FORMAT_A420_10LE,
|
||||
SPA_VIDEO_FORMAT_A422_10BE,
|
||||
SPA_VIDEO_FORMAT_A422_10LE,
|
||||
SPA_VIDEO_FORMAT_A444_10BE,
|
||||
SPA_VIDEO_FORMAT_A444_10LE,
|
||||
SPA_VIDEO_FORMAT_NV61,
|
||||
SPA_VIDEO_FORMAT_P010_10BE,
|
||||
SPA_VIDEO_FORMAT_P010_10LE,
|
||||
SPA_VIDEO_FORMAT_IYU2,
|
||||
SPA_VIDEO_FORMAT_VYUY,
|
||||
SPA_VIDEO_FORMAT_GBRA,
|
||||
SPA_VIDEO_FORMAT_GBRA_10BE,
|
||||
SPA_VIDEO_FORMAT_GBRA_10LE,
|
||||
SPA_VIDEO_FORMAT_GBR_12BE,
|
||||
SPA_VIDEO_FORMAT_GBR_12LE,
|
||||
SPA_VIDEO_FORMAT_GBRA_12BE,
|
||||
SPA_VIDEO_FORMAT_GBRA_12LE,
|
||||
SPA_VIDEO_FORMAT_I420_12BE,
|
||||
SPA_VIDEO_FORMAT_I420_12LE,
|
||||
SPA_VIDEO_FORMAT_I422_12BE,
|
||||
SPA_VIDEO_FORMAT_I422_12LE,
|
||||
SPA_VIDEO_FORMAT_Y444_12BE,
|
||||
SPA_VIDEO_FORMAT_Y444_12LE,
|
||||
|
||||
SPA_VIDEO_FORMAT_RGBA_F16,
|
||||
SPA_VIDEO_FORMAT_RGBA_F32,
|
||||
|
||||
SPA_VIDEO_FORMAT_xRGB_210LE, /**< 32-bit x:R:G:B 2:10:10:10 little endian */
|
||||
SPA_VIDEO_FORMAT_xBGR_210LE, /**< 32-bit x:B:G:R 2:10:10:10 little endian */
|
||||
SPA_VIDEO_FORMAT_RGBx_102LE, /**< 32-bit R:G:B:x 10:10:10:2 little endian */
|
||||
SPA_VIDEO_FORMAT_BGRx_102LE, /**< 32-bit B:G:R:x 10:10:10:2 little endian */
|
||||
SPA_VIDEO_FORMAT_ARGB_210LE, /**< 32-bit A:R:G:B 2:10:10:10 little endian */
|
||||
SPA_VIDEO_FORMAT_ABGR_210LE, /**< 32-bit A:B:G:R 2:10:10:10 little endian */
|
||||
SPA_VIDEO_FORMAT_RGBA_102LE, /**< 32-bit R:G:B:A 10:10:10:2 little endian */
|
||||
SPA_VIDEO_FORMAT_BGRA_102LE, /**< 32-bit B:G:R:A 10:10:10:2 little endian */
|
||||
|
||||
/* Aliases */
|
||||
SPA_VIDEO_FORMAT_DSP_F32 = SPA_VIDEO_FORMAT_RGBA_F32,
|
||||
};
|
||||
|
||||
/**
|
||||
* Extra video flags
|
||||
*/
|
||||
enum spa_video_flags {
|
||||
SPA_VIDEO_FLAG_NONE = 0, /**< no flags */
|
||||
SPA_VIDEO_FLAG_VARIABLE_FPS = (1 << 0), /**< a variable fps is selected, fps_n and fps_d
|
||||
* denote the maximum fps of the video */
|
||||
SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA = (1 << 1), /**< Each color has been scaled by the alpha value. */
|
||||
SPA_VIDEO_FLAG_MODIFIER = (1 << 2), /**< use the format modifier */
|
||||
};
|
||||
|
||||
/**
|
||||
* The possible values of the #spa_video_interlace_mode describing the interlace
|
||||
* mode of the stream.
|
||||
*/
|
||||
enum spa_video_interlace_mode {
|
||||
SPA_VIDEO_INTERLACE_MODE_PROGRESSIVE = 0, /**< all frames are progressive */
|
||||
SPA_VIDEO_INTERLACE_MODE_INTERLEAVED, /**< 2 fields are interleaved in one video frame.
|
||||
* Extra buffer flags describe the field order. */
|
||||
SPA_VIDEO_INTERLACE_MODE_MIXED, /**< frames contains both interlaced and progressive
|
||||
* video, the buffer flags describe the frame and
|
||||
* fields. */
|
||||
SPA_VIDEO_INTERLACE_MODE_FIELDS, /**< 2 fields are stored in one buffer, use the
|
||||
* frame ID to get access to the required
|
||||
* field. For multiview (the 'views'
|
||||
* property > 1) the fields of view N can
|
||||
* be found at frame ID (N * 2) and (N *
|
||||
* 2) + 1. Each field has only half the
|
||||
* amount of lines as noted in the height
|
||||
* property. This mode requires multiple
|
||||
* spa_data to describe the fields. */
|
||||
};
|
||||
|
||||
/**
|
||||
*/
|
||||
struct spa_video_info_raw {
|
||||
enum spa_video_format format; /**< the format */
|
||||
uint32_t flags; /**< extra video flags */
|
||||
uint64_t modifier; /**< format modifier
|
||||
* only used with DMA-BUF */
|
||||
struct spa_rectangle size; /**< the frame size of the video */
|
||||
struct spa_fraction framerate; /**< the framerate of the video, 0/1 means variable rate */
|
||||
struct spa_fraction max_framerate; /**< the maximum framerate of the video. This is only valid when
|
||||
\ref framerate is 0/1 */
|
||||
uint32_t views; /**< the number of views in this video */
|
||||
enum spa_video_interlace_mode interlace_mode; /**< the interlace mode */
|
||||
struct spa_fraction pixel_aspect_ratio; /**< the pixel aspect ratio */
|
||||
enum spa_video_multiview_mode multiview_mode; /**< multiview mode */
|
||||
enum spa_video_multiview_flags multiview_flags; /**< multiview flags */
|
||||
enum spa_video_chroma_site chroma_site; /**< the chroma siting */
|
||||
enum spa_video_color_range color_range; /**< the color range. This is the valid range for the samples.
|
||||
* It is used to convert the samples to Y'PbPr values. */
|
||||
enum spa_video_color_matrix color_matrix; /**< the color matrix. Used to convert between Y'PbPr and
|
||||
* non-linear RGB (R'G'B') */
|
||||
enum spa_video_transfer_function transfer_function; /**< the transfer function. used to convert between R'G'B' and RGB */
|
||||
enum spa_video_color_primaries color_primaries; /**< color primaries. used to convert between R'G'B' and CIE XYZ */
|
||||
};
|
||||
|
||||
#define SPA_VIDEO_INFO_RAW_INIT(...) ((struct spa_video_info_raw) { __VA_ARGS__ })
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VIDEO_RAW_H */
|
@ -0,0 +1,10 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VIDEO_TYPES_H
|
||||
#define SPA_VIDEO_TYPES_H
|
||||
|
||||
#include <spa/param/video/raw-types.h>
|
||||
|
||||
#endif /* SPA_VIDEO_TYPES_H */
|
@ -0,0 +1,681 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_POD_BUILDER_H
|
||||
#define SPA_POD_BUILDER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup spa_pod POD
|
||||
* Binary data serialization format
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup spa_pod
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <spa/utils/hook.h>
|
||||
#include <spa/pod/iter.h>
|
||||
#include <spa/pod/vararg.h>
|
||||
|
||||
struct spa_pod_builder_state {
|
||||
uint32_t offset;
|
||||
#define SPA_POD_BUILDER_FLAG_BODY (1<<0)
|
||||
#define SPA_POD_BUILDER_FLAG_FIRST (1<<1)
|
||||
uint32_t flags;
|
||||
struct spa_pod_frame *frame;
|
||||
};
|
||||
|
||||
struct spa_pod_builder;
|
||||
|
||||
struct spa_pod_builder_callbacks {
|
||||
#define SPA_VERSION_POD_BUILDER_CALLBACKS 0
|
||||
uint32_t version;
|
||||
|
||||
int (*overflow) (void *data, uint32_t size);
|
||||
};
|
||||
|
||||
struct spa_pod_builder {
|
||||
void *data;
|
||||
uint32_t size;
|
||||
uint32_t _padding;
|
||||
struct spa_pod_builder_state state;
|
||||
struct spa_callbacks callbacks;
|
||||
};
|
||||
|
||||
#define SPA_POD_BUILDER_INIT(buffer,size) ((struct spa_pod_builder){ (buffer), (size), 0, {}, {} })
|
||||
|
||||
static inline void
|
||||
spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
|
||||
{
|
||||
*state = builder->state;
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_pod_builder_set_callbacks(struct spa_pod_builder *builder,
|
||||
const struct spa_pod_builder_callbacks *callbacks, void *data)
|
||||
{
|
||||
builder->callbacks = SPA_CALLBACKS_INIT(callbacks, data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
|
||||
{
|
||||
struct spa_pod_frame *f;
|
||||
uint32_t size = builder->state.offset - state->offset;
|
||||
builder->state = *state;
|
||||
for (f = builder->state.frame; f ; f = f->parent)
|
||||
f->pod.size -= size;
|
||||
}
|
||||
|
||||
static inline void spa_pod_builder_init(struct spa_pod_builder *builder, void *data, uint32_t size)
|
||||
{
|
||||
*builder = SPA_POD_BUILDER_INIT(data, size);
|
||||
}
|
||||
|
||||
static inline struct spa_pod *
|
||||
spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
|
||||
{
|
||||
uint32_t size = builder->size;
|
||||
if (offset + 8 <= size) {
|
||||
struct spa_pod *pod = SPA_PTROFF(builder->data, offset, struct spa_pod);
|
||||
if (offset + SPA_POD_SIZE(pod) <= size)
|
||||
return pod;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct spa_pod *
|
||||
spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
|
||||
{
|
||||
if (frame->offset + SPA_POD_SIZE(&frame->pod) <= builder->size)
|
||||
return SPA_PTROFF(builder->data, frame->offset, struct spa_pod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_pod_builder_push(struct spa_pod_builder *builder,
|
||||
struct spa_pod_frame *frame,
|
||||
const struct spa_pod *pod,
|
||||
uint32_t offset)
|
||||
{
|
||||
frame->pod = *pod;
|
||||
frame->offset = offset;
|
||||
frame->parent = builder->state.frame;
|
||||
frame->flags = builder->state.flags;
|
||||
builder->state.frame = frame;
|
||||
|
||||
if (frame->pod.type == SPA_TYPE_Array || frame->pod.type == SPA_TYPE_Choice)
|
||||
builder->state.flags = SPA_POD_BUILDER_FLAG_FIRST | SPA_POD_BUILDER_FLAG_BODY;
|
||||
}
|
||||
|
||||
static inline int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
|
||||
{
|
||||
int res = 0;
|
||||
struct spa_pod_frame *f;
|
||||
uint32_t offset = builder->state.offset;
|
||||
|
||||
if (offset + size > builder->size) {
|
||||
res = -ENOSPC;
|
||||
if (offset <= builder->size)
|
||||
spa_callbacks_call_res(&builder->callbacks,
|
||||
struct spa_pod_builder_callbacks, res,
|
||||
overflow, 0, offset + size);
|
||||
}
|
||||
if (res == 0 && data)
|
||||
memcpy(SPA_PTROFF(builder->data, offset, void), data, size);
|
||||
|
||||
builder->state.offset += size;
|
||||
|
||||
for (f = builder->state.frame; f ; f = f->parent)
|
||||
f->pod.size += size;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_builder_pad(struct spa_pod_builder *builder, uint32_t size)
|
||||
{
|
||||
uint64_t zeroes = 0;
|
||||
size = SPA_ROUND_UP_N(size, 8) - size;
|
||||
return size ? spa_pod_builder_raw(builder, &zeroes, size) : 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size)
|
||||
{
|
||||
int r, res = spa_pod_builder_raw(builder, data, size);
|
||||
if ((r = spa_pod_builder_pad(builder, size)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
|
||||
{
|
||||
struct spa_pod *pod;
|
||||
|
||||
if (SPA_FLAG_IS_SET(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST)) {
|
||||
const struct spa_pod p = { 0, SPA_TYPE_None };
|
||||
spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
}
|
||||
if ((pod = (struct spa_pod*)spa_pod_builder_frame(builder, frame)) != NULL)
|
||||
*pod = frame->pod;
|
||||
|
||||
builder->state.frame = frame->parent;
|
||||
builder->state.flags = frame->flags;
|
||||
spa_pod_builder_pad(builder, builder->state.offset);
|
||||
return pod;
|
||||
}
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
|
||||
{
|
||||
const void *data;
|
||||
uint32_t size;
|
||||
int r, res;
|
||||
|
||||
if (builder->state.flags == SPA_POD_BUILDER_FLAG_BODY) {
|
||||
data = SPA_POD_BODY_CONST(p);
|
||||
size = SPA_POD_BODY_SIZE(p);
|
||||
} else {
|
||||
data = p;
|
||||
size = SPA_POD_SIZE(p);
|
||||
SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST);
|
||||
}
|
||||
res = spa_pod_builder_raw(builder, data, size);
|
||||
if (builder->state.flags != SPA_POD_BUILDER_FLAG_BODY)
|
||||
if ((r = spa_pod_builder_pad(builder, size)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT(size,type) ((struct spa_pod) { (size), (type) })
|
||||
|
||||
#define SPA_POD_INIT_None() SPA_POD_INIT(0, SPA_TYPE_None)
|
||||
|
||||
static inline int spa_pod_builder_none(struct spa_pod_builder *builder)
|
||||
{
|
||||
const struct spa_pod p = SPA_POD_INIT_None();
|
||||
return spa_pod_builder_primitive(builder, &p);
|
||||
}
|
||||
|
||||
static inline int spa_pod_builder_child(struct spa_pod_builder *builder, uint32_t size, uint32_t type)
|
||||
{
|
||||
const struct spa_pod p = SPA_POD_INIT(size,type);
|
||||
SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST);
|
||||
return spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Bool(val) ((struct spa_pod_bool){ { sizeof(uint32_t), SPA_TYPE_Bool }, (val) ? 1 : 0, 0 })
|
||||
|
||||
static inline int spa_pod_builder_bool(struct spa_pod_builder *builder, bool val)
|
||||
{
|
||||
const struct spa_pod_bool p = SPA_POD_INIT_Bool(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Id(val) ((struct spa_pod_id){ { sizeof(uint32_t), SPA_TYPE_Id }, (val), 0 })
|
||||
|
||||
static inline int spa_pod_builder_id(struct spa_pod_builder *builder, uint32_t val)
|
||||
{
|
||||
const struct spa_pod_id p = SPA_POD_INIT_Id(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Int(val) ((struct spa_pod_int){ { sizeof(int32_t), SPA_TYPE_Int }, (val), 0 })
|
||||
|
||||
static inline int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
|
||||
{
|
||||
const struct spa_pod_int p = SPA_POD_INIT_Int(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Long(val) ((struct spa_pod_long){ { sizeof(int64_t), SPA_TYPE_Long }, (val) })
|
||||
|
||||
static inline int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
|
||||
{
|
||||
const struct spa_pod_long p = SPA_POD_INIT_Long(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Float(val) ((struct spa_pod_float){ { sizeof(float), SPA_TYPE_Float }, (val), 0 })
|
||||
|
||||
static inline int spa_pod_builder_float(struct spa_pod_builder *builder, float val)
|
||||
{
|
||||
const struct spa_pod_float p = SPA_POD_INIT_Float(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Double(val) ((struct spa_pod_double){ { sizeof(double), SPA_TYPE_Double }, (val) })
|
||||
|
||||
static inline int spa_pod_builder_double(struct spa_pod_builder *builder, double val)
|
||||
{
|
||||
const struct spa_pod_double p = SPA_POD_INIT_Double(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_String(len) ((struct spa_pod_string){ { (len), SPA_TYPE_String } })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_write_string(struct spa_pod_builder *builder, const char *str, uint32_t len)
|
||||
{
|
||||
int r, res;
|
||||
res = spa_pod_builder_raw(builder, str, len);
|
||||
if ((r = spa_pod_builder_raw(builder, "", 1)) < 0)
|
||||
res = r;
|
||||
if ((r = spa_pod_builder_pad(builder, builder->state.offset)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_string_len(struct spa_pod_builder *builder, const char *str, uint32_t len)
|
||||
{
|
||||
const struct spa_pod_string p = SPA_POD_INIT_String(len+1);
|
||||
int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
if ((r = spa_pod_builder_write_string(builder, str, len)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_builder_string(struct spa_pod_builder *builder, const char *str)
|
||||
{
|
||||
uint32_t len = str ? strlen(str) : 0;
|
||||
return spa_pod_builder_string_len(builder, str ? str : "", len);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Bytes(len) ((struct spa_pod_bytes){ { (len), SPA_TYPE_Bytes } })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_bytes(struct spa_pod_builder *builder, const void *bytes, uint32_t len)
|
||||
{
|
||||
const struct spa_pod_bytes p = SPA_POD_INIT_Bytes(len);
|
||||
int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
if ((r = spa_pod_builder_raw_padded(builder, bytes, len)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
static inline void *
|
||||
spa_pod_builder_reserve_bytes(struct spa_pod_builder *builder, uint32_t len)
|
||||
{
|
||||
uint32_t offset = builder->state.offset;
|
||||
if (spa_pod_builder_bytes(builder, NULL, len) < 0)
|
||||
return NULL;
|
||||
return SPA_POD_BODY(spa_pod_builder_deref(builder, offset));
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Pointer(type,value) ((struct spa_pod_pointer){ { sizeof(struct spa_pod_pointer_body), SPA_TYPE_Pointer }, { (type), 0, (value) } })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_pointer(struct spa_pod_builder *builder, uint32_t type, const void *val)
|
||||
{
|
||||
const struct spa_pod_pointer p = SPA_POD_INIT_Pointer(type, val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Fd(fd) ((struct spa_pod_fd){ { sizeof(int64_t), SPA_TYPE_Fd }, (fd) })
|
||||
|
||||
static inline int spa_pod_builder_fd(struct spa_pod_builder *builder, int64_t fd)
|
||||
{
|
||||
const struct spa_pod_fd p = SPA_POD_INIT_Fd(fd);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Rectangle(val) ((struct spa_pod_rectangle){ { sizeof(struct spa_rectangle), SPA_TYPE_Rectangle }, (val) })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_rectangle(struct spa_pod_builder *builder, uint32_t width, uint32_t height)
|
||||
{
|
||||
const struct spa_pod_rectangle p = SPA_POD_INIT_Rectangle(SPA_RECTANGLE(width, height));
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Fraction(val) ((struct spa_pod_fraction){ { sizeof(struct spa_fraction), SPA_TYPE_Fraction }, (val) })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_fraction(struct spa_pod_builder *builder, uint32_t num, uint32_t denom)
|
||||
{
|
||||
const struct spa_pod_fraction p = SPA_POD_INIT_Fraction(SPA_FRACTION(num, denom));
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_push_array(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
|
||||
{
|
||||
const struct spa_pod_array p =
|
||||
{ {sizeof(struct spa_pod_array_body) - sizeof(struct spa_pod), SPA_TYPE_Array},
|
||||
{{0, 0}} };
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_array(struct spa_pod_builder *builder,
|
||||
uint32_t child_size, uint32_t child_type, uint32_t n_elems, const void *elems)
|
||||
{
|
||||
const struct spa_pod_array p = {
|
||||
{(uint32_t)(sizeof(struct spa_pod_array_body) + n_elems * child_size), SPA_TYPE_Array},
|
||||
{{child_size, child_type}}
|
||||
};
|
||||
int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
if ((r = spa_pod_builder_raw_padded(builder, elems, child_size * n_elems)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_CHOICE_BODY(type, flags, child_size, child_type) \
|
||||
((struct spa_pod_choice_body) { (type), (flags), { (child_size), (child_type) }})
|
||||
|
||||
#define SPA_POD_INIT_Choice(type, ctype, child_type, n_vals, ...) \
|
||||
((struct { struct spa_pod_choice choice; ctype vals[(n_vals)];}) \
|
||||
{ { { (n_vals) * sizeof(ctype) + sizeof(struct spa_pod_choice_body), SPA_TYPE_Choice }, \
|
||||
{ (type), 0, { sizeof(ctype), (child_type) } } }, { __VA_ARGS__ } })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
|
||||
uint32_t type, uint32_t flags)
|
||||
{
|
||||
const struct spa_pod_choice p =
|
||||
{ {sizeof(struct spa_pod_choice_body) - sizeof(struct spa_pod), SPA_TYPE_Choice},
|
||||
{ type, flags, {0, 0}} };
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Struct(size) ((struct spa_pod_struct){ { (size), SPA_TYPE_Struct } })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
|
||||
{
|
||||
const struct spa_pod_struct p = SPA_POD_INIT_Struct(0);
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Object(size,type,id,...) ((struct spa_pod_object){ { (size), SPA_TYPE_Object }, { (type), (id) }, ##__VA_ARGS__ })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
|
||||
uint32_t type, uint32_t id)
|
||||
{
|
||||
const struct spa_pod_object p =
|
||||
SPA_POD_INIT_Object(sizeof(struct spa_pod_object_body), type, id);
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Prop(key,flags,size,type) \
|
||||
((struct spa_pod_prop){ (key), (flags), { (size), (type) } })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t flags)
|
||||
{
|
||||
const struct { uint32_t key; uint32_t flags; } p = { key, flags };
|
||||
return spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Sequence(size,unit) \
|
||||
((struct spa_pod_sequence){ { (size), SPA_TYPE_Sequence}, {(unit), 0 } })
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_push_sequence(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t unit)
|
||||
{
|
||||
const struct spa_pod_sequence p =
|
||||
SPA_POD_INIT_Sequence(sizeof(struct spa_pod_sequence_body), unit);
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
spa_pod_builder_control(struct spa_pod_builder *builder, uint32_t offset, uint32_t type)
|
||||
{
|
||||
const struct { uint32_t offset; uint32_t type; } p = { offset, type };
|
||||
return spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
}
|
||||
|
||||
static inline uint32_t spa_choice_from_id(char id)
|
||||
{
|
||||
switch (id) {
|
||||
case 'r':
|
||||
return SPA_CHOICE_Range;
|
||||
case 's':
|
||||
return SPA_CHOICE_Step;
|
||||
case 'e':
|
||||
return SPA_CHOICE_Enum;
|
||||
case 'f':
|
||||
return SPA_CHOICE_Flags;
|
||||
case 'n':
|
||||
default:
|
||||
return SPA_CHOICE_None;
|
||||
}
|
||||
}
|
||||
|
||||
#define SPA_POD_BUILDER_COLLECT(builder,type,args) \
|
||||
do { \
|
||||
switch (type) { \
|
||||
case 'b': \
|
||||
spa_pod_builder_bool(builder, !!va_arg(args, int)); \
|
||||
break; \
|
||||
case 'I': \
|
||||
spa_pod_builder_id(builder, va_arg(args, uint32_t)); \
|
||||
break; \
|
||||
case 'i': \
|
||||
spa_pod_builder_int(builder, va_arg(args, int)); \
|
||||
break; \
|
||||
case 'l': \
|
||||
spa_pod_builder_long(builder, va_arg(args, int64_t)); \
|
||||
break; \
|
||||
case 'f': \
|
||||
spa_pod_builder_float(builder, va_arg(args, double)); \
|
||||
break; \
|
||||
case 'd': \
|
||||
spa_pod_builder_double(builder, va_arg(args, double)); \
|
||||
break; \
|
||||
case 's': \
|
||||
{ \
|
||||
char *strval = va_arg(args, char *); \
|
||||
if (strval != NULL) { \
|
||||
size_t len = strlen(strval); \
|
||||
spa_pod_builder_string_len(builder, strval, len); \
|
||||
} \
|
||||
else \
|
||||
spa_pod_builder_none(builder); \
|
||||
break; \
|
||||
} \
|
||||
case 'S': \
|
||||
{ \
|
||||
char *strval = va_arg(args, char *); \
|
||||
size_t len = va_arg(args, int); \
|
||||
spa_pod_builder_string_len(builder, strval, len); \
|
||||
break; \
|
||||
} \
|
||||
case 'y': \
|
||||
{ \
|
||||
void *ptr = va_arg(args, void *); \
|
||||
int len = va_arg(args, int); \
|
||||
spa_pod_builder_bytes(builder, ptr, len); \
|
||||
break; \
|
||||
} \
|
||||
case 'R': \
|
||||
{ \
|
||||
struct spa_rectangle *rectval = \
|
||||
va_arg(args, struct spa_rectangle *); \
|
||||
spa_pod_builder_rectangle(builder, \
|
||||
rectval->width, rectval->height); \
|
||||
break; \
|
||||
} \
|
||||
case 'F': \
|
||||
{ \
|
||||
struct spa_fraction *fracval = \
|
||||
va_arg(args, struct spa_fraction *); \
|
||||
spa_pod_builder_fraction(builder, fracval->num, fracval->denom);\
|
||||
break; \
|
||||
} \
|
||||
case 'a': \
|
||||
{ \
|
||||
int child_size = va_arg(args, int); \
|
||||
int child_type = va_arg(args, int); \
|
||||
int n_elems = va_arg(args, int); \
|
||||
void *elems = va_arg(args, void *); \
|
||||
spa_pod_builder_array(builder, child_size, \
|
||||
child_type, n_elems, elems); \
|
||||
break; \
|
||||
} \
|
||||
case 'p': \
|
||||
{ \
|
||||
int t = va_arg(args, uint32_t); \
|
||||
spa_pod_builder_pointer(builder, t, va_arg(args, void *)); \
|
||||
break; \
|
||||
} \
|
||||
case 'h': \
|
||||
spa_pod_builder_fd(builder, va_arg(args, int)); \
|
||||
break; \
|
||||
case 'P': \
|
||||
case 'O': \
|
||||
case 'T': \
|
||||
case 'V': \
|
||||
{ \
|
||||
struct spa_pod *pod = va_arg(args, struct spa_pod *); \
|
||||
if (pod == NULL) \
|
||||
spa_pod_builder_none(builder); \
|
||||
else \
|
||||
spa_pod_builder_primitive(builder, pod); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
static inline int
|
||||
spa_pod_builder_addv(struct spa_pod_builder *builder, va_list args)
|
||||
{
|
||||
int res = 0;
|
||||
struct spa_pod_frame *frame = builder->state.frame;
|
||||
uint32_t ftype = frame ? frame->pod.type : (uint32_t)SPA_TYPE_None;
|
||||
|
||||
do {
|
||||
const char *format;
|
||||
int n_values = 1;
|
||||
struct spa_pod_frame f;
|
||||
bool choice;
|
||||
|
||||
switch (ftype) {
|
||||
case SPA_TYPE_Object:
|
||||
{
|
||||
uint32_t key = va_arg(args, uint32_t);
|
||||
if (key == 0)
|
||||
goto exit;
|
||||
spa_pod_builder_prop(builder, key, 0);
|
||||
break;
|
||||
}
|
||||
case SPA_TYPE_Sequence:
|
||||
{
|
||||
uint32_t offset = va_arg(args, uint32_t);
|
||||
uint32_t type = va_arg(args, uint32_t);
|
||||
if (type == 0)
|
||||
goto exit;
|
||||
spa_pod_builder_control(builder, offset, type);
|
||||
SPA_FALLTHROUGH
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((format = va_arg(args, const char *)) == NULL)
|
||||
break;
|
||||
|
||||
choice = *format == '?';
|
||||
if (choice) {
|
||||
uint32_t type = spa_choice_from_id(*++format);
|
||||
if (*format != '\0')
|
||||
format++;
|
||||
|
||||
spa_pod_builder_push_choice(builder, &f, type, 0);
|
||||
|
||||
n_values = va_arg(args, int);
|
||||
}
|
||||
while (n_values-- > 0)
|
||||
SPA_POD_BUILDER_COLLECT(builder, *format, args);
|
||||
|
||||
if (choice)
|
||||
spa_pod_builder_pop(builder, &f);
|
||||
} while (true);
|
||||
|
||||
exit:
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_builder_add(struct spa_pod_builder *builder, ...)
|
||||
{
|
||||
int res;
|
||||
va_list args;
|
||||
|
||||
va_start(args, builder);
|
||||
res = spa_pod_builder_addv(builder, args);
|
||||
va_end(args);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define spa_pod_builder_add_object(b,type,id,...) \
|
||||
({ \
|
||||
struct spa_pod_builder *_b = (b); \
|
||||
struct spa_pod_frame _f; \
|
||||
spa_pod_builder_push_object(_b, &_f, type, id); \
|
||||
spa_pod_builder_add(_b, ##__VA_ARGS__, 0); \
|
||||
spa_pod_builder_pop(_b, &_f); \
|
||||
})
|
||||
|
||||
#define spa_pod_builder_add_struct(b,...) \
|
||||
({ \
|
||||
struct spa_pod_builder *_b = (b); \
|
||||
struct spa_pod_frame _f; \
|
||||
spa_pod_builder_push_struct(_b, &_f); \
|
||||
spa_pod_builder_add(_b, ##__VA_ARGS__, NULL); \
|
||||
spa_pod_builder_pop(_b, &_f); \
|
||||
})
|
||||
|
||||
#define spa_pod_builder_add_sequence(b,unit,...) \
|
||||
({ \
|
||||
struct spa_pod_builder *_b = (b); \
|
||||
struct spa_pod_frame _f; \
|
||||
spa_pod_builder_push_sequence(_b, &_f, unit); \
|
||||
spa_pod_builder_add(_b, ##__VA_ARGS__, 0, 0); \
|
||||
spa_pod_builder_pop(_b, &_f); \
|
||||
})
|
||||
|
||||
/** Copy a pod structure */
|
||||
static inline struct spa_pod *
|
||||
spa_pod_copy(const struct spa_pod *pod)
|
||||
{
|
||||
size_t size;
|
||||
struct spa_pod *c;
|
||||
|
||||
size = SPA_POD_SIZE(pod);
|
||||
if ((c = (struct spa_pod *) malloc(size)) == NULL)
|
||||
return NULL;
|
||||
return (struct spa_pod *) memcpy(c, pod, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_POD_BUILDER_H */
|
@ -0,0 +1,49 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_COMMAND_H
|
||||
#define SPA_COMMAND_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
/**
|
||||
* \addtogroup spa_pod
|
||||
* \{
|
||||
*/
|
||||
|
||||
struct spa_command_body {
|
||||
struct spa_pod_object_body body;
|
||||
};
|
||||
|
||||
struct spa_command {
|
||||
struct spa_pod pod;
|
||||
struct spa_command_body body;
|
||||
};
|
||||
|
||||
#define SPA_COMMAND_TYPE(cmd) ((cmd)->body.body.type)
|
||||
#define SPA_COMMAND_ID(cmd,type) (SPA_COMMAND_TYPE(cmd) == (type) ? \
|
||||
(cmd)->body.body.id : SPA_ID_INVALID)
|
||||
|
||||
#define SPA_COMMAND_INIT_FULL(t,size,type,id,...) ((t) \
|
||||
{ { (size), SPA_TYPE_Object }, \
|
||||
{ { (type), (id) }, ##__VA_ARGS__ } })
|
||||
|
||||
#define SPA_COMMAND_INIT(type,id) \
|
||||
SPA_COMMAND_INIT_FULL(struct spa_command, \
|
||||
sizeof(struct spa_command_body), type, id)
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_COMMAND_H */
|
@ -0,0 +1,48 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_EVENT_H
|
||||
#define SPA_EVENT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
/**
|
||||
* \addtogroup spa_pod
|
||||
* \{
|
||||
*/
|
||||
|
||||
struct spa_event_body {
|
||||
struct spa_pod_object_body body;
|
||||
};
|
||||
|
||||
struct spa_event {
|
||||
struct spa_pod pod;
|
||||
struct spa_event_body body;
|
||||
};
|
||||
|
||||
#define SPA_EVENT_TYPE(ev) ((ev)->body.body.type)
|
||||
#define SPA_EVENT_ID(ev,type) (SPA_EVENT_TYPE(ev) == (type) ? \
|
||||
(ev)->body.body.id : SPA_ID_INVALID)
|
||||
|
||||
#define SPA_EVENT_INIT_FULL(t,size,type,id,...) ((t) \
|
||||
{ { (size), SPA_TYPE_OBJECT }, \
|
||||
{ { (type), (id) }, ##__VA_ARGS__ } }) \
|
||||
|
||||
#define SPA_EVENT_INIT(type,id) \
|
||||
SPA_EVENT_INIT_FULL(struct spa_event, \
|
||||
sizeof(struct spa_event_body), type, id)
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_EVENT_H */
|
455
src/java.desktop/unix/native/libpipewire/include/spa/pod/iter.h
Normal file
455
src/java.desktop/unix/native/libpipewire/include/spa/pod/iter.h
Normal file
@ -0,0 +1,455 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_POD_ITER_H
|
||||
#define SPA_POD_ITER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
/**
|
||||
* \addtogroup spa_pod
|
||||
* \{
|
||||
*/
|
||||
|
||||
struct spa_pod_frame {
|
||||
struct spa_pod pod;
|
||||
struct spa_pod_frame *parent;
|
||||
uint32_t offset;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
static inline bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
|
||||
{
|
||||
return SPA_POD_BODY(iter) <= SPA_PTROFF(pod, size, void) &&
|
||||
SPA_PTROFF(iter, SPA_POD_SIZE(iter), void) <= SPA_PTROFF(pod, size, void);
|
||||
}
|
||||
|
||||
static inline void *spa_pod_next(const void *iter)
|
||||
{
|
||||
return SPA_PTROFF(iter, SPA_ROUND_UP_N(SPA_POD_SIZE(iter), 8), void);
|
||||
}
|
||||
|
||||
static inline struct spa_pod_prop *spa_pod_prop_first(const struct spa_pod_object_body *body)
|
||||
{
|
||||
return SPA_PTROFF(body, sizeof(struct spa_pod_object_body), struct spa_pod_prop);
|
||||
}
|
||||
|
||||
static inline bool spa_pod_prop_is_inside(const struct spa_pod_object_body *body,
|
||||
uint32_t size, const struct spa_pod_prop *iter)
|
||||
{
|
||||
return SPA_POD_CONTENTS(struct spa_pod_prop, iter) <= SPA_PTROFF(body, size, void) &&
|
||||
SPA_PTROFF(iter, SPA_POD_PROP_SIZE(iter), void) <= SPA_PTROFF(body, size, void);
|
||||
}
|
||||
|
||||
static inline struct spa_pod_prop *spa_pod_prop_next(const struct spa_pod_prop *iter)
|
||||
{
|
||||
return SPA_PTROFF(iter, SPA_ROUND_UP_N(SPA_POD_PROP_SIZE(iter), 8), struct spa_pod_prop);
|
||||
}
|
||||
|
||||
static inline struct spa_pod_control *spa_pod_control_first(const struct spa_pod_sequence_body *body)
|
||||
{
|
||||
return SPA_PTROFF(body, sizeof(struct spa_pod_sequence_body), struct spa_pod_control);
|
||||
}
|
||||
|
||||
static inline bool spa_pod_control_is_inside(const struct spa_pod_sequence_body *body,
|
||||
uint32_t size, const struct spa_pod_control *iter)
|
||||
{
|
||||
return SPA_POD_CONTENTS(struct spa_pod_control, iter) <= SPA_PTROFF(body, size, void) &&
|
||||
SPA_PTROFF(iter, SPA_POD_CONTROL_SIZE(iter), void) <= SPA_PTROFF(body, size, void);
|
||||
}
|
||||
|
||||
static inline struct spa_pod_control *spa_pod_control_next(const struct spa_pod_control *iter)
|
||||
{
|
||||
return SPA_PTROFF(iter, SPA_ROUND_UP_N(SPA_POD_CONTROL_SIZE(iter), 8), struct spa_pod_control);
|
||||
}
|
||||
|
||||
#define SPA_POD_ARRAY_BODY_FOREACH(body, _size, iter) \
|
||||
for ((iter) = (__typeof__(iter))SPA_PTROFF((body), sizeof(struct spa_pod_array_body), void); \
|
||||
(iter) < (__typeof__(iter))SPA_PTROFF((body), (_size), void); \
|
||||
(iter) = (__typeof__(iter))SPA_PTROFF((iter), (body)->child.size, void))
|
||||
|
||||
#define SPA_POD_ARRAY_FOREACH(obj, iter) \
|
||||
SPA_POD_ARRAY_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
|
||||
|
||||
#define SPA_POD_CHOICE_BODY_FOREACH(body, _size, iter) \
|
||||
for ((iter) = (__typeof__(iter))SPA_PTROFF((body), sizeof(struct spa_pod_choice_body), void); \
|
||||
(iter) < (__typeof__(iter))SPA_PTROFF((body), (_size), void); \
|
||||
(iter) = (__typeof__(iter))SPA_PTROFF((iter), (body)->child.size, void))
|
||||
|
||||
#define SPA_POD_CHOICE_FOREACH(obj, iter) \
|
||||
SPA_POD_CHOICE_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
|
||||
|
||||
#define SPA_POD_FOREACH(pod, size, iter) \
|
||||
for ((iter) = (pod); \
|
||||
spa_pod_is_inside(pod, size, iter); \
|
||||
(iter) = (__typeof__(iter))spa_pod_next(iter))
|
||||
|
||||
#define SPA_POD_STRUCT_FOREACH(obj, iter) \
|
||||
SPA_POD_FOREACH(SPA_POD_BODY(obj), SPA_POD_BODY_SIZE(obj), iter)
|
||||
|
||||
#define SPA_POD_OBJECT_BODY_FOREACH(body, size, iter) \
|
||||
for ((iter) = spa_pod_prop_first(body); \
|
||||
spa_pod_prop_is_inside(body, size, iter); \
|
||||
(iter) = spa_pod_prop_next(iter))
|
||||
|
||||
#define SPA_POD_OBJECT_FOREACH(obj, iter) \
|
||||
SPA_POD_OBJECT_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
|
||||
|
||||
#define SPA_POD_SEQUENCE_BODY_FOREACH(body, size, iter) \
|
||||
for ((iter) = spa_pod_control_first(body); \
|
||||
spa_pod_control_is_inside(body, size, iter); \
|
||||
(iter) = spa_pod_control_next(iter))
|
||||
|
||||
#define SPA_POD_SEQUENCE_FOREACH(seq, iter) \
|
||||
SPA_POD_SEQUENCE_BODY_FOREACH(&(seq)->body, SPA_POD_BODY_SIZE(seq), iter)
|
||||
|
||||
|
||||
static inline void *spa_pod_from_data(void *data, size_t maxsize, off_t offset, size_t size)
|
||||
{
|
||||
void *pod;
|
||||
if (size < sizeof(struct spa_pod) || offset + size > maxsize)
|
||||
return NULL;
|
||||
pod = SPA_PTROFF(data, offset, void);
|
||||
if (SPA_POD_SIZE(pod) > size)
|
||||
return NULL;
|
||||
return pod;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_none(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_None);
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_bool(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Bool && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_bool(const struct spa_pod *pod, bool *value)
|
||||
{
|
||||
if (!spa_pod_is_bool(pod))
|
||||
return -EINVAL;
|
||||
*value = !!SPA_POD_VALUE(struct spa_pod_bool, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_id(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Id && SPA_POD_BODY_SIZE(pod) >= sizeof(uint32_t));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_id(const struct spa_pod *pod, uint32_t *value)
|
||||
{
|
||||
if (!spa_pod_is_id(pod))
|
||||
return -EINVAL;
|
||||
*value = SPA_POD_VALUE(struct spa_pod_id, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_int(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Int && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_int(const struct spa_pod *pod, int32_t *value)
|
||||
{
|
||||
if (!spa_pod_is_int(pod))
|
||||
return -EINVAL;
|
||||
*value = SPA_POD_VALUE(struct spa_pod_int, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_long(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Long && SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_long(const struct spa_pod *pod, int64_t *value)
|
||||
{
|
||||
if (!spa_pod_is_long(pod))
|
||||
return -EINVAL;
|
||||
*value = SPA_POD_VALUE(struct spa_pod_long, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_float(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Float && SPA_POD_BODY_SIZE(pod) >= sizeof(float));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_float(const struct spa_pod *pod, float *value)
|
||||
{
|
||||
if (!spa_pod_is_float(pod))
|
||||
return -EINVAL;
|
||||
*value = SPA_POD_VALUE(struct spa_pod_float, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_double(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Double && SPA_POD_BODY_SIZE(pod) >= sizeof(double));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_double(const struct spa_pod *pod, double *value)
|
||||
{
|
||||
if (!spa_pod_is_double(pod))
|
||||
return -EINVAL;
|
||||
*value = SPA_POD_VALUE(struct spa_pod_double, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_string(const struct spa_pod *pod)
|
||||
{
|
||||
const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_String &&
|
||||
SPA_POD_BODY_SIZE(pod) > 0 &&
|
||||
s[SPA_POD_BODY_SIZE(pod)-1] == '\0');
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_string(const struct spa_pod *pod, const char **value)
|
||||
{
|
||||
if (!spa_pod_is_string(pod))
|
||||
return -EINVAL;
|
||||
*value = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_copy_string(const struct spa_pod *pod, size_t maxlen, char *dest)
|
||||
{
|
||||
const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
|
||||
if (!spa_pod_is_string(pod) || maxlen < 1)
|
||||
return -EINVAL;
|
||||
strncpy(dest, s, maxlen-1);
|
||||
dest[maxlen-1]= '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_bytes(const struct spa_pod *pod)
|
||||
{
|
||||
return SPA_POD_TYPE(pod) == SPA_TYPE_Bytes;
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_bytes(const struct spa_pod *pod, const void **value, uint32_t *len)
|
||||
{
|
||||
if (!spa_pod_is_bytes(pod))
|
||||
return -EINVAL;
|
||||
*value = (const void *)SPA_POD_CONTENTS(struct spa_pod_bytes, pod);
|
||||
*len = SPA_POD_BODY_SIZE(pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_pointer(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Pointer &&
|
||||
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_pointer_body));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_pointer(const struct spa_pod *pod, uint32_t *type, const void **value)
|
||||
{
|
||||
if (!spa_pod_is_pointer(pod))
|
||||
return -EINVAL;
|
||||
*type = ((struct spa_pod_pointer*)pod)->body.type;
|
||||
*value = ((struct spa_pod_pointer*)pod)->body.value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_fd(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Fd &&
|
||||
SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_fd(const struct spa_pod *pod, int64_t *value)
|
||||
{
|
||||
if (!spa_pod_is_fd(pod))
|
||||
return -EINVAL;
|
||||
*value = SPA_POD_VALUE(struct spa_pod_fd, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_rectangle(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Rectangle &&
|
||||
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_rectangle));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_rectangle(const struct spa_pod *pod, struct spa_rectangle *value)
|
||||
{
|
||||
if (!spa_pod_is_rectangle(pod))
|
||||
return -EINVAL;
|
||||
*value = SPA_POD_VALUE(struct spa_pod_rectangle, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_fraction(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Fraction &&
|
||||
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_fraction));
|
||||
}
|
||||
|
||||
static inline int spa_pod_get_fraction(const struct spa_pod *pod, struct spa_fraction *value)
|
||||
{
|
||||
spa_return_val_if_fail(spa_pod_is_fraction(pod), -EINVAL);
|
||||
*value = SPA_POD_VALUE(struct spa_pod_fraction, pod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_bitmap(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Bitmap &&
|
||||
SPA_POD_BODY_SIZE(pod) >= sizeof(uint8_t));
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_array(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Array &&
|
||||
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_array_body));
|
||||
}
|
||||
|
||||
static inline void *spa_pod_get_array(const struct spa_pod *pod, uint32_t *n_values)
|
||||
{
|
||||
spa_return_val_if_fail(spa_pod_is_array(pod), NULL);
|
||||
*n_values = SPA_POD_ARRAY_N_VALUES(pod);
|
||||
return SPA_POD_ARRAY_VALUES(pod);
|
||||
}
|
||||
|
||||
static inline uint32_t spa_pod_copy_array(const struct spa_pod *pod, uint32_t type,
|
||||
void *values, uint32_t max_values)
|
||||
{
|
||||
uint32_t n_values;
|
||||
void *v = spa_pod_get_array(pod, &n_values);
|
||||
if (v == NULL || max_values == 0 || SPA_POD_ARRAY_VALUE_TYPE(pod) != type)
|
||||
return 0;
|
||||
n_values = SPA_MIN(n_values, max_values);
|
||||
memcpy(values, v, SPA_POD_ARRAY_VALUE_SIZE(pod) * n_values);
|
||||
return n_values;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_choice(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Choice &&
|
||||
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_choice_body));
|
||||
}
|
||||
|
||||
static inline struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
|
||||
{
|
||||
if (pod->type == SPA_TYPE_Choice) {
|
||||
*n_vals = SPA_POD_CHOICE_N_VALUES(pod);
|
||||
if ((*choice = SPA_POD_CHOICE_TYPE(pod)) == SPA_CHOICE_None)
|
||||
*n_vals = SPA_MIN(1u, SPA_POD_CHOICE_N_VALUES(pod));
|
||||
return (struct spa_pod*)SPA_POD_CHOICE_CHILD(pod);
|
||||
} else {
|
||||
*n_vals = 1;
|
||||
*choice = SPA_CHOICE_None;
|
||||
return (struct spa_pod*)pod;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_struct(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Struct);
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_object(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Object &&
|
||||
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_object_body));
|
||||
}
|
||||
|
||||
static inline bool spa_pod_is_object_type(const struct spa_pod *pod, uint32_t type)
|
||||
{
|
||||
return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_TYPE(pod) == type);
|
||||
}
|
||||
|
||||
static inline bool spa_pod_is_object_id(const struct spa_pod *pod, uint32_t id)
|
||||
{
|
||||
return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_ID(pod) == id);
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_sequence(const struct spa_pod *pod)
|
||||
{
|
||||
return (SPA_POD_TYPE(pod) == SPA_TYPE_Sequence &&
|
||||
SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_sequence_body));
|
||||
}
|
||||
|
||||
static inline const struct spa_pod_prop *spa_pod_object_find_prop(const struct spa_pod_object *pod,
|
||||
const struct spa_pod_prop *start, uint32_t key)
|
||||
{
|
||||
const struct spa_pod_prop *first, *res;
|
||||
|
||||
first = spa_pod_prop_first(&pod->body);
|
||||
start = start ? spa_pod_prop_next(start) : first;
|
||||
|
||||
for (res = start; spa_pod_prop_is_inside(&pod->body, pod->pod.size, res);
|
||||
res = spa_pod_prop_next(res)) {
|
||||
if (res->key == key)
|
||||
return res;
|
||||
}
|
||||
for (res = first; res != start; res = spa_pod_prop_next(res)) {
|
||||
if (res->key == key)
|
||||
return res;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const struct spa_pod_prop *spa_pod_find_prop(const struct spa_pod *pod,
|
||||
const struct spa_pod_prop *start, uint32_t key)
|
||||
{
|
||||
if (!spa_pod_is_object(pod))
|
||||
return NULL;
|
||||
return spa_pod_object_find_prop((const struct spa_pod_object *)pod, start, key);
|
||||
}
|
||||
|
||||
static inline int spa_pod_object_fixate(struct spa_pod_object *pod)
|
||||
{
|
||||
struct spa_pod_prop *res;
|
||||
SPA_POD_OBJECT_FOREACH(pod, res) {
|
||||
if (res->value.type == SPA_TYPE_Choice &&
|
||||
!SPA_FLAG_IS_SET(res->flags, SPA_POD_PROP_FLAG_DONT_FIXATE))
|
||||
((struct spa_pod_choice*)&res->value)->body.type = SPA_CHOICE_None;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_fixate(struct spa_pod *pod)
|
||||
{
|
||||
if (!spa_pod_is_object(pod))
|
||||
return -EINVAL;
|
||||
return spa_pod_object_fixate((struct spa_pod_object *)pod);
|
||||
}
|
||||
|
||||
static inline int spa_pod_object_is_fixated(const struct spa_pod_object *pod)
|
||||
{
|
||||
struct spa_pod_prop *res;
|
||||
SPA_POD_OBJECT_FOREACH(pod, res) {
|
||||
if (res->value.type == SPA_TYPE_Choice &&
|
||||
((struct spa_pod_choice*)&res->value)->body.type != SPA_CHOICE_None)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int spa_pod_is_fixated(const struct spa_pod *pod)
|
||||
{
|
||||
if (!spa_pod_is_object(pod))
|
||||
return -EINVAL;
|
||||
return spa_pod_object_is_fixated((const struct spa_pod_object *)pod);
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_POD_H */
|
@ -0,0 +1,574 @@
|
||||
/* Spa */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_POD_PARSER_H
|
||||
#define SPA_POD_PARSER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <spa/pod/iter.h>
|
||||
#include <spa/pod/vararg.h>
|
||||
|
||||
/**
|
||||
* \addtogroup spa_pod
|
||||
* \{
|
||||
*/
|
||||
|
||||
struct spa_pod_parser_state {
|
||||
uint32_t offset;
|
||||
uint32_t flags;
|
||||
struct spa_pod_frame *frame;
|
||||
};
|
||||
|
||||
struct spa_pod_parser {
|
||||
const void *data;
|
||||
uint32_t size;
|
||||
uint32_t _padding;
|
||||
struct spa_pod_parser_state state;
|
||||
};
|
||||
|
||||
#define SPA_POD_PARSER_INIT(buffer,size) ((struct spa_pod_parser){ (buffer), (size), 0, {} })
|
||||
|
||||
static inline void spa_pod_parser_init(struct spa_pod_parser *parser,
|
||||
const void *data, uint32_t size)
|
||||
{
|
||||
*parser = SPA_POD_PARSER_INIT(data, size);
|
||||
}
|
||||
|
||||
static inline void spa_pod_parser_pod(struct spa_pod_parser *parser,
|
||||
const struct spa_pod *pod)
|
||||
{
|
||||
spa_pod_parser_init(parser, pod, SPA_POD_SIZE(pod));
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_pod_parser_get_state(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
|
||||
{
|
||||
*state = parser->state;
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_pod_parser_reset(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
|
||||
{
|
||||
parser->state = *state;
|
||||
}
|
||||
|
||||
static inline struct spa_pod *
|
||||
spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size)
|
||||
{
|
||||
/* Cast to uint64_t to avoid wraparound. Add 8 for the pod itself. */
|
||||
const uint64_t long_offset = (uint64_t)offset + 8;
|
||||
if (long_offset <= size && (offset & 7) == 0) {
|
||||
/* Use void* because creating a misaligned pointer is undefined. */
|
||||
void *pod = SPA_PTROFF(parser->data, offset, void);
|
||||
/*
|
||||
* Check that the pointer is aligned and that the size (rounded
|
||||
* to the next multiple of 8) is in bounds.
|
||||
*/
|
||||
if (SPA_IS_ALIGNED(pod, __alignof__(struct spa_pod)) &&
|
||||
long_offset + SPA_ROUND_UP_N((uint64_t)SPA_POD_BODY_SIZE(pod), 8) <= size)
|
||||
return (struct spa_pod *)pod;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame)
|
||||
{
|
||||
return SPA_PTROFF(parser->data, frame->offset, struct spa_pod);
|
||||
}
|
||||
|
||||
static inline void spa_pod_parser_push(struct spa_pod_parser *parser,
|
||||
struct spa_pod_frame *frame, const struct spa_pod *pod, uint32_t offset)
|
||||
{
|
||||
frame->pod = *pod;
|
||||
frame->offset = offset;
|
||||
frame->parent = parser->state.frame;
|
||||
frame->flags = parser->state.flags;
|
||||
parser->state.frame = frame;
|
||||
}
|
||||
|
||||
static inline struct spa_pod *spa_pod_parser_current(struct spa_pod_parser *parser)
|
||||
{
|
||||
struct spa_pod_frame *f = parser->state.frame;
|
||||
uint32_t size = f ? f->offset + SPA_POD_SIZE(&f->pod) : parser->size;
|
||||
return spa_pod_parser_deref(parser, parser->state.offset, size);
|
||||
}
|
||||
|
||||
static inline void spa_pod_parser_advance(struct spa_pod_parser *parser, const struct spa_pod *pod)
|
||||
{
|
||||
parser->state.offset += SPA_ROUND_UP_N(SPA_POD_SIZE(pod), 8);
|
||||
}
|
||||
|
||||
static inline struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser)
|
||||
{
|
||||
struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return pod;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_pop(struct spa_pod_parser *parser,
|
||||
struct spa_pod_frame *frame)
|
||||
{
|
||||
parser->state.frame = frame->parent;
|
||||
parser->state.offset = frame->offset + SPA_ROUND_UP_N(SPA_POD_SIZE(&frame->pod), 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_bool(struct spa_pod_parser *parser, bool *value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_bool(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_id(struct spa_pod_parser *parser, uint32_t *value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_id(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_int(struct spa_pod_parser *parser, int32_t *value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_int(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_long(struct spa_pod_parser *parser, int64_t *value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_long(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_float(struct spa_pod_parser *parser, float *value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_float(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_double(struct spa_pod_parser *parser, double *value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_double(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_string(struct spa_pod_parser *parser, const char **value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_string(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_bytes(struct spa_pod_parser *parser, const void **value, uint32_t *len)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_bytes(pod, value, len)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_pointer(struct spa_pod_parser *parser, uint32_t *type, const void **value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_pointer(pod, type, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_fd(struct spa_pod_parser *parser, int64_t *value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_fd(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_rectangle(struct spa_pod_parser *parser, struct spa_rectangle *value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_rectangle(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_fraction(struct spa_pod_parser *parser, struct spa_fraction *value)
|
||||
{
|
||||
int res = -EPIPE;
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod != NULL && (res = spa_pod_get_fraction(pod, value)) >= 0)
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get_pod(struct spa_pod_parser *parser, struct spa_pod **value)
|
||||
{
|
||||
struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod == NULL)
|
||||
return -EPIPE;
|
||||
*value = pod;
|
||||
spa_pod_parser_advance(parser, pod);
|
||||
return 0;
|
||||
}
|
||||
static inline int spa_pod_parser_push_struct(struct spa_pod_parser *parser,
|
||||
struct spa_pod_frame *frame)
|
||||
{
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod == NULL)
|
||||
return -EPIPE;
|
||||
if (!spa_pod_is_struct(pod))
|
||||
return -EINVAL;
|
||||
spa_pod_parser_push(parser, frame, pod, parser->state.offset);
|
||||
parser->state.offset += sizeof(struct spa_pod_struct);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_push_object(struct spa_pod_parser *parser,
|
||||
struct spa_pod_frame *frame, uint32_t type, uint32_t *id)
|
||||
{
|
||||
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
||||
if (pod == NULL)
|
||||
return -EPIPE;
|
||||
if (!spa_pod_is_object(pod))
|
||||
return -EINVAL;
|
||||
if (type != SPA_POD_OBJECT_TYPE(pod))
|
||||
return -EPROTO;
|
||||
if (id != NULL)
|
||||
*id = SPA_POD_OBJECT_ID(pod);
|
||||
spa_pod_parser_push(parser, frame, pod, parser->state.offset);
|
||||
parser->state.offset = parser->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type)
|
||||
{
|
||||
if (pod == NULL)
|
||||
return false;
|
||||
|
||||
if (SPA_POD_TYPE(pod) == SPA_TYPE_Choice) {
|
||||
if (!spa_pod_is_choice(pod))
|
||||
return false;
|
||||
if (type == 'V')
|
||||
return true;
|
||||
if (SPA_POD_CHOICE_TYPE(pod) != SPA_CHOICE_None)
|
||||
return false;
|
||||
pod = SPA_POD_CHOICE_CHILD(pod);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'P':
|
||||
return true;
|
||||
case 'b':
|
||||
return spa_pod_is_bool(pod);
|
||||
case 'I':
|
||||
return spa_pod_is_id(pod);
|
||||
case 'i':
|
||||
return spa_pod_is_int(pod);
|
||||
case 'l':
|
||||
return spa_pod_is_long(pod);
|
||||
case 'f':
|
||||
return spa_pod_is_float(pod);
|
||||
case 'd':
|
||||
return spa_pod_is_double(pod);
|
||||
case 's':
|
||||
return spa_pod_is_string(pod) || spa_pod_is_none(pod);
|
||||
case 'S':
|
||||
return spa_pod_is_string(pod);
|
||||
case 'y':
|
||||
return spa_pod_is_bytes(pod);
|
||||
case 'R':
|
||||
return spa_pod_is_rectangle(pod);
|
||||
case 'F':
|
||||
return spa_pod_is_fraction(pod);
|
||||
case 'B':
|
||||
return spa_pod_is_bitmap(pod);
|
||||
case 'a':
|
||||
return spa_pod_is_array(pod);
|
||||
case 'p':
|
||||
return spa_pod_is_pointer(pod);
|
||||
case 'h':
|
||||
return spa_pod_is_fd(pod);
|
||||
case 'T':
|
||||
return spa_pod_is_struct(pod) || spa_pod_is_none(pod);
|
||||
case 'O':
|
||||
return spa_pod_is_object(pod) || spa_pod_is_none(pod);
|
||||
case 'V':
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#define SPA_POD_PARSER_COLLECT(pod,_type,args) \
|
||||
do { \
|
||||
switch (_type) { \
|
||||
case 'b': \
|
||||
*va_arg(args, bool*) = SPA_POD_VALUE(struct spa_pod_bool, pod); \
|
||||
break; \
|
||||
case 'I': \
|
||||
case 'i': \
|
||||
*va_arg(args, int32_t*) = SPA_POD_VALUE(struct spa_pod_int, pod); \
|
||||
break; \
|
||||
case 'l': \
|
||||
*va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_long, pod); \
|
||||
break; \
|
||||
case 'f': \
|
||||
*va_arg(args, float*) = SPA_POD_VALUE(struct spa_pod_float, pod); \
|
||||
break; \
|
||||
case 'd': \
|
||||
*va_arg(args, double*) = SPA_POD_VALUE(struct spa_pod_double, pod); \
|
||||
break; \
|
||||
case 's': \
|
||||
*va_arg(args, char**) = \
|
||||
((pod) == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \
|
||||
? NULL \
|
||||
: (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod)); \
|
||||
break; \
|
||||
case 'S': \
|
||||
{ \
|
||||
char *dest = va_arg(args, char*); \
|
||||
uint32_t maxlen = va_arg(args, uint32_t); \
|
||||
strncpy(dest, (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod), maxlen-1); \
|
||||
dest[maxlen-1] = '\0'; \
|
||||
break; \
|
||||
} \
|
||||
case 'y': \
|
||||
*(va_arg(args, void **)) = SPA_POD_CONTENTS(struct spa_pod_bytes, pod); \
|
||||
*(va_arg(args, uint32_t *)) = SPA_POD_BODY_SIZE(pod); \
|
||||
break; \
|
||||
case 'R': \
|
||||
*va_arg(args, struct spa_rectangle*) = \
|
||||
SPA_POD_VALUE(struct spa_pod_rectangle, pod); \
|
||||
break; \
|
||||
case 'F': \
|
||||
*va_arg(args, struct spa_fraction*) = \
|
||||
SPA_POD_VALUE(struct spa_pod_fraction, pod); \
|
||||
break; \
|
||||
case 'B': \
|
||||
*va_arg(args, uint32_t **) = \
|
||||
(uint32_t *) SPA_POD_CONTENTS(struct spa_pod_bitmap, pod); \
|
||||
break; \
|
||||
case 'a': \
|
||||
*va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_SIZE(pod); \
|
||||
*va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_TYPE(pod); \
|
||||
*va_arg(args, uint32_t*) = SPA_POD_ARRAY_N_VALUES(pod); \
|
||||
*va_arg(args, void**) = SPA_POD_ARRAY_VALUES(pod); \
|
||||
break; \
|
||||
case 'p': \
|
||||
{ \
|
||||
struct spa_pod_pointer_body *b = \
|
||||
(struct spa_pod_pointer_body *) SPA_POD_BODY(pod); \
|
||||
*(va_arg(args, uint32_t *)) = b->type; \
|
||||
*(va_arg(args, const void **)) = b->value; \
|
||||
break; \
|
||||
} \
|
||||
case 'h': \
|
||||
*va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_fd, pod); \
|
||||
break; \
|
||||
case 'P': \
|
||||
case 'T': \
|
||||
case 'O': \
|
||||
case 'V': \
|
||||
{ \
|
||||
const struct spa_pod **d = va_arg(args, const struct spa_pod**); \
|
||||
if (d) \
|
||||
*d = ((pod) == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \
|
||||
? NULL : (pod)); \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
#define SPA_POD_PARSER_SKIP(_type,args) \
|
||||
do { \
|
||||
switch (_type) { \
|
||||
case 'S': \
|
||||
va_arg(args, char*); \
|
||||
va_arg(args, uint32_t); \
|
||||
break; \
|
||||
case 'a': \
|
||||
va_arg(args, void*); \
|
||||
va_arg(args, void*); \
|
||||
SPA_FALLTHROUGH \
|
||||
case 'p': \
|
||||
case 'y': \
|
||||
va_arg(args, void*); \
|
||||
SPA_FALLTHROUGH \
|
||||
case 'b': \
|
||||
case 'I': \
|
||||
case 'i': \
|
||||
case 'l': \
|
||||
case 'f': \
|
||||
case 'd': \
|
||||
case 's': \
|
||||
case 'R': \
|
||||
case 'F': \
|
||||
case 'B': \
|
||||
case 'h': \
|
||||
case 'V': \
|
||||
case 'P': \
|
||||
case 'T': \
|
||||
case 'O': \
|
||||
va_arg(args, void*); \
|
||||
break; \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
static inline int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list args)
|
||||
{
|
||||
struct spa_pod_frame *f = parser->state.frame;
|
||||
uint32_t ftype = f ? f->pod.type : (uint32_t)SPA_TYPE_Struct;
|
||||
const struct spa_pod_prop *prop = NULL;
|
||||
int count = 0;
|
||||
|
||||
do {
|
||||
bool optional;
|
||||
const struct spa_pod *pod = NULL;
|
||||
const char *format;
|
||||
|
||||
if (ftype == SPA_TYPE_Object) {
|
||||
uint32_t key = va_arg(args, uint32_t);
|
||||
const struct spa_pod_object *object;
|
||||
|
||||
if (key == 0)
|
||||
break;
|
||||
|
||||
object = (const struct spa_pod_object *)spa_pod_parser_frame(parser, f);
|
||||
prop = spa_pod_object_find_prop(object, prop, key);
|
||||
pod = prop ? &prop->value : NULL;
|
||||
}
|
||||
|
||||
if ((format = va_arg(args, char *)) == NULL)
|
||||
break;
|
||||
|
||||
if (ftype == SPA_TYPE_Struct)
|
||||
pod = spa_pod_parser_next(parser);
|
||||
|
||||
if ((optional = (*format == '?')))
|
||||
format++;
|
||||
|
||||
if (!spa_pod_parser_can_collect(pod, *format)) {
|
||||
if (!optional) {
|
||||
if (pod == NULL)
|
||||
return -ESRCH;
|
||||
else
|
||||
return -EPROTO;
|
||||
}
|
||||
SPA_POD_PARSER_SKIP(*format, args);
|
||||
} else {
|
||||
if (pod->type == SPA_TYPE_Choice && *format != 'V')
|
||||
pod = SPA_POD_CHOICE_CHILD(pod);
|
||||
|
||||
SPA_POD_PARSER_COLLECT(pod, *format, args);
|
||||
count++;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline int spa_pod_parser_get(struct spa_pod_parser *parser, ...)
|
||||
{
|
||||
int res;
|
||||
va_list args;
|
||||
|
||||
va_start(args, parser);
|
||||
res = spa_pod_parser_getv(parser, args);
|
||||
va_end(args);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_OPT_Bool(val) "?" SPA_POD_Bool(val)
|
||||
#define SPA_POD_OPT_Id(val) "?" SPA_POD_Id(val)
|
||||
#define SPA_POD_OPT_Int(val) "?" SPA_POD_Int(val)
|
||||
#define SPA_POD_OPT_Long(val) "?" SPA_POD_Long(val)
|
||||
#define SPA_POD_OPT_Float(val) "?" SPA_POD_Float(val)
|
||||
#define SPA_POD_OPT_Double(val) "?" SPA_POD_Double(val)
|
||||
#define SPA_POD_OPT_String(val) "?" SPA_POD_String(val)
|
||||
#define SPA_POD_OPT_Stringn(val,len) "?" SPA_POD_Stringn(val,len)
|
||||
#define SPA_POD_OPT_Bytes(val,len) "?" SPA_POD_Bytes(val,len)
|
||||
#define SPA_POD_OPT_Rectangle(val) "?" SPA_POD_Rectangle(val)
|
||||
#define SPA_POD_OPT_Fraction(val) "?" SPA_POD_Fraction(val)
|
||||
#define SPA_POD_OPT_Array(csize,ctype,n_vals,vals) "?" SPA_POD_Array(csize,ctype,n_vals,vals)
|
||||
#define SPA_POD_OPT_Pointer(type,val) "?" SPA_POD_Pointer(type,val)
|
||||
#define SPA_POD_OPT_Fd(val) "?" SPA_POD_Fd(val)
|
||||
#define SPA_POD_OPT_Pod(val) "?" SPA_POD_Pod(val)
|
||||
#define SPA_POD_OPT_PodObject(val) "?" SPA_POD_PodObject(val)
|
||||
#define SPA_POD_OPT_PodStruct(val) "?" SPA_POD_PodStruct(val)
|
||||
#define SPA_POD_OPT_PodChoice(val) "?" SPA_POD_PodChoice(val)
|
||||
|
||||
#define spa_pod_parser_get_object(p,type,id,...) \
|
||||
({ \
|
||||
struct spa_pod_frame _f; \
|
||||
int _res; \
|
||||
if ((_res = spa_pod_parser_push_object(p, &_f, type, id)) == 0) { \
|
||||
_res = spa_pod_parser_get(p,##__VA_ARGS__, 0); \
|
||||
spa_pod_parser_pop(p, &_f); \
|
||||
} \
|
||||
_res; \
|
||||
})
|
||||
|
||||
#define spa_pod_parser_get_struct(p,...) \
|
||||
({ \
|
||||
struct spa_pod_frame _f; \
|
||||
int _res; \
|
||||
if ((_res = spa_pod_parser_push_struct(p, &_f)) == 0) { \
|
||||
_res = spa_pod_parser_get(p,##__VA_ARGS__, NULL); \
|
||||
spa_pod_parser_pop(p, &_f); \
|
||||
} \
|
||||
_res; \
|
||||
})
|
||||
|
||||
#define spa_pod_parse_object(pod,type,id,...) \
|
||||
({ \
|
||||
struct spa_pod_parser _p; \
|
||||
spa_pod_parser_pod(&_p, pod); \
|
||||
spa_pod_parser_get_object(&_p,type,id,##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define spa_pod_parse_struct(pod,...) \
|
||||
({ \
|
||||
struct spa_pod_parser _p; \
|
||||
spa_pod_parser_pod(&_p, pod); \
|
||||
spa_pod_parser_get_struct(&_p,##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_POD_PARSER_H */
|
226
src/java.desktop/unix/native/libpipewire/include/spa/pod/pod.h
Normal file
226
src/java.desktop/unix/native/libpipewire/include/spa/pod/pod.h
Normal file
@ -0,0 +1,226 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_POD_H
|
||||
#define SPA_POD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/type.h>
|
||||
|
||||
/**
|
||||
* \addtogroup spa_pod
|
||||
* \{
|
||||
*/
|
||||
|
||||
#define SPA_POD_BODY_SIZE(pod) (((struct spa_pod*)(pod))->size)
|
||||
#define SPA_POD_TYPE(pod) (((struct spa_pod*)(pod))->type)
|
||||
#define SPA_POD_SIZE(pod) ((uint64_t)sizeof(struct spa_pod) + SPA_POD_BODY_SIZE(pod))
|
||||
#define SPA_POD_CONTENTS_SIZE(type,pod) (SPA_POD_SIZE(pod)-sizeof(type))
|
||||
|
||||
#define SPA_POD_CONTENTS(type,pod) SPA_PTROFF((pod),sizeof(type),void)
|
||||
#define SPA_POD_CONTENTS_CONST(type,pod) SPA_PTROFF((pod),sizeof(type),const void)
|
||||
#define SPA_POD_BODY(pod) SPA_PTROFF((pod),sizeof(struct spa_pod),void)
|
||||
#define SPA_POD_BODY_CONST(pod) SPA_PTROFF((pod),sizeof(struct spa_pod),const void)
|
||||
|
||||
struct spa_pod {
|
||||
uint32_t size; /* size of the body */
|
||||
uint32_t type; /* a basic id of enum spa_type */
|
||||
};
|
||||
|
||||
#define SPA_POD_VALUE(type,pod) (((type*)(pod))->value)
|
||||
|
||||
struct spa_pod_bool {
|
||||
struct spa_pod pod;
|
||||
int32_t value;
|
||||
int32_t _padding;
|
||||
};
|
||||
|
||||
struct spa_pod_id {
|
||||
struct spa_pod pod;
|
||||
uint32_t value;
|
||||
int32_t _padding;
|
||||
};
|
||||
|
||||
struct spa_pod_int {
|
||||
struct spa_pod pod;
|
||||
int32_t value;
|
||||
int32_t _padding;
|
||||
};
|
||||
|
||||
struct spa_pod_long {
|
||||
struct spa_pod pod;
|
||||
int64_t value;
|
||||
};
|
||||
|
||||
struct spa_pod_float {
|
||||
struct spa_pod pod;
|
||||
float value;
|
||||
int32_t _padding;
|
||||
};
|
||||
|
||||
struct spa_pod_double {
|
||||
struct spa_pod pod;
|
||||
double value;
|
||||
};
|
||||
|
||||
struct spa_pod_string {
|
||||
struct spa_pod pod;
|
||||
/* value here */
|
||||
};
|
||||
|
||||
struct spa_pod_bytes {
|
||||
struct spa_pod pod;
|
||||
/* value here */
|
||||
};
|
||||
|
||||
struct spa_pod_rectangle {
|
||||
struct spa_pod pod;
|
||||
struct spa_rectangle value;
|
||||
};
|
||||
|
||||
struct spa_pod_fraction {
|
||||
struct spa_pod pod;
|
||||
struct spa_fraction value;
|
||||
};
|
||||
|
||||
struct spa_pod_bitmap {
|
||||
struct spa_pod pod;
|
||||
/* array of uint8_t follows with the bitmap */
|
||||
};
|
||||
|
||||
#define SPA_POD_ARRAY_CHILD(arr) (&((struct spa_pod_array*)(arr))->body.child)
|
||||
#define SPA_POD_ARRAY_VALUE_TYPE(arr) (SPA_POD_TYPE(SPA_POD_ARRAY_CHILD(arr)))
|
||||
#define SPA_POD_ARRAY_VALUE_SIZE(arr) (SPA_POD_BODY_SIZE(SPA_POD_ARRAY_CHILD(arr)))
|
||||
#define SPA_POD_ARRAY_N_VALUES(arr) (SPA_POD_ARRAY_VALUE_SIZE(arr) ? ((SPA_POD_BODY_SIZE(arr) - sizeof(struct spa_pod_array_body)) / SPA_POD_ARRAY_VALUE_SIZE(arr)) : 0)
|
||||
#define SPA_POD_ARRAY_VALUES(arr) SPA_POD_CONTENTS(struct spa_pod_array, arr)
|
||||
|
||||
struct spa_pod_array_body {
|
||||
struct spa_pod child;
|
||||
/* array with elements of child.size follows */
|
||||
};
|
||||
|
||||
struct spa_pod_array {
|
||||
struct spa_pod pod;
|
||||
struct spa_pod_array_body body;
|
||||
};
|
||||
|
||||
#define SPA_POD_CHOICE_CHILD(choice) (&((struct spa_pod_choice*)(choice))->body.child)
|
||||
#define SPA_POD_CHOICE_TYPE(choice) (((struct spa_pod_choice*)(choice))->body.type)
|
||||
#define SPA_POD_CHOICE_FLAGS(choice) (((struct spa_pod_choice*)(choice))->body.flags)
|
||||
#define SPA_POD_CHOICE_VALUE_TYPE(choice) (SPA_POD_TYPE(SPA_POD_CHOICE_CHILD(choice)))
|
||||
#define SPA_POD_CHOICE_VALUE_SIZE(choice) (SPA_POD_BODY_SIZE(SPA_POD_CHOICE_CHILD(choice)))
|
||||
#define SPA_POD_CHOICE_N_VALUES(choice) (SPA_POD_CHOICE_VALUE_SIZE(choice) ? ((SPA_POD_BODY_SIZE(choice) - sizeof(struct spa_pod_choice_body)) / SPA_POD_CHOICE_VALUE_SIZE(choice)) : 0)
|
||||
#define SPA_POD_CHOICE_VALUES(choice) (SPA_POD_CONTENTS(struct spa_pod_choice, choice))
|
||||
|
||||
enum spa_choice_type {
|
||||
SPA_CHOICE_None, /**< no choice, first value is current */
|
||||
SPA_CHOICE_Range, /**< range: default, min, max */
|
||||
SPA_CHOICE_Step, /**< range with step: default, min, max, step */
|
||||
SPA_CHOICE_Enum, /**< list: default, alternative,... */
|
||||
SPA_CHOICE_Flags, /**< flags: default, possible flags,... */
|
||||
};
|
||||
|
||||
struct spa_pod_choice_body {
|
||||
uint32_t type; /**< type of choice, one of enum spa_choice_type */
|
||||
uint32_t flags; /**< extra flags */
|
||||
struct spa_pod child;
|
||||
/* array with elements of child.size follows. Note that there might be more
|
||||
* elements than required by \a type, which should be ignored. */
|
||||
};
|
||||
|
||||
struct spa_pod_choice {
|
||||
struct spa_pod pod;
|
||||
struct spa_pod_choice_body body;
|
||||
};
|
||||
|
||||
struct spa_pod_struct {
|
||||
struct spa_pod pod;
|
||||
/* one or more spa_pod follow */
|
||||
};
|
||||
|
||||
#define SPA_POD_OBJECT_TYPE(obj) (((struct spa_pod_object*)(obj))->body.type)
|
||||
#define SPA_POD_OBJECT_ID(obj) (((struct spa_pod_object*)(obj))->body.id)
|
||||
|
||||
struct spa_pod_object_body {
|
||||
uint32_t type; /**< one of enum spa_type */
|
||||
uint32_t id; /**< id of the object, depends on the object type */
|
||||
/* contents follow, series of spa_pod_prop */
|
||||
};
|
||||
|
||||
struct spa_pod_object {
|
||||
struct spa_pod pod;
|
||||
struct spa_pod_object_body body;
|
||||
};
|
||||
|
||||
struct spa_pod_pointer_body {
|
||||
uint32_t type; /**< pointer id, one of enum spa_type */
|
||||
uint32_t _padding;
|
||||
const void *value;
|
||||
};
|
||||
|
||||
struct spa_pod_pointer {
|
||||
struct spa_pod pod;
|
||||
struct spa_pod_pointer_body body;
|
||||
};
|
||||
|
||||
struct spa_pod_fd {
|
||||
struct spa_pod pod;
|
||||
int64_t value;
|
||||
};
|
||||
|
||||
#define SPA_POD_PROP_SIZE(prop) (sizeof(struct spa_pod_prop) + (prop)->value.size)
|
||||
|
||||
/* props can be inside an object */
|
||||
struct spa_pod_prop {
|
||||
uint32_t key; /**< key of property, list of valid keys depends on the
|
||||
* object type */
|
||||
#define SPA_POD_PROP_FLAG_READONLY (1u<<0) /**< is read-only */
|
||||
#define SPA_POD_PROP_FLAG_HARDWARE (1u<<1) /**< some sort of hardware parameter */
|
||||
#define SPA_POD_PROP_FLAG_HINT_DICT (1u<<2) /**< contains a dictionary struct as
|
||||
* (Struct(
|
||||
* Int : n_items,
|
||||
* (String : key,
|
||||
* String : value)*)) */
|
||||
#define SPA_POD_PROP_FLAG_MANDATORY (1u<<3) /**< is mandatory */
|
||||
#define SPA_POD_PROP_FLAG_DONT_FIXATE (1u<<4) /**< choices need no fixation */
|
||||
uint32_t flags; /**< flags for property */
|
||||
struct spa_pod value;
|
||||
/* value follows */
|
||||
};
|
||||
|
||||
#define SPA_POD_CONTROL_SIZE(ev) (sizeof(struct spa_pod_control) + (ev)->value.size)
|
||||
|
||||
/* controls can be inside a sequence and mark timed values */
|
||||
struct spa_pod_control {
|
||||
uint32_t offset; /**< media offset */
|
||||
uint32_t type; /**< type of control, enum spa_control_type */
|
||||
struct spa_pod value; /**< control value, depends on type */
|
||||
/* value contents follow */
|
||||
};
|
||||
|
||||
struct spa_pod_sequence_body {
|
||||
uint32_t unit;
|
||||
uint32_t pad;
|
||||
/* series of struct spa_pod_control follows */
|
||||
};
|
||||
|
||||
/** a sequence of timed controls */
|
||||
struct spa_pod_sequence {
|
||||
struct spa_pod pod;
|
||||
struct spa_pod_sequence_body body;
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_POD_H */
|
@ -0,0 +1,93 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_POD_VARARG_H
|
||||
#define SPA_POD_VARARG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
/**
|
||||
* \addtogroup spa_pod
|
||||
* \{
|
||||
*/
|
||||
|
||||
#define SPA_POD_Prop(key,...) \
|
||||
key, ##__VA_ARGS__
|
||||
|
||||
#define SPA_POD_Control(offset,type,...) \
|
||||
offset, type, ##__VA_ARGS__
|
||||
|
||||
#define SPA_CHOICE_RANGE(def,min,max) 3,(def),(min),(max)
|
||||
#define SPA_CHOICE_STEP(def,min,max,step) 4,(def),(min),(max),(step)
|
||||
#define SPA_CHOICE_ENUM(n_vals,...) (n_vals),##__VA_ARGS__
|
||||
#define SPA_CHOICE_FLAGS(flags) 1, (flags)
|
||||
#define SPA_CHOICE_BOOL(def) 3,(def),(def),!(def)
|
||||
|
||||
#define SPA_POD_Bool(val) "b", val
|
||||
#define SPA_POD_CHOICE_Bool(def) "?eb", SPA_CHOICE_BOOL(def)
|
||||
|
||||
#define SPA_POD_Id(val) "I", val
|
||||
#define SPA_POD_CHOICE_ENUM_Id(n_vals,...) "?eI", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
|
||||
|
||||
#define SPA_POD_Int(val) "i", val
|
||||
#define SPA_POD_CHOICE_ENUM_Int(n_vals,...) "?ei", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
|
||||
#define SPA_POD_CHOICE_RANGE_Int(def,min,max) "?ri", SPA_CHOICE_RANGE(def, min, max)
|
||||
#define SPA_POD_CHOICE_STEP_Int(def,min,max,step) "?si", SPA_CHOICE_STEP(def, min, max, step)
|
||||
#define SPA_POD_CHOICE_FLAGS_Int(flags) "?fi", SPA_CHOICE_FLAGS(flags)
|
||||
|
||||
#define SPA_POD_Long(val) "l", val
|
||||
#define SPA_POD_CHOICE_ENUM_Long(n_vals,...) "?el", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
|
||||
#define SPA_POD_CHOICE_RANGE_Long(def,min,max) "?rl", SPA_CHOICE_RANGE(def, min, max)
|
||||
#define SPA_POD_CHOICE_STEP_Long(def,min,max,step) "?sl", SPA_CHOICE_STEP(def, min, max, step)
|
||||
#define SPA_POD_CHOICE_FLAGS_Long(flags) "?fl", SPA_CHOICE_FLAGS(flags)
|
||||
|
||||
#define SPA_POD_Float(val) "f", val
|
||||
#define SPA_POD_CHOICE_ENUM_Float(n_vals,...) "?ef", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
|
||||
#define SPA_POD_CHOICE_RANGE_Float(def,min,max) "?rf", SPA_CHOICE_RANGE(def, min, max)
|
||||
#define SPA_POD_CHOICE_STEP_Float(def,min,max,step) "?sf", SPA_CHOICE_STEP(def, min, max, step)
|
||||
|
||||
#define SPA_POD_Double(val) "d", val
|
||||
#define SPA_POD_CHOICE_ENUM_Double(n_vals,...) "?ed", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
|
||||
#define SPA_POD_CHOICE_RANGE_Double(def,min,max) "?rd", SPA_CHOICE_RANGE(def, min, max)
|
||||
#define SPA_POD_CHOICE_STEP_Double(def,min,max,step) "?sd", SPA_CHOICE_STEP(def, min, max, step)
|
||||
|
||||
#define SPA_POD_String(val) "s",val
|
||||
#define SPA_POD_Stringn(val,len) "S",val,len
|
||||
|
||||
#define SPA_POD_Bytes(val,len) "y",val,len
|
||||
|
||||
#define SPA_POD_Rectangle(val) "R",val
|
||||
#define SPA_POD_CHOICE_ENUM_Rectangle(n_vals,...) "?eR", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
|
||||
#define SPA_POD_CHOICE_RANGE_Rectangle(def,min,max) "?rR", SPA_CHOICE_RANGE((def),(min),(max))
|
||||
#define SPA_POD_CHOICE_STEP_Rectangle(def,min,max,step) "?sR", SPA_CHOICE_STEP((def),(min),(max),(step))
|
||||
|
||||
#define SPA_POD_Fraction(val) "F",val
|
||||
#define SPA_POD_CHOICE_ENUM_Fraction(n_vals,...) "?eF", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
|
||||
#define SPA_POD_CHOICE_RANGE_Fraction(def,min,max) "?rF", SPA_CHOICE_RANGE((def),(min),(max))
|
||||
#define SPA_POD_CHOICE_STEP_Fraction(def,min,max,step) "?sF", SPA_CHOICE_STEP(def, min, max, step)
|
||||
|
||||
#define SPA_POD_Array(csize,ctype,n_vals,vals) "a", csize,ctype,n_vals,vals
|
||||
#define SPA_POD_Pointer(type,val) "p", type,val
|
||||
#define SPA_POD_Fd(val) "h", val
|
||||
#define SPA_POD_None() "P", NULL
|
||||
#define SPA_POD_Pod(val) "P", val
|
||||
#define SPA_POD_PodObject(val) "O", val
|
||||
#define SPA_POD_PodStruct(val) "T", val
|
||||
#define SPA_POD_PodChoice(val) "V", val
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_POD_VARARG_H */
|
@ -0,0 +1,318 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_LOOP_H
|
||||
#define SPA_LOOP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/hook.h>
|
||||
#include <spa/support/system.h>
|
||||
|
||||
/** \defgroup spa_loop Loop
|
||||
* Event loop interface
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup spa_loop
|
||||
* \{
|
||||
*/
|
||||
|
||||
#define SPA_TYPE_INTERFACE_Loop SPA_TYPE_INFO_INTERFACE_BASE "Loop"
|
||||
#define SPA_TYPE_INTERFACE_DataLoop SPA_TYPE_INFO_INTERFACE_BASE "DataLoop"
|
||||
#define SPA_VERSION_LOOP 0
|
||||
struct spa_loop { struct spa_interface iface; };
|
||||
|
||||
#define SPA_TYPE_INTERFACE_LoopControl SPA_TYPE_INFO_INTERFACE_BASE "LoopControl"
|
||||
#define SPA_VERSION_LOOP_CONTROL 1
|
||||
struct spa_loop_control { struct spa_interface iface; };
|
||||
|
||||
#define SPA_TYPE_INTERFACE_LoopUtils SPA_TYPE_INFO_INTERFACE_BASE "LoopUtils"
|
||||
#define SPA_VERSION_LOOP_UTILS 0
|
||||
struct spa_loop_utils { struct spa_interface iface; };
|
||||
|
||||
struct spa_source;
|
||||
|
||||
typedef void (*spa_source_func_t) (struct spa_source *source);
|
||||
|
||||
struct spa_source {
|
||||
struct spa_loop *loop;
|
||||
spa_source_func_t func;
|
||||
void *data;
|
||||
int fd;
|
||||
uint32_t mask;
|
||||
uint32_t rmask;
|
||||
/* private data for the loop implementer */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
typedef int (*spa_invoke_func_t) (struct spa_loop *loop,
|
||||
bool async,
|
||||
uint32_t seq,
|
||||
const void *data,
|
||||
size_t size,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Register sources and work items to an event loop
|
||||
*/
|
||||
struct spa_loop_methods {
|
||||
/* the version of this structure. This can be used to expand this
|
||||
* structure in the future */
|
||||
#define SPA_VERSION_LOOP_METHODS 0
|
||||
uint32_t version;
|
||||
|
||||
/** add a source to the loop */
|
||||
int (*add_source) (void *object,
|
||||
struct spa_source *source);
|
||||
|
||||
/** update the source io mask */
|
||||
int (*update_source) (void *object,
|
||||
struct spa_source *source);
|
||||
|
||||
/** remove a source from the loop */
|
||||
int (*remove_source) (void *object,
|
||||
struct spa_source *source);
|
||||
|
||||
/** invoke a function in the context of this loop */
|
||||
int (*invoke) (void *object,
|
||||
spa_invoke_func_t func,
|
||||
uint32_t seq,
|
||||
const void *data,
|
||||
size_t size,
|
||||
bool block,
|
||||
void *user_data);
|
||||
};
|
||||
|
||||
#define spa_loop_method(o,method,version,...) \
|
||||
({ \
|
||||
int _res = -ENOTSUP; \
|
||||
struct spa_loop *_o = o; \
|
||||
spa_interface_call_res(&_o->iface, \
|
||||
struct spa_loop_methods, _res, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
_res; \
|
||||
})
|
||||
|
||||
#define spa_loop_add_source(l,...) spa_loop_method(l,add_source,0,##__VA_ARGS__)
|
||||
#define spa_loop_update_source(l,...) spa_loop_method(l,update_source,0,##__VA_ARGS__)
|
||||
#define spa_loop_remove_source(l,...) spa_loop_method(l,remove_source,0,##__VA_ARGS__)
|
||||
#define spa_loop_invoke(l,...) spa_loop_method(l,invoke,0,##__VA_ARGS__)
|
||||
|
||||
|
||||
/** Control hooks. These hooks can't be removed from their
|
||||
* callbacks and must be removed from a safe place (when the loop
|
||||
* is not running or when it is locked). */
|
||||
struct spa_loop_control_hooks {
|
||||
#define SPA_VERSION_LOOP_CONTROL_HOOKS 0
|
||||
uint32_t version;
|
||||
/** Executed right before waiting for events. It is typically used to
|
||||
* release locks. */
|
||||
void (*before) (void *data);
|
||||
/** Executed right after waiting for events. It is typically used to
|
||||
* reacquire locks. */
|
||||
void (*after) (void *data);
|
||||
};
|
||||
|
||||
#define spa_loop_control_hook_before(l) \
|
||||
({ \
|
||||
struct spa_hook_list *_l = l; \
|
||||
struct spa_hook *_h; \
|
||||
spa_list_for_each_reverse(_h, &_l->list, link) \
|
||||
spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, before, 0); \
|
||||
})
|
||||
|
||||
#define spa_loop_control_hook_after(l) \
|
||||
({ \
|
||||
struct spa_hook_list *_l = l; \
|
||||
struct spa_hook *_h; \
|
||||
spa_list_for_each(_h, &_l->list, link) \
|
||||
spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, after, 0); \
|
||||
})
|
||||
|
||||
/**
|
||||
* Control an event loop
|
||||
*/
|
||||
struct spa_loop_control_methods {
|
||||
/* the version of this structure. This can be used to expand this
|
||||
* structure in the future */
|
||||
#define SPA_VERSION_LOOP_CONTROL_METHODS 1
|
||||
uint32_t version;
|
||||
|
||||
int (*get_fd) (void *object);
|
||||
|
||||
/** Add a hook
|
||||
* \param ctrl the control to change
|
||||
* \param hooks the hooks to add
|
||||
*
|
||||
* Adds hooks to the loop controlled by \a ctrl.
|
||||
*/
|
||||
void (*add_hook) (void *object,
|
||||
struct spa_hook *hook,
|
||||
const struct spa_loop_control_hooks *hooks,
|
||||
void *data);
|
||||
|
||||
/** Enter a loop
|
||||
* \param ctrl the control
|
||||
*
|
||||
* Start an iteration of the loop. This function should be called
|
||||
* before calling iterate and is typically used to capture the thread
|
||||
* that this loop will run in.
|
||||
*/
|
||||
void (*enter) (void *object);
|
||||
/** Leave a loop
|
||||
* \param ctrl the control
|
||||
*
|
||||
* Ends the iteration of a loop. This should be called after calling
|
||||
* iterate.
|
||||
*/
|
||||
void (*leave) (void *object);
|
||||
|
||||
/** Perform one iteration of the loop.
|
||||
* \param ctrl the control
|
||||
* \param timeout an optional timeout in milliseconds.
|
||||
* 0 for no timeout, -1 for infinite timeout.
|
||||
*
|
||||
* This function will block
|
||||
* up to \a timeout milliseconds and then dispatch the fds with activity.
|
||||
* The number of dispatched fds is returned.
|
||||
*/
|
||||
int (*iterate) (void *object, int timeout);
|
||||
|
||||
/** Check context of the loop
|
||||
* \param ctrl the control
|
||||
*
|
||||
* This function will check if the current thread is currently the
|
||||
* one that did the enter call. Since version 1:1.
|
||||
*
|
||||
* returns 1 on success, 0 or negative errno value on error.
|
||||
*/
|
||||
int (*check) (void *object);
|
||||
};
|
||||
|
||||
#define spa_loop_control_method_v(o,method,version,...) \
|
||||
({ \
|
||||
struct spa_loop_control *_o = o; \
|
||||
spa_interface_call(&_o->iface, \
|
||||
struct spa_loop_control_methods, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define spa_loop_control_method_r(o,method,version,...) \
|
||||
({ \
|
||||
int _res = -ENOTSUP; \
|
||||
struct spa_loop_control *_o = o; \
|
||||
spa_interface_call_res(&_o->iface, \
|
||||
struct spa_loop_control_methods, _res, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
_res; \
|
||||
})
|
||||
|
||||
#define spa_loop_control_get_fd(l) spa_loop_control_method_r(l,get_fd,0)
|
||||
#define spa_loop_control_add_hook(l,...) spa_loop_control_method_v(l,add_hook,0,__VA_ARGS__)
|
||||
#define spa_loop_control_enter(l) spa_loop_control_method_v(l,enter,0)
|
||||
#define spa_loop_control_leave(l) spa_loop_control_method_v(l,leave,0)
|
||||
#define spa_loop_control_iterate(l,...) spa_loop_control_method_r(l,iterate,0,__VA_ARGS__)
|
||||
#define spa_loop_control_check(l) spa_loop_control_method_r(l,check,1)
|
||||
|
||||
typedef void (*spa_source_io_func_t) (void *data, int fd, uint32_t mask);
|
||||
typedef void (*spa_source_idle_func_t) (void *data);
|
||||
typedef void (*spa_source_event_func_t) (void *data, uint64_t count);
|
||||
typedef void (*spa_source_timer_func_t) (void *data, uint64_t expirations);
|
||||
typedef void (*spa_source_signal_func_t) (void *data, int signal_number);
|
||||
|
||||
/**
|
||||
* Create sources for an event loop
|
||||
*/
|
||||
struct spa_loop_utils_methods {
|
||||
/* the version of this structure. This can be used to expand this
|
||||
* structure in the future */
|
||||
#define SPA_VERSION_LOOP_UTILS_METHODS 0
|
||||
uint32_t version;
|
||||
|
||||
struct spa_source *(*add_io) (void *object,
|
||||
int fd,
|
||||
uint32_t mask,
|
||||
bool close,
|
||||
spa_source_io_func_t func, void *data);
|
||||
|
||||
int (*update_io) (void *object, struct spa_source *source, uint32_t mask);
|
||||
|
||||
struct spa_source *(*add_idle) (void *object,
|
||||
bool enabled,
|
||||
spa_source_idle_func_t func, void *data);
|
||||
int (*enable_idle) (void *object, struct spa_source *source, bool enabled);
|
||||
|
||||
struct spa_source *(*add_event) (void *object,
|
||||
spa_source_event_func_t func, void *data);
|
||||
int (*signal_event) (void *object, struct spa_source *source);
|
||||
|
||||
struct spa_source *(*add_timer) (void *object,
|
||||
spa_source_timer_func_t func, void *data);
|
||||
int (*update_timer) (void *object,
|
||||
struct spa_source *source,
|
||||
struct timespec *value,
|
||||
struct timespec *interval,
|
||||
bool absolute);
|
||||
struct spa_source *(*add_signal) (void *object,
|
||||
int signal_number,
|
||||
spa_source_signal_func_t func, void *data);
|
||||
|
||||
/** destroy a source allocated with this interface. This function
|
||||
* should only be called when the loop is not running or from the
|
||||
* context of the running loop */
|
||||
void (*destroy_source) (void *object, struct spa_source *source);
|
||||
};
|
||||
|
||||
#define spa_loop_utils_method_v(o,method,version,...) \
|
||||
({ \
|
||||
struct spa_loop_utils *_o = o; \
|
||||
spa_interface_call(&_o->iface, \
|
||||
struct spa_loop_utils_methods, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define spa_loop_utils_method_r(o,method,version,...) \
|
||||
({ \
|
||||
int _res = -ENOTSUP; \
|
||||
struct spa_loop_utils *_o = o; \
|
||||
spa_interface_call_res(&_o->iface, \
|
||||
struct spa_loop_utils_methods, _res, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
_res; \
|
||||
})
|
||||
#define spa_loop_utils_method_s(o,method,version,...) \
|
||||
({ \
|
||||
struct spa_source *_res = NULL; \
|
||||
struct spa_loop_utils *_o = o; \
|
||||
spa_interface_call_res(&_o->iface, \
|
||||
struct spa_loop_utils_methods, _res, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
_res; \
|
||||
})
|
||||
|
||||
|
||||
#define spa_loop_utils_add_io(l,...) spa_loop_utils_method_s(l,add_io,0,__VA_ARGS__)
|
||||
#define spa_loop_utils_update_io(l,...) spa_loop_utils_method_r(l,update_io,0,__VA_ARGS__)
|
||||
#define spa_loop_utils_add_idle(l,...) spa_loop_utils_method_s(l,add_idle,0,__VA_ARGS__)
|
||||
#define spa_loop_utils_enable_idle(l,...) spa_loop_utils_method_r(l,enable_idle,0,__VA_ARGS__)
|
||||
#define spa_loop_utils_add_event(l,...) spa_loop_utils_method_s(l,add_event,0,__VA_ARGS__)
|
||||
#define spa_loop_utils_signal_event(l,...) spa_loop_utils_method_r(l,signal_event,0,__VA_ARGS__)
|
||||
#define spa_loop_utils_add_timer(l,...) spa_loop_utils_method_s(l,add_timer,0,__VA_ARGS__)
|
||||
#define spa_loop_utils_update_timer(l,...) spa_loop_utils_method_r(l,update_timer,0,__VA_ARGS__)
|
||||
#define spa_loop_utils_add_signal(l,...) spa_loop_utils_method_s(l,add_signal,0,__VA_ARGS__)
|
||||
#define spa_loop_utils_destroy_source(l,...) spa_loop_utils_method_v(l,destroy_source,0,__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_LOOP_H */
|
@ -0,0 +1,145 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_SYSTEM_H
|
||||
#define SPA_SYSTEM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct itimerspec;
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/hook.h>
|
||||
|
||||
/** \defgroup spa_system System
|
||||
* I/O, clock, polling, timer, and signal interfaces
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup spa_system
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* a collection of core system functions
|
||||
*/
|
||||
#define SPA_TYPE_INTERFACE_System SPA_TYPE_INFO_INTERFACE_BASE "System"
|
||||
#define SPA_TYPE_INTERFACE_DataSystem SPA_TYPE_INFO_INTERFACE_BASE "DataSystem"
|
||||
|
||||
#define SPA_VERSION_SYSTEM 0
|
||||
struct spa_system { struct spa_interface iface; };
|
||||
|
||||
/* IO events */
|
||||
#define SPA_IO_IN (1 << 0)
|
||||
#define SPA_IO_OUT (1 << 2)
|
||||
#define SPA_IO_ERR (1 << 3)
|
||||
#define SPA_IO_HUP (1 << 4)
|
||||
|
||||
/* flags */
|
||||
#define SPA_FD_CLOEXEC (1<<0)
|
||||
#define SPA_FD_NONBLOCK (1<<1)
|
||||
#define SPA_FD_EVENT_SEMAPHORE (1<<2)
|
||||
#define SPA_FD_TIMER_ABSTIME (1<<3)
|
||||
#define SPA_FD_TIMER_CANCEL_ON_SET (1<<4)
|
||||
|
||||
struct spa_poll_event {
|
||||
uint32_t events;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct spa_system_methods {
|
||||
#define SPA_VERSION_SYSTEM_METHODS 0
|
||||
uint32_t version;
|
||||
|
||||
/* read/write/ioctl */
|
||||
ssize_t (*read) (void *object, int fd, void *buf, size_t count);
|
||||
ssize_t (*write) (void *object, int fd, const void *buf, size_t count);
|
||||
int (*ioctl) (void *object, int fd, unsigned long request, ...);
|
||||
int (*close) (void *object, int fd);
|
||||
|
||||
/* clock */
|
||||
int (*clock_gettime) (void *object,
|
||||
int clockid, struct timespec *value);
|
||||
int (*clock_getres) (void *object,
|
||||
int clockid, struct timespec *res);
|
||||
|
||||
/* poll */
|
||||
int (*pollfd_create) (void *object, int flags);
|
||||
int (*pollfd_add) (void *object, int pfd, int fd, uint32_t events, void *data);
|
||||
int (*pollfd_mod) (void *object, int pfd, int fd, uint32_t events, void *data);
|
||||
int (*pollfd_del) (void *object, int pfd, int fd);
|
||||
int (*pollfd_wait) (void *object, int pfd,
|
||||
struct spa_poll_event *ev, int n_ev, int timeout);
|
||||
|
||||
/* timers */
|
||||
int (*timerfd_create) (void *object, int clockid, int flags);
|
||||
int (*timerfd_settime) (void *object,
|
||||
int fd, int flags,
|
||||
const struct itimerspec *new_value,
|
||||
struct itimerspec *old_value);
|
||||
int (*timerfd_gettime) (void *object,
|
||||
int fd, struct itimerspec *curr_value);
|
||||
int (*timerfd_read) (void *object, int fd, uint64_t *expirations);
|
||||
|
||||
/* events */
|
||||
int (*eventfd_create) (void *object, int flags);
|
||||
int (*eventfd_write) (void *object, int fd, uint64_t count);
|
||||
int (*eventfd_read) (void *object, int fd, uint64_t *count);
|
||||
|
||||
/* signals */
|
||||
int (*signalfd_create) (void *object, int signal, int flags);
|
||||
int (*signalfd_read) (void *object, int fd, int *signal);
|
||||
};
|
||||
|
||||
#define spa_system_method_r(o,method,version,...) \
|
||||
({ \
|
||||
volatile int _res = -ENOTSUP; \
|
||||
struct spa_system *_o = o; \
|
||||
spa_interface_call_res(&_o->iface, \
|
||||
struct spa_system_methods, _res, \
|
||||
method, version, ##__VA_ARGS__); \
|
||||
_res; \
|
||||
})
|
||||
|
||||
|
||||
#define spa_system_read(s,...) spa_system_method_r(s,read,0,__VA_ARGS__)
|
||||
#define spa_system_write(s,...) spa_system_method_r(s,write,0,__VA_ARGS__)
|
||||
#define spa_system_ioctl(s,...) spa_system_method_r(s,ioctl,0,__VA_ARGS__)
|
||||
#define spa_system_close(s,...) spa_system_method_r(s,close,0,__VA_ARGS__)
|
||||
|
||||
#define spa_system_clock_gettime(s,...) spa_system_method_r(s,clock_gettime,0,__VA_ARGS__)
|
||||
#define spa_system_clock_getres(s,...) spa_system_method_r(s,clock_getres,0,__VA_ARGS__)
|
||||
|
||||
#define spa_system_pollfd_create(s,...) spa_system_method_r(s,pollfd_create,0,__VA_ARGS__)
|
||||
#define spa_system_pollfd_add(s,...) spa_system_method_r(s,pollfd_add,0,__VA_ARGS__)
|
||||
#define spa_system_pollfd_mod(s,...) spa_system_method_r(s,pollfd_mod,0,__VA_ARGS__)
|
||||
#define spa_system_pollfd_del(s,...) spa_system_method_r(s,pollfd_del,0,__VA_ARGS__)
|
||||
#define spa_system_pollfd_wait(s,...) spa_system_method_r(s,pollfd_wait,0,__VA_ARGS__)
|
||||
|
||||
#define spa_system_timerfd_create(s,...) spa_system_method_r(s,timerfd_create,0,__VA_ARGS__)
|
||||
#define spa_system_timerfd_settime(s,...) spa_system_method_r(s,timerfd_settime,0,__VA_ARGS__)
|
||||
#define spa_system_timerfd_gettime(s,...) spa_system_method_r(s,timerfd_gettime,0,__VA_ARGS__)
|
||||
#define spa_system_timerfd_read(s,...) spa_system_method_r(s,timerfd_read,0,__VA_ARGS__)
|
||||
|
||||
#define spa_system_eventfd_create(s,...) spa_system_method_r(s,eventfd_create,0,__VA_ARGS__)
|
||||
#define spa_system_eventfd_write(s,...) spa_system_method_r(s,eventfd_write,0,__VA_ARGS__)
|
||||
#define spa_system_eventfd_read(s,...) spa_system_method_r(s,eventfd_read,0,__VA_ARGS__)
|
||||
|
||||
#define spa_system_signalfd_create(s,...) spa_system_method_r(s,signalfd_create,0,__VA_ARGS__)
|
||||
#define spa_system_signalfd_read(s,...) spa_system_method_r(s,signalfd_read,0,__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_SYSTEM_H */
|
@ -0,0 +1,382 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_UTILS_DEFS_H
|
||||
#define SPA_UTILS_DEFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# if __cplusplus >= 201103L
|
||||
# define SPA_STATIC_ASSERT_IMPL(expr, msg, ...) static_assert(expr, msg)
|
||||
# endif
|
||||
#else
|
||||
# include <stdbool.h>
|
||||
# if __STDC_VERSION__ >= 201112L
|
||||
# define SPA_STATIC_ASSERT_IMPL(expr, msg, ...) _Static_assert(expr, msg)
|
||||
# endif
|
||||
#endif
|
||||
#ifndef SPA_STATIC_ASSERT_IMPL
|
||||
#define SPA_STATIC_ASSERT_IMPL(expr, ...) \
|
||||
((void)sizeof(struct { int spa_static_assertion_failed : 2 * !!(expr) - 1; }))
|
||||
#endif
|
||||
|
||||
#define SPA_STATIC_ASSERT(expr, ...) SPA_STATIC_ASSERT_IMPL(expr, ## __VA_ARGS__, "`" #expr "` evaluated to false")
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* \defgroup spa_utils_defs Miscellaneous
|
||||
* Helper macros and functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup spa_utils_defs
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch
|
||||
* cases that fall through without a break or return statement. SPA_FALLTHROUGH
|
||||
* is only needed on cases that have code:
|
||||
*
|
||||
* switch (foo) {
|
||||
* case 1: // These cases have no code. No fallthrough annotations are needed.
|
||||
* case 2:
|
||||
* case 3:
|
||||
* foo = 4; // This case has code, so a fallthrough annotation is needed:
|
||||
* SPA_FALLTHROUGH;
|
||||
* default:
|
||||
* return foo;
|
||||
* }
|
||||
*/
|
||||
#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L
|
||||
/* clang's fallthrough annotations are only available starting in C++11. */
|
||||
# define SPA_FALLTHROUGH [[clang::fallthrough]];
|
||||
#elif __GNUC__ >= 7 || __clang_major__ >= 10
|
||||
# define SPA_FALLTHROUGH __attribute__ ((fallthrough));
|
||||
#else
|
||||
# define SPA_FALLTHROUGH /* FALLTHROUGH */
|
||||
#endif
|
||||
|
||||
#define SPA_FLAG_MASK(field,mask,flag) (((field) & (mask)) == (flag))
|
||||
#define SPA_FLAG_IS_SET(field,flag) SPA_FLAG_MASK(field, flag, flag)
|
||||
|
||||
#define SPA_FLAG_SET(field,flag) ((field) |= (flag))
|
||||
#define SPA_FLAG_CLEAR(field, flag) \
|
||||
({ \
|
||||
SPA_STATIC_ASSERT(__builtin_constant_p(flag) ? \
|
||||
(__typeof__(flag))(__typeof__(field))(__typeof__(flag))(flag) == (flag) : \
|
||||
sizeof(field) >= sizeof(flag), \
|
||||
"truncation problem when masking " #field \
|
||||
" with ~" #flag); \
|
||||
((field) &= ~(__typeof__(field))(flag)); \
|
||||
})
|
||||
#define SPA_FLAG_UPDATE(field,flag,val) ((val) ? SPA_FLAG_SET((field),(flag)) : SPA_FLAG_CLEAR((field),(flag)))
|
||||
|
||||
enum spa_direction {
|
||||
SPA_DIRECTION_INPUT = 0,
|
||||
SPA_DIRECTION_OUTPUT = 1,
|
||||
};
|
||||
|
||||
#define SPA_DIRECTION_REVERSE(d) ((d) ^ 1)
|
||||
|
||||
#define SPA_RECTANGLE(width,height) ((struct spa_rectangle){ (width), (height) })
|
||||
struct spa_rectangle {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
#define SPA_POINT(x,y) ((struct spa_point){ (x), (y) })
|
||||
struct spa_point {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
};
|
||||
|
||||
#define SPA_REGION(x,y,width,height) ((struct spa_region){ SPA_POINT(x,y), SPA_RECTANGLE(width,height) })
|
||||
struct spa_region {
|
||||
struct spa_point position;
|
||||
struct spa_rectangle size;
|
||||
};
|
||||
|
||||
#define SPA_FRACTION(num,denom) ((struct spa_fraction){ (num), (denom) })
|
||||
struct spa_fraction {
|
||||
uint32_t num;
|
||||
uint32_t denom;
|
||||
};
|
||||
|
||||
#define SPA_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
/**
|
||||
* Array iterator macro. Usage:
|
||||
* ```c
|
||||
* struct foo array[16];
|
||||
* struct foo *f;
|
||||
* SPA_FOR_EACH_ELEMENT(array, f) {
|
||||
* f->bar = baz;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
#define SPA_FOR_EACH_ELEMENT(arr, ptr) \
|
||||
for ((ptr) = arr; (void*)(ptr) < SPA_PTROFF(arr, sizeof(arr), void); (ptr)++)
|
||||
|
||||
#define SPA_FOR_EACH_ELEMENT_VAR(arr, var) \
|
||||
for (__typeof__((arr)[0])* var = arr; (void*)(var) < SPA_PTROFF(arr, sizeof(arr), void); (var)++)
|
||||
|
||||
#define SPA_ABS(a) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
SPA_LIKELY(_a >= 0) ? _a : -_a; \
|
||||
})
|
||||
#define SPA_MIN(a,b) \
|
||||
({ \
|
||||
__typeof__(a) _min_a = (a); \
|
||||
__typeof__(b) _min_b = (b); \
|
||||
SPA_LIKELY(_min_a <= _min_b) ? _min_a : _min_b; \
|
||||
})
|
||||
#define SPA_MAX(a,b) \
|
||||
({ \
|
||||
__typeof__(a) _max_a = (a); \
|
||||
__typeof__(b) _max_b = (b); \
|
||||
SPA_LIKELY(_max_a >= _max_b) ? _max_a : _max_b; \
|
||||
})
|
||||
#define SPA_CLAMP(v,low,high) \
|
||||
({ \
|
||||
__typeof__(v) _v = (v); \
|
||||
__typeof__(low) _low = (low); \
|
||||
__typeof__(high) _high = (high); \
|
||||
SPA_MIN(SPA_MAX(_v, _low), _high); \
|
||||
})
|
||||
|
||||
#define SPA_CLAMPF(v,low,high) \
|
||||
({ \
|
||||
fminf(fmaxf(v, low), high); \
|
||||
})
|
||||
|
||||
|
||||
#define SPA_SWAP(a,b) \
|
||||
({ \
|
||||
__typeof__(a) _t = (a); \
|
||||
(a) = b; (b) = _t; \
|
||||
})
|
||||
|
||||
#define SPA_TYPECHECK(type,x) \
|
||||
({ type _dummy; \
|
||||
typeof(x) _dummy2; \
|
||||
(void)(&_dummy == &_dummy2); \
|
||||
x; \
|
||||
})
|
||||
|
||||
/**
|
||||
* Return the address (buffer + offset) as pointer of \a type
|
||||
*/
|
||||
#define SPA_PTROFF(ptr_,offset_,type_) ((type_*)((uintptr_t)(ptr_) + (ptrdiff_t)(offset_)))
|
||||
#define SPA_PTROFF_ALIGN(ptr_,offset_,alignment_,type_) \
|
||||
SPA_PTR_ALIGN(SPA_PTROFF(ptr_,offset_,type_),alignment_,type_)
|
||||
|
||||
|
||||
/**
|
||||
* Deprecated, use SPA_PTROFF and SPA_PTROFF_ALIGN instead
|
||||
*/
|
||||
#define SPA_MEMBER(b,o,t) SPA_PTROFF(b,o,t)
|
||||
#define SPA_MEMBER_ALIGN(b,o,a,t) SPA_PTROFF_ALIGN(b,o,a,t)
|
||||
|
||||
#define SPA_CONTAINER_OF(p,t,m) ((t*)((uintptr_t)(p) - offsetof(t,m)))
|
||||
|
||||
#define SPA_PTRDIFF(p1,p2) ((intptr_t)(p1) - (intptr_t)(p2))
|
||||
|
||||
#define SPA_PTR_TO_INT(p) ((int) ((intptr_t) (p)))
|
||||
#define SPA_INT_TO_PTR(u) ((void*) ((intptr_t) (u)))
|
||||
|
||||
#define SPA_PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
|
||||
#define SPA_UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u)))
|
||||
|
||||
#define SPA_TIME_INVALID ((int64_t)INT64_MIN)
|
||||
#define SPA_IDX_INVALID ((unsigned int)-1)
|
||||
#define SPA_ID_INVALID ((uint32_t)0xffffffff)
|
||||
|
||||
#define SPA_NSEC_PER_SEC (1000000000LL)
|
||||
#define SPA_NSEC_PER_MSEC (1000000ll)
|
||||
#define SPA_NSEC_PER_USEC (1000ll)
|
||||
#define SPA_USEC_PER_SEC (1000000ll)
|
||||
#define SPA_USEC_PER_MSEC (1000ll)
|
||||
#define SPA_MSEC_PER_SEC (1000ll)
|
||||
|
||||
#define SPA_TIMESPEC_TO_NSEC(ts) ((ts)->tv_sec * SPA_NSEC_PER_SEC + (ts)->tv_nsec)
|
||||
#define SPA_TIMESPEC_TO_USEC(ts) ((ts)->tv_sec * SPA_USEC_PER_SEC + (ts)->tv_nsec / SPA_NSEC_PER_USEC)
|
||||
#define SPA_TIMEVAL_TO_NSEC(tv) ((tv)->tv_sec * SPA_NSEC_PER_SEC + (tv)->tv_usec * SPA_NSEC_PER_USEC)
|
||||
#define SPA_TIMEVAL_TO_USEC(tv) ((tv)->tv_sec * SPA_USEC_PER_SEC + (tv)->tv_usec)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define SPA_PRINTF_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
|
||||
#define SPA_FORMAT_ARG_FUNC(arg1) __attribute__((format_arg(arg1)))
|
||||
#define SPA_ALIGNED(align) __attribute__((aligned(align)))
|
||||
#define SPA_DEPRECATED __attribute__ ((deprecated))
|
||||
#define SPA_EXPORT __attribute__((visibility("default")))
|
||||
#define SPA_SENTINEL __attribute__((__sentinel__))
|
||||
#define SPA_UNUSED __attribute__ ((unused))
|
||||
#define SPA_NORETURN __attribute__ ((noreturn))
|
||||
#define SPA_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
|
||||
#else
|
||||
#define SPA_PRINTF_FUNC(fmt, arg1)
|
||||
#define SPA_FORMAT_ARG_FUNC(arg1)
|
||||
#define SPA_ALIGNED(align)
|
||||
#define SPA_DEPRECATED
|
||||
#define SPA_EXPORT
|
||||
#define SPA_SENTINEL
|
||||
#define SPA_UNUSED
|
||||
#define SPA_NORETURN
|
||||
#define SPA_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
#define SPA_RESTRICT restrict
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define SPA_RESTRICT __restrict__
|
||||
#else
|
||||
#define SPA_RESTRICT
|
||||
#endif
|
||||
|
||||
#define SPA_ROUND_DOWN(num,value) \
|
||||
({ \
|
||||
__typeof__(num) _num = (num); \
|
||||
((_num) - ((_num) % (value))); \
|
||||
})
|
||||
#define SPA_ROUND_UP(num,value) \
|
||||
({ \
|
||||
__typeof__(value) _v = (value); \
|
||||
((((num) + (_v) - 1) / (_v)) * (_v)); \
|
||||
})
|
||||
|
||||
#define SPA_ROUND_MASK(num,mask) ((__typeof__(num))((mask)-1))
|
||||
|
||||
#define SPA_ROUND_DOWN_N(num,align) ((num) & ~SPA_ROUND_MASK(num, align))
|
||||
#define SPA_ROUND_UP_N(num,align) ((((num)-1) | SPA_ROUND_MASK(num, align))+1)
|
||||
|
||||
#define SPA_SCALE32_UP(val,num,denom) \
|
||||
({ \
|
||||
uint64_t _val = (val); \
|
||||
uint64_t _denom = (denom); \
|
||||
(uint32_t)(((_val) * (num) + (_denom)-1) / (_denom)); \
|
||||
})
|
||||
|
||||
|
||||
#define SPA_PTR_ALIGNMENT(p,align) ((intptr_t)(p) & ((align)-1))
|
||||
#define SPA_IS_ALIGNED(p,align) (SPA_PTR_ALIGNMENT(p,align) == 0)
|
||||
#define SPA_PTR_ALIGN(p,align,type) ((type*)SPA_ROUND_UP_N((intptr_t)(p), (intptr_t)(align)))
|
||||
|
||||
#ifndef SPA_LIKELY
|
||||
#ifdef __GNUC__
|
||||
#define SPA_LIKELY(x) (__builtin_expect(!!(x),1))
|
||||
#define SPA_UNLIKELY(x) (__builtin_expect(!!(x),0))
|
||||
#else
|
||||
#define SPA_LIKELY(x) (x)
|
||||
#define SPA_UNLIKELY(x) (x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SPA_STRINGIFY_1(...) #__VA_ARGS__
|
||||
#define SPA_STRINGIFY(...) SPA_STRINGIFY_1(__VA_ARGS__)
|
||||
|
||||
#define spa_return_if_fail(expr) \
|
||||
do { \
|
||||
if (SPA_UNLIKELY(!(expr))) { \
|
||||
fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
|
||||
#expr , __FILE__, __LINE__, __func__); \
|
||||
return; \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
#define spa_return_val_if_fail(expr, val) \
|
||||
do { \
|
||||
if (SPA_UNLIKELY(!(expr))) { \
|
||||
fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
|
||||
#expr , __FILE__, __LINE__, __func__); \
|
||||
return (val); \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
/* spa_assert_se() is an assert which guarantees side effects of x,
|
||||
* i.e. is never optimized away, regardless of NDEBUG or FASTPATH. */
|
||||
#ifndef __COVERITY__
|
||||
#define spa_assert_se(expr) \
|
||||
do { \
|
||||
if (SPA_UNLIKELY(!(expr))) { \
|
||||
fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
|
||||
#expr , __FILE__, __LINE__, __func__); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (false)
|
||||
#else
|
||||
#define spa_assert_se(expr) \
|
||||
do { \
|
||||
int _unique_var = (expr); \
|
||||
if (!_unique_var) \
|
||||
abort(); \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
/* Does exactly nothing */
|
||||
#define spa_nop() do {} while (false)
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define spa_assert(expr) spa_nop()
|
||||
#elif defined (FASTPATH)
|
||||
#define spa_assert(expr) spa_assert_se(expr)
|
||||
#else
|
||||
#define spa_assert(expr) spa_assert_se(expr)
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define spa_assert_not_reached() abort()
|
||||
#else
|
||||
#define spa_assert_not_reached() \
|
||||
do { \
|
||||
fprintf(stderr, "Code should not be reached at %s:%u %s()\n", \
|
||||
__FILE__, __LINE__, __func__); \
|
||||
abort(); \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
#define spa_memzero(x,l) (memset((x), 0, (l)))
|
||||
#define spa_zero(x) (spa_memzero(&(x), sizeof(x)))
|
||||
|
||||
#ifdef SPA_DEBUG_MEMCPY
|
||||
#define spa_memcpy(d,s,n) \
|
||||
({ \
|
||||
fprintf(stderr, "%s:%u %s() memcpy(%p, %p, %zd)\n", \
|
||||
__FILE__, __LINE__, __func__, (d), (s), (size_t)(n)); \
|
||||
memcpy(d,s,n); \
|
||||
})
|
||||
#define spa_memmove(d,s,n) \
|
||||
({ \
|
||||
fprintf(stderr, "%s:%u %s() memmove(%p, %p, %zd)\n", \
|
||||
__FILE__, __LINE__, __func__, (d), (s), (size_t)(n)); \
|
||||
memmove(d,s,n); \
|
||||
})
|
||||
#else
|
||||
#define spa_memcpy(d,s,n) memcpy(d,s,n)
|
||||
#define spa_memmove(d,s,n) memmove(d,s,n)
|
||||
#endif
|
||||
|
||||
#define spa_aprintf(_fmt, ...) \
|
||||
({ \
|
||||
char *_strp; \
|
||||
if (asprintf(&(_strp), (_fmt), ## __VA_ARGS__ ) == -1) \
|
||||
_strp = NULL; \
|
||||
_strp; \
|
||||
})
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_UTILS_DEFS_H */
|
@ -0,0 +1,100 @@
|
||||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_DICT_H
|
||||
#define SPA_DICT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
|
||||
/**
|
||||
* \defgroup spa_dict Dictionary
|
||||
* Dictionary data structure
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup spa_dict
|
||||
* \{
|
||||
*/
|
||||
|
||||
struct spa_dict_item {
|
||||
const char *key;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
#define SPA_DICT_ITEM_INIT(key,value) ((struct spa_dict_item) { (key), (value) })
|
||||
|
||||
struct spa_dict {
|
||||
#define SPA_DICT_FLAG_SORTED (1<<0) /**< items are sorted */
|
||||
uint32_t flags;
|
||||
uint32_t n_items;
|
||||
const struct spa_dict_item *items;
|
||||
};
|
||||
|
||||
#define SPA_DICT_INIT(items,n_items) ((struct spa_dict) { 0, (n_items), (items) })
|
||||
#define SPA_DICT_INIT_ARRAY(items) ((struct spa_dict) { 0, SPA_N_ELEMENTS(items), (items) })
|
||||
|
||||
#define spa_dict_for_each(item, dict) \
|
||||
for ((item) = (dict)->items; \
|
||||
(item) < &(dict)->items[(dict)->n_items]; \
|
||||
(item)++)
|
||||
|
||||
static inline int spa_dict_item_compare(const void *i1, const void *i2)
|
||||
{
|
||||
const struct spa_dict_item *it1 = (const struct spa_dict_item *)i1,
|
||||
*it2 = (const struct spa_dict_item *)i2;
|
||||
return strcmp(it1->key, it2->key);
|
||||
}
|
||||
|
||||
static inline void spa_dict_qsort(struct spa_dict *dict)
|
||||
{
|
||||
if (dict->n_items > 0)
|
||||
qsort((void*)dict->items, dict->n_items, sizeof(struct spa_dict_item),
|
||||
spa_dict_item_compare);
|
||||
SPA_FLAG_SET(dict->flags, SPA_DICT_FLAG_SORTED);
|
||||
}
|
||||
|
||||
static inline const struct spa_dict_item *spa_dict_lookup_item(const struct spa_dict *dict,
|
||||
const char *key)
|
||||
{
|
||||
const struct spa_dict_item *item;
|
||||
|
||||
if (SPA_FLAG_IS_SET(dict->flags, SPA_DICT_FLAG_SORTED) &&
|
||||
dict->n_items > 0) {
|
||||
struct spa_dict_item k = SPA_DICT_ITEM_INIT(key, NULL);
|
||||
item = (const struct spa_dict_item *)bsearch(&k,
|
||||
(const void *) dict->items, dict->n_items,
|
||||
sizeof(struct spa_dict_item),
|
||||
spa_dict_item_compare);
|
||||
if (item != NULL)
|
||||
return item;
|
||||
} else {
|
||||
spa_dict_for_each(item, dict) {
|
||||
if (!strcmp(item->key, key))
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const char *spa_dict_lookup(const struct spa_dict *dict, const char *key)
|
||||
{
|
||||
const struct spa_dict_item *item = spa_dict_lookup_item(dict, key);
|
||||
return item ? item->value : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_DICT_H */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user