pw-dump.c 38 KB
Newer Older
Wim Taymans's avatar
Wim Taymans committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* PipeWire
 *
 * Copyright © 2020 Wim Taymans <wim.taymans@gmail.com>
 *
 * 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.
 */

25
#include <string.h>
Wim Taymans's avatar
Wim Taymans committed
26
#include <unistd.h>
Wim Taymans's avatar
Wim Taymans committed
27
28
29
30
31
32
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <getopt.h>
#include <limits.h>
#include <math.h>
Wim Taymans's avatar
Wim Taymans committed
33
#include <fnmatch.h>
34
#include <locale.h>
Wim Taymans's avatar
Wim Taymans committed
35

Wim Taymans's avatar
Wim Taymans committed
36
37
38
39
#if !defined(FNM_EXTMATCH)
#define FNM_EXTMATCH 0
#endif

Wim Taymans's avatar
Wim Taymans committed
40
#include <spa/utils/result.h>
41
#include <spa/utils/string.h>
Wim Taymans's avatar
Wim Taymans committed
42
#include <spa/pod/iter.h>
Wim Taymans's avatar
Wim Taymans committed
43
#include <spa/debug/types.h>
Wim Taymans's avatar
Wim Taymans committed
44
#include <spa/utils/json.h>
45
#include <spa/utils/ansi.h>
Wim Taymans's avatar
Wim Taymans committed
46
#include <spa/utils/string.h>
Wim Taymans's avatar
Wim Taymans committed
47
48

#include <pipewire/pipewire.h>
49
#include <pipewire/extensions/metadata.h>
Wim Taymans's avatar
Wim Taymans committed
50
51
52

#define INDENT 2

Wim Taymans's avatar
Wim Taymans committed
53
54
static bool colors = false;

55
56
57
58
59
#define NORMAL	(colors ? SPA_ANSI_RESET : "")
#define LITERAL	(colors ? SPA_ANSI_BRIGHT_MAGENTA : "")
#define NUMBER	(colors ? SPA_ANSI_BRIGHT_CYAN : "")
#define STRING	(colors ? SPA_ANSI_BRIGHT_GREEN : "")
#define KEY	(colors ? SPA_ANSI_BRIGHT_BLUE : "")
Wim Taymans's avatar
Wim Taymans committed
60

Wim Taymans's avatar
Wim Taymans committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
struct data {
	struct pw_main_loop *loop;
	struct pw_context *context;

	struct pw_core_info *info;
	struct pw_core *core;
	struct spa_hook core_listener;
	int sync_seq;

	struct pw_registry *registry;
	struct spa_hook registry_listener;

	struct spa_list object_list;

Wim Taymans's avatar
Wim Taymans committed
75
	const char *pattern;
Wim Taymans's avatar
Wim Taymans committed
76

Wim Taymans's avatar
Wim Taymans committed
77
78
	FILE *out;
	int level;
79
80
81
82
83
84
#define STATE_KEY	(1<<0)
#define STATE_COMMA	(1<<1)
#define STATE_FIRST	(1<<2)
#define STATE_MASK	0xffff0000
#define STATE_SIMPLE	(1<<16)
	uint32_t state;
85
86

	unsigned int monitor:1;
Wim Taymans's avatar
Wim Taymans committed
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
};

struct param {
	uint32_t id;
	struct spa_list link;
	struct spa_pod *param;
};

struct object;

struct class {
	const char *type;
	uint32_t version;
	const void *events;
	void (*destroy) (struct object *object);
	void (*dump) (struct object *object);
Wim Taymans's avatar
Wim Taymans committed
103
	const char *name_key;
Wim Taymans's avatar
Wim Taymans committed
104
105
106
107
108
109
110
111
112
};

struct object {
	struct spa_list link;

	struct data *data;

	uint32_t id;
	uint32_t permissions;
Wim Taymans's avatar
Wim Taymans committed
113
114
	char *type;
	uint32_t version;
Wim Taymans's avatar
Wim Taymans committed
115
	struct pw_properties *props;
Wim Taymans's avatar
Wim Taymans committed
116
117

	const struct class *class;
Wim Taymans's avatar
Wim Taymans committed
118
119
120
121
122
	void *info;

	int changed;
	struct spa_list param_list;
	struct spa_list pending_list;
Wim Taymans's avatar
Wim Taymans committed
123
	struct spa_list data_list;
Wim Taymans's avatar
Wim Taymans committed
124
125
126
127
128
129
130
131
132
133
134
135

	struct pw_proxy *proxy;
	struct spa_hook proxy_listener;
	struct spa_hook object_listener;
};

static void core_sync(struct data *d)
{
	d->sync_seq = pw_core_sync(d->core, PW_ID_CORE, d->sync_seq);
	pw_log_debug("sync start %u", d->sync_seq);
}

Wim Taymans's avatar
Wim Taymans committed
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
static uint32_t clear_params(struct spa_list *param_list, uint32_t id)
{
	struct param *p, *t;
	uint32_t count = 0;

	spa_list_for_each_safe(p, t, param_list, link) {
		if (id == SPA_ID_INVALID || p->id == id) {
			spa_list_remove(&p->link);
			free(p);
			count++;
		}
	}
	return count;
}

