1 /* PipeWire
2 *
3 * Copyright © 2018 Wim Taymans
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <errno.h>
26
27 #include <spa/debug/types.h>
28 #include <spa/utils/string.h>
29
30 #include <pipewire/protocol.h>
31 #include <pipewire/private.h>
32 #include <pipewire/type.h>
33
34 PW_LOG_TOPIC_EXTERN(log_protocol);
35 #define PW_LOG_TOPIC_DEFAULT log_protocol
36
37 /** \cond */
38 struct impl {
39 struct pw_protocol this;
40 };
41
42 struct marshal {
43 struct spa_list link;
44 const struct pw_protocol_marshal *marshal;
45 };
46 /** \endcond */
47
48 SPA_EXPORT
pw_protocol_new(struct pw_context * context,const char * name,size_t user_data_size)49 struct pw_protocol *pw_protocol_new(struct pw_context *context,
50 const char *name,
51 size_t user_data_size)
52 {
53 struct pw_protocol *protocol;
54
55 protocol = calloc(1, sizeof(struct impl) + user_data_size);
56 if (protocol == NULL)
57 return NULL;
58
59 protocol->context = context;
60 protocol->name = strdup(name);
61
62 spa_list_init(&protocol->marshal_list);
63 spa_list_init(&protocol->server_list);
64 spa_list_init(&protocol->client_list);
65 spa_hook_list_init(&protocol->listener_list);
66
67 if (user_data_size > 0)
68 protocol->user_data = SPA_PTROFF(protocol, sizeof(struct impl), void);
69
70 spa_list_append(&context->protocol_list, &protocol->link);
71
72 pw_log_debug("%p: Created protocol %s", protocol, name);
73
74 return protocol;
75 }
76
77 SPA_EXPORT
pw_protocol_get_context(struct pw_protocol * protocol)78 struct pw_context *pw_protocol_get_context(struct pw_protocol *protocol)
79 {
80 return protocol->context;
81 }
82
83 SPA_EXPORT
pw_protocol_get_user_data(struct pw_protocol * protocol)84 void *pw_protocol_get_user_data(struct pw_protocol *protocol)
85 {
86 return protocol->user_data;
87 }
88
89 SPA_EXPORT
90 const struct pw_protocol_implementation *
pw_protocol_get_implementation(struct pw_protocol * protocol)91 pw_protocol_get_implementation(struct pw_protocol *protocol)
92 {
93 return protocol->implementation;
94 }
95
96 SPA_EXPORT
97 const void *
pw_protocol_get_extension(struct pw_protocol * protocol)98 pw_protocol_get_extension(struct pw_protocol *protocol)
99 {
100 return protocol->extension;
101 }
102
103 SPA_EXPORT
pw_protocol_destroy(struct pw_protocol * protocol)104 void pw_protocol_destroy(struct pw_protocol *protocol)
105 {
106 struct impl *impl = SPA_CONTAINER_OF(protocol, struct impl, this);
107 struct marshal *marshal, *t1;
108 struct pw_protocol_server *server;
109 struct pw_protocol_client *client;
110
111 pw_log_debug("%p: destroy", protocol);
112 pw_protocol_emit_destroy(protocol);
113
114 spa_hook_list_clean(&protocol->listener_list);
115
116 spa_list_remove(&protocol->link);
117
118 spa_list_consume(server, &protocol->server_list, link)
119 pw_protocol_server_destroy(server);
120
121 spa_list_consume(client, &protocol->client_list, link)
122 pw_protocol_client_destroy(client);
123
124 spa_list_for_each_safe(marshal, t1, &protocol->marshal_list, link)
125 free(marshal);
126
127 free(protocol->name);
128
129 free(impl);
130 }
131
132 SPA_EXPORT
pw_protocol_add_listener(struct pw_protocol * protocol,struct spa_hook * listener,const struct pw_protocol_events * events,void * data)133 void pw_protocol_add_listener(struct pw_protocol *protocol,
134 struct spa_hook *listener,
135 const struct pw_protocol_events *events,
136 void *data)
137 {
138 spa_hook_list_append(&protocol->listener_list, listener, events, data);
139 }
140
141 SPA_EXPORT
142 int
pw_protocol_add_marshal(struct pw_protocol * protocol,const struct pw_protocol_marshal * marshal)143 pw_protocol_add_marshal(struct pw_protocol *protocol,
144 const struct pw_protocol_marshal *marshal)
145 {
146 struct marshal *impl;
147
148 impl = calloc(1, sizeof(struct marshal));
149 if (impl == NULL)
150 return -errno;
151
152 impl->marshal = marshal;
153
154 spa_list_append(&protocol->marshal_list, &impl->link);
155
156 pw_log_debug("%p: Add marshal %s/%d to protocol %s", protocol,
157 marshal->type, marshal->version, protocol->name);
158
159 return 0;
160 }
161
162 SPA_EXPORT
163 const struct pw_protocol_marshal *
pw_protocol_get_marshal(struct pw_protocol * protocol,const char * type,uint32_t version,uint32_t flags)164 pw_protocol_get_marshal(struct pw_protocol *protocol, const char *type, uint32_t version, uint32_t flags)
165 {
166 struct marshal *impl;
167
168 spa_list_for_each(impl, &protocol->marshal_list, link) {
169 if (spa_streq(impl->marshal->type, type) &&
170 (impl->marshal->flags & flags) == flags)
171 return impl->marshal;
172 }
173 pw_log_debug("%p: No marshal %s/%d for protocol %s", protocol,
174 type, version, protocol->name);
175 return NULL;
176 }
177
178 SPA_EXPORT
pw_context_find_protocol(struct pw_context * context,const char * name)179 struct pw_protocol *pw_context_find_protocol(struct pw_context *context, const char *name)
180 {
181 struct pw_protocol *protocol;
182
183 spa_list_for_each(protocol, &context->protocol_list, link) {
184 if (spa_streq(protocol->name, name))
185 return protocol;
186 }
187 return NULL;
188 }
189