summaryrefslogtreecommitdiff
path: root/src/pipewire/private.h
blob: 5f83dce02c16011582fbe469c1c859dbece9996b (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
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
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
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
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
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
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
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
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
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
/* PipeWire
 *
 * Copyright © 2018 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.
 */

#ifndef PIPEWIRE_PRIVATE_H
#define PIPEWIRE_PRIVATE_H

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/socket.h>
#include <sys/types.h> /* for pthread_t */

#include "pipewire/impl.h"

#include <spa/support/plugin.h>
#include <spa/pod/builder.h>
#include <spa/utils/result.h>
#include <spa/utils/type-info.h>

#ifdef __FreeBSD__
struct ucred {
};
#endif

#ifndef spa_debug
#define spa_debug(...) pw_log_trace(__VA_ARGS__)
#endif

struct defaults {
	uint32_t clock_rate;
	uint32_t clock_quantum;
	uint32_t clock_min_quantum;
	uint32_t clock_max_quantum;
	struct spa_rectangle video_size;
	struct spa_fraction video_rate;
	uint32_t link_max_buffers;
	unsigned int mem_allow_mlock;
};

struct ratelimit {
	uint64_t interval;
	uint64_t begin;
	unsigned burst;
	unsigned n_printed, n_missed;
};

static inline bool ratelimit_test(struct ratelimit *r, uint64_t now)
{
	if (r->begin + r->interval < now) {
		if (r->n_missed)
			pw_log_warn("%u events suppressed", r->n_missed);
		r->begin = now;
		r->n_printed = 0;
		r->n_missed = 0;
	} else if (r->n_printed >= r->burst) {
		r->n_missed++;
		return false;
	}
	r->n_printed++;
	return true;
}

#define MAX_PARAMS	32

#define pw_protocol_emit_destroy(p) spa_hook_list_call(&p->listener_list, struct pw_protocol_events, destroy, 0)

struct pw_protocol {
	struct spa_list link;                   /**< link in context protocol_list */
	struct pw_context *context;                   /**< context for this protocol */

	char *name;                             /**< type name of the protocol */

	struct spa_list marshal_list;           /**< list of marshallers for supported interfaces */
	struct spa_list client_list;            /**< list of current clients */
	struct spa_list server_list;            /**< list of current servers */
	struct spa_hook_list listener_list;	/**< event listeners */

	const struct pw_protocol_implementaton *implementation; /**< implementation of the protocol */

	const void *extension;  /**< extension API */

	void *user_data;        /**< user data for the implementation */
};

/** the permission function. It returns the allowed access permissions for \a global
  * for \a client */
typedef uint32_t (*pw_permission_func_t) (struct pw_global *global,
					  struct pw_impl_client *client, void *data);

#define pw_impl_client_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_client_events, m, v, ##__VA_ARGS__)

#define pw_impl_client_emit_destroy(o)			pw_impl_client_emit(o, destroy, 0)
#define pw_impl_client_emit_free(o)			pw_impl_client_emit(o, free, 0)
#define pw_impl_client_emit_initialized(o)		pw_impl_client_emit(o, initialized, 0)
#define pw_impl_client_emit_info_changed(o,i)		pw_impl_client_emit(o, info_changed, 0, i)
#define pw_impl_client_emit_resource_added(o,r)		pw_impl_client_emit(o, resource_added, 0, r)
#define pw_impl_client_emit_resource_impl(o,r)		pw_impl_client_emit(o, resource_impl, 0, r)
#define pw_impl_client_emit_resource_removed(o,r)	pw_impl_client_emit(o, resource_removed, 0, r)
#define pw_impl_client_emit_busy_changed(o,b)		pw_impl_client_emit(o, busy_changed, 0, b)

enum spa_node0_event {
	SPA_NODE0_EVENT_START	= SPA_TYPE_VENDOR_PipeWire,
	SPA_NODE0_EVENT_RequestClockUpdate,
};

enum spa_node0_command {
	SPA_NODE0_COMMAND_START	= SPA_TYPE_VENDOR_PipeWire,
	SPA_NODE0_COMMAND_ClockUpdate,
};

struct protocol_compat_v2 {
	/* v2 typemap */
	struct pw_map types;
	unsigned int send_types:1;
};

#define pw_impl_core_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_impl_core_events, m, v, ##__VA_ARGS__)

#define pw_impl_core_emit_destroy(s)		pw_impl_core_emit(s, destroy, 0)
#define pw_impl_core_emit_free(s)		pw_impl_core_emit(s, free, 0)
#define pw_impl_core_emit_initialized(s)	pw_impl_core_emit(s, initialized, 0)

struct pw_impl_core {
	struct pw_context *context;
	struct spa_list link;			/**< link in context object core_impl list */
	struct pw_global *global;		/**< global object created for this core */
	struct spa_hook global_listener;

	struct pw_properties *properties;	/**< core properties */
	struct pw_core_info info;		/**< core info */

	struct spa_hook_list listener_list;
	void *user_data;			/**< extra user data */

	unsigned int registered:1;
};

struct pw_impl_client {
	struct pw_impl_core *core;		/**< core object */
	struct pw_context *context;		/**< context object */

	struct spa_list link;			/**< link in context object client list */
	struct pw_global *global;		/**< global object created for this client */
	struct spa_hook global_listener;

	pw_permission_func_t permission_func;	/**< get permissions of an object */
	void *permission_data;			/**< data passed to permission function */

	struct pw_properties *properties;	/**< Client properties */

	struct pw_client_info info;	/**< client info */

	struct pw_mempool *pool;		/**< client mempool */
	struct pw_resource *core_resource;	/**< core resource object */
	struct pw_resource *client_resource;	/**< client resource object */

	struct pw_map objects;		/**< list of resource objects */

	struct spa_hook_list listener_list;

	struct pw_protocol *protocol;	/**< protocol in use */
	int recv_seq;			/**< last received sequence number */
	int send_seq;			/**< last sender sequence number */

	void *user_data;		/**< extra user data */

	struct ucred ucred;		/**< ucred information */
	unsigned int registered:1;
	unsigned int ucred_valid:1;	/**< if the ucred member is valid */
	unsigned int busy:1;

	/* v2 compatibility data */
	void *compat_v2;
};

#define pw_global_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_global_events, m, v, ##__VA_ARGS__)

#define pw_global_emit_registering(g)	pw_global_emit(g, registering, 0)
#define pw_global_emit_destroy(g)	pw_global_emit(g, destroy, 0)
#define pw_global_emit_free(g)		pw_global_emit(g, free, 0)
#define pw_global_emit_permissions_changed(g,...)	pw_global_emit(g, permissions_changed, 0, __VA_ARGS__)

struct pw_global {
	struct pw_context *context;		/**< the context */

	struct spa_list link;		/**< link in context list of globals */
	uint32_t id;			/**< server id of the object */

	struct pw_properties *properties;	/**< properties of the global */

	struct spa_hook_list listener_list;

	const char *type;		/**< type of interface */
	uint32_t version;		/**< version of interface */

	pw_global_bind_func_t func;	/**< bind function */
	void *object;			/**< object associated with the interface */

	struct spa_list resource_list;	/**< The list of resources of this global */
};

#define pw_core_resource(r,m,v,...)	pw_resource_call(r, struct pw_core_events, m, v, ##__VA_ARGS__)
#define pw_core_resource_info(r,...)		pw_core_resource(r,info,0,__VA_ARGS__)
#define pw_core_resource_done(r,...)		pw_core_resource(r,done,0,__VA_ARGS__)
#define pw_core_resource_ping(r,...)		pw_core_resource(r,ping,0,__VA_ARGS__)
#define pw_core_resource_error(r,...)		pw_core_resource(r,error,0,__VA_ARGS__)
#define pw_core_resource_remove_id(r,...)	pw_core_resource(r,remove_id,0,__VA_ARGS__)
#define pw_core_resource_bound_id(r,...)	pw_core_resource(r,bound_id,0,__VA_ARGS__)
#define pw_core_resource_add_mem(r,...)		pw_core_resource(r,add_mem,0,__VA_ARGS__)
#define pw_core_resource_remove_mem(r,...)	pw_core_resource(r,remove_mem,0,__VA_ARGS__)

static inline SPA_PRINTF_FUNC(5,0) void
pw_core_resource_errorv(struct pw_resource *resource, 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';
	pw_log_debug("resource %p: id:%d seq:%d res:%d (%s) msg:\"%s\"",
			resource, id, seq, res, spa_strerror(res), buffer);
	pw_core_resource_error(resource, id, seq, res, buffer);
}

static inline SPA_PRINTF_FUNC(5,6) void
pw_core_resource_errorf(struct pw_resource *resource, uint32_t id, int seq,
		int res, const char *message, ...)
{
        va_list args;
	va_start(args, message);
	pw_core_resource_errorv(resource, id, seq, res, message, args);
	va_end(args);
}

#define pw_context_driver_emit(c,m,v,...) spa_hook_list_call_simple(&c->driver_listener_list, struct pw_context_driver_events, m, v, ##__VA_ARGS__)
#define pw_context_driver_emit_start(c,n)	pw_context_driver_emit(c, start, 0, n)
#define pw_context_driver_emit_xrun(c,n)	pw_context_driver_emit(c, xrun, 0, n)
#define pw_context_driver_emit_incomplete(c,n)	pw_context_driver_emit(c, incomplete, 0, n)
#define pw_context_driver_emit_timeout(c,n)	pw_context_driver_emit(c, timeout, 0, n)
#define pw_context_driver_emit_drained(c,n)	pw_context_driver_emit(c, drained, 0, n)

struct pw_context_driver_events {
#define PW_VERSION_CONTEXT_DRIVER_EVENTS	0
	uint32_t version;

	/** The driver graph is started */
	void (*start) (void *data, struct pw_impl_node *node);
	/** The driver under/overruns */
	void (*xrun) (void *data, struct pw_impl_node *node);
	/** The driver could not complete the graph */
	void (*incomplete) (void *data, struct pw_impl_node *node);
	/** The driver got a sync timeout */
	void (*timeout) (void *data, struct pw_impl_node *node);
	/** a node drained */
	void (*drained) (void *data, struct pw_impl_node *node);
};

#define pw_registry_resource(r,m,v,...) pw_resource_call(r, struct pw_registry_events,m,v,##__VA_ARGS__)
#define pw_registry_resource_global(r,...)        pw_registry_resource(r,global,0,__VA_ARGS__)
#define pw_registry_resource_global_remove(r,...) pw_registry_resource(r,global_remove,0,__VA_ARGS__)

#define pw_context_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_context_events, m, v, ##__VA_ARGS__)
#define pw_context_emit_destroy(c)		pw_context_emit(c, destroy, 0)
#define pw_context_emit_free(c)			pw_context_emit(c, free, 0)
#define pw_context_emit_info_changed(c,i)	pw_context_emit(c, info_changed, 0, i)
#define pw_context_emit_check_access(c,cl)	pw_context_emit(c, check_access, 0, cl)
#define pw_context_emit_global_added(c,g)	pw_context_emit(c, global_added, 0, g)
#define pw_context_emit_global_removed(c,g)	pw_context_emit(c, global_removed, 0, g)

struct pw_context {
	struct pw_impl_core *core;		/**< core object */

	struct pw_properties *properties;	/**< properties of the context */

	struct defaults defaults;		/**< default parameters */

	struct pw_mempool *pool;		/**< global memory pool */

	struct pw_map globals;			/**< map of globals */

	struct spa_list core_impl_list;		/**< list of core_imp */
	struct spa_list protocol_list;		/**< list of protocols */
	struct spa_list core_list;		/**< list of core connections */
	struct spa_list registry_resource_list;	/**< list of registry resources */
	struct spa_list module_list;		/**< list of modules */
	struct spa_list device_list;		/**< list of devices */
	struct spa_list global_list;		/**< list of globals */
	struct spa_list client_list;		/**< list of clients */
	struct spa_list node_list;		/**< list of nodes */
	struct spa_list factory_list;		/**< list of factories */
	struct spa_list link_list;		/**< list of links */
	struct spa_list control_list[2];	/**< list of controls, indexed by direction */
	struct spa_list export_list;		/**< list of export types */
	struct spa_list driver_list;		/**< list of driver nodes */

	struct spa_hook_list driver_listener_list;
	struct spa_hook_list listener_list;

	struct pw_loop *main_loop;	/**< main loop for control */
	struct pw_loop *data_loop;	/**< data loop for data passing */
        struct pw_data_loop *data_loop_impl;
	struct spa_system *data_system;	/**< data system for data passing */

	struct spa_support support[16];	/**< support for spa plugins */
	uint32_t n_support;		/**< number of support items */
	struct pw_array factory_lib;	/**< mapping of factory_name regexp to library */

	struct pw_array objects;	/**< objects */

	struct pw_impl_client *current_client;	/**< client currently executing code in mainloop */

	long sc_pagesize;

	void *user_data;		/**< extra user data */
};

#define pw_data_loop_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_data_loop_events, m, v, ##__VA_ARGS__)
#define pw_data_loop_emit_destroy(o) pw_data_loop_emit(o, destroy, 0)

struct pw_data_loop {
	struct pw_loop *loop;

	struct spa_hook_list listener_list;
	struct spa_source *event;

	pthread_t thread;
	unsigned int created:1;
	unsigned int running:1;
};

#define pw_main_loop_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_main_loop_events, m, v, ##__VA_ARGS__)
#define pw_main_loop_emit_destroy(o) pw_main_loop_emit(o, destroy, 0)

struct pw_main_loop {
        struct pw_loop *loop;

	struct spa_hook_list listener_list;
	struct spa_source *event;

	unsigned int created:1;
	unsigned int running:1;
};

#define pw_impl_device_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_device_events, m, v, ##__VA_ARGS__)
#define pw_impl_device_emit_destroy(m)		pw_impl_device_emit(m, destroy, 0)
#define pw_impl_device_emit_free(m)		pw_impl_device_emit(m, free, 0)
#define pw_impl_device_emit_initialized(m)	pw_impl_device_emit(m, initialized, 0)
#define pw_impl_device_emit_info_changed(n,i)	pw_impl_device_emit(n, info_changed, 0, i)

struct pw_impl_device {
	struct pw_context *context;           /**< the context object */
	struct spa_list link;           /**< link in the context device_list */
	struct pw_global *global;       /**< global object for this device */
	struct spa_hook global_listener;

	struct pw_properties *properties;	/**< properties of the device */
	struct pw_device_info info;		/**< introspectable device info */
	struct spa_param_info params[MAX_PARAMS];

	char *name;				/**< device name for debug */

	struct spa_device *device;		/**< device implementation */
	struct spa_hook listener;
	struct spa_hook_list listener_list;

	struct spa_list object_list;

	void *user_data;                /**< device user_data */

	unsigned int registered:1;
};

#define pw_impl_module_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_module_events, m, v, ##__VA_ARGS__)
#define pw_impl_module_emit_destroy(m)		pw_impl_module_emit(m, destroy, 0)
#define pw_impl_module_emit_free(m)		pw_impl_module_emit(m, free, 0)
#define pw_impl_module_emit_initialized(m)	pw_impl_module_emit(m, initialized, 0)
#define pw_impl_module_emit_registered(m)	pw_impl_module_emit(m, registered, 0)

struct pw_impl_module {
	struct pw_context *context;	/**< the context object */
	struct spa_list link;		/**< link in the context module_list */
	struct pw_global *global;	/**< global object for this module */
	struct spa_hook global_listener;

	struct pw_properties *properties;	/**< properties of the module */
	struct pw_module_info info;	/**< introspectable module info */

	struct spa_hook_list listener_list;

	void *user_data;		/**< module user_data */
};

struct pw_node_activation_state {
	int status;                     /**< current status, the result of spa_node_process() */
	int32_t required;		/**< required number of signals */
	int32_t pending;		/**< number of pending signals */
};

static inline void pw_node_activation_state_reset(struct pw_node_activation_state *state)
{
        state->pending = state->required;
}

#define pw_node_activation_state_dec(s,c) (__atomic_sub_fetch(&(s)->pending, c, __ATOMIC_SEQ_CST) == 0)

struct pw_node_target {
	struct spa_list link;
	struct pw_impl_node *node;
	struct pw_node_activation *activation;
	int (*signal) (void *data);
	void *data;
};

struct pw_node_activation {
#define PW_NODE_ACTIVATION_NOT_TRIGGERED	0
#define PW_NODE_ACTIVATION_TRIGGERED		1
#define PW_NODE_ACTIVATION_AWAKE		2
#define PW_NODE_ACTIVATION_FINISHED		3
	uint32_t status;

	unsigned int version:1;
	unsigned int pending_sync:1;			/* a sync is pending */
	unsigned int pending_new_pos:1;			/* a new position is pending */

	struct pw_node_activation_state state[2];	/* one current state and one next state,
							 * as version flag */
	uint64_t signal_time;
	uint64_t awake_time;
	uint64_t finish_time;
	uint64_t prev_signal_time;

	/* updates */
	struct spa_io_segment reposition;		/* reposition info, used when driver reposition_owner
							 * has this node id */
	struct spa_io_segment segment;			/* update for the extra segment info fields.
							 * used when driver segment_owner has this node id */

	/* for drivers, shared with all nodes */
	uint32_t segment_owner[32];			/* id of owners for each segment info struct.
							 * nodes that want to update segment info need to
							 * CAS their node id in this array. */
	struct spa_io_position position;		/* contains current position and segment info.
							 * extra info is updated by nodes that have set
							 * themselves as owner in the segment structs */

	uint64_t sync_timeout;				/* sync timeout in nanoseconds
							 * position goes to RUNNING without waiting any
							 * longer for sync clients. */
	uint64_t sync_left;				/* number of cycles before timeout */


	float cpu_load[3];				/* averaged over short, medium, long time */
	uint32_t xrun_count;				/* number of xruns */
	uint64_t xrun_time;				/* time of last xrun in microseconds */
	uint64_t xrun_delay;				/* delay of last xrun in microseconds */
	uint64_t max_delay;				/* max of all xruns in microseconds */

#define PW_NODE_ACTIVATION_COMMAND_NONE		0
#define PW_NODE_ACTIVATION_COMMAND_START	1
#define PW_NODE_ACTIVATION_COMMAND_STOP		2
	uint32_t command;				/* next command */
	uint32_t reposition_owner;			/* owner id with new reposition info, last one
							 * to update wins */
};

#define ATOMIC_CAS(v,ov,nv)						\
({									\
	__typeof__(v) __ov = (ov);					\
	__atomic_compare_exchange_n(&(v), &__ov, (nv),			\
			0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);		\
})

#define ATOMIC_DEC(s)			__atomic_sub_fetch(&(s), 1, __ATOMIC_SEQ_CST)
#define ATOMIC_INC(s)			__atomic_add_fetch(&(s), 1, __ATOMIC_SEQ_CST)
#define ATOMIC_LOAD(s)			__atomic_load_n(&(s), __ATOMIC_SEQ_CST)
#define ATOMIC_STORE(s,v)		__atomic_store_n(&(s), (v), __ATOMIC_SEQ_CST)
#define ATOMIC_XCHG(s,v)		__atomic_exchange_n(&(s), (v), __ATOMIC_SEQ_CST)

#define SEQ_WRITE(s)			ATOMIC_INC(s)
#define SEQ_WRITE_SUCCESS(s1,s2)	((s1) + 1 == (s2) && ((s2) & 1) == 0)

#define SEQ_READ(s)			ATOMIC_LOAD(s)
#define SEQ_READ_SUCCESS(s1,s2)		((s1) == (s2) && ((s2) & 1) == 0)

#define pw_impl_node_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_node_events, m, v, ##__VA_ARGS__)
#define pw_impl_node_emit_destroy(n)			pw_impl_node_emit(n, destroy, 0)
#define pw_impl_node_emit_free(n)			pw_impl_node_emit(n, free, 0)
#define pw_impl_node_emit_initialized(n)		pw_impl_node_emit(n, initialized, 0)
#define pw_impl_node_emit_port_init(n,p)		pw_impl_node_emit(n, port_init, 0, p)
#define pw_impl_node_emit_port_added(n,p)		pw_impl_node_emit(n, port_added, 0, p)
#define pw_impl_node_emit_port_removed(n,p)		pw_impl_node_emit(n, port_removed, 0, p)
#define pw_impl_node_emit_info_changed(n,i)		pw_impl_node_emit(n, info_changed, 0, i)
#define pw_impl_node_emit_port_info_changed(n,p,i)	pw_impl_node_emit(n, port_info_changed, 0, p, i)
#define pw_impl_node_emit_active_changed(n,a)		pw_impl_node_emit(n, active_changed, 0, a)
#define pw_impl_node_emit_state_request(n,s)		pw_impl_node_emit(n, state_request, 0, s)
#define pw_impl_node_emit_state_changed(n,o,s,e)	pw_impl_node_emit(n, state_changed, 0, o, s, e)
#define pw_impl_node_emit_async_complete(n,s,r)		pw_impl_node_emit(n, async_complete, 0, s, r)
#define pw_impl_node_emit_result(n,s,r,t,result)	pw_impl_node_emit(n, result, 0, s, r, t, result)
#define pw_impl_node_emit_event(n,e)			pw_impl_node_emit(n, event, 0, e)
#define pw_impl_node_emit_driver_changed(n,o,d)		pw_impl_node_emit(n, driver_changed, 0, o, d)
#define pw_impl_node_emit_peer_added(n,p)		pw_impl_node_emit(n, peer_added, 0, p)
#define pw_impl_node_emit_peer_removed(n,p)		pw_impl_node_emit(n, peer_removed, 0, p)
#define pw_impl_node_emit_enabled_changed(n,e)		pw_impl_node_emit(n, enabled_changed, 1, e)

struct pw_impl_node {
	struct pw_context *context;		/**< context object */
	struct spa_list link;		/**< link in context node_list */
	struct pw_global *global;	/**< global for this node */
	struct spa_hook global_listener;

	struct pw_properties *properties;	/**< properties of the node */

	struct pw_node_info info;		/**< introspectable node info */
	struct spa_param_info params[MAX_PARAMS];

	char *name;				/** for debug */

	uint32_t priority_driver;	/** priority for being driver */
	uint32_t group_id;		/** group to schedule this node in */
	uint32_t spa_flags;

	unsigned int registered:1;
	unsigned int active:1;		/**< if the node is active */
	unsigned int live:1;		/**< if the node is live */
	unsigned int driver:1;		/**< if the node can drive the graph */
	unsigned int exported:1;	/**< if the node is exported */
	unsigned int remote:1;		/**< if the node is implemented remotely */
	unsigned int driving:1;		/**< a driving node is one of the driver nodes that
					  *  is selected to drive the graph */
	unsigned int visited:1;		/**< for sorting */
	unsigned int want_driver:1;	/**< this node wants to be assigned to a driver */
	unsigned int passive:1;		/**< driver graph only has passive links */
	unsigned int enabled:1;		/**< if the node is enabled */

	uint32_t port_user_data_size;	/**< extra size for port user data */

	struct spa_list driver_link;
	struct pw_impl_node *driver_node;
	struct spa_list follower_list;
	struct spa_list follower_link;

	struct spa_list sort_link;	/**< link used to sort nodes */

	struct spa_node *node;		/**< SPA node implementation */
	struct spa_hook listener;

	struct spa_list input_ports;		/**< list of input ports */
	struct pw_map input_port_map;		/**< map from port_id to port */
	struct spa_list output_ports;		/**< list of output ports */
	struct pw_map output_port_map;		/**< map from port_id to port */

	struct spa_hook_list listener_list;

	struct pw_loop *data_loop;		/**< the data loop for this node */

	uint32_t quantum_size;			/**< desired quantum */
	struct spa_source source;		/**< source to remotely trigger this node */
	struct pw_memblock *activation;
	struct {
		struct spa_io_clock *clock;	/**< io area of the clock or NULL */
		struct spa_io_position *position;
		struct pw_node_activation *activation;

		struct spa_list target_list;		/* list of targets to signal after
							 * this node */
		struct pw_node_target driver_target;	/* driver target that we signal */
		struct spa_list input_mix;		/* our input ports (and mixers) */
		struct spa_list output_mix;		/* output ports (and mixers) */

		struct pw_node_target target;		/* our target that is signaled by the
							   driver */
		struct spa_list driver_link;		/* our link in driver */

		struct ratelimit rate_limit;
	} rt;

        void *user_data;                /**< extra user data */
};

struct pw_impl_port_mix {
	struct spa_list link;
	struct spa_list rt_link;
	struct pw_impl_port *p;
	struct {
		enum spa_direction direction;
		uint32_t port_id;
	} port;
	struct spa_io_buffers *io;
	uint32_t id;
	unsigned int have_buffers:1;
};

struct pw_impl_port_implementation {
#define PW_VERSION_PORT_IMPLEMENTATION       0
	uint32_t version;

	int (*init_mix) (void *data, struct pw_impl_port_mix *mix);
	int (*release_mix) (void *data, struct pw_impl_port_mix *mix);
};

#define pw_impl_port_call(p,m,v,...)				\
({								\
	int _res = 0;						\
	spa_callbacks_call_res(&(p)->impl,			\
			struct pw_impl_port_implementation,	\
			_res, m, v, ## __VA_ARGS__);		\
	_res;							\
})

#define pw_impl_port_call_init_mix(p,m)		pw_impl_port_call(p,init_mix,0,m)
#define pw_impl_port_call_release_mix(p,m)	pw_impl_port_call(p,release_mix,0,m)

#define pw_impl_port_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_port_events, m, v, ##__VA_ARGS__)
#define pw_impl_port_emit_destroy(p)			pw_impl_port_emit(p, destroy, 0)
#define pw_impl_port_emit_free(p)			pw_impl_port_emit(p, free, 0)
#define pw_impl_port_emit_initialized(p)		pw_impl_port_emit(p, initialized, 0)
#define pw_impl_port_emit_info_changed(p,i)		pw_impl_port_emit(p, info_changed, 0, i)
#define pw_impl_port_emit_link_added(p,l)		pw_impl_port_emit(p, link_added, 0, l)
#define pw_impl_port_emit_link_removed(p,l)		pw_impl_port_emit(p, link_removed, 0, l)
#define pw_impl_port_emit_state_changed(p,o,s,e)	pw_impl_port_emit(p, state_changed, 0, o, s, e)
#define pw_impl_port_emit_control_added(p,c)		pw_impl_port_emit(p, control_added, 0, c)
#define pw_impl_port_emit_control_removed(p,c)		pw_impl_port_emit(p, control_removed, 0, c)
#define pw_impl_port_emit_param_changed(p,i)		pw_impl_port_emit(p, param_changed, 1, i)

#define PW_IMPL_PORT_IS_CONTROL(port)	SPA_FLAG_MASK(port->flags, \
						PW_IMPL_PORT_FLAG_BUFFERS|PW_IMPL_PORT_FLAG_CONTROL,\
						PW_IMPL_PORT_FLAG_CONTROL)
struct pw_impl_port {
	struct spa_list link;		/**< link in node port_list */

	struct pw_impl_node *node;		/**< owner node */
	struct pw_global *global;	/**< global for this port */
	struct spa_hook global_listener;

#define PW_IMPL_PORT_FLAG_TO_REMOVE		(1<<0)		/**< if the port should be removed from the
								  *  implementation when destroyed */
#define PW_IMPL_PORT_FLAG_BUFFERS		(1<<1)		/**< port has data */
#define PW_IMPL_PORT_FLAG_CONTROL		(1<<2)		/**< port has control */
#define PW_IMPL_PORT_FLAG_NO_MIXER		(1<<3)		/**< don't try to add mixer to port */
	uint32_t flags;
	uint32_t spa_flags;

	enum pw_direction direction;	/**< port direction */
	uint32_t port_id;		/**< port id */

	enum pw_impl_port_state state;	/**< state of the port */
	const char *error;		/**< error state */

	struct pw_properties *properties;	/**< properties of the port */
	struct pw_port_info info;
	struct spa_param_info params[MAX_PARAMS];

	struct pw_buffers buffers;	/**< buffers managed by this port, only on
					  *  output ports, shared with all links */

	struct spa_list links;		/**< list of \ref pw_impl_link */

	struct spa_list control_list[2];/**< list of \ref pw_control indexed by direction */

	struct spa_hook_list listener_list;

	struct spa_callbacks impl;

	struct spa_node *mix;		/**< port buffer mix/split */
#define PW_IMPL_PORT_MIX_FLAG_MULTI	(1<<0)	/**< multi input or output */
#define PW_IMPL_PORT_MIX_FLAG_MIX_ONLY	(1<<1)	/**< only negotiate mix ports */
#define PW_IMPL_PORT_MIX_FLAG_NEGOTIATE	(1<<2)	/**< negotiate buffers  */
	uint32_t mix_flags;		/**< flags for the mixing */
	struct spa_handle *mix_handle;	/**< mix plugin handle */
	struct pw_buffers mix_buffers;	/**< buffers between mixer and node */

	struct spa_list mix_list;	/**< list of \ref pw_impl_port_mix */
	struct pw_map mix_port_map;	/**< map from port_id from mixer */
	uint32_t n_mix;

	struct {
		struct spa_io_buffers io;	/**< io area of the port */
		struct spa_io_clock clock;	/**< io area of the clock */
		struct spa_list mix_list;
		struct spa_list node_link;
	} rt;					/**< data only accessed from the data thread */

        void *owner_data;		/**< extra owner data */
        void *user_data;                /**< extra user data */
};

struct pw_control_link {
	struct spa_list out_link;
	struct spa_list in_link;
	struct pw_control *output;
	struct pw_control *input;
	uint32_t out_port;
	uint32_t in_port;
	unsigned int valid:1;
};

#define pw_impl_link_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_link_events, m, v, ##__VA_ARGS__)
#define pw_impl_link_emit_destroy(l)		pw_impl_link_emit(l, destroy, 0)
#define pw_impl_link_emit_free(l)		pw_impl_link_emit(l, free, 0)
#define pw_impl_link_emit_initialized(l)	pw_impl_link_emit(l, initialized, 0)
#define pw_impl_link_emit_info_changed(l,i)	pw_impl_link_emit(l, info_changed, 0, i)
#define pw_impl_link_emit_state_changed(l,...)	pw_impl_link_emit(l, state_changed, 0, __VA_ARGS__)
#define pw_impl_link_emit_port_unlinked(l,p)	pw_impl_link_emit(l, port_unlinked, 0, p)

struct pw_impl_link {
	struct pw_context *context;		/**< context object */
	struct spa_list link;			/**< link in context link_list */
	struct pw_global *global;		/**< global for this link */
	struct spa_hook global_listener;

	char *name;

	struct pw_link_info info;		/**< introspectable link info */
	struct pw_properties *properties;	/**< extra link properties */

	struct spa_io_buffers *io;		/**< link io area */

	struct pw_impl_port *output;		/**< output port */
	struct spa_list output_link;		/**< link in output port links */
	struct pw_impl_port *input;		/**< input port */
	struct spa_list input_link;		/**< link in input port links */

	struct spa_hook_list listener_list;

	struct pw_control_link control;
	struct pw_control_link notify;

	struct {
		struct pw_impl_port_mix out_mix;	/**< port added to the output mixer */
		struct pw_impl_port_mix in_mix;		/**< port added to the input mixer */
		struct pw_node_target target;		/**< target to trigger the input node */
	} rt;

	void *user_data;

	unsigned int registered:1;
	unsigned int feedback:1;
	unsigned int preparing:1;
	unsigned int prepared:1;
	unsigned int passive:1;
};

#define pw_resource_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_resource_events, m, v, ##__VA_ARGS__)

#define pw_resource_emit_destroy(o)	pw_resource_emit(o, destroy, 0)
#define pw_resource_emit_pong(o,s)	pw_resource_emit(o, pong, 0, s)
#define pw_resource_emit_error(o,s,r,m)	pw_resource_emit(o, error, 0, s, r, m)

struct pw_resource {
	struct spa_interface impl;	/**< object implementation */

	struct pw_context *context;	/**< the context object */
	struct pw_global *global;	/**< global of resource */
	struct spa_list link;		/**< link in global resource_list */

	struct pw_impl_client *client;	/**< owner client */

	uint32_t id;			/**< per client unique id, index in client objects */
	uint32_t permissions;		/**< resource permissions */
	const char *type;		/**< type of the client interface */
	uint32_t version;		/**< version of the client interface */
	uint32_t bound_id;		/**< global id we are bound to */

	unsigned int removed:1;		/**< resource was removed from server */

	struct spa_hook_list listener_list;
	struct spa_hook_list object_listener_list;

        const struct pw_protocol_marshal *marshal;

	void *user_data;		/**< extra user data */
};

#define pw_proxy_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_proxy_events, m, v, ##__VA_ARGS__)
#define pw_proxy_emit_destroy(p)	pw_proxy_emit(p, destroy, 0)
#define pw_proxy_emit_bound(p,g)	pw_proxy_emit(p, bound, 0, g)
#define pw_proxy_emit_removed(p)	pw_proxy_emit(p, removed, 0)
#define pw_proxy_emit_done(p,s)		pw_proxy_emit(p, done, 0, s)
#define pw_proxy_emit_error(p,s,r,m)	pw_proxy_emit(p, error, 0, s, r, m)

struct pw_proxy {
	struct spa_interface impl;	/**< object implementation */

	struct pw_core *core;		/**< the owner core of this proxy */

	uint32_t id;			/**< client side id */
	const char *type;		/**< type of the interface */
	uint32_t version;		/**< client side version */
	uint32_t bound_id;		/**< global id we are bound to */
	int refcount;
	unsigned int zombie:1;		/**< proxy is removed locally and waiting to
					  *  be removed from server */
	unsigned int removed:1;		/**< proxy was removed from server */
	unsigned int destroyed:1;	/**< proxy was destroyed by client */
	unsigned int in_map:1;		/**< proxy is in core object map */

	struct spa_hook_list listener_list;
	struct spa_hook_list object_listener_list;

	const struct pw_protocol_marshal *marshal;	/**< protocol specific marshal functions */

	void *user_data;		/**< extra user data */
};

struct pw_core {
	struct pw_proxy proxy;

	struct pw_context *context;		/**< context */
	struct spa_list link;			/**< link in context core_list */
	struct pw_properties *properties;	/**< extra properties */

	struct pw_mempool *pool;		/**< memory pool */
	struct pw_core *core;			/**< proxy for the core object */
	struct spa_hook core_listener;
	struct spa_hook proxy_core_listener;

	struct pw_map objects;			/**< map of client side proxy objects
						 *   indexed with the client id */
	struct pw_client *client;		/**< proxy for the client object */

	struct spa_list stream_list;		/**< list of \ref pw_stream objects */
	struct spa_list filter_list;		/**< list of \ref pw_stream objects */

	struct pw_protocol_client *conn;	/**< the protocol client connection */
	int recv_seq;				/**< last received sequence number */
	int send_seq;				/**< last protocol result code */

	unsigned int removed:1;
	unsigned int destroyed:1;

	void *user_data;			/**< extra user data */
};

#define pw_stream_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_stream_events, m, v, ##__VA_ARGS__)
#define pw_stream_emit_destroy(s)		pw_stream_emit(s, destroy, 0)
#define pw_stream_emit_state_changed(s,o,n,e)	pw_stream_emit(s, state_changed,0,o,n,e)
#define pw_stream_emit_io_changed(s,i,a,t)	pw_stream_emit(s, io_changed,0,i,a,t)
#define pw_stream_emit_param_changed(s,i,p)	pw_stream_emit(s, param_changed,0,i,p)
#define pw_stream_emit_add_buffer(s,b)		pw_stream_emit(s, add_buffer, 0, b)
#define pw_stream_emit_remove_buffer(s,b)	pw_stream_emit(s, remove_buffer, 0, b)
#define pw_stream_emit_process(s)		pw_stream_emit(s, process, 0)
#define pw_stream_emit_drained(s)		pw_stream_emit(s, drained,0)
#define pw_stream_emit_control_info(s,i,c)	pw_stream_emit(s, control_info, 0, i, c)


struct pw_stream {
	struct pw_core *core;			/**< the owner core */
	struct spa_hook core_listener;

	struct spa_list link;			/**< link in the core */

	char *name;				/**< the name of the stream */
	struct pw_properties *properties;	/**< properties of the stream */

	uint32_t node_id;			/**< node id for remote node, available from
						  *  CONFIGURE state and higher */
	enum pw_stream_state state;		/**< stream state */
	char *error;				/**< error reason when state is in error */

	struct spa_hook_list listener_list;

	struct pw_proxy *proxy;
	struct spa_hook proxy_listener;

	struct spa_hook node_listener;

	struct spa_list controls;
};

#define pw_filter_emit(s,m,v,...) spa_hook_list_call(&(s)->listener_list, struct pw_filter_events, m, v, ##__VA_ARGS__)
#define pw_filter_emit_destroy(s)		pw_filter_emit(s, destroy, 0)
#define pw_filter_emit_state_changed(s,o,n,e)	pw_filter_emit(s, state_changed,0,o,n,e)
#define pw_filter_emit_io_changed(s,p,i,d,t)	pw_filter_emit(s, io_changed,0,p,i,d,t)
#define pw_filter_emit_param_changed(s,p,i,f)	pw_filter_emit(s, param_changed,0,p,i,f)
#define pw_filter_emit_add_buffer(s,p,b)	pw_filter_emit(s, add_buffer, 0, p, b)
#define pw_filter_emit_remove_buffer(s,p,b)	pw_filter_emit(s, remove_buffer, 0, p, b)
#define pw_filter_emit_process(s,p)		pw_filter_emit(s, process, 0, p)
#define pw_filter_emit_drained(s)		pw_filter_emit(s, drained, 0)


struct pw_filter {
	struct pw_core *core;	/**< the owner core proxy */
	struct spa_hook core_listener;

	struct spa_list link;			/**< link in the core proxy */

	char *name;				/**< the name of the filter */
	struct pw_properties *properties;	/**< properties of the filter */

	uint32_t node_id;			/**< node id for remote node, available from
						  *  CONFIGURE state and higher */
	enum pw_filter_state state;		/**< filter state */
	char *error;				/**< error reason when state is in error */

	struct spa_hook_list listener_list;

	struct pw_proxy *proxy;
	struct spa_hook proxy_listener;

	struct spa_list controls;
};

#define pw_impl_factory_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_impl_factory_events, m, v, ##__VA_ARGS__)

#define pw_impl_factory_emit_destroy(s)		pw_impl_factory_emit(s, destroy, 0)
#define pw_impl_factory_emit_free(s)		pw_impl_factory_emit(s, free, 0)
#define pw_impl_factory_emit_initialized(s)	pw_impl_factory_emit(s, initialized, 0)

struct pw_impl_factory {
	struct pw_context *context;		/**< the context */
	struct spa_list link;		/**< link in context node_factory_list */
	struct pw_global *global;	/**< global for this factory */
	struct spa_hook global_listener;

	struct pw_factory_info info;	/**< introspectable factory info */
	struct pw_properties *properties;	/**< properties of the factory */

	struct spa_hook_list listener_list;	/**< event listeners */

	struct spa_callbacks impl;

	void *user_data;

	unsigned int registered:1;
};

#define pw_control_emit(c,m,v,...) spa_hook_list_call(&c->listener_list, struct pw_control_events, m, v, ##__VA_ARGS__)
#define pw_control_emit_destroy(c)	pw_control_emit(c, destroy, 0)
#define pw_control_emit_free(c)		pw_control_emit(c, free, 0)
#define pw_control_emit_linked(c,o)	pw_control_emit(c, linked, 0, o)
#define pw_control_emit_unlinked(c,o)	pw_control_emit(c, unlinked, 0, o)

struct pw_control {
	struct spa_list link;		/**< link in context control_list */
	struct pw_context *context;		/**< the context */

	struct pw_impl_port *port;		/**< owner port or NULL */
	struct spa_list port_link;	/**< link in port control_list */

	enum spa_direction direction;	/**< the direction */
	struct spa_list links;		/**< list of pw_control_link */

	uint32_t id;
	int32_t size;

	struct spa_hook_list listener_list;

	void *user_data;
};

/** Find a good format between 2 ports */
int pw_context_find_format(struct pw_context *context,
			struct pw_impl_port *output,
			struct pw_impl_port *input,
			struct pw_properties *props,
			uint32_t n_format_filters,
			struct spa_pod **format_filters,
			struct spa_pod **format,
			struct spa_pod_builder *builder,
			char **error);

/** Find a ports compatible with \a other_port and the format filters */
struct pw_impl_port *
pw_context_find_port(struct pw_context *context,
		  struct pw_impl_port *other_port,
		  uint32_t id,
		  struct pw_properties *props,
		  uint32_t n_format_filters,
		  struct spa_pod **format_filters,
		  char **error);

int pw_context_debug_port_params(struct pw_context *context,
		struct spa_node *node, enum spa_direction direction,
		uint32_t port_id, uint32_t id, int err, const char *debug, ...);

const struct pw_export_type *pw_context_find_export_type(struct pw_context *context, const char *type);

int pw_proxy_init(struct pw_proxy *proxy, const char *type, uint32_t version);

void pw_proxy_remove(struct pw_proxy *proxy);

int pw_context_recalc_graph(struct pw_context *context, const char *reason);

void pw_impl_port_update_info(struct pw_impl_port *port, const struct spa_port_info *info);

int pw_impl_port_register(struct pw_impl_port *port,
		     struct pw_properties *properties);

/** Get the user data of a port, the size of the memory was given \ref in pw_context_create_port */
void * pw_impl_port_get_user_data(struct pw_impl_port *port);

int pw_impl_port_set_mix(struct pw_impl_port *port, struct spa_node *node, uint32_t flags);

int pw_impl_port_init_mix(struct pw_impl_port *port, struct pw_impl_port_mix *mix);
int pw_impl_port_release_mix(struct pw_impl_port *port, struct pw_impl_port_mix *mix);

void pw_impl_port_update_state(struct pw_impl_port *port, enum pw_impl_port_state state, char *error);

/** Unlink a port \memberof pw_impl_port */
void pw_impl_port_unlink(struct pw_impl_port *port);

/** Destroy a port \memberof pw_impl_port */
void pw_impl_port_destroy(struct pw_impl_port *port);

/** Iterate the params of the given port. The callback should return
 * 1 to fetch the next item, 0 to stop iteration or <0 on error.
 * The function returns 0 on success or the error returned by the callback. */
int pw_impl_port_for_each_param(struct pw_impl_port *port,
			   int seq, uint32_t param_id,
			   uint32_t index, uint32_t max,
			   const struct spa_pod *filter,
			   int (*callback) (void *data, int seq,
					    uint32_t id, uint32_t index, uint32_t next,
					    struct spa_pod *param),
			   void *data);

int pw_impl_port_for_each_filtered_param(struct pw_impl_port *in_port,
				    struct pw_impl_port *out_port,
				    int seq,
				    uint32_t in_param_id,
				    uint32_t out_param_id,
				    const struct spa_pod *filter,
				    int (*callback) (void *data, int seq,
						     uint32_t id, uint32_t index, uint32_t next,
						     struct spa_pod *param),
				    void *data);

/** Iterate the links of the port. 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
 * items are iterated. */
int pw_impl_port_for_each_link(struct pw_impl_port *port,
			   int (*callback) (void *data, struct pw_impl_link *link),
			   void *data);

/** Set a param on a port \memberof pw_impl_port, use SPA_ID_INVALID for mix_id to set
 * the param on all mix ports */
int pw_impl_port_set_param(struct pw_impl_port *port,
		uint32_t id, uint32_t flags, const struct spa_pod *param);

/** Use buffers on a port \memberof pw_impl_port */
int pw_impl_port_use_buffers(struct pw_impl_port *port, struct pw_impl_port_mix *mix, uint32_t flags,
		struct spa_buffer **buffers, uint32_t n_buffers);

/** Change the state of the node */
int pw_impl_node_set_state(struct pw_impl_node *node, enum pw_node_state state);

int pw_impl_node_set_param(struct pw_impl_node *node,
		uint32_t id, uint32_t flags, const struct spa_pod *param);

int pw_impl_node_update_ports(struct pw_impl_node *node);

int pw_impl_node_set_driver(struct pw_impl_node *node, struct pw_impl_node *driver);

/** Prepare a link \memberof pw_impl_link
  * Starts the negotiation of formats and buffers on \a link */
int pw_impl_link_prepare(struct pw_impl_link *link);
/** starts streaming on a link */
int pw_impl_link_activate(struct pw_impl_link *link);

/** Deactivate a link \memberof pw_impl_link */
int pw_impl_link_deactivate(struct pw_impl_link *link);

struct pw_control *
pw_control_new(struct pw_context *context,
	       struct pw_impl_port *owner,		/**< can be NULL */
	       uint32_t id, uint32_t size,
	       size_t user_data_size		/**< extra user data */);

int pw_control_add_link(struct pw_control *control, uint32_t cmix,
		struct pw_control *other, uint32_t omix,
		struct pw_control_link *link);

int pw_control_remove_link(struct pw_control_link *link);

void pw_control_destroy(struct pw_control *control);

void pw_proxy_unref(struct pw_proxy *proxy);
void pw_proxy_ref(struct pw_proxy *proxy);

#define PW_LOG_OBJECT_POD	(1<<0)
void pw_log_log_object(enum spa_log_level level, const char *file, int line,
	   const char *func, uint32_t flags, const void *object);

#define pw_log_object(lev,fl,obj)						\
({										\
	if (SPA_UNLIKELY(pw_log_level_enabled (lev)))				\
		pw_log_log_object(lev,__FILE__,__LINE__,__func__,(fl),(obj));	\
})

#define pw_log_pod(lev,pod) pw_log_object(lev,PW_LOG_OBJECT_POD,pod)
#define pw_log_format(lev,pod) pw_log_object(lev,PW_LOG_OBJECT_POD,pod)

bool pw_log_is_default(void);

/** \endcond */

#ifdef __cplusplus
}
#endif

#endif /* PIPEWIRE_PRIVATE_H */