summaryrefslogtreecommitdiffstats
path: root/doc/spa-pod.dox
blob: 0c88bb763e4f28ae402ae1875cbbb6e3ac78a48e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
/** \page page_spa_pod SPA POD

\ref spa_pod (plain old data) is a sort of data container. It is comparable to
DBus Variant or LV2 Atom.

A POD can express nested structures of objects (with properties), vectors,
arrays, sequences and various primitives types. All information in the POD
is laid out sequentially in memory and can be written directly to
storage or exchanged between processes or threads without additional
marshalling.

Each POD is made of a 32 bits size followed by a 32 bits type field,
followed by the POD contents. This makes it possible to skip over unknown
POD types. The POD start is always aligned to 8 bytes.

POD's can be efficiently constructed and parsed in real-time threads without
requiring memory allocations.

POD's use the SPA type system for the basic types and containers. See
the SPA types for more info.


# Types

POD's can contain a number of basic SPA types:

- `SPA_TYPE_None`: No value or a NULL pointer.
- `SPA_TYPE_Bool`: A boolean value.
- `SPA_TYPE_Id`: An enumerated value.
- `SPA_TYPE_Int`, `SPA_TYPE_Long`, `SPA_TYPE_Float`, `SPA_TYPE_Double`:
  various numeral types, 32 and 64 bits.
- `SPA_TYPE_String`: A string.
- `SPA_TYPE_Bytes`: A byte array.
- `SPA_TYPE_Rectangle`: A rectangle with width and height.
- `SPA_TYPE_Fraction`: A fraction with numerator and denominator.
- `SPA_TYPE_Bitmap`: An array of bits.

POD's can be grouped together in these container types:

- `SPA_TYPE_Array`: An array of equal sized objects.
- `SPA_TYPE_Struct`: A collection of types and objects.
- `SPA_TYPE_Object`: An object with properties.
- `SPA_TYPE_Sequence`: A timed sequence of POD's.

POD's can also contain some extra types:

- `SPA_TYPE_Pointer`: A typed pointer in memory.
- `SPA_TYPE_Fd`: A file descriptor.
- `SPA_TYPE_Choice`: A choice of values.
- `SPA_TYPE_Pod`: A generic type for the POD itself.


# Constructing A POD

A POD is usually constructed with a `struct spa_pod_builder`. The builder
needs to be initialized with a memory region to write into. It is
also possible to dynamically grow the memory as needed.

The most common way to construct a POD is on the stack. This does
not require any memory allocations. The size of the POD can be
estimated pretty easily and if the buffer is not large enough, an
appropriate error will be generated.

The code fragment below initializes a POD builder to write into
the stack allocated buffer.

\code{.c}
uint8_t buffer[4096];
struct spa_pod_builder b;
spa_pod_builder_init(&b, buffer, sizeof(buffer));
\endcode

Next we need to write some object into the builder. Let's write
a simple struct with an Int and Float in it. Structs are comparable
to JSON arrays.

\code{.c}
struct spa_pod_frame f;
spa_pod_builder_push_struct(&b, &f);
\endcode

First we open the struct container, the `struct spa_pod_frame` keeps
track of the container context. Next we add some values to
the container like this:

\code{.c}
spa_pod_builder_int(&b, 5);
spa_pod_builder_float(&b, 3.1415f);
\endcode

Then we close the container by popping the frame again:

\code{.c}
struct spa_pod *pod;
pod = spa_pod_builder_pop(&b, &f);
\endcode

`spa_pod_builder_pop()` returns a reference to the object we completed
on the stack.

## Using varargs Builder

We can also use the following construct to make POD objects:

\code{.c}
spa_pod_builder_push_struct(&b, &f);
spa_pod_builder_add(&b,
	SPA_POD_Int(5),
	SPA_POD_Float(3.1415f));
pod = spa_pod_builder_pop(&b, &f);
\endcode

Or even shorter:

\code{.c}
pod = spa_pod_builder_add_struct(&b,
	SPA_POD_Int(5),
	SPA_POD_Float(3.1415f));
\endcode

It's not possible to use the varargs builder to make a sequence or
array, use the normal builder methods for that.

## Making Objects

POD objects are containers for properties and are comparable to JSON
objects.

Start by pushing an object:

\code{.c}
spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
\endcode

An object requires an object type (`SPA_TYPE_OBJECT_Props`) and a context
ID (`SPA_PARAM_Props`). The object type defines the properties that can be
added to the object and their meaning. The SPA type system allows you to
make this connection (See the type system).

Next we can push some properties in the object:

\code{.c}
spa_pod_builder_prop(&b, SPA_PROP_device, 0);
spa_pod_builder_string(&b, "hw:0");
spa_pod_builder_prop(&b, SPA_PROP_frequency, 0);
spa_pod_builder_float(&b, 440.0);
\endcode

As can be seen, we always need to push a prop (with key and flags)
and then the associated value. For performance reasons it is a good
idea to always push (and parse) the object keys in ascending order.

Don't forget to pop the result when the object is finished:

\code{.c}
pod = spa_pod_builder_pop(&b, &f);
\endcode

There is a shortcut for making objects:

\code{.c}
pod = spa_pod_builder_add_object(&b,
	SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
	SPA_PROP_device,    SPA_POD_String("hw:0"),
	SPA_PROP_frequency, SPA_POD_Float(440.0f));
\endcode

## Choice Values

It is possible to express ranges or enumerations of possible
values for properties (and to some extend structs). This is achieved
with choice values.

Choice values are really just a choice type and an array of choice values
(of the same type). Depending on the choice type, the array values are
interpreted in different ways:

- `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`: Enum: default, alternative,...
- `SPA_CHOICE_Flags`: Bitmask of flags.

Let's illustrate this with a props object that specifies a range of
possible values for the frequency:

\code{.c}
struct spa_pod_frame f2;

spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
spa_pod_builder_prop(&b, SPA_PROP_frequency, 0);
spa_pod_builder_push_choice(&b, &f2, SPA_CHOICE_Range, 0);
spa_pod_builder_float(&b, 440.0);   //  default
spa_pod_builder_float(&b, 110.0);   //  min
spa_pod_builder_float(&b, 880.0);   //  min
pod = spa_pod_builder_pop(&b, &f2);
pod = spa_pod_builder_pop(&b, &f);
\endcode

As you can see, first push the choice as a range, then the values. A range
choice expects at least three values, the default value, minimum and maximum
values. There is a shortcut for this as well using varargs:

\code{.c}
pod = spa_pod_builder_add_object(&b,
	SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
	SPA_PROP_frequency, SPA_POD_CHOICE_RANGE_Float(440.0f, 110.0f, 880.0f));
\endcode

## Choice Examples

This is a description of a possible `SPA_TYPE_OBJECT_Format` as used when
enumerating allowed formats (`SPA_PARAM_EnumFormat`) in SPA objects:

\code{.c}
pod = spa_pod_builder_add_object(&b,
	SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
	//  specify the media type and subtype
	SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_audio),
	SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
	//  audio/raw properties
	SPA_FORMAT_AUDIO_format,   SPA_POD_CHOICE_ENUM_Id(
					SPA_AUDIO_FORMAT_S16, //  default
					SPA_AUDIO_FORMAT_S16, //  alternative1
					SPA_AUDIO_FORMAT_S32, //  alternative2
					SPA_AUDIO_FORMAT_f32  //  alternative3
				   ),
	SPA_FORMAT_AUDIO_rate,     SPA_POD_CHOICE_RANGE_Int(
					44100,		//  default
					8000,		//  min
					192000		//  max
				   ),
	SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2));
\endcode

## Fixate

We can remove all choice values from the object with the
`spa_pod_object_fixate()` method. This modifies the pod in-place and sets all
choice properties to `SPA_CHOICE_None`, forcing the default value as the
only available value in the choice.

Running fixate on our previous example would result in an object equivalent
to:

\code{.c}
pod = spa_pod_builder_add_object(&b,
	SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
	//  specify the media type and subtype
	SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_audio),
	SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
	//  audio/raw properties
	SPA_FORMAT_AUDIO_format,   SPA_POD_Id(SPA_AUDIO_FORMAT_S16),
	SPA_FORMAT_AUDIO_rate,     SPA_POD_Int(44100),
	SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2));
\endcode


# Parsing A POD

Parsing a POD usually consists of:

- Validating if raw bytes + size can contain a valid POD.
- Inspecting the type of a POD.
- Looping over the items in an object or struct.
- Getting data out of POD's.

## Validating Bytes

Use `spa_pod_from_data()` to check if maxsize of bytes in data contain
a POD at the size bytes starting at offset. This function checks that
the POD size will fit and not overflow.

\code{.c}
struct spa_pod *pod;
pod = spa_pod_from_data(data, maxsize, offset, size);
\endcode

## Checking The Type Of POD

Use one of `spa_pod_is_bool()`, `spa_pod_is_int()`, etc to check
for the type of the pod. For simple (non-container) types,
`spa_pod_get_bool()`, `spa_pod_get_int()` etc can be used to
extract the value of the pod.

`spa_pod_is_object_type()` can be used to check if the POD contains
an object of the expected type.

## Struct Fields

To iterate over the fields of a struct use:

\code{.c}
struct spa_pod *pod, *obj;
SPA_POD_STRUCT_FOREACH(obj, pod) {
	printf("field type:%d\n", pod->type);
}
\endcode

For parsing structs it is usually much easier to use the parser
below.

## Object Properties

To iterate over the properties in an object you can do:

\code{.c}
struct spa_pod_prop *prop;
struct spa_pod_object *obj = (struct spa_pod_object*)pod;
SPA_POD_OBJECT_FOREACH(pod, prop) {
	printf("prop key:%d\n", prop->key);
}
\endcode

There is a function to retrieve the property for a certain key
in the object. If the properties of the object are in ascending
order, you can start searching from the previous key.

\code{.c}
struct spa_pod_prop *prop;
prop = spa_pod_find_prop(obj, NULL, SPA_FORMAT_AUDIO_format);
  //  .. use first prop
prop = spa_pod_find_prop(obj, prop, SPA_FORMAT_AUDIO_rate);
  //  .. use next prop
\endcode

## Parser

Similar to the builder, there is a parser object as well.

If the fields in a struct are known, it is much easier to use the
parser. Similarly, if the object type (and thus its keys) are known,
the parser is easier.

First initialize a `struct spa_pod_parser`:

\code{.c}
struct spa_pod_parser p;
spa_pod_parser_pod(&p, obj);
\endcode

You can then enter containers such as objects or structs with a push
operation:

\code{.c}
struct spa_pod_frame f;
spa_pod_parser_push_struct(&p, &f);
\endcode

You need to store the context in a `struct spa_pod_frame` to be able
to exit the container again later.

You can then parse each field. The parser takes care of moving to the
next field.

\code{.c}
uint32_t id, val;
spa_pod_parser_get_id(&p, &id);
spa_pod_parser_get_int(&p, &val);
...
\endcode

And finally exit the container again:

\code{.c}
spa_pod_parser_pop(&p, &f);
\endcode

## Parser With Variable Arguments

In most cases, parsing objects is easier with the variable argument
functions. The parse function look like the mirror image of the builder
functions.

To parse a struct:

\code{.c}
spa_pod_parser_get_struct(&p,
	SPA_POD_Id(&id),
	SPA_POD_Int(&val));
\endcode

To parse properties in an object:

\code{.c}
uint32_t type, subtype, format, rate, channels;
spa_pod_parser_get_object(&p,
	SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
	SPA_FORMAT_mediaType,      SPA_POD_Id(&type),
	SPA_FORMAT_mediaSubtype,   SPA_POD_Id(&subtype),
	SPA_FORMAT_AUDIO_format,   SPA_POD_Id(&format),
	SPA_FORMAT_AUDIO_rate,     SPA_POD_Int(&rate),
	SPA_FORMAT_AUDIO_channels, SPA_POD_Int(&channels));
\endcode

When parsing objects it is possible to have optional fields. You can
make a field optional be parsing it with the `SPA_POD_OPT_` prefix
for the type.

In the next example, the rate and channels fields are optional
and when they are not present, the variables will not be changed.

\code{.c}
uint32_t type, subtype, format, rate = 0, channels = 0;
spa_pod_parser_get_object(&p,
	SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
	SPA_FORMAT_mediaType,      SPA_POD_Id(&type),
	SPA_FORMAT_mediaSubtype,   SPA_POD_Id(&subtype),
	SPA_FORMAT_AUDIO_format,   SPA_POD_Id(&format),
	SPA_FORMAT_AUDIO_rate,     SPA_POD_OPT_Int(&rate),
	SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&channels));
\endcode

It is not possible to parse a sequence or array with the parser.
Use the iterator for this.

## Choice Values

The parser will handle choice values as long as they are of type
`none`. It will then parse the single value from the choice. When
dealing with other choice values, it's possible to parse the
property values into a `struct spa_pod` and then inspect the choice
manually, if needed.

Here is an example of parsing the format values as a POD:

\code{.c}
uint32_t type, subtype;
struct spa_pod *format;
spa_pod_parser_get_object(&p,
	SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
	SPA_FORMAT_mediaType,      SPA_POD_Id(&type),
	SPA_FORMAT_mediaSubtype,   SPA_POD_Id(&subtype),
	SPA_FORMAT_AUDIO_format,   SPA_POD_Pod(&format));
\endcode

`spa_pod_get_values()` is a useful function. It returns a
`struct spa_pod*` with and array of values. For normal POD's
and choice none values, it simply returns the POD and one value.
For other choice values it returns the choice type and an array
of values:

\code{.c}
struct spa_pod *value;
uint32_t n_vals, choice;

value = spa_pod_get_values(pod, &n_vals, &choice);

switch (choice) {
case SPA_CHOICE_None:
        //  one single value
	break;
case SPA_CHOICE_Range:
        // array of values of type of pod, cast to right type
	// to iterate.
	uint32_t *v = SPA_POD_BODY(values);
	if (n_vals < 3)
		break;
	printf("default value: %u\n", v[0]);
	printf("min value: %u\n", v[1]);
	printf("max value: %u\n", v[2]);
	break;

	//  ...
default:
	break;
}
\endcode


# Filter

Given two POD objects of the same type (object, struct, ..) one can
run a filter and generate a new POD that only contains values that
are compatible with both input POD's.

This is, for example, used to find a compatible format between two ports.

As an example we can run a filter on two simple POD's:

\code{.c}
pod = spa_pod_builder_add_object(&b,
	SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
	SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_audio),
	SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
	SPA_FORMAT_AUDIO_format,   SPA_POD_CHOICE_ENUM_Id(
					SPA_AUDIO_FORMAT_S16, //  default
					SPA_AUDIO_FORMAT_S16, //  alternative1
					SPA_AUDIO_FORMAT_S32, //  alternative2
					SPA_AUDIO_FORMAT_f32  //  alternative3
				   ));

filter = spa_pod_builder_add_object(&b,
	SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
	SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_audio),
	SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
	SPA_FORMAT_AUDIO_format,   SPA_POD_CHOICE_ENUM_Id(
					SPA_AUDIO_FORMAT_S16, //  default
					SPA_AUDIO_FORMAT_S16, //  alternative1
					SPA_AUDIO_FORMAT_f64  //  alternative2
				   ));

struct spa_pod *result;
if (spa_pod_filter(&b, &result, pod, filter) < 0)
	goto exit_error;
\endcode

Filter will contain a POD equivalent to:

\code{.c}
result = spa_pod_builder_add_object(&b,
	SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
	SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_audio),
	SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
	SPA_FORMAT_AUDIO_format,   SPA_AUDIO_FORMAT_S16);
\endcode

# POD Layout

Each POD has a 32 bits size field, followed by a 32 bits type field. The size
field specifies the size following the type field.

Each POD is aligned to an 8 byte boundary.


\addtogroup spa_pod

See: \ref page_spa_pod

*/