Wim Taymans's avatar
Wim Taymans committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
static struct param *add_param(struct spa_list *params, uint32_t id, const struct spa_pod *param)
{
	struct param *p;

	if (id == SPA_ID_INVALID) {
		if (param == NULL || !spa_pod_is_object(param)) {
			errno = EINVAL;
			return NULL;
		}
		id = SPA_POD_OBJECT_ID(param);
	}

	p = malloc(sizeof(*p) + (param != NULL ? SPA_POD_SIZE(param) : 0));
	if (p == NULL)
		return NULL;

	p->id = id;
	if (param != NULL) {
169
		p->param = SPA_PTROFF(p, sizeof(*p), struct spa_pod);
Wim Taymans's avatar
Wim Taymans committed
170
171
172
173
174
175
176
177
178
179
		memcpy(p->param, param, SPA_POD_SIZE(param));
	} else {
		clear_params(params, id);
		p->param = NULL;
	}
	spa_list_append(params, &p->link);

	return p;
}

Wim Taymans's avatar
Wim Taymans committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
static struct object *find_object(struct data *d, uint32_t id)
{
	struct object *o;
	spa_list_for_each(o, &d->object_list, link) {
		if (o->id == id)
			return o;
	}
	return NULL;
}

static void object_update_params(struct object *o)
{
	struct param *p;

	spa_list_consume(p, &o->pending_list, link) {
		spa_list_remove(&p->link);
Wim Taymans's avatar
Wim Taymans committed
196
197
198
199
200
201
		if (p->param == NULL) {
			clear_params(&o->param_list, p->id);
			free(p);
		} else {
			spa_list_append(&o->param_list, &p->link);
		}
Wim Taymans's avatar
Wim Taymans committed
202
203
204
205
206
207
208
209
	}
}

static void object_destroy(struct object *o)
{
	spa_list_remove(&o->link);
	if (o->proxy)
		pw_proxy_destroy(o->proxy);
210
	pw_properties_free(o->props);
Wim Taymans's avatar
Wim Taymans committed
211
212
	clear_params(&o->param_list, SPA_ID_INVALID);
	clear_params(&o->pending_list, SPA_ID_INVALID);
Wim Taymans's avatar
Wim Taymans committed
213
	free(o->type);
Wim Taymans's avatar
Wim Taymans committed
214
215
216
	free(o);
}

217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
static void put_key(struct data *d, const char *key);

static SPA_PRINTF_FUNC(3,4) void put_fmt(struct data *d, const char *key, const char *fmt, ...)
{
	va_list va;
	if (key)
		put_key(d, key);
	fprintf(d->out, "%s%s%*s",
			d->state & STATE_COMMA ? "," : "",
			d->state & (STATE_MASK | STATE_KEY) ? " " : d->state & STATE_FIRST ? "" : "\n",
			d->state & (STATE_MASK | STATE_KEY) ? 0 : d->level, "");
	va_start(va, fmt);
	vfprintf(d->out, fmt, va);
	va_end(va);
	d->state = (d->state & STATE_MASK) + STATE_COMMA;
}

Wim Taymans's avatar
Wim Taymans committed
234
235
static void put_key(struct data *d, const char *key)
{
Wim Taymans's avatar
Wim Taymans committed
236
	int size = (strlen(key) + 1) * 4;
Wim Taymans's avatar
Wim Taymans committed
237
238
	char *str = alloca(size);
	spa_json_encode_string(str, size, key);
239
240
	put_fmt(d, NULL, "%s%s%s:", KEY, str, NORMAL);
	d->state = (d->state & STATE_MASK) + STATE_KEY;
Wim Taymans's avatar
Wim Taymans committed
241
242
243
}

static void put_begin(struct data *d, const char *key, const char *type, uint32_t flags)
Wim Taymans's avatar
Wim Taymans committed
244
{
245
	put_fmt(d, key, "%s", type);
Wim Taymans's avatar
Wim Taymans committed
246
	d->level += INDENT;
247
	d->state = (d->state & STATE_MASK) + (flags & STATE_SIMPLE);
Wim Taymans's avatar
Wim Taymans committed
248
249
250
251
252
}

static void put_end(struct data *d, const char *type, uint32_t flags)
{
	d->level -= INDENT;
253
254
255
	d->state = d->state & STATE_MASK;
	put_fmt(d, NULL, "%s", type);
	d->state = (d->state & STATE_MASK) + STATE_COMMA - (flags & STATE_SIMPLE);
Wim Taymans's avatar
Wim Taymans committed
256
257
}

258
259
260
261
static void put_encoded_string(struct data *d, const char *key, const char *val)
{
	put_fmt(d, key, "%s%s%s", STRING, val, NORMAL);
}
Wim Taymans's avatar
Wim Taymans committed
262
263
static void put_string(struct data *d, const char *key, const char *val)
{
Wim Taymans's avatar
Wim Taymans committed
264
	int size = (strlen(val) + 1) * 4;
Wim Taymans's avatar
Wim Taymans committed
265
266
	char *str = alloca(size);
	spa_json_encode_string(str, size, val);
267
	put_encoded_string(d, key, str);
Wim Taymans's avatar
Wim Taymans committed
268
269
270
271
}

