8280982: [Wayland] [XWayland] java.awt.Robot taking screenshots

Reviewed-by: prr, kizune, psadhukhan
This commit is contained in:
Alexander Zvegintsev 2023-06-07 13:08:11 +00:00
parent a1ab377d99
commit 9d7bf5329e
106 changed files with 15062 additions and 40 deletions

View File

@ -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 \

View File

@ -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) \

View File

@ -35,19 +35,41 @@ 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")
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;
@ -100,15 +122,31 @@ final class XRobotPeer implements RobotPeer {
@Override
public int getRGBPixel(int x, int y) {
int[] pixelArray = new int[1];
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,
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;
}

View File

@ -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;
}
}

View 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();
}
}

View File

@ -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;
}
}
}

View 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.
```

View 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

View File

@ -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;

View File

@ -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;
}

View File

@ -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,
@ -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 */

View File

@ -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);

View File

@ -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,
&param,
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;
}

View File

@ -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

View 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;
}

View File

@ -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

View File

@ -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 */

View 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 */

View 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 */

View File

@ -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 */

View 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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View 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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View 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 */

View File

@ -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 */

View 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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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