static void put_literal(struct data *d, const char *key, const char *val)
{
Wim Taymans's avatar
Wim Taymans committed
272
	put_fmt(d, key, "%s%s%s", LITERAL, val, NORMAL);
Wim Taymans's avatar
Wim Taymans committed
273
274
275
276
}

static void put_int(struct data *d, const char *key, int64_t val)
{
Wim Taymans's avatar
Wim Taymans committed
277
	put_fmt(d, key, "%s%"PRIi64"%s", NUMBER, val, NORMAL);
Wim Taymans's avatar
Wim Taymans committed
278
279
280
281
}

static void put_double(struct data *d, const char *key, double val)
{
282
283
	char buf[128];
	put_fmt(d, key, "%s%s%s", NUMBER,
284
			spa_json_format_float(buf, sizeof(buf), val), NORMAL);
Wim Taymans's avatar
Wim Taymans committed
285
286
287
288
}

static void put_value(struct data *d, const char *key, const char *val)
{
289
	int64_t li;
290
	float fv;
Wim Taymans's avatar
Wim Taymans committed
291
292
293

	if (val == NULL)
		put_literal(d, key, "null");
294
	else if (spa_streq(val, "true") || spa_streq(val, "false"))
Wim Taymans's avatar
Wim Taymans committed
295
		put_literal(d, key, val);
296
	else if (spa_atoi64(val, &li, 10))
Wim Taymans's avatar
Wim Taymans committed
297
		put_int(d, key, li);
298
299
	else if (spa_json_parse_float(val, strlen(val), &fv))
		put_double(d, key, fv);
Wim Taymans's avatar
Wim Taymans committed
300
301
302
303
304
305
306
	else
		put_string(d, key, val);
}

static void put_dict(struct data *d, const char *key, struct spa_dict *dict)
{
	const struct spa_dict_item *it;
Wim Taymans's avatar
Wim Taymans committed
307
	put_begin(d, key, "{", 0);
Wim Taymans's avatar
Wim Taymans committed
308
309
310
311
312
	spa_dict_for_each(it, dict)
		put_value(d, it->key, it->value);
	put_end(d, "}", 0);
}

Wim Taymans's avatar
Wim Taymans committed
313
static void put_pod_value(struct data *d, const char *key, const struct spa_type_info *info,
Wim Taymans's avatar
Wim Taymans committed
314
315
		uint32_t type, void *body, uint32_t size)
{
Wim Taymans's avatar
Wim Taymans committed
316
317
	if (key)
		put_key(d, key);
Wim Taymans's avatar
Wim Taymans committed
318
319
320
321
322
	switch (type) {
	case SPA_TYPE_Bool:
		put_value(d, NULL, *(int32_t*)body ? "true" : "false");
		break;
	case SPA_TYPE_Id:
323
324
325
326
327
328
	{
		const char *str;
		char fallback[32];
		uint32_t id = *(uint32_t*)body;
		str = spa_debug_type_find_short_name(info, *(uint32_t*)body);
		if (str == NULL) {
329
			snprintf(fallback, sizeof(fallback), "id-%08x", id);
330
331
332
			str = fallback;
		}
		put_value(d, NULL, str);
Wim Taymans's avatar
Wim Taymans committed
333
		break;
334
	}
Wim Taymans's avatar
Wim Taymans committed
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
	case SPA_TYPE_Int:
		put_int(d, NULL, *(int32_t*)body);
		break;
	case SPA_TYPE_Fd:
	case SPA_TYPE_Long:
		put_int(d, NULL, *(int64_t*)body);
		break;
	case SPA_TYPE_Float:
		put_double(d, NULL, *(float*)body);
		break;
	case SPA_TYPE_Double:
		put_double(d, NULL, *(double*)body);
		break;
	case SPA_TYPE_String:
		put_string(d, NULL, (const char*)body);
		break;
	case SPA_TYPE_Rectangle:
	{
                struct spa_rectangle *r = (struct spa_rectangle *)body;
354
		put_begin(d, NULL, "{", STATE_SIMPLE);
Wim Taymans's avatar
Wim Taymans committed
355
356
		put_int(d, "width", r->width);
		put_int(d, "height", r->height);
357
		put_end(d, "}", STATE_SIMPLE);
Wim Taymans's avatar
Wim Taymans committed
358
359
360
361
362
		break;
	}
	case SPA_TYPE_Fraction:
	{
                struct spa_fraction *f = (struct spa_fraction *)body;
363
		put_begin(d, NULL, "{", STATE_SIMPLE);
Wim Taymans's avatar
Wim Taymans committed
364
365
		put_int(d, "num", f->num);
		put_int(d, "denom", f->denom);
366
		put_end(d, "}", STATE_SIMPLE);
Wim Taymans's avatar
Wim Taymans committed
367
368
369
370
371
372
		break;
	}
	case SPA_TYPE_Array:
	{
		struct spa_pod_array_body *b = (struct spa_pod_array_body *)body;
		void *p;
373
		info = info && info->values ? info->values: info;
374
		put_begin(d, NULL, "[", STATE_SIMPLE);
Wim Taymans's avatar
Wim Taymans committed
375
		SPA_POD_ARRAY_BODY_FOREACH(b, size, p)
Wim Taymans's avatar
Wim Taymans committed
376
			put_pod_value(d, NULL, info, b->child.type, p, b->child.size);
377
		put_end(d, "]", STATE_SIMPLE);
Wim Taymans's avatar
Wim Taymans committed
378
379
380
381
382
383
384
385
		break;
	}
	case SPA_TYPE_Choice:
	{
		struct spa_pod_choice_body *b = (struct spa_pod_choice_body *)body;
		int index = 0;

		if (b->type == SPA_CHOICE_None) {
Wim Taymans's avatar
Wim Taymans committed
386
			put_pod_value(d, NULL, info, b->child.type,
Wim Taymans's avatar
Wim Taymans committed
387
388
389
					SPA_POD_CONTENTS(struct spa_pod, &b->child),
					b->child.size);
		} else {
390
391
392
393
394
395
396
			static const char * const range_labels[] = { "default", "min", "max", NULL };
			static const char * const step_labels[] = { "default", "min", "max", "step", NULL };
			static const char * const enum_labels[] = { "default", "alt%u" };
			static const char * const flags_labels[] = { "default", "flag%u" };

			const char * const *labels;
			const char *label;
Wim Taymans's avatar
Wim Taymans committed
397
			char buffer[64];
Wim Taymans's avatar
Wim Taymans committed
398
			int max_labels, flags = 0;
399
			void *p;
Wim Taymans's avatar
Wim Taymans committed
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

			switch (b->type) {
			case SPA_CHOICE_Range:
				labels = range_labels;
				max_labels = 3;
				flags |= STATE_SIMPLE;
				break;
			case SPA_CHOICE_Step:
				labels = step_labels;
				max_labels = 4;
				flags |= STATE_SIMPLE;
				break;
			case SPA_CHOICE_Enum:
				labels = enum_labels;
				max_labels = 1;
				break;
			case SPA_CHOICE_Flags:
				labels = flags_labels;
				max_labels = 1;
				break;
			default:
				labels = NULL;
				break;
			}
			if (labels == NULL)
				break;
Wim Taymans's avatar
Wim Taymans committed
426

Wim Taymans's avatar
Wim Taymans committed
427
			put_begin(d, NULL, "{", flags);
Wim Taymans's avatar
Wim Taymans committed
428
			SPA_POD_CHOICE_BODY_FOREACH(b, size, p) {
Wim Taymans's avatar
Wim Taymans committed
429
				if ((label = labels[SPA_CLAMP(index, 0, max_labels)]) == NULL)
Wim Taymans's avatar
Wim Taymans committed
430
431
					break;
				snprintf(buffer, sizeof(buffer), label, index);
Wim Taymans's avatar
Wim Taymans committed
432
				put_pod_value(d, buffer, info, b->child.type, p, b->child.size);
Wim Taymans's avatar
Wim Taymans committed
433
434
				index++;
			}
Wim Taymans's avatar
Wim Taymans committed
435
			put_end(d, "}", flags);
Wim Taymans's avatar
Wim Taymans committed
436
437
438
439
440
		}
		break;
	}
	case SPA_TYPE_Object:
        {
Wim Taymans's avatar
Wim Taymans committed
441
		put_begin(d, NULL, "{", 0);
Wim Taymans's avatar
Wim Taymans committed
442
443
444
445
446
447
448
449
450
451
452
		struct spa_pod_object_body *b = (struct spa_pod_object_body *)body;
		struct spa_pod_prop *p;
		const struct spa_type_info *ti, *ii;

		ti = spa_debug_type_find(info, b->type);
		ii = ti ? spa_debug_type_find(ti->values, 0) : NULL;
		ii = ii ? spa_debug_type_find(ii->values, b->id) : NULL;

		info = ti ? ti->values : info;

		SPA_POD_OBJECT_BODY_FOREACH(b, size, p) {
453
454
455
			char fallback[32];
			const char *name;

Wim Taymans's avatar
Wim Taymans committed
456
			ii = spa_debug_type_find(info, p->key);
457
458
459
460
461
462
			name = ii ? spa_debug_type_short_name(ii->name) : NULL;
			if (name == NULL) {
				snprintf(fallback, sizeof(fallback), "id-%08x", p->key);
				name = fallback;
			}
			put_pod_value(d, name,
Wim Taymans's avatar
Wim Taymans committed
463
					ii ? ii->values : NULL,
Wim Taymans's avatar
Wim Taymans committed
464
465
466
467
468
469
470
471
472
473
					p->value.type,
					SPA_POD_CONTENTS(struct spa_pod_prop, p),
					p->value.size);
		}
		put_end(d, "}", 0);
		break;
	}
	case SPA_TYPE_Struct:
	{
		struct spa_pod *b = (struct spa_pod *)body, *p;
Wim Taymans's avatar
Wim Taymans committed
474
		put_begin(d, NULL, "[", 0);
Wim Taymans's avatar
Wim Taymans committed
475
		SPA_POD_FOREACH(b, size, p)
Wim Taymans's avatar
Wim Taymans committed
476
			put_pod_value(d, NULL, info, p->type, SPA_POD_BODY(p), p->size);
Wim Taymans's avatar
Wim Taymans committed
477
478
479
480
		put_end(d, "]", 0);
		break;
	}
	case SPA_TYPE_None:
Wim Taymans's avatar
Wim Taymans committed
481
		put_value(d, NULL, NULL);
Wim Taymans's avatar
Wim Taymans committed
482
483
484
		break;
	}
}
Wim Taymans's avatar
Wim Taymans committed
485
static void put_pod(struct data *d, const char *key, const struct spa_pod *pod)
Wim Taymans's avatar
Wim Taymans committed
486
{
487
488
489
490
491
492
493
494
	if (pod == NULL) {
		put_value(d, key, NULL);
	} else {
		put_pod_value(d, key, SPA_TYPE_ROOT,
				SPA_POD_TYPE(pod),
				SPA_POD_BODY(pod),
				SPA_POD_BODY_SIZE(pod));
	}
Wim Taymans's avatar
Wim Taymans committed
495
496
497
498
499
500
501
502
}

static void put_params(struct data *d, const char *key,
		struct spa_param_info *params, uint32_t n_params,
		struct spa_list *list)
{
	uint32_t i;

Wim Taymans's avatar
Wim Taymans committed
503
	put_begin(d, key, "{", 0);
Wim Taymans's avatar
Wim Taymans committed
504
505
506
507
508
	for (i = 0; i < n_params; i++) {
		struct spa_param_info *pi = &params[i];
		struct param *p;
		uint32_t flags;

509
		flags = pi->flags & SPA_PARAM_INFO_READ ? 0 : STATE_SIMPLE;
Wim Taymans's avatar
Wim Taymans committed
510

Wim Taymans's avatar
Wim Taymans committed
511
512
		put_begin(d, spa_debug_type_find_short_name(spa_type_param, pi->id),
				"[", flags);
Wim Taymans's avatar
Wim Taymans committed
513
		spa_list_for_each(p, list, link) {
Wim Taymans's avatar
Wim Taymans committed
514
			if (p->id == pi->id)
Wim Taymans's avatar
Wim Taymans committed
515
				put_pod(d, NULL, p->param);
Wim Taymans's avatar
Wim Taymans committed
516
517
518
519
520
521
		}
		put_end(d, "]", flags);
	}
	put_end(d, "}", 0);
}

Wim Taymans's avatar
Wim Taymans committed
522
struct flags_info {
523
524
525
526
	const char *name;
	uint64_t mask;
};

Wim Taymans's avatar
Wim Taymans committed
527
static void put_flags(struct data *d, const char *key,
528
		uint64_t flags, const struct flags_info *info)
529
530
{
	uint32_t i;
531
	put_begin(d, key, "[", STATE_SIMPLE);
532
	for (i = 0; info[i].name != NULL; i++) {
Wim Taymans's avatar
Wim Taymans committed
533
		if (info[i].mask & flags)
534
535
			put_string(d, NULL, info[i].name);
	}
536
	put_end(d, "]", STATE_SIMPLE);
537
538
}

Wim Taymans's avatar
Wim Taymans committed
539
540
541
/* core */
static void core_dump(struct object *o)
{
542
	static const struct flags_info fl[] = {
543
544
545
		{ "props", PW_CORE_CHANGE_MASK_PROPS },
		{ NULL, 0 },
	};
546
547
548
549

	struct data *d = o->data;
	struct pw_core_info *i = d->info;

Wim Taymans's avatar
Wim Taymans committed
550
	put_begin(d, "info", "{", 0);
Wim Taymans's avatar
Wim Taymans committed
551
552
553
554
555
	put_int(d, "cookie", i->cookie);
	put_value(d, "user-name", i->user_name);
	put_value(d, "host-name", i->host_name);
	put_value(d, "version", i->version);
	put_value(d, "name", i->name);
Wim Taymans's avatar
Wim Taymans committed
556
	put_flags(d, "change-mask", i->change_mask, fl);
Wim Taymans's avatar
Wim Taymans committed
557
558
559
560
561
562
563
564
	put_dict(d, "props", i->props);
	put_end(d, "}", 0);
}

static const struct class core_class = {
	.type = PW_TYPE_INTERFACE_Core,
	.version = PW_VERSION_CORE,
	.dump = core_dump,
Wim Taymans's avatar
Wim Taymans committed
565
	.name_key = PW_KEY_CORE_NAME,
Wim Taymans's avatar
Wim Taymans committed
566
567
568
569
570
};

/* client */
static void client_dump(struct object *o)
{
571
	static const struct flags_info fl[] = {
572
573
574
		{ "props", PW_CLIENT_CHANGE_MASK_PROPS },
		{ NULL, 0 },
	};
575
576
577
578

	struct data *d = o->data;
	struct pw_client_info *i = o->info;

Wim Taymans's avatar
Wim Taymans committed
579
580
	put_begin(d, "info", "{", 0);
	put_flags(d, "change-mask", i->change_mask, fl);
Wim Taymans's avatar
Wim Taymans committed
581
582
583
584
	put_dict(d, "props", i->props);
	put_end(d, "}", 0);
}

585
static void client_event_info(void *data, const struct pw_client_info *info)
Wim Taymans's avatar
Wim Taymans committed
586
{
587
	struct object *o = data;
Wim Taymans's avatar
Wim Taymans committed
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
	int changed = 0;

        pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->id, info->change_mask);

        info = o->info = pw_client_info_update(o->info, info);

	if (info->change_mask & PW_CLIENT_CHANGE_MASK_PROPS)
		changed++;

	if (changed) {
		o->changed += changed;
		core_sync(o->data);
	}
}

static const struct pw_client_events client_events = {
	PW_VERSION_CLIENT_EVENTS,
	.info = client_event_info,
};

static void client_destroy(struct object *o)
{
	if (o->info) {
		pw_client_info_free(o->info);
		o->info = NULL;
	}
}

static const struct class client_class = {
	.type = PW_TYPE_INTERFACE_Client,
	.version = PW_VERSION_CLIENT,
	.events = &client_events,
	.destroy = client_destroy,
	.dump = client_dump,
Wim Taymans's avatar
Wim Taymans committed
622
	.name_key = PW_KEY_APP_NAME,
Wim Taymans's avatar
Wim Taymans committed
623
624
625
626
627
};

/* module */
static void module_dump(struct object *o)
{
628
	static const struct flags_info fl[] = {
629
630
631
		{ "props", PW_MODULE_CHANGE_MASK_PROPS },
		{ NULL, 0 },
	};
632
633
634
635

	struct data *d = o->data;
	struct pw_module_info *i = o->info;

Wim Taymans's avatar
Wim Taymans committed
636
	put_begin(d, "info", "{", 0);
Wim Taymans's avatar
Wim Taymans committed
637
638
639
	put_value(d, "name", i->name);
	put_value(d, "filename", i->filename);
	put_value(d, "args", i->args);
Wim Taymans's avatar
Wim Taymans committed
640
	put_flags(d, "change-mask", i->change_mask, fl);
Wim Taymans's avatar
Wim Taymans committed
641
642
643
644
	put_dict(d, "props", i->props);
	put_end(d, "}", 0);
}

645
static void module_event_info(void *data, const struct pw_module_info *info)
Wim Taymans's avatar
Wim Taymans committed
646
{
647
        struct object *o = data;
Wim Taymans's avatar
Wim Taymans committed
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
	int changed = 0;

        pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->id, info->change_mask);

        info = o->info = pw_module_info_update(o->info, info);

	if (info->change_mask & PW_MODULE_CHANGE_MASK_PROPS)
		changed++;

	if (changed) {
		o->changed += changed;
		core_sync(o->data);
	}
}

static const struct pw_module_events module_events = {
	PW_VERSION_MODULE_EVENTS,
	.info = module_event_info,
};

static void module_destroy(struct object *o)
{
	if (o->info) {
		pw_module_info_free(o->info);
		o->info = NULL;
	}
}

static const struct class module_class = {
	.type = PW_TYPE_INTERFACE_Module,
	.version = PW_VERSION_MODULE,
	.events = &module_events,
	.destroy = module_destroy,
	.dump = module_dump,
Wim Taymans's avatar
Wim Taymans committed
682
	.name_key = PW_KEY_MODULE_NAME,
Wim Taymans's avatar
Wim Taymans committed
683
684
685
686
687
};

/* factory */
static void factory_dump(struct object *o)
{
688
	static const struct flags_info fl[] = {
689
690
691
		{ "props", PW_FACTORY_CHANGE_MASK_PROPS },
		{ NULL, 0 },
	};
692
693
694
695

	struct data *d = o->data;
	struct pw_factory_info *i = o->info;

Wim Taymans's avatar
Wim Taymans committed
696
	put_begin(d, "info", "{", 0);
Wim Taymans's avatar
Wim Taymans committed
697
698
699
	put_value(d, "name", i->name);
	put_value(d, "type", i->type);
	put_int(d, "version", i->version);
Wim Taymans's avatar
Wim Taymans committed
700
	put_flags(d, "change-mask", i->change_mask, fl);
Wim Taymans's avatar
Wim Taymans committed
701
702
703
704
	put_dict(d, "props", i->props);
	put_end(d, "}", 0);
}

705
static void factory_event_info(void *data, const struct pw_factory_info *info)
Wim Taymans's avatar
Wim Taymans committed
706
{
707
        struct object *o = data;
Wim Taymans's avatar
Wim Taymans committed
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
	int changed = 0;

        pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->id, info->change_mask);

        info = o->info = pw_factory_info_update(o->info, info);

	if (info->change_mask & PW_FACTORY_CHANGE_MASK_PROPS)
		changed++;

	if (changed) {
		o->changed += changed;
		core_sync(o->data);
	}
}

static const struct pw_factory_events factory_events = {
	PW_VERSION_FACTORY_EVENTS,
	.info = factory_event_info,
};

static void factory_destroy(struct object *o)
{
	if (o->info) {
		pw_factory_info_free(o->info);
		o->info = NULL;
	}
}

static const struct class factory_class = {
	.type = PW_TYPE_INTERFACE_Factory,
	.version = PW_VERSION_FACTORY,
	.events = &factory_events,
	.destroy = factory_destroy,
	.dump = factory_dump,
Wim Taymans's avatar
Wim Taymans committed
742
	.name_key = PW_KEY_FACTORY_NAME,
Wim Taymans's avatar
Wim Taymans committed
743
744
745
746
747
};

/* device */
static void device_dump(struct object *o)
{
748
	static const struct flags_info fl[] = {
749
750
751
752
		{ "props", PW_DEVICE_CHANGE_MASK_PROPS },
		{ "params", PW_DEVICE_CHANGE_MASK_PARAMS },
		{ NULL, 0 },
	};
753
754
755
756

	struct data *d = o->data;
	struct pw_device_info *i = o->info;

Wim Taymans's avatar
Wim Taymans committed
757
758
	put_begin(d, "info", "{", 0);
	put_flags(d, "change-mask", i->change_mask, fl);
Wim Taymans's avatar
Wim Taymans committed
759
760
761
762
763
	put_dict(d, "props", i->props);
	put_params(d, "params", i->params, i->n_params, &o->param_list);
	put_end(d, "}", 0);
}

764
static void device_event_info(void *data, const struct pw_device_info *info)
Wim Taymans's avatar
Wim Taymans committed
765
{
766
	struct object *o = data;
Wim Taymans's avatar
Wim Taymans committed
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
	uint32_t i, changed = 0;

	pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->id, info->change_mask);

	info = o->info = pw_device_info_update(o->info, info);

	if (info->change_mask & PW_DEVICE_CHANGE_MASK_PROPS)
		changed++;

	if (info->change_mask & PW_DEVICE_CHANGE_MASK_PARAMS) {
		for (i = 0; i < info->n_params; i++) {
			uint32_t id = info->params[i].id;

			if (info->params[i].user == 0)
				continue;
			info->params[i].user = 0;

			changed++;
			clear_params(&o->pending_list, id);
			if (!(info->params[i].flags & SPA_PARAM_INFO_READ))
				continue;

			pw_device_enum_params((struct pw_device*)o->proxy,
					0, id, 0, -1, NULL);
		}
	}
	if (changed) {
		o->changed += changed;
		core_sync(o->data);
	}
}

799
static void device_event_param(void *data, int seq,
Wim Taymans's avatar
Wim Taymans committed
800
801
802
		uint32_t id, uint32_t index, uint32_t next,
		const struct spa_pod *param)
{
803
	struct object *o = data;
Wim Taymans's avatar
Wim Taymans committed
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
	add_param(&o->pending_list, id, param);
}

static const struct pw_device_events device_events = {
	PW_VERSION_DEVICE_EVENTS,
	.info = device_event_info,
	.param = device_event_param,
};

static void device_destroy(struct object *o)
{
	if (o->info) {
		pw_device_info_free(o->info);
		o->info = NULL;
	}
}

static const struct class device_class = {
	.type = PW_TYPE_INTERFACE_Device,
	.version = PW_VERSION_DEVICE,
	.events = &device_events,
	.destroy = device_destroy,
	.dump = device_dump,
Wim Taymans's avatar
Wim Taymans committed
827
	.name_key = PW_KEY_DEVICE_NAME,
Wim Taymans's avatar
Wim Taymans committed
828
829
830
831
832
};

/* node */
static void node_dump(struct object *o)
{
833
	static const struct flags_info fl[] = {
834
835
836
837
838
839
840
		{ "input-ports", PW_NODE_CHANGE_MASK_INPUT_PORTS },
		{ "output-ports", PW_NODE_CHANGE_MASK_OUTPUT_PORTS },
		{ "state", PW_NODE_CHANGE_MASK_STATE },
		{ "props", PW_NODE_CHANGE_MASK_PROPS },
		{ "params", PW_NODE_CHANGE_MASK_PARAMS },
		{ NULL, 0 },
	};
841
842
843
844

	struct data *d = o->data;
	struct pw_node_info *i = o->info;

Wim Taymans's avatar
Wim Taymans committed
845
	put_begin(d, "info", "{", 0);
Wim Taymans's avatar
Wim Taymans committed
846
847
	put_int(d, "max-input-ports", i->max_input_ports);
	put_int(d, "max-output-ports", i->max_output_ports);
Wim Taymans's avatar
Wim Taymans committed
848
	put_flags(d, "change-mask", i->change_mask, fl);
Wim Taymans's avatar
Wim Taymans committed
849
850
851
852
853
854
855
856
857
	put_int(d, "n-input-ports", i->n_input_ports);
	put_int(d, "n-output-ports", i->n_output_ports);
	put_value(d, "state", pw_node_state_as_string(i->state));
	put_value(d, "error", i->error);
	put_dict(d, "props", i->props);
	put_params(d, "params", i->params, i->n_params, &o->param_list);
	put_end(d, "}", 0);
}

858
static void node_event_info(void *data, const struct pw_node_info *info)
Wim Taymans's avatar
Wim Taymans committed
859
{
860
	struct object *o = data;
Wim Taymans's avatar
Wim Taymans committed
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
	uint32_t i, changed = 0;

	pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->id, info->change_mask);

	info = o->info = pw_node_info_update(o->info, info);

	if (info->change_mask & PW_NODE_CHANGE_MASK_STATE)
		changed++;

	if (info->change_mask & PW_NODE_CHANGE_MASK_PROPS)
		changed++;

	if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
		for (i = 0; i < info->n_params; i++) {
			uint32_t id = info->params[i].id;

			if (info->params[i].user == 0)
				continue;
			info->params[i].user = 0;

			changed++;
Wim Taymans's avatar
Wim Taymans committed
882
			add_param(&o->pending_list, id, NULL);
Wim Taymans's avatar
Wim Taymans committed
883
884
885
886
887
888
889
890
891
892
893
894
895
			if (!(info->params[i].flags & SPA_PARAM_INFO_READ))
				continue;

			pw_node_enum_params((struct pw_node*)o->proxy,
					0, id, 0, -1, NULL);
		}
	}
	if (changed) {
		o->changed += changed;
		core_sync(o->data);
	}
}

896
static void node_event_param(void *data, int seq,
Wim Taymans's avatar
Wim Taymans committed
897
898
899
		uint32_t id, uint32_t index, uint32_t next,
		const struct spa_pod *param)
{
900
	struct object *o = data;
Wim Taymans's avatar
Wim Taymans committed
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
	add_param(&o->pending_list, id, param);
}

static const struct pw_node_events node_events = {
	PW_VERSION_NODE_EVENTS,
	.info = node_event_info,
	.param = node_event_param,
};

static void node_destroy(struct object *o)
{
	if (o->info) {
		pw_node_info_free(o->info);
		o->info = NULL;
	}
}

static const struct class node_class = {
	.type = PW_TYPE_INTERFACE_Node,
	.version = PW_VERSION_NODE,
	.events = &node_events,
	.destroy = node_destroy,
	.dump = node_dump,
Wim Taymans's avatar
Wim Taymans committed
924
	.name_key = PW_KEY_NODE_NAME,
Wim Taymans's avatar
Wim Taymans committed
925
926
927
928
929
};

/* port */
static void port_dump(struct object *o)
{
930
	static const struct flags_info fl[] = {
931
932
933
934
		{ "props", PW_PORT_CHANGE_MASK_PROPS },
		{ "params", PW_PORT_CHANGE_MASK_PARAMS },
		{ NULL, },
	};
935
936
937
938

	struct data *d = o->data;
	struct pw_port_info *i = o->info;

Wim Taymans's avatar
Wim Taymans committed
939
	put_begin(d, "info", "{", 0);
Wim Taymans's avatar
Wim Taymans committed
940
	put_value(d, "direction", pw_direction_as_string(i->direction));
Wim Taymans's avatar
Wim Taymans committed
941
	put_flags(d, "change-mask", i->change_mask, fl);
Wim Taymans's avatar
Wim Taymans committed
942
943
944
945
946
	put_dict(d, "props", i->props);
	put_params(d, "params", i->params, i->n_params, &o->param_list);
	put_end(d, "}", 0);
}

947
static void port_event_info(void *data, const struct pw_port_info *info)
Wim Taymans's avatar
Wim Taymans committed
948
{
949
	struct object *o = data;
Wim Taymans's avatar
Wim Taymans committed
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
	uint32_t i, changed = 0;

	pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->id, info->change_mask);

	info = o->info = pw_port_info_update(o->info, info);

	if (info->change_mask & PW_PORT_CHANGE_MASK_PROPS)
		changed++;

	if (info->change_mask & PW_PORT_CHANGE_MASK_PARAMS) {
		for (i = 0; i < info->n_params; i++) {
			uint32_t id = info->params[i].id;

			if (info->params[i].user == 0)
				continue;
			info->params[i].user = 0;

			changed++;
Wim Taymans's avatar
Wim Taymans committed
968
			add_param(&o->pending_list, id, NULL);
Wim Taymans's avatar
Wim Taymans committed
969
970
971
972
973
974
975
976
977
978
979
980
981
			if (!(info->params[i].flags & SPA_PARAM_INFO_READ))
				continue;

			pw_port_enum_params((struct pw_port*)o->proxy,
					0, id, 0, -1, NULL);
		}
	}
	if (changed) {
		o->changed += changed;
		core_sync(o->data);
	}
}

982
static void port_event_param(void *data, int seq,
Wim Taymans's avatar
Wim Taymans committed
983
984
985
		uint32_t id, uint32_t index, uint32_t next,
		const struct spa_pod *param)
{
986
	struct object *o = data;
Wim Taymans's avatar
Wim Taymans committed
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
	add_param(&o->pending_list, id, param);
}

static const struct pw_port_events port_events = {
	PW_VERSION_PORT_EVENTS,
	.info = port_event_info,
	.param = port_event_param,
};

static void port_destroy(struct object *o)
{
	if (o->info) {
		pw_port_info_free(o->info);
		o->info = NULL;