mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
Make native protocol
Remove DBus and work towards something like wayland. Remove more glib stuff from the client code
This commit is contained in:
parent
efae64a759
commit
27bba6f587
55 changed files with 3089 additions and 4969 deletions
|
|
@ -39,6 +39,7 @@ typedef struct {
|
||||||
int fds[MAX_FDS];
|
int fds[MAX_FDS];
|
||||||
unsigned int n_fds;
|
unsigned int n_fds;
|
||||||
|
|
||||||
|
uint32_t dest_id;
|
||||||
PinosMessageType type;
|
PinosMessageType type;
|
||||||
off_t offset;
|
off_t offset;
|
||||||
void *data;
|
void *data;
|
||||||
|
|
@ -52,32 +53,77 @@ struct _PinosConnection {
|
||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
connection_get_fd (PinosConnection *conn,
|
||||||
|
int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= conn->in.n_fds)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return conn->in.fds[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
connection_add_fd (PinosConnection *conn,
|
||||||
|
int fd)
|
||||||
|
{
|
||||||
|
int index, i;
|
||||||
|
|
||||||
|
for (i = 0; i < conn->out.n_fds; i++) {
|
||||||
|
if (conn->out.fds[i] == fd)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = conn->out.n_fds;
|
||||||
|
conn->out.fds[index] = fd;
|
||||||
|
conn->out.n_fds++;
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define PINOS_DEBUG_MESSAGE(format,args...) pinos_log_debug(stderr, format,##args)
|
#define PINOS_DEBUG_MESSAGE(format,args...) pinos_log_debug(stderr, format,##args)
|
||||||
#else
|
#else
|
||||||
#define PINOS_DEBUG_MESSAGE(format,args...)
|
#define PINOS_DEBUG_MESSAGE(format,args...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
read_length (uint8_t * data, unsigned int size, size_t * length, size_t * skip)
|
connection_parse_notify_global (PinosConnection *conn, PinosMessageNotifyGlobal *ng)
|
||||||
{
|
{
|
||||||
uint8_t b;
|
void *p;
|
||||||
|
|
||||||
/* start reading the length, we need this to skip to the data later */
|
p = conn->in.data;
|
||||||
*length = *skip = 0;
|
memcpy (ng, p, sizeof (PinosMessageNotifyGlobal));
|
||||||
do {
|
if (ng->type)
|
||||||
if (*skip >= size)
|
ng->type = SPA_MEMBER (p, SPA_PTR_TO_INT (ng->type), const char);
|
||||||
return false;
|
}
|
||||||
|
|
||||||
b = data[(*skip)++];
|
static void
|
||||||
*length = (*length << 7) | (b & 0x7f);
|
connection_parse_create_node (PinosConnection *conn, PinosMessageCreateNode *m)
|
||||||
} while (b & 0x80);
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
/* check remaining command size */
|
p = conn->in.data;
|
||||||
if (size - *skip < *length)
|
memcpy (m, p, sizeof (PinosMessageCreateNode));
|
||||||
return false;
|
if (m->factory_name)
|
||||||
|
m->factory_name = SPA_MEMBER (p, SPA_PTR_TO_INT (m->factory_name), const char);
|
||||||
|
if (m->name)
|
||||||
|
m->name = SPA_MEMBER (p, SPA_PTR_TO_INT (m->name), const char);
|
||||||
|
if (m->props)
|
||||||
|
m->props = pinos_serialize_dict_deserialize (p, SPA_PTR_TO_INT (m->props));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
static void
|
||||||
|
connection_parse_create_client_node (PinosConnection *conn, PinosMessageCreateClientNode *m)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
p = conn->in.data;
|
||||||
|
memcpy (m, p, sizeof (PinosMessageCreateClientNode));
|
||||||
|
if (m->name)
|
||||||
|
m->name = SPA_MEMBER (p, SPA_PTR_TO_INT (m->name), const char);
|
||||||
|
if (m->props)
|
||||||
|
m->props = pinos_serialize_dict_deserialize (p, SPA_PTR_TO_INT (m->props));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -173,34 +219,122 @@ connection_ensure_size (PinosConnection *conn, ConnectionBuffer *buf, size_t siz
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
connection_add_message (PinosConnection *conn, PinosMessageType type, size_t size)
|
connection_add_message (PinosConnection *conn,
|
||||||
|
uint32_t dest_id,
|
||||||
|
PinosMessageType type,
|
||||||
|
size_t size)
|
||||||
{
|
{
|
||||||
uint8_t *p;
|
uint32_t *p;
|
||||||
unsigned int plen;
|
|
||||||
ConnectionBuffer *buf = &conn->out;
|
ConnectionBuffer *buf = &conn->out;
|
||||||
|
|
||||||
plen = 1;
|
/* 4 for dest_id, 2 for cmd, 2 for size and size for payload */
|
||||||
while (size >> (7 * plen))
|
p = connection_ensure_size (conn, buf, 8 + size);
|
||||||
plen++;
|
|
||||||
|
|
||||||
/* 1 for cmd, plen for size and size for payload */
|
|
||||||
p = connection_ensure_size (conn, buf, 1 + plen + size);
|
|
||||||
|
|
||||||
buf->type = type;
|
buf->type = type;
|
||||||
buf->offset = buf->buffer_size;
|
buf->offset = buf->buffer_size;
|
||||||
buf->buffer_size += 1 + plen + size;
|
buf->buffer_size += 8 + size;
|
||||||
|
|
||||||
|
*p++ = dest_id;
|
||||||
|
*p++ = (type << 16) | (size & 0xffff);
|
||||||
|
|
||||||
*p++ = type;
|
|
||||||
/* write length */
|
|
||||||
while (plen) {
|
|
||||||
plen--;
|
|
||||||
*p++ = ((plen > 0) ? 0x80 : 0) | ((size >> (7 * plen)) & 0x7f);
|
|
||||||
}
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_add_node_update (PinosConnection *conn, PinosMessageNodeUpdate *nu)
|
connection_add_notify_global (PinosConnection *conn,
|
||||||
|
uint32_t dest_id,
|
||||||
|
PinosMessageNotifyGlobal *m)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
void *p;
|
||||||
|
PinosMessageNotifyGlobal *d;
|
||||||
|
|
||||||
|
/* calc len */
|
||||||
|
len = sizeof (PinosMessageNotifyGlobal);
|
||||||
|
len += m->type ? strlen (m->type) + 1 : 0;
|
||||||
|
|
||||||
|
p = connection_add_message (conn, dest_id, PINOS_MESSAGE_NOTIFY_GLOBAL, len);
|
||||||
|
memcpy (p, m, sizeof (PinosMessageNotifyGlobal));
|
||||||
|
d = p;
|
||||||
|
|
||||||
|
p = SPA_MEMBER (d, sizeof (PinosMessageNotifyGlobal), void);
|
||||||
|
if (m->type) {
|
||||||
|
strcpy (p, m->type);
|
||||||
|
d->type = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
connection_add_create_node (PinosConnection *conn, uint32_t dest_id, PinosMessageCreateNode *m)
|
||||||
|
{
|
||||||
|
size_t len, slen;
|
||||||
|
void *p;
|
||||||
|
PinosMessageCreateNode *d;
|
||||||
|
|
||||||
|
/* calc len */
|
||||||
|
len = sizeof (PinosMessageCreateNode);
|
||||||
|
len += m->factory_name ? strlen (m->factory_name) + 1 : 0;
|
||||||
|
len += m->name ? strlen (m->name) + 1 : 0;
|
||||||
|
len += pinos_serialize_dict_get_size (m->props);
|
||||||
|
|
||||||
|
p = connection_add_message (conn, dest_id, PINOS_MESSAGE_CREATE_NODE, len);
|
||||||
|
memcpy (p, m, sizeof (PinosMessageCreateNode));
|
||||||
|
d = p;
|
||||||
|
|
||||||
|
p = SPA_MEMBER (d, sizeof (PinosMessageCreateNode), void);
|
||||||
|
if (m->factory_name) {
|
||||||
|
slen = strlen (m->factory_name) + 1;
|
||||||
|
memcpy (p, m->factory_name, slen);
|
||||||
|
d->factory_name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d));
|
||||||
|
p += slen;
|
||||||
|
}
|
||||||
|
if (m->name) {
|
||||||
|
slen = strlen (m->name) + 1;
|
||||||
|
memcpy (p, m->name, slen);
|
||||||
|
d->name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d));
|
||||||
|
p += slen;
|
||||||
|
}
|
||||||
|
if (m->props) {
|
||||||
|
len = pinos_serialize_dict_serialize (p, m->props);
|
||||||
|
d->props = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d));
|
||||||
|
} else {
|
||||||
|
d->props = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
connection_add_create_client_node (PinosConnection *conn, uint32_t dest_id, PinosMessageCreateClientNode *m)
|
||||||
|
{
|
||||||
|
size_t len, slen;
|
||||||
|
void *p;
|
||||||
|
PinosMessageCreateClientNode *d;
|
||||||
|
|
||||||
|
/* calc len */
|
||||||
|
len = sizeof (PinosMessageCreateClientNode);
|
||||||
|
len += m->name ? strlen (m->name) + 1 : 0;
|
||||||
|
len += pinos_serialize_dict_get_size (m->props);
|
||||||
|
|
||||||
|
p = connection_add_message (conn, dest_id, PINOS_MESSAGE_CREATE_CLIENT_NODE, len);
|
||||||
|
memcpy (p, m, sizeof (PinosMessageCreateClientNode));
|
||||||
|
d = p;
|
||||||
|
|
||||||
|
p = SPA_MEMBER (d, sizeof (PinosMessageCreateClientNode), void);
|
||||||
|
if (m->name) {
|
||||||
|
slen = strlen (m->name) + 1;
|
||||||
|
memcpy (p, m->name, slen);
|
||||||
|
d->name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d));
|
||||||
|
p += slen;
|
||||||
|
}
|
||||||
|
if (m->props) {
|
||||||
|
len = pinos_serialize_dict_serialize (p, m->props);
|
||||||
|
d->props = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d));
|
||||||
|
} else {
|
||||||
|
d->props = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
connection_add_node_update (PinosConnection *conn, uint32_t dest_id, PinosMessageNodeUpdate *nu)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
@ -210,7 +344,7 @@ connection_add_node_update (PinosConnection *conn, PinosMessageNodeUpdate *nu)
|
||||||
len = sizeof (PinosMessageNodeUpdate);
|
len = sizeof (PinosMessageNodeUpdate);
|
||||||
len += pinos_serialize_props_get_size (nu->props);
|
len += pinos_serialize_props_get_size (nu->props);
|
||||||
|
|
||||||
p = connection_add_message (conn, PINOS_MESSAGE_NODE_UPDATE, len);
|
p = connection_add_message (conn, dest_id, PINOS_MESSAGE_NODE_UPDATE, len);
|
||||||
memcpy (p, nu, sizeof (PinosMessageNodeUpdate));
|
memcpy (p, nu, sizeof (PinosMessageNodeUpdate));
|
||||||
d = p;
|
d = p;
|
||||||
|
|
||||||
|
|
@ -224,7 +358,7 @@ connection_add_node_update (PinosConnection *conn, PinosMessageNodeUpdate *nu)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_add_port_update (PinosConnection *conn, PinosMessagePortUpdate *pu)
|
connection_add_port_update (PinosConnection *conn, uint32_t dest_id, PinosMessagePortUpdate *pu)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
@ -243,7 +377,7 @@ connection_add_port_update (PinosConnection *conn, PinosMessagePortUpdate *pu)
|
||||||
if (pu->info)
|
if (pu->info)
|
||||||
len += pinos_serialize_port_info_get_size (pu->info);
|
len += pinos_serialize_port_info_get_size (pu->info);
|
||||||
|
|
||||||
p = connection_add_message (conn, PINOS_MESSAGE_PORT_UPDATE, len);
|
p = connection_add_message (conn, dest_id, PINOS_MESSAGE_PORT_UPDATE, len);
|
||||||
memcpy (p, pu, sizeof (PinosMessagePortUpdate));
|
memcpy (p, pu, sizeof (PinosMessagePortUpdate));
|
||||||
d = p;
|
d = p;
|
||||||
|
|
||||||
|
|
@ -285,7 +419,7 @@ connection_add_port_update (PinosConnection *conn, PinosMessagePortUpdate *pu)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_add_set_format (PinosConnection *conn, PinosMessageSetFormat *sf)
|
connection_add_set_format (PinosConnection *conn, uint32_t dest_id, PinosMessageSetFormat *sf)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
@ -293,7 +427,7 @@ connection_add_set_format (PinosConnection *conn, PinosMessageSetFormat *sf)
|
||||||
/* calculate length */
|
/* calculate length */
|
||||||
/* port_id + format + mask */
|
/* port_id + format + mask */
|
||||||
len = sizeof (PinosMessageSetFormat) + pinos_serialize_format_get_size (sf->format);
|
len = sizeof (PinosMessageSetFormat) + pinos_serialize_format_get_size (sf->format);
|
||||||
p = connection_add_message (conn, PINOS_MESSAGE_SET_FORMAT, len);
|
p = connection_add_message (conn, dest_id, PINOS_MESSAGE_SET_FORMAT, len);
|
||||||
memcpy (p, sf, sizeof (PinosMessageSetFormat));
|
memcpy (p, sf, sizeof (PinosMessageSetFormat));
|
||||||
sf = p;
|
sf = p;
|
||||||
|
|
||||||
|
|
@ -306,7 +440,7 @@ connection_add_set_format (PinosConnection *conn, PinosMessageSetFormat *sf)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_add_use_buffers (PinosConnection *conn, PinosMessageUseBuffers *ub)
|
connection_add_use_buffers (PinosConnection *conn, uint32_t dest_id, PinosMessageUseBuffers *ub)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -317,7 +451,7 @@ connection_add_use_buffers (PinosConnection *conn, PinosMessageUseBuffers *ub)
|
||||||
len = sizeof (PinosMessageUseBuffers);
|
len = sizeof (PinosMessageUseBuffers);
|
||||||
len += ub->n_buffers * sizeof (PinosMessageMemRef);
|
len += ub->n_buffers * sizeof (PinosMessageMemRef);
|
||||||
|
|
||||||
d = connection_add_message (conn, PINOS_MESSAGE_USE_BUFFERS, len);
|
d = connection_add_message (conn, dest_id, PINOS_MESSAGE_USE_BUFFERS, len);
|
||||||
memcpy (d, ub, sizeof (PinosMessageUseBuffers));
|
memcpy (d, ub, sizeof (PinosMessageUseBuffers));
|
||||||
|
|
||||||
mr = SPA_MEMBER (d, sizeof (PinosMessageUseBuffers), void);
|
mr = SPA_MEMBER (d, sizeof (PinosMessageUseBuffers), void);
|
||||||
|
|
@ -332,7 +466,7 @@ connection_add_use_buffers (PinosConnection *conn, PinosMessageUseBuffers *ub)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_add_node_event (PinosConnection *conn, PinosMessageNodeEvent *ev)
|
connection_add_node_event (PinosConnection *conn, uint32_t dest_id, PinosMessageNodeEvent *ev)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
@ -342,7 +476,7 @@ connection_add_node_event (PinosConnection *conn, PinosMessageNodeEvent *ev)
|
||||||
len = sizeof (PinosMessageNodeEvent);
|
len = sizeof (PinosMessageNodeEvent);
|
||||||
len += ev->event->size;
|
len += ev->event->size;
|
||||||
|
|
||||||
p = connection_add_message (conn, PINOS_MESSAGE_NODE_EVENT, len);
|
p = connection_add_message (conn, dest_id, PINOS_MESSAGE_NODE_EVENT, len);
|
||||||
memcpy (p, ev, sizeof (PinosMessageNodeEvent));
|
memcpy (p, ev, sizeof (PinosMessageNodeEvent));
|
||||||
d = p;
|
d = p;
|
||||||
|
|
||||||
|
|
@ -353,7 +487,7 @@ connection_add_node_event (PinosConnection *conn, PinosMessageNodeEvent *ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_add_node_command (PinosConnection *conn, PinosMessageNodeCommand *cm)
|
connection_add_node_command (PinosConnection *conn, uint32_t dest_id, PinosMessageNodeCommand *cm)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
@ -363,7 +497,7 @@ connection_add_node_command (PinosConnection *conn, PinosMessageNodeCommand *cm)
|
||||||
len = sizeof (PinosMessageNodeCommand);
|
len = sizeof (PinosMessageNodeCommand);
|
||||||
len += cm->command->size;
|
len += cm->command->size;
|
||||||
|
|
||||||
p = connection_add_message (conn, PINOS_MESSAGE_NODE_COMMAND, len);
|
p = connection_add_message (conn, dest_id, PINOS_MESSAGE_NODE_COMMAND, len);
|
||||||
memcpy (p, cm, sizeof (PinosMessageNodeCommand));
|
memcpy (p, cm, sizeof (PinosMessageNodeCommand));
|
||||||
d = p;
|
d = p;
|
||||||
|
|
||||||
|
|
@ -374,7 +508,7 @@ connection_add_node_command (PinosConnection *conn, PinosMessageNodeCommand *cm)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_add_port_command (PinosConnection *conn, PinosMessagePortCommand *cm)
|
connection_add_port_command (PinosConnection *conn, uint32_t dest_id, PinosMessagePortCommand *cm)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
@ -384,7 +518,7 @@ connection_add_port_command (PinosConnection *conn, PinosMessagePortCommand *cm)
|
||||||
len = sizeof (PinosMessagePortCommand);
|
len = sizeof (PinosMessagePortCommand);
|
||||||
len += cm->command->size;
|
len += cm->command->size;
|
||||||
|
|
||||||
p = connection_add_message (conn, PINOS_MESSAGE_PORT_COMMAND, len);
|
p = connection_add_message (conn, dest_id, PINOS_MESSAGE_PORT_COMMAND, len);
|
||||||
memcpy (p, cm, sizeof (PinosMessagePortCommand));
|
memcpy (p, cm, sizeof (PinosMessagePortCommand));
|
||||||
d = p;
|
d = p;
|
||||||
|
|
||||||
|
|
@ -422,7 +556,7 @@ refill_buffer (PinosConnection *conn, ConnectionBuffer *buf)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < 4)
|
if (len < 8)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
buf->buffer_size += len;
|
buf->buffer_size += len;
|
||||||
|
|
@ -450,14 +584,6 @@ recv_error:
|
||||||
static void
|
static void
|
||||||
clear_buffer (ConnectionBuffer *buf)
|
clear_buffer (ConnectionBuffer *buf)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < buf->n_fds; i++) {
|
|
||||||
if (buf->fds[i] > 0) {
|
|
||||||
if (close (buf->fds[i]) < 0)
|
|
||||||
perror ("close");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf->n_fds = 0;
|
buf->n_fds = 0;
|
||||||
buf->type = PINOS_MESSAGE_INVALID;
|
buf->type = PINOS_MESSAGE_INVALID;
|
||||||
buf->offset = 0;
|
buf->offset = 0;
|
||||||
|
|
@ -471,6 +597,7 @@ pinos_connection_new (int fd)
|
||||||
PinosConnection *c;
|
PinosConnection *c;
|
||||||
|
|
||||||
c = calloc (1, sizeof (PinosConnection));
|
c = calloc (1, sizeof (PinosConnection));
|
||||||
|
pinos_log_debug ("connection %p: new", c);
|
||||||
c->fd = fd;
|
c->fd = fd;
|
||||||
c->out.buffer_data = malloc (MAX_BUFFER_SIZE);
|
c->out.buffer_data = malloc (MAX_BUFFER_SIZE);
|
||||||
c->out.buffer_maxsize = MAX_BUFFER_SIZE;
|
c->out.buffer_maxsize = MAX_BUFFER_SIZE;
|
||||||
|
|
@ -482,8 +609,9 @@ pinos_connection_new (int fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pinos_connection_free (PinosConnection *conn)
|
pinos_connection_destroy (PinosConnection *conn)
|
||||||
{
|
{
|
||||||
|
pinos_log_debug ("connection %p: destroy", conn);
|
||||||
free (conn->out.buffer_data);
|
free (conn->out.buffer_data);
|
||||||
free (conn->in.buffer_data);
|
free (conn->in.buffer_data);
|
||||||
free (conn);
|
free (conn);
|
||||||
|
|
@ -498,11 +626,15 @@ pinos_connection_free (PinosConnection *conn)
|
||||||
* Returns: %true if more packets are available.
|
* Returns: %true if more packets are available.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
pinos_connection_has_next (PinosConnection *conn)
|
pinos_connection_get_next (PinosConnection *conn,
|
||||||
|
PinosMessageType *type,
|
||||||
|
uint32_t *dest_id,
|
||||||
|
size_t *sz)
|
||||||
{
|
{
|
||||||
size_t len, size, skip;
|
size_t len, size;
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
ConnectionBuffer *buf;
|
ConnectionBuffer *buf;
|
||||||
|
uint32_t *p;
|
||||||
|
|
||||||
spa_return_val_if_fail (conn != NULL, false);
|
spa_return_val_if_fail (conn != NULL, false);
|
||||||
|
|
||||||
|
|
@ -530,30 +662,35 @@ again:
|
||||||
data += buf->offset;
|
data += buf->offset;
|
||||||
size -= buf->offset;
|
size -= buf->offset;
|
||||||
|
|
||||||
buf->type = *data;
|
if (size < 8) {
|
||||||
data++;
|
connection_ensure_size (conn, buf, 8);
|
||||||
size--;
|
buf->update = true;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
p = (uint32_t *) data;
|
||||||
|
data += 8;
|
||||||
|
size -= 8;
|
||||||
|
|
||||||
if (!read_length (data, size, &len, &skip)) {
|
buf->dest_id = p[0];
|
||||||
connection_ensure_size (conn, buf, len + skip);
|
buf->type = p[1] >> 16;
|
||||||
|
len = p[1] & 0xffff;
|
||||||
|
|
||||||
|
if (len > size) {
|
||||||
|
connection_ensure_size (conn, buf, len);
|
||||||
buf->update = true;
|
buf->update = true;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
buf->size = len;
|
buf->size = len;
|
||||||
buf->data = data + skip;
|
buf->data = data;
|
||||||
buf->offset += 1 + skip;
|
buf->offset += 8;
|
||||||
|
|
||||||
|
*type = buf->type;
|
||||||
|
*dest_id = buf->dest_id;
|
||||||
|
*sz = buf->size;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PinosMessageType
|
|
||||||
pinos_connection_get_type (PinosConnection *conn)
|
|
||||||
{
|
|
||||||
spa_return_val_if_fail (conn != NULL, PINOS_MESSAGE_INVALID);
|
|
||||||
|
|
||||||
return conn->in.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pinos_connection_parse_message (PinosConnection *conn,
|
pinos_connection_parse_message (PinosConnection *conn,
|
||||||
void *message)
|
void *message)
|
||||||
|
|
@ -561,6 +698,58 @@ pinos_connection_parse_message (PinosConnection *conn,
|
||||||
spa_return_val_if_fail (conn != NULL, false);
|
spa_return_val_if_fail (conn != NULL, false);
|
||||||
|
|
||||||
switch (conn->in.type) {
|
switch (conn->in.type) {
|
||||||
|
case PINOS_MESSAGE_SYNC:
|
||||||
|
if (conn->in.size < sizeof (PinosMessageSync))
|
||||||
|
return false;
|
||||||
|
memcpy (message, conn->in.data, sizeof (PinosMessageSync));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_NOTIFY_DONE:
|
||||||
|
if (conn->in.size < sizeof (PinosMessageNotifyDone))
|
||||||
|
return false;
|
||||||
|
memcpy (message, conn->in.data, sizeof (PinosMessageNotifyDone));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_SUBSCRIBE:
|
||||||
|
if (conn->in.size < sizeof (PinosMessageSubscribe))
|
||||||
|
return false;
|
||||||
|
memcpy (message, conn->in.data, sizeof (PinosMessageSubscribe));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_NOTIFY_GLOBAL:
|
||||||
|
connection_parse_notify_global (conn, message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE:
|
||||||
|
if (conn->in.size < sizeof (PinosMessageNotifyGlobalRemove))
|
||||||
|
return false;
|
||||||
|
memcpy (message, conn->in.data, sizeof (PinosMessageNotifyGlobalRemove));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_CREATE_NODE:
|
||||||
|
connection_parse_create_node (conn, message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_CREATE_NODE_DONE:
|
||||||
|
if (conn->in.size < sizeof (PinosMessageCreateNodeDone))
|
||||||
|
return false;
|
||||||
|
memcpy (message, conn->in.data, sizeof (PinosMessageCreateNodeDone));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_CREATE_CLIENT_NODE:
|
||||||
|
connection_parse_create_client_node (conn, message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE:
|
||||||
|
{
|
||||||
|
PinosMessageCreateClientNodeDone *d = message;
|
||||||
|
if (conn->in.size < sizeof (PinosMessageCreateClientNodeDone))
|
||||||
|
return false;
|
||||||
|
memcpy (message, conn->in.data, sizeof (PinosMessageCreateClientNodeDone));
|
||||||
|
d->datafd = connection_get_fd (conn, d->datafd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* C -> S */
|
/* C -> S */
|
||||||
case PINOS_MESSAGE_NODE_UPDATE:
|
case PINOS_MESSAGE_NODE_UPDATE:
|
||||||
connection_parse_node_update (conn, message);
|
connection_parse_node_update (conn, message);
|
||||||
|
|
@ -603,21 +792,19 @@ pinos_connection_parse_message (PinosConnection *conn,
|
||||||
|
|
||||||
/* bidirectional */
|
/* bidirectional */
|
||||||
case PINOS_MESSAGE_ADD_MEM:
|
case PINOS_MESSAGE_ADD_MEM:
|
||||||
|
{
|
||||||
|
PinosMessageAddMem *d = message;
|
||||||
if (conn->in.size < sizeof (PinosMessageAddMem))
|
if (conn->in.size < sizeof (PinosMessageAddMem))
|
||||||
return false;
|
return false;
|
||||||
memcpy (message, conn->in.data, sizeof (PinosMessageAddMem));
|
memcpy (message, conn->in.data, sizeof (PinosMessageAddMem));
|
||||||
|
d->memfd = connection_get_fd (conn, d->memfd);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PINOS_MESSAGE_USE_BUFFERS:
|
case PINOS_MESSAGE_USE_BUFFERS:
|
||||||
connection_parse_use_buffers (conn, message);
|
connection_parse_use_buffers (conn, message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_PROCESS_BUFFER:
|
|
||||||
if (conn->in.size < sizeof (PinosMessageProcessBuffer))
|
|
||||||
return false;
|
|
||||||
memcpy (message, conn->in.data, sizeof (PinosMessageProcessBuffer));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PINOS_MESSAGE_NODE_EVENT:
|
case PINOS_MESSAGE_NODE_EVENT:
|
||||||
connection_parse_node_event (conn, message);
|
connection_parse_node_event (conn, message);
|
||||||
break;
|
break;
|
||||||
|
|
@ -631,10 +818,14 @@ pinos_connection_parse_message (PinosConnection *conn,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_TRANSPORT_UPDATE:
|
case PINOS_MESSAGE_TRANSPORT_UPDATE:
|
||||||
|
{
|
||||||
|
PinosMessageTransportUpdate *d = message;
|
||||||
if (conn->in.size < sizeof (PinosMessageTransportUpdate))
|
if (conn->in.size < sizeof (PinosMessageTransportUpdate))
|
||||||
return false;
|
return false;
|
||||||
memcpy (message, conn->in.data, sizeof (PinosMessageTransportUpdate));
|
memcpy (message, conn->in.data, sizeof (PinosMessageTransportUpdate));
|
||||||
|
d->memfd = connection_get_fd (conn, d->memfd);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PINOS_MESSAGE_INVALID:
|
case PINOS_MESSAGE_INVALID:
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -642,66 +833,6 @@ pinos_connection_parse_message (PinosConnection *conn,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_connection_get_fd:
|
|
||||||
* @conn: a #PinosConnection
|
|
||||||
* @index: an index
|
|
||||||
* @steal: steal the fd
|
|
||||||
*
|
|
||||||
* Get the file descriptor at @index in @conn.
|
|
||||||
*
|
|
||||||
* Returns: a file descriptor at @index in @conn. The file descriptor
|
|
||||||
* is not duplicated in any way. -1 is returned on error.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
pinos_connection_get_fd (PinosConnection *conn,
|
|
||||||
unsigned int index,
|
|
||||||
bool close)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
spa_return_val_if_fail (conn != NULL, -1);
|
|
||||||
spa_return_val_if_fail (index < conn->in.n_fds, -1);
|
|
||||||
|
|
||||||
fd = conn->in.fds[index];
|
|
||||||
if (fd < 0)
|
|
||||||
fd = -fd;
|
|
||||||
conn->in.fds[index] = close ? fd : -fd;
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_connection_add_fd:
|
|
||||||
* @conn: a #PinosConnection
|
|
||||||
* @fd: a valid fd
|
|
||||||
* @close: if the descriptor should be closed when sent
|
|
||||||
*
|
|
||||||
* Add the file descriptor @fd to @builder.
|
|
||||||
*
|
|
||||||
* Returns: the index of the file descriptor in @builder.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
pinos_connection_add_fd (PinosConnection *conn,
|
|
||||||
int fd,
|
|
||||||
bool close)
|
|
||||||
{
|
|
||||||
int index, i;
|
|
||||||
|
|
||||||
spa_return_val_if_fail (conn != NULL, -1);
|
|
||||||
|
|
||||||
for (i = 0; i < conn->out.n_fds; i++) {
|
|
||||||
if (conn->out.fds[i] == fd || conn->out.fds[i] == -fd)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
index = conn->out.n_fds;
|
|
||||||
conn->out.fds[index] = close ? fd : -fd;
|
|
||||||
conn->out.n_fds++;
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pinos_connection_add_message:
|
* pinos_connection_add_message:
|
||||||
* @conn: a #PinosConnection
|
* @conn: a #PinosConnection
|
||||||
|
|
@ -714,6 +845,7 @@ pinos_connection_add_fd (PinosConnection *conn,
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
pinos_connection_add_message (PinosConnection *conn,
|
pinos_connection_add_message (PinosConnection *conn,
|
||||||
|
uint32_t dest_id,
|
||||||
PinosMessageType type,
|
PinosMessageType type,
|
||||||
void *message)
|
void *message)
|
||||||
{
|
{
|
||||||
|
|
@ -723,37 +855,83 @@ pinos_connection_add_message (PinosConnection *conn,
|
||||||
spa_return_val_if_fail (message != NULL, false);
|
spa_return_val_if_fail (message != NULL, false);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case PINOS_MESSAGE_SYNC:
|
||||||
|
p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageSync));
|
||||||
|
memcpy (p, message, sizeof (PinosMessageSync));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_NOTIFY_DONE:
|
||||||
|
p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageNotifyDone));
|
||||||
|
memcpy (p, message, sizeof (PinosMessageNotifyDone));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_SUBSCRIBE:
|
||||||
|
p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageSubscribe));
|
||||||
|
memcpy (p, message, sizeof (PinosMessageSubscribe));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_NOTIFY_GLOBAL:
|
||||||
|
connection_add_notify_global (conn, dest_id, message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE:
|
||||||
|
p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageNotifyGlobalRemove));
|
||||||
|
memcpy (p, message, sizeof (PinosMessageNotifyGlobalRemove));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_CREATE_NODE:
|
||||||
|
connection_add_create_node (conn, dest_id, message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_CREATE_NODE_DONE:
|
||||||
|
p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageCreateNodeDone));
|
||||||
|
memcpy (p, message, sizeof (PinosMessageCreateNodeDone));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_CREATE_CLIENT_NODE:
|
||||||
|
connection_add_create_client_node (conn, dest_id, message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE:
|
||||||
|
{
|
||||||
|
PinosMessageCreateClientNodeDone *d;
|
||||||
|
d = connection_add_message (conn, dest_id, type, sizeof (PinosMessageCreateClientNodeDone));
|
||||||
|
memcpy (d, message, sizeof (PinosMessageCreateClientNodeDone));
|
||||||
|
d->datafd = connection_add_fd (conn, d->datafd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* C -> S */
|
/* C -> S */
|
||||||
case PINOS_MESSAGE_NODE_UPDATE:
|
case PINOS_MESSAGE_NODE_UPDATE:
|
||||||
connection_add_node_update (conn, message);
|
connection_add_node_update (conn, dest_id, message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_PORT_UPDATE:
|
case PINOS_MESSAGE_PORT_UPDATE:
|
||||||
connection_add_port_update (conn, message);
|
connection_add_port_update (conn, dest_id, message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_PORT_STATUS_CHANGE:
|
case PINOS_MESSAGE_PORT_STATUS_CHANGE:
|
||||||
p = connection_add_message (conn, type, 0);
|
p = connection_add_message (conn, dest_id, type, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_NODE_STATE_CHANGE:
|
case PINOS_MESSAGE_NODE_STATE_CHANGE:
|
||||||
p = connection_add_message (conn, type, sizeof (PinosMessageNodeStateChange));
|
p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageNodeStateChange));
|
||||||
memcpy (p, message, sizeof (PinosMessageNodeStateChange));
|
memcpy (p, message, sizeof (PinosMessageNodeStateChange));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* S -> C */
|
/* S -> C */
|
||||||
case PINOS_MESSAGE_ADD_PORT:
|
case PINOS_MESSAGE_ADD_PORT:
|
||||||
p = connection_add_message (conn, type, sizeof (PinosMessageAddPort));
|
p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageAddPort));
|
||||||
memcpy (p, message, sizeof (PinosMessageAddPort));
|
memcpy (p, message, sizeof (PinosMessageAddPort));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_REMOVE_PORT:
|
case PINOS_MESSAGE_REMOVE_PORT:
|
||||||
p = connection_add_message (conn, type, sizeof (PinosMessageRemovePort));
|
p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageRemovePort));
|
||||||
memcpy (p, message, sizeof (PinosMessageRemovePort));
|
memcpy (p, message, sizeof (PinosMessageRemovePort));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_SET_FORMAT:
|
case PINOS_MESSAGE_SET_FORMAT:
|
||||||
connection_add_set_format (conn, message);
|
connection_add_set_format (conn, dest_id, message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_SET_PROPERTY:
|
case PINOS_MESSAGE_SET_PROPERTY:
|
||||||
|
|
@ -762,35 +940,38 @@ pinos_connection_add_message (PinosConnection *conn,
|
||||||
|
|
||||||
/* bidirectional */
|
/* bidirectional */
|
||||||
case PINOS_MESSAGE_ADD_MEM:
|
case PINOS_MESSAGE_ADD_MEM:
|
||||||
p = connection_add_message (conn, type, sizeof (PinosMessageAddMem));
|
{
|
||||||
memcpy (p, message, sizeof (PinosMessageAddMem));
|
PinosMessageAddMem *d;
|
||||||
|
d = connection_add_message (conn, dest_id, type, sizeof (PinosMessageAddMem));
|
||||||
|
memcpy (d, message, sizeof (PinosMessageAddMem));
|
||||||
|
d->memfd = connection_add_fd (conn, d->memfd);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PINOS_MESSAGE_USE_BUFFERS:
|
case PINOS_MESSAGE_USE_BUFFERS:
|
||||||
connection_add_use_buffers (conn, message);
|
connection_add_use_buffers (conn, dest_id, message);
|
||||||
break;
|
|
||||||
|
|
||||||
case PINOS_MESSAGE_PROCESS_BUFFER:
|
|
||||||
p = connection_add_message (conn, type, sizeof (PinosMessageProcessBuffer));
|
|
||||||
memcpy (p, message, sizeof (PinosMessageProcessBuffer));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_NODE_EVENT:
|
case PINOS_MESSAGE_NODE_EVENT:
|
||||||
connection_add_node_event (conn, message);
|
connection_add_node_event (conn, dest_id, message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_NODE_COMMAND:
|
case PINOS_MESSAGE_NODE_COMMAND:
|
||||||
connection_add_node_command (conn, message);
|
connection_add_node_command (conn, dest_id, message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_PORT_COMMAND:
|
case PINOS_MESSAGE_PORT_COMMAND:
|
||||||
connection_add_port_command (conn, message);
|
connection_add_port_command (conn, dest_id, message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_TRANSPORT_UPDATE:
|
case PINOS_MESSAGE_TRANSPORT_UPDATE:
|
||||||
p = connection_add_message (conn, type, sizeof (PinosMessageTransportUpdate));
|
{
|
||||||
memcpy (p, message, sizeof (PinosMessageTransportUpdate));
|
PinosMessageTransportUpdate *d;
|
||||||
|
d = connection_add_message (conn, dest_id, type, sizeof (PinosMessageTransportUpdate));
|
||||||
|
memcpy (d, message, sizeof (PinosMessageTransportUpdate));
|
||||||
|
d->memfd = connection_add_fd (conn, d->memfd);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PINOS_MESSAGE_INVALID:
|
case PINOS_MESSAGE_INVALID:
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -34,34 +34,100 @@ typedef struct _PinosConnection PinosConnection;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PINOS_MESSAGE_INVALID = 0,
|
PINOS_MESSAGE_INVALID = 0,
|
||||||
/* client to server */
|
|
||||||
PINOS_MESSAGE_NODE_UPDATE = 1,
|
|
||||||
PINOS_MESSAGE_PORT_UPDATE = 2,
|
|
||||||
PINOS_MESSAGE_NODE_STATE_CHANGE = 3,
|
|
||||||
|
|
||||||
PINOS_MESSAGE_PORT_STATUS_CHANGE = 4,
|
PINOS_MESSAGE_SYNC,
|
||||||
PINOS_MESSAGE_NODE_EVENT = 5,
|
PINOS_MESSAGE_NOTIFY_DONE,
|
||||||
|
|
||||||
|
PINOS_MESSAGE_SUBSCRIBE,
|
||||||
|
PINOS_MESSAGE_NOTIFY_GLOBAL,
|
||||||
|
PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE,
|
||||||
|
|
||||||
|
PINOS_MESSAGE_CREATE_NODE,
|
||||||
|
PINOS_MESSAGE_CREATE_NODE_DONE,
|
||||||
|
|
||||||
|
PINOS_MESSAGE_CREATE_CLIENT_NODE,
|
||||||
|
PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE,
|
||||||
|
|
||||||
|
/* client to server */
|
||||||
|
PINOS_MESSAGE_NODE_UPDATE,
|
||||||
|
PINOS_MESSAGE_PORT_UPDATE,
|
||||||
|
PINOS_MESSAGE_NODE_STATE_CHANGE,
|
||||||
|
|
||||||
|
PINOS_MESSAGE_PORT_STATUS_CHANGE,
|
||||||
|
PINOS_MESSAGE_NODE_EVENT,
|
||||||
|
|
||||||
/* server to client */
|
/* server to client */
|
||||||
PINOS_MESSAGE_TRANSPORT_UPDATE = 32,
|
PINOS_MESSAGE_TRANSPORT_UPDATE,
|
||||||
|
|
||||||
PINOS_MESSAGE_ADD_PORT = 33,
|
PINOS_MESSAGE_ADD_PORT,
|
||||||
PINOS_MESSAGE_REMOVE_PORT = 34,
|
PINOS_MESSAGE_REMOVE_PORT,
|
||||||
|
|
||||||
PINOS_MESSAGE_SET_FORMAT = 35,
|
PINOS_MESSAGE_SET_FORMAT,
|
||||||
PINOS_MESSAGE_SET_PROPERTY = 36,
|
PINOS_MESSAGE_SET_PROPERTY,
|
||||||
|
|
||||||
PINOS_MESSAGE_NODE_COMMAND = 37,
|
PINOS_MESSAGE_NODE_COMMAND,
|
||||||
PINOS_MESSAGE_PORT_COMMAND = 38,
|
PINOS_MESSAGE_PORT_COMMAND,
|
||||||
|
|
||||||
/* both */
|
/* both */
|
||||||
PINOS_MESSAGE_ADD_MEM = 64,
|
PINOS_MESSAGE_ADD_MEM,
|
||||||
PINOS_MESSAGE_USE_BUFFERS = 66,
|
PINOS_MESSAGE_USE_BUFFERS,
|
||||||
|
|
||||||
PINOS_MESSAGE_PROCESS_BUFFER = 67,
|
|
||||||
|
|
||||||
} PinosMessageType;
|
} PinosMessageType;
|
||||||
|
|
||||||
|
/* PINOS_MESSAGE_SYNC */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t seq;
|
||||||
|
} PinosMessageSync;
|
||||||
|
|
||||||
|
/* PINOS_MESSAGE_NOTIFY_DONE */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t seq;
|
||||||
|
} PinosMessageNotifyDone;
|
||||||
|
|
||||||
|
/* PINOS_MESSAGE_SUBSCRIBE */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t seq;
|
||||||
|
} PinosMessageSubscribe;
|
||||||
|
|
||||||
|
/* PINOS_MESSAGE_NOTIFY_GLOBAL */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id;
|
||||||
|
const char * type;
|
||||||
|
} PinosMessageNotifyGlobal;
|
||||||
|
|
||||||
|
/* PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id;
|
||||||
|
} PinosMessageNotifyGlobalRemove;
|
||||||
|
|
||||||
|
/* PINOS_MESSAGE_CREATE_NODE */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t seq;
|
||||||
|
const char *factory_name;
|
||||||
|
const char *name;
|
||||||
|
SpaDict *props;
|
||||||
|
uint32_t id;
|
||||||
|
} PinosMessageCreateNode;
|
||||||
|
|
||||||
|
/* PINOS_MESSAGE_CREATE_NODE_DONE */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t seq;
|
||||||
|
} PinosMessageCreateNodeDone;
|
||||||
|
|
||||||
|
/* PINOS_MESSAGE_CREATE_CLIENT_NODE */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t seq;
|
||||||
|
const char *name;
|
||||||
|
SpaDict *props;
|
||||||
|
uint32_t id;
|
||||||
|
} PinosMessageCreateClientNode;
|
||||||
|
|
||||||
|
/* PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t seq;
|
||||||
|
int datafd;
|
||||||
|
} PinosMessageCreateClientNodeDone;
|
||||||
|
|
||||||
/* PINOS_MESSAGE_NODE_UPDATE */
|
/* PINOS_MESSAGE_NODE_UPDATE */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
#define PINOS_MESSAGE_NODE_UPDATE_MAX_INPUTS (1 << 0)
|
#define PINOS_MESSAGE_NODE_UPDATE_MAX_INPUTS (1 << 0)
|
||||||
|
|
@ -147,7 +213,7 @@ typedef struct {
|
||||||
|
|
||||||
/* PINOS_MESSAGE_TRANSPORT_UPDATE */
|
/* PINOS_MESSAGE_TRANSPORT_UPDATE */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int memfd_index;
|
int memfd;
|
||||||
off_t offset;
|
off_t offset;
|
||||||
size_t size;
|
size_t size;
|
||||||
} PinosMessageTransportUpdate;
|
} PinosMessageTransportUpdate;
|
||||||
|
|
@ -158,7 +224,7 @@ typedef struct {
|
||||||
uint32_t port_id;
|
uint32_t port_id;
|
||||||
uint32_t mem_id;
|
uint32_t mem_id;
|
||||||
SpaDataType type;
|
SpaDataType type;
|
||||||
unsigned int fd_index;
|
int memfd;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
off_t offset;
|
off_t offset;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
@ -179,28 +245,17 @@ typedef struct {
|
||||||
PinosMessageMemRef *buffers;
|
PinosMessageMemRef *buffers;
|
||||||
} PinosMessageUseBuffers;
|
} PinosMessageUseBuffers;
|
||||||
|
|
||||||
/* PINOS_MESSAGE_PROCESS_BUFFER */
|
|
||||||
typedef struct {
|
|
||||||
SpaDirection direction;
|
|
||||||
uint32_t port_id;
|
|
||||||
uint32_t buffer_id;
|
|
||||||
} PinosMessageProcessBuffer;
|
|
||||||
|
|
||||||
PinosConnection * pinos_connection_new (int fd);
|
PinosConnection * pinos_connection_new (int fd);
|
||||||
void pinos_connection_free (PinosConnection *conn);
|
void pinos_connection_destroy (PinosConnection *conn);
|
||||||
|
|
||||||
bool pinos_connection_has_next (PinosConnection *conn);
|
bool pinos_connection_get_next (PinosConnection *conn,
|
||||||
PinosMessageType pinos_connection_get_type (PinosConnection *conn);
|
PinosMessageType *type,
|
||||||
|
uint32_t *dest_id,
|
||||||
|
size_t *size);
|
||||||
bool pinos_connection_parse_message (PinosConnection *conn,
|
bool pinos_connection_parse_message (PinosConnection *conn,
|
||||||
void *msg);
|
void *msg);
|
||||||
int pinos_connection_get_fd (PinosConnection *conn,
|
|
||||||
unsigned int index,
|
|
||||||
bool close);
|
|
||||||
|
|
||||||
int pinos_connection_add_fd (PinosConnection *conn,
|
|
||||||
int fd,
|
|
||||||
bool close);
|
|
||||||
bool pinos_connection_add_message (PinosConnection *conn,
|
bool pinos_connection_add_message (PinosConnection *conn,
|
||||||
|
uint32_t dest_id,
|
||||||
PinosMessageType type,
|
PinosMessageType type,
|
||||||
void *msg);
|
void *msg);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,283 +17,31 @@
|
||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "pinos/client/pinos.h"
|
#include "pinos/client/pinos.h"
|
||||||
|
|
||||||
#include "pinos/client/context.h"
|
#include "pinos/client/context.h"
|
||||||
#include "pinos/client/enumtypes.h"
|
#include "pinos/client/connection.h"
|
||||||
#include "pinos/client/subscribe.h"
|
#include "pinos/client/subscribe.h"
|
||||||
|
|
||||||
#include "pinos/client/private.h"
|
typedef struct {
|
||||||
|
PinosContext this;
|
||||||
|
|
||||||
#define PINOS_CONTEXT_GET_PRIVATE(obj) \
|
int fd;
|
||||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_CONTEXT, PinosContextPrivate))
|
PinosConnection *connection;
|
||||||
|
SpaSource source;
|
||||||
|
|
||||||
G_DEFINE_TYPE (PinosContext, pinos_context, G_TYPE_OBJECT);
|
bool disconnecting;
|
||||||
|
|
||||||
static void subscription_state (GObject *object, GParamSpec *pspec, gpointer user_data);
|
PinosSubscriptionFlags subscribe_mask;
|
||||||
static void subscription_cb (PinosSubscribe *subscribe,
|
PinosSubscriptionFunc subscribe_func;
|
||||||
PinosSubscriptionEvent event,
|
void *subscribe_data;
|
||||||
PinosSubscriptionFlags flags,
|
} PinosContextImpl;
|
||||||
GDBusProxy *object,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MAIN_CONTEXT,
|
|
||||||
PROP_NAME,
|
|
||||||
PROP_PROPERTIES,
|
|
||||||
PROP_STATE,
|
|
||||||
PROP_CONNECTION,
|
|
||||||
PROP_SUBSCRIPTION_MASK,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
SIGNAL_SUBSCRIPTION_EVENT,
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
static guint signals[LAST_SIGNAL] = { 0 };
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_context_get_property (GObject *_object,
|
|
||||||
guint prop_id,
|
|
||||||
GValue *value,
|
|
||||||
GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
PinosContext *context = PINOS_CONTEXT (_object);
|
|
||||||
PinosContextPrivate *priv = context->priv;
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MAIN_CONTEXT:
|
|
||||||
g_value_set_boxed (value, priv->context);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_NAME:
|
|
||||||
g_value_set_string (value, priv->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_PROPERTIES:
|
|
||||||
g_value_set_boxed (value, priv->properties);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_STATE:
|
|
||||||
g_value_set_enum (value, priv->state);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_CONNECTION:
|
|
||||||
g_value_set_object (value, priv->connection);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_SUBSCRIPTION_MASK:
|
|
||||||
g_value_set_flags (value, priv->subscription_mask);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (context, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_context_set_property (GObject *_object,
|
|
||||||
guint prop_id,
|
|
||||||
const GValue *value,
|
|
||||||
GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
PinosContext *context = PINOS_CONTEXT (_object);
|
|
||||||
PinosContextPrivate *priv = context->priv;
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MAIN_CONTEXT:
|
|
||||||
priv->context = g_value_dup_boxed (value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_NAME:
|
|
||||||
g_free (priv->name);
|
|
||||||
priv->name = g_value_dup_string (value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_PROPERTIES:
|
|
||||||
if (priv->properties)
|
|
||||||
pinos_properties_free (priv->properties);
|
|
||||||
priv->properties = g_value_dup_boxed (value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_SUBSCRIPTION_MASK:
|
|
||||||
priv->subscription_mask = g_value_get_flags (value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (context, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_context_finalize (GObject * object)
|
|
||||||
{
|
|
||||||
PinosContext *context = PINOS_CONTEXT (object);
|
|
||||||
PinosContextPrivate *priv = context->priv;
|
|
||||||
|
|
||||||
pinos_log_debug ("free context %p", context);
|
|
||||||
|
|
||||||
if (priv->id)
|
|
||||||
g_bus_unwatch_name(priv->id);
|
|
||||||
|
|
||||||
g_clear_pointer (&priv->context, g_main_context_unref);
|
|
||||||
g_free (priv->name);
|
|
||||||
if (priv->properties)
|
|
||||||
pinos_properties_free (priv->properties);
|
|
||||||
|
|
||||||
g_list_free (priv->nodes);
|
|
||||||
g_list_free (priv->links);
|
|
||||||
g_list_free (priv->clients);
|
|
||||||
g_clear_object (&priv->subscribe);
|
|
||||||
g_clear_error (&priv->error);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (pinos_context_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_context_class_init (PinosContextClass * klass)
|
|
||||||
{
|
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
||||||
|
|
||||||
g_type_class_add_private (klass, sizeof (PinosContextPrivate));
|
|
||||||
|
|
||||||
gobject_class->finalize = pinos_context_finalize;
|
|
||||||
gobject_class->set_property = pinos_context_set_property;
|
|
||||||
gobject_class->get_property = pinos_context_get_property;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PinosContext:main-context
|
|
||||||
*
|
|
||||||
* The main context to use
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_MAIN_CONTEXT,
|
|
||||||
g_param_spec_boxed ("main-context",
|
|
||||||
"Main Context",
|
|
||||||
"The main context to use",
|
|
||||||
G_TYPE_MAIN_CONTEXT,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_CONSTRUCT_ONLY |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosContext:name
|
|
||||||
*
|
|
||||||
* The application name of the context.
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_NAME,
|
|
||||||
g_param_spec_string ("name",
|
|
||||||
"Name",
|
|
||||||
"The application name",
|
|
||||||
NULL,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosContext:properties
|
|
||||||
*
|
|
||||||
* Properties of the context.
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_PROPERTIES,
|
|
||||||
g_param_spec_boxed ("properties",
|
|
||||||
"Properties",
|
|
||||||
"Extra properties",
|
|
||||||
PINOS_TYPE_PROPERTIES,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosContext:state
|
|
||||||
*
|
|
||||||
* The state of the context.
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_STATE,
|
|
||||||
g_param_spec_enum ("state",
|
|
||||||
"State",
|
|
||||||
"The context state",
|
|
||||||
PINOS_TYPE_CONTEXT_STATE,
|
|
||||||
PINOS_CONTEXT_STATE_UNCONNECTED,
|
|
||||||
G_PARAM_READABLE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosContext:connection
|
|
||||||
*
|
|
||||||
* The connection of the context.
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_CONNECTION,
|
|
||||||
g_param_spec_object ("connection",
|
|
||||||
"Connection",
|
|
||||||
"The DBus connection",
|
|
||||||
G_TYPE_DBUS_CONNECTION,
|
|
||||||
G_PARAM_READABLE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosContext:subscription-mask
|
|
||||||
*
|
|
||||||
* The subscription mask
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_SUBSCRIPTION_MASK,
|
|
||||||
g_param_spec_flags ("subscription-mask",
|
|
||||||
"Subscription Mask",
|
|
||||||
"The object to receive subscription events of",
|
|
||||||
PINOS_TYPE_SUBSCRIPTION_FLAGS,
|
|
||||||
0,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosContext:subscription-event
|
|
||||||
* @subscribe: The #PinosContext emitting the signal.
|
|
||||||
* @event: A #PinosSubscriptionEvent
|
|
||||||
* @flags: #PinosSubscriptionFlags indicating the object
|
|
||||||
* @object: the GDBusProxy object
|
|
||||||
*
|
|
||||||
* Notify about a new object that was added/removed/modified.
|
|
||||||
*/
|
|
||||||
signals[SIGNAL_SUBSCRIPTION_EVENT] = g_signal_new ("subscription-event",
|
|
||||||
G_TYPE_FROM_CLASS (klass),
|
|
||||||
G_SIGNAL_RUN_LAST,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
g_cclosure_marshal_generic,
|
|
||||||
G_TYPE_NONE,
|
|
||||||
3,
|
|
||||||
PINOS_TYPE_SUBSCRIPTION_EVENT,
|
|
||||||
PINOS_TYPE_SUBSCRIPTION_FLAGS,
|
|
||||||
G_TYPE_DBUS_PROXY);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_context_init (PinosContext * context)
|
|
||||||
{
|
|
||||||
PinosContextPrivate *priv = context->priv = PINOS_CONTEXT_GET_PRIVATE (context);
|
|
||||||
|
|
||||||
pinos_log_debug ("new context %p", context);
|
|
||||||
|
|
||||||
priv->state = PINOS_CONTEXT_STATE_UNCONNECTED;
|
|
||||||
|
|
||||||
priv->subscribe = pinos_subscribe_new ();
|
|
||||||
g_object_set (priv->subscribe,
|
|
||||||
"subscription-mask", PINOS_SUBSCRIPTION_FLAGS_ALL,
|
|
||||||
NULL);
|
|
||||||
g_signal_connect (priv->subscribe,
|
|
||||||
"subscription-event",
|
|
||||||
(GCallback) subscription_cb,
|
|
||||||
context);
|
|
||||||
g_signal_connect (priv->subscribe,
|
|
||||||
"notify::state",
|
|
||||||
(GCallback) subscription_state,
|
|
||||||
context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pinos_context_state_as_string:
|
* pinos_context_state_as_string:
|
||||||
|
|
@ -303,15 +51,157 @@ pinos_context_init (PinosContext * context)
|
||||||
*
|
*
|
||||||
* Returns: the string representation of @state.
|
* Returns: the string representation of @state.
|
||||||
*/
|
*/
|
||||||
const gchar *
|
const char *
|
||||||
pinos_context_state_as_string (PinosContextState state)
|
pinos_context_state_as_string (PinosContextState state)
|
||||||
{
|
{
|
||||||
GEnumValue *val;
|
switch (state) {
|
||||||
|
case PINOS_CONTEXT_STATE_ERROR:
|
||||||
|
return "error";
|
||||||
|
case PINOS_CONTEXT_STATE_UNCONNECTED:
|
||||||
|
return "unconnected";
|
||||||
|
case PINOS_CONTEXT_STATE_CONNECTING:
|
||||||
|
return "connecting";
|
||||||
|
case PINOS_CONTEXT_STATE_CONNECTED:
|
||||||
|
return "connected";
|
||||||
|
}
|
||||||
|
return "invalid-state";
|
||||||
|
}
|
||||||
|
|
||||||
val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (PINOS_TYPE_CONTEXT_STATE)),
|
static void
|
||||||
state);
|
context_set_state (PinosContext *context,
|
||||||
|
PinosContextState state,
|
||||||
|
const char *fmt,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
if (context->state != state) {
|
||||||
|
pinos_log_debug ("context %p: update state from %s -> %s", context,
|
||||||
|
pinos_context_state_as_string (context->state),
|
||||||
|
pinos_context_state_as_string (state));
|
||||||
|
|
||||||
return val == NULL ? "invalid-state" : val->value_nick;
|
if (context->error)
|
||||||
|
free (context->error);
|
||||||
|
|
||||||
|
if (fmt) {
|
||||||
|
va_list varargs;
|
||||||
|
|
||||||
|
va_start (varargs, fmt);
|
||||||
|
vasprintf (&context->error, fmt, varargs);
|
||||||
|
va_end (varargs);
|
||||||
|
} else {
|
||||||
|
context->error = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->state = state;
|
||||||
|
pinos_signal_emit (&context->state_changed, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SpaResult
|
||||||
|
core_dispatch_func (void *object,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
PinosContext *context = data;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case PINOS_MESSAGE_NOTIFY_DONE:
|
||||||
|
{
|
||||||
|
PinosMessageNotifyDone *nd = message;
|
||||||
|
|
||||||
|
if (nd->seq == 0)
|
||||||
|
context_set_state (context, PINOS_CONTEXT_STATE_CONNECTED, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PINOS_MESSAGE_NOTIFY_GLOBAL:
|
||||||
|
{
|
||||||
|
PinosMessageNotifyGlobal *ng = message;
|
||||||
|
pinos_log_warn ("global %u %s", ng->id, ng->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
pinos_log_warn ("unhandled message %d", type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PinosProxy *
|
||||||
|
find_proxy (PinosContext *context,
|
||||||
|
uint32_t id)
|
||||||
|
{
|
||||||
|
PinosProxy *p;
|
||||||
|
|
||||||
|
spa_list_for_each (p, &context->proxy_list, link) {
|
||||||
|
if (p->id == id)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_context_data (SpaSource *source,
|
||||||
|
int fd,
|
||||||
|
SpaIO mask,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
PinosContextImpl *impl = data;
|
||||||
|
PinosContext *this = &impl->this;
|
||||||
|
|
||||||
|
if (mask & (SPA_IO_ERR | SPA_IO_HUP)) {
|
||||||
|
context_set_state (this,
|
||||||
|
PINOS_CONTEXT_STATE_ERROR,
|
||||||
|
"connection closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & SPA_IO_IN) {
|
||||||
|
PinosConnection *conn = impl->connection;
|
||||||
|
PinosMessageType type;
|
||||||
|
uint32_t id;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
while (pinos_connection_get_next (conn, &type, &id, &size)) {
|
||||||
|
void *p = alloca (size);
|
||||||
|
PinosProxy *proxy;
|
||||||
|
|
||||||
|
pinos_log_error ("context %p: got message %d from %u", this, type, id);
|
||||||
|
|
||||||
|
if (!pinos_connection_parse_message (conn, p)) {
|
||||||
|
pinos_log_error ("context %p: failed to parse message", this);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy = find_proxy (this, id);
|
||||||
|
if (proxy == NULL) {
|
||||||
|
pinos_log_error ("context %p: could not find proxy %u", this, id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->dispatch_func (proxy, type, p, proxy->dispatch_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SpaResult
|
||||||
|
context_send_func (void *object,
|
||||||
|
uint32_t id,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
bool flush,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
PinosContextImpl *impl = SPA_CONTAINER_OF (data, PinosContextImpl, this);
|
||||||
|
|
||||||
|
pinos_log_error ("context %p: send message %d to %u", &impl->this, type, id);
|
||||||
|
pinos_connection_add_message (impl->connection,
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
message);
|
||||||
|
if (flush)
|
||||||
|
pinos_connection_flush (impl->connection);
|
||||||
|
|
||||||
|
return SPA_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -325,197 +215,67 @@ pinos_context_state_as_string (PinosContextState state)
|
||||||
* Returns: a new unconnected #PinosContext
|
* Returns: a new unconnected #PinosContext
|
||||||
*/
|
*/
|
||||||
PinosContext *
|
PinosContext *
|
||||||
pinos_context_new (GMainContext *context,
|
pinos_context_new (PinosLoop *loop,
|
||||||
const gchar *name,
|
const char *name,
|
||||||
PinosProperties *properties)
|
PinosProperties *properties)
|
||||||
{
|
{
|
||||||
PinosContext *ctx;
|
PinosContextImpl *impl;
|
||||||
|
PinosContext *this;
|
||||||
|
|
||||||
g_return_val_if_fail (name != NULL, NULL);
|
impl = calloc (1, sizeof (PinosContextImpl));
|
||||||
|
this = &impl->this;
|
||||||
|
pinos_log_debug ("context %p: new", impl);
|
||||||
|
|
||||||
|
this->name = strdup (name);
|
||||||
|
|
||||||
if (properties == NULL)
|
if (properties == NULL)
|
||||||
properties = pinos_properties_new ("application.name", name, NULL);
|
properties = pinos_properties_new ("application.name", name, NULL);
|
||||||
|
|
||||||
pinos_fill_context_properties (properties);
|
pinos_fill_context_properties (properties);
|
||||||
|
this->properties = properties;
|
||||||
|
|
||||||
ctx = g_object_new (PINOS_TYPE_CONTEXT,
|
this->loop = loop;
|
||||||
"main-context", context,
|
|
||||||
"name", name,
|
|
||||||
"properties", properties,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
pinos_properties_free (properties);
|
this->state = PINOS_CONTEXT_STATE_UNCONNECTED;
|
||||||
|
|
||||||
return ctx;
|
this->send_func = context_send_func;
|
||||||
|
this->send_data = this;
|
||||||
|
|
||||||
|
pinos_map_init (&this->objects, 64);
|
||||||
|
|
||||||
|
spa_list_init (&this->stream_list);
|
||||||
|
spa_list_init (&this->global_list);
|
||||||
|
spa_list_init (&this->proxy_list);
|
||||||
|
|
||||||
|
pinos_signal_init (&this->state_changed);
|
||||||
|
pinos_signal_init (&this->destroy_signal);
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
void
|
||||||
do_notify_state (PinosContext *context)
|
pinos_context_destroy (PinosContext *context)
|
||||||
{
|
{
|
||||||
g_object_notify (G_OBJECT (context), "state");
|
PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this);
|
||||||
g_object_unref (context);
|
PinosStream *stream, *t1;
|
||||||
return FALSE;
|
PinosProxy *proxy, *t2;
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
pinos_log_debug ("context %p: destroy", context);
|
||||||
context_set_state (PinosContext *context,
|
pinos_signal_emit (&context->destroy_signal, context);
|
||||||
PinosContextState state,
|
|
||||||
GError *error)
|
|
||||||
{
|
|
||||||
if (context->priv->state != state) {
|
|
||||||
if (error) {
|
|
||||||
g_clear_error (&context->priv->error);
|
|
||||||
context->priv->error = error;
|
|
||||||
}
|
|
||||||
context->priv->state = state;
|
|
||||||
g_main_context_invoke (context->priv->context,
|
|
||||||
(GSourceFunc) do_notify_state,
|
|
||||||
g_object_ref (context));
|
|
||||||
} else {
|
|
||||||
if (error)
|
|
||||||
g_error_free (error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
spa_list_for_each_safe (stream, t1, &context->stream_list, link)
|
||||||
on_daemon_connected (GObject *source_object,
|
pinos_stream_destroy (stream);
|
||||||
GAsyncResult *res,
|
spa_list_for_each_safe (proxy, t2, &context->proxy_list, link)
|
||||||
gpointer user_data)
|
pinos_proxy_destroy (proxy);
|
||||||
{
|
|
||||||
PinosContext *context = user_data;
|
|
||||||
|
|
||||||
context_set_state (context, PINOS_CONTEXT_STATE_CONNECTED, NULL);
|
if (context->name)
|
||||||
}
|
free (context->name);
|
||||||
|
if (context->properties)
|
||||||
|
pinos_properties_free (context->properties);
|
||||||
|
|
||||||
static void
|
if (context->error)
|
||||||
subscription_cb (PinosSubscribe *subscribe,
|
free (context->error);
|
||||||
PinosSubscriptionEvent event,
|
|
||||||
PinosSubscriptionFlags flags,
|
|
||||||
GDBusProxy *object,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosContext *context = user_data;
|
|
||||||
PinosContextPrivate *priv = context->priv;
|
|
||||||
|
|
||||||
switch (flags) {
|
free (impl);
|
||||||
case PINOS_SUBSCRIPTION_FLAG_DAEMON:
|
|
||||||
priv->daemon = g_object_ref (object);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PINOS_SUBSCRIPTION_FLAG_CLIENT:
|
|
||||||
if (event == PINOS_SUBSCRIPTION_EVENT_NEW)
|
|
||||||
priv->clients = g_list_prepend (priv->clients, object);
|
|
||||||
else if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE)
|
|
||||||
priv->clients = g_list_remove (priv->clients, object);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PINOS_SUBSCRIPTION_FLAG_NODE:
|
|
||||||
if (event == PINOS_SUBSCRIPTION_EVENT_NEW)
|
|
||||||
priv->nodes = g_list_prepend (priv->nodes, object);
|
|
||||||
else if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE)
|
|
||||||
priv->nodes = g_list_remove (priv->nodes, object);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PINOS_SUBSCRIPTION_FLAG_LINK:
|
|
||||||
if (event == PINOS_SUBSCRIPTION_EVENT_NEW)
|
|
||||||
priv->links = g_list_prepend (priv->links, object);
|
|
||||||
else if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE)
|
|
||||||
priv->links = g_list_remove (priv->links, object);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & priv->subscription_mask)
|
|
||||||
g_signal_emit (context,
|
|
||||||
signals[SIGNAL_SUBSCRIPTION_EVENT],
|
|
||||||
0,
|
|
||||||
event,
|
|
||||||
flags,
|
|
||||||
object);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
subscription_state (GObject *object,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosContext *context = user_data;
|
|
||||||
PinosContextPrivate *priv = context->priv;
|
|
||||||
PinosSubscriptionState state;
|
|
||||||
|
|
||||||
g_assert (object == G_OBJECT (priv->subscribe));
|
|
||||||
|
|
||||||
state = pinos_subscribe_get_state (priv->subscribe);
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case PINOS_SUBSCRIPTION_STATE_READY:
|
|
||||||
on_daemon_connected (NULL, NULL, context);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_name_appeared (GDBusConnection *connection,
|
|
||||||
const gchar *name,
|
|
||||||
const gchar *name_owner,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosContext *context = user_data;
|
|
||||||
PinosContextPrivate *priv = context->priv;
|
|
||||||
|
|
||||||
priv->connection = connection;
|
|
||||||
|
|
||||||
g_object_set (priv->subscribe, "connection", priv->connection,
|
|
||||||
"service", name, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_name_vanished (GDBusConnection *connection,
|
|
||||||
const gchar *name,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosContext *context = user_data;
|
|
||||||
PinosContextPrivate *priv = context->priv;
|
|
||||||
|
|
||||||
priv->connection = connection;
|
|
||||||
|
|
||||||
g_object_set (priv->subscribe, "connection", connection, NULL);
|
|
||||||
|
|
||||||
if (priv->flags & PINOS_CONTEXT_FLAGS_NOFAIL) {
|
|
||||||
context_set_state (context, PINOS_CONTEXT_STATE_CONNECTING, NULL);
|
|
||||||
} else {
|
|
||||||
context_set_state (context,
|
|
||||||
PINOS_CONTEXT_STATE_ERROR,
|
|
||||||
g_error_new_literal (G_IO_ERROR,
|
|
||||||
G_IO_ERROR_CLOSED,
|
|
||||||
"Connection closed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
do_connect (PinosContext *context)
|
|
||||||
{
|
|
||||||
PinosContextPrivate *priv = context->priv;
|
|
||||||
GBusNameWatcherFlags nw_flags;
|
|
||||||
|
|
||||||
nw_flags = G_BUS_NAME_WATCHER_FLAGS_NONE;
|
|
||||||
if (!(priv->flags & PINOS_CONTEXT_FLAGS_NOAUTOSPAWN))
|
|
||||||
nw_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START;
|
|
||||||
|
|
||||||
priv->id = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
|
||||||
PINOS_DBUS_SERVICE,
|
|
||||||
nw_flags,
|
|
||||||
on_name_appeared,
|
|
||||||
on_name_vanished,
|
|
||||||
context,
|
|
||||||
NULL);
|
|
||||||
g_object_unref (context);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -527,38 +287,77 @@ do_connect (PinosContext *context)
|
||||||
*
|
*
|
||||||
* Returns: %TRUE on success.
|
* Returns: %TRUE on success.
|
||||||
*/
|
*/
|
||||||
gboolean
|
bool
|
||||||
pinos_context_connect (PinosContext *context,
|
pinos_context_connect (PinosContext *context)
|
||||||
PinosContextFlags flags)
|
|
||||||
{
|
{
|
||||||
PinosContextPrivate *priv;
|
PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this);
|
||||||
|
struct sockaddr_un addr;
|
||||||
g_return_val_if_fail (PINOS_IS_CONTEXT (context), FALSE);
|
socklen_t size;
|
||||||
|
const char *runtime_dir, *name = NULL;
|
||||||
priv = context->priv;
|
int name_size, fd;
|
||||||
g_return_val_if_fail (priv->connection == NULL, FALSE);
|
PinosMessageSubscribe sm;
|
||||||
|
|
||||||
priv->flags = flags;
|
|
||||||
|
|
||||||
context_set_state (context, PINOS_CONTEXT_STATE_CONNECTING, NULL);
|
context_set_state (context, PINOS_CONTEXT_STATE_CONNECTING, NULL);
|
||||||
g_main_context_invoke (priv->context,
|
|
||||||
(GSourceFunc) do_connect,
|
|
||||||
g_object_ref (context));
|
|
||||||
|
|
||||||
return TRUE;
|
if ((runtime_dir = getenv ("XDG_RUNTIME_DIR")) == NULL) {
|
||||||
}
|
context_set_state (context,
|
||||||
|
PINOS_CONTEXT_STATE_ERROR,
|
||||||
static void
|
"connect failed: XDG_RUNTIME_DIR not set in the environment");
|
||||||
do_disconnect (PinosContext *context)
|
return false;
|
||||||
{
|
|
||||||
PinosContextPrivate *priv = context->priv;
|
|
||||||
|
|
||||||
g_clear_object (&priv->daemon);
|
|
||||||
if (priv->id) {
|
|
||||||
g_bus_unwatch_name(priv->id);
|
|
||||||
priv->id = 0;
|
|
||||||
}
|
}
|
||||||
context_set_state (context, PINOS_CONTEXT_STATE_UNCONNECTED, NULL);
|
|
||||||
|
if (name == NULL)
|
||||||
|
name = getenv("PINOS_CORE");
|
||||||
|
if (name == NULL)
|
||||||
|
name = "pinos-0";
|
||||||
|
|
||||||
|
if ((fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memset (&addr, 0, sizeof (addr));
|
||||||
|
addr.sun_family = AF_LOCAL;
|
||||||
|
name_size = snprintf (addr.sun_path, sizeof (addr.sun_path),
|
||||||
|
"%s/%s", runtime_dir, name) + 1;
|
||||||
|
|
||||||
|
if (name_size > (int)sizeof addr.sun_path) {
|
||||||
|
pinos_log_error ("socket path \"%s/%s\" plus null terminator exceeds 108 bytes",
|
||||||
|
runtime_dir, name);
|
||||||
|
close (fd);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
||||||
|
|
||||||
|
if (connect (fd, (struct sockaddr *) &addr, size) < 0) {
|
||||||
|
context_set_state (context,
|
||||||
|
PINOS_CONTEXT_STATE_ERROR,
|
||||||
|
"connect failed: %s", strerror (errno));
|
||||||
|
close (fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl->fd = fd;
|
||||||
|
impl->connection = pinos_connection_new (fd);
|
||||||
|
|
||||||
|
pinos_loop_add_io (context->loop,
|
||||||
|
fd,
|
||||||
|
SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR,
|
||||||
|
false,
|
||||||
|
on_context_data,
|
||||||
|
impl);
|
||||||
|
|
||||||
|
context->core_proxy = pinos_proxy_new (context,
|
||||||
|
SPA_ID_INVALID,
|
||||||
|
0);
|
||||||
|
context->core_proxy->dispatch_func = core_dispatch_func;
|
||||||
|
context->core_proxy->dispatch_data = context;
|
||||||
|
|
||||||
|
sm.seq = 0;
|
||||||
|
pinos_proxy_send_message (context->core_proxy,
|
||||||
|
PINOS_MESSAGE_SUBSCRIBE,
|
||||||
|
&sm,
|
||||||
|
true);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -569,60 +368,89 @@ do_disconnect (PinosContext *context)
|
||||||
*
|
*
|
||||||
* Returns: %TRUE on success.
|
* Returns: %TRUE on success.
|
||||||
*/
|
*/
|
||||||
gboolean
|
bool
|
||||||
pinos_context_disconnect (PinosContext *context)
|
pinos_context_disconnect (PinosContext *context)
|
||||||
{
|
{
|
||||||
PinosContextPrivate *priv;
|
PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this);
|
||||||
|
|
||||||
g_return_val_if_fail (PINOS_IS_CONTEXT (context), FALSE);
|
impl->disconnecting = true;
|
||||||
|
|
||||||
priv = context->priv;
|
pinos_connection_destroy (impl->connection);
|
||||||
g_return_val_if_fail (!priv->disconnecting, FALSE);
|
close (impl->fd);
|
||||||
|
|
||||||
priv->disconnecting = TRUE;
|
context_set_state (context, PINOS_CONTEXT_STATE_UNCONNECTED, NULL);
|
||||||
|
|
||||||
g_main_context_invoke (priv->context,
|
return true;
|
||||||
(GSourceFunc) do_disconnect,
|
|
||||||
g_object_ref (context));
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void
|
||||||
* pinos_context_get_state:
|
pinos_context_subscribe (PinosContext *context,
|
||||||
* @context: a #PinosContext
|
PinosSubscriptionFlags mask,
|
||||||
*
|
PinosSubscriptionFunc func,
|
||||||
* Get the state of @context.
|
void *data)
|
||||||
*
|
|
||||||
* Returns: the state of @context
|
|
||||||
*/
|
|
||||||
PinosContextState
|
|
||||||
pinos_context_get_state (PinosContext *context)
|
|
||||||
{
|
{
|
||||||
PinosContextPrivate *priv;
|
PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this);
|
||||||
|
|
||||||
g_return_val_if_fail (PINOS_IS_CONTEXT (context), PINOS_CONTEXT_STATE_ERROR);
|
impl->subscribe_mask = mask;
|
||||||
priv = context->priv;
|
impl->subscribe_func = func;
|
||||||
|
impl->subscribe_data = data;
|
||||||
return priv->state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void
|
||||||
* pinos_context_get_error:
|
pinos_context_get_daemon_info (PinosContext *context,
|
||||||
* @context: a #PinosContext
|
PinosDaemonInfoCallback cb,
|
||||||
*
|
void *user_data)
|
||||||
* Get the current error of @context or %NULL when the context state
|
|
||||||
* is not #PINOS_CONTEXT_STATE_ERROR
|
|
||||||
*
|
|
||||||
* Returns: the last error or %NULL
|
|
||||||
*/
|
|
||||||
const GError *
|
|
||||||
pinos_context_get_error (PinosContext *context)
|
|
||||||
{
|
{
|
||||||
PinosContextPrivate *priv;
|
cb (context, SPA_RESULT_OK, NULL, user_data);
|
||||||
|
}
|
||||||
g_return_val_if_fail (PINOS_IS_CONTEXT (context), NULL);
|
|
||||||
priv = context->priv;
|
void
|
||||||
|
pinos_context_list_client_info (PinosContext *context,
|
||||||
return priv->error;
|
PinosClientInfoCallback cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
cb (context, SPA_RESULT_OK, NULL, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pinos_context_get_client_info_by_id (PinosContext *context,
|
||||||
|
uint32_t id,
|
||||||
|
PinosClientInfoCallback cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
cb (context, SPA_RESULT_OK, NULL, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pinos_context_list_node_info (PinosContext *context,
|
||||||
|
PinosNodeInfoCallback cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
cb (context, SPA_RESULT_OK, NULL, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pinos_context_get_node_info_by_id (PinosContext *context,
|
||||||
|
uint32_t id,
|
||||||
|
PinosNodeInfoCallback cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
cb (context, SPA_RESULT_OK, NULL, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pinos_context_list_link_info (PinosContext *context,
|
||||||
|
PinosLinkInfoCallback cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
cb (context, SPA_RESULT_OK, NULL, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pinos_context_get_link_info_by_id (PinosContext *context,
|
||||||
|
uint32_t id,
|
||||||
|
PinosLinkInfoCallback cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
cb (context, SPA_RESULT_OK, NULL, user_data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,42 +20,18 @@
|
||||||
#ifndef __PINOS_CONTEXT_H__
|
#ifndef __PINOS_CONTEXT_H__
|
||||||
#define __PINOS_CONTEXT_H__
|
#define __PINOS_CONTEXT_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
typedef struct _PinosContext PinosContext;
|
typedef struct _PinosContext PinosContext;
|
||||||
typedef struct _PinosContextClass PinosContextClass;
|
|
||||||
typedef struct _PinosContextPrivate PinosContextPrivate;
|
|
||||||
|
|
||||||
|
#include <pinos/client/map.h>
|
||||||
|
#include <pinos/client/loop.h>
|
||||||
#include <pinos/client/subscribe.h>
|
#include <pinos/client/subscribe.h>
|
||||||
#include <pinos/client/properties.h>
|
#include <pinos/client/properties.h>
|
||||||
|
#include <pinos/client/connection.h>
|
||||||
#define PINOS_TYPE_CONTEXT (pinos_context_get_type ())
|
#include <pinos/client/proxy.h>
|
||||||
#define PINOS_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_CONTEXT))
|
|
||||||
#define PINOS_IS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_CONTEXT))
|
|
||||||
#define PINOS_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_CONTEXT, PinosContextClass))
|
|
||||||
#define PINOS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_CONTEXT, PinosContext))
|
|
||||||
#define PINOS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_CONTEXT, PinosContextClass))
|
|
||||||
#define PINOS_CONTEXT_CAST(obj) ((PinosContext*)(obj))
|
|
||||||
#define PINOS_CONTEXT_CLASS_CAST(klass) ((PinosContextClass*)(klass))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PinosContextFlags:
|
|
||||||
* @PINOS_CONTEXT_FLAGS_NONE: no flags
|
|
||||||
* @PINOS_CONTEXT_FLAGS_NOAUTOSPAWN: disable autostart of the daemon
|
|
||||||
* @PINOS_CONTEXT_FLAGS_NOFAIL: Don't fail if the daemon is not available,
|
|
||||||
* instead enter PINOS_CONTEXT_CONNECTING state and wait for the daemon
|
|
||||||
* to appear.
|
|
||||||
*
|
|
||||||
* Context flags passed to pinos_context_connect()
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
PINOS_CONTEXT_FLAGS_NONE = 0,
|
|
||||||
PINOS_CONTEXT_FLAGS_NOAUTOSPAWN = (1 << 0),
|
|
||||||
PINOS_CONTEXT_FLAGS_NOFAIL = (1 << 1)
|
|
||||||
} PinosContextFlags;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosContextState:
|
* PinosContextState:
|
||||||
|
|
@ -73,7 +49,7 @@ typedef enum {
|
||||||
PINOS_CONTEXT_STATE_CONNECTED = 2,
|
PINOS_CONTEXT_STATE_CONNECTED = 2,
|
||||||
} PinosContextState;
|
} PinosContextState;
|
||||||
|
|
||||||
const gchar * pinos_context_state_as_string (PinosContextState state);
|
const char * pinos_context_state_as_string (PinosContextState state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosContext:
|
* PinosContext:
|
||||||
|
|
@ -81,33 +57,42 @@ const gchar * pinos_context_state_as_string (PinosContextState state);
|
||||||
* Pinos context object class.
|
* Pinos context object class.
|
||||||
*/
|
*/
|
||||||
struct _PinosContext {
|
struct _PinosContext {
|
||||||
GObject object;
|
char *name;
|
||||||
|
PinosProperties *properties;
|
||||||
|
|
||||||
PinosContextPrivate *priv;
|
PinosLoop *loop;
|
||||||
|
|
||||||
|
PinosProxy *core_proxy;
|
||||||
|
|
||||||
|
PinosMap objects;
|
||||||
|
|
||||||
|
SpaList global_list;
|
||||||
|
SpaList stream_list;
|
||||||
|
SpaList proxy_list;
|
||||||
|
|
||||||
|
PinosSendFunc send_func;
|
||||||
|
void *send_data;
|
||||||
|
|
||||||
|
PinosContextState state;
|
||||||
|
char *error;
|
||||||
|
PINOS_SIGNAL (state_changed, (PinosListener *listener,
|
||||||
|
PinosContext *context));
|
||||||
|
|
||||||
|
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
||||||
|
PinosContext *context));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
PinosContext * pinos_context_new (PinosLoop *loop,
|
||||||
* PinosContextClass:
|
const char *name,
|
||||||
*
|
PinosProperties *properties);
|
||||||
* Pinos context object class.
|
void pinos_context_destroy (PinosContext *context);
|
||||||
*/
|
|
||||||
struct _PinosContextClass {
|
|
||||||
GObjectClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* normal GObject stuff */
|
bool pinos_context_connect (PinosContext *context);
|
||||||
GType pinos_context_get_type (void);
|
bool pinos_context_disconnect (PinosContext *context);
|
||||||
|
|
||||||
PinosContext * pinos_context_new (GMainContext *ctx,
|
#ifdef __cplusplus
|
||||||
const gchar *name,
|
}
|
||||||
PinosProperties *properties);
|
#endif
|
||||||
|
|
||||||
gboolean pinos_context_connect (PinosContext *context, PinosContextFlags flags);
|
|
||||||
gboolean pinos_context_disconnect (PinosContext *context);
|
|
||||||
|
|
||||||
PinosContextState pinos_context_get_state (PinosContext *context);
|
|
||||||
const GError * pinos_context_get_error (PinosContext *context);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __PINOS_CONTEXT_H__ */
|
#endif /* __PINOS_CONTEXT_H__ */
|
||||||
|
|
|
||||||
|
|
@ -22,270 +22,8 @@
|
||||||
#include "pinos/client/pinos.h"
|
#include "pinos/client/pinos.h"
|
||||||
|
|
||||||
#include "pinos/client/context.h"
|
#include "pinos/client/context.h"
|
||||||
#include "pinos/client/enumtypes.h"
|
|
||||||
#include "pinos/client/subscribe.h"
|
#include "pinos/client/subscribe.h"
|
||||||
|
|
||||||
#include "pinos/client/private.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_context_info_finish:
|
|
||||||
* @object: a #GObject
|
|
||||||
* @res: a #GAsyncResult
|
|
||||||
* @error: location to place an error
|
|
||||||
*
|
|
||||||
* Call this function in the introspection GAsyncReadyCallback function
|
|
||||||
* to get the final result of the operation.
|
|
||||||
*
|
|
||||||
* Returns: %TRUE if the lookup was successful. If %FALSE is returned, @error
|
|
||||||
* will contain more details.
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
pinos_context_info_finish (GObject *object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (g_task_is_valid (res, object), FALSE);
|
|
||||||
|
|
||||||
return g_task_propagate_boolean (G_TASK (res), error);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SET_STRING(name, field, idx) \
|
|
||||||
G_STMT_START { \
|
|
||||||
GVariant *variant; \
|
|
||||||
if (!changed || g_hash_table_contains (changed, name)) \
|
|
||||||
info->change_mask |= 1 << idx; \
|
|
||||||
if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \
|
|
||||||
info->field = g_variant_get_string (variant, NULL); \
|
|
||||||
g_variant_unref (variant); \
|
|
||||||
} else { \
|
|
||||||
info->field = "Unknown"; \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define SET_UINT32(name, field, idx, def) \
|
|
||||||
G_STMT_START { \
|
|
||||||
GVariant *variant; \
|
|
||||||
if (!changed || g_hash_table_contains (changed, name)) \
|
|
||||||
info->change_mask |= 1 << idx; \
|
|
||||||
if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \
|
|
||||||
info->field = g_variant_get_uint32 (variant); \
|
|
||||||
g_variant_unref (variant); \
|
|
||||||
} else { \
|
|
||||||
info->field = def; \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define SET_PROPERTIES(name, field, idx) \
|
|
||||||
G_STMT_START { \
|
|
||||||
GVariant *variant; \
|
|
||||||
if (!changed || g_hash_table_contains (changed, name)) \
|
|
||||||
info->change_mask |= 1 << idx; \
|
|
||||||
if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \
|
|
||||||
info->field = pinos_properties_from_variant (variant); \
|
|
||||||
g_variant_unref (variant); \
|
|
||||||
} else { \
|
|
||||||
info->field = NULL; \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define SET_BYTES(name, field, idx) \
|
|
||||||
G_STMT_START { \
|
|
||||||
GVariant *variant; \
|
|
||||||
if (!changed || g_hash_table_contains (changed, name)) \
|
|
||||||
info->change_mask |= 1 << idx; \
|
|
||||||
if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \
|
|
||||||
gsize len; \
|
|
||||||
gchar *bytes = g_variant_dup_string (variant, &len); \
|
|
||||||
info->field = g_bytes_new_take (bytes, len +1); \
|
|
||||||
g_variant_unref (variant); \
|
|
||||||
} else { \
|
|
||||||
info->field = NULL; \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define SET_OBJV(name, field, idx) \
|
|
||||||
G_STMT_START { \
|
|
||||||
GVariant *variant; \
|
|
||||||
if (!changed || g_hash_table_contains (changed, name)) \
|
|
||||||
info->change_mask |= 1 << idx; \
|
|
||||||
if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \
|
|
||||||
info->field = g_variant_dup_objv (variant, NULL); \
|
|
||||||
g_variant_unref (variant); \
|
|
||||||
} else { \
|
|
||||||
info->field = NULL; \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
static void
|
|
||||||
daemon_fill_info (PinosDaemonInfo *info, GDBusProxy *proxy)
|
|
||||||
{
|
|
||||||
GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties");
|
|
||||||
|
|
||||||
info->id = proxy;
|
|
||||||
info->daemon_path = g_dbus_proxy_get_object_path (proxy);
|
|
||||||
|
|
||||||
info->change_mask = 0;
|
|
||||||
SET_STRING ("UserName", user_name, 0);
|
|
||||||
SET_STRING ("HostName", host_name, 1);
|
|
||||||
SET_STRING ("Version", version, 2);
|
|
||||||
SET_STRING ("Name", name, 3);
|
|
||||||
SET_UINT32 ("Cookie", cookie, 4, 0);
|
|
||||||
SET_PROPERTIES ("Properties", properties, 5);
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
g_hash_table_remove_all (changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
daemon_clear_info (PinosDaemonInfo *info)
|
|
||||||
{
|
|
||||||
if (info->properties)
|
|
||||||
pinos_properties_free (info->properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_context_get_daemon_info:
|
|
||||||
* @context: a #PinosContext
|
|
||||||
* @flags: extra flags
|
|
||||||
* @cb: a callback
|
|
||||||
* @cancelable: a #GCancellable
|
|
||||||
* @callback: a #GAsyncReadyCallback to call when the operation is finished
|
|
||||||
* @user_data: user data passed to @cb
|
|
||||||
*
|
|
||||||
* Get the information of the daemon @context is connected to.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pinos_context_get_daemon_info (PinosContext *context,
|
|
||||||
PinosDaemonInfoFlags flags,
|
|
||||||
PinosDaemonInfoCallback cb,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosDaemonInfo info;
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_CONTEXT (context));
|
|
||||||
g_return_if_fail (cb != NULL);
|
|
||||||
|
|
||||||
task = g_task_new (context, cancellable, callback, user_data);
|
|
||||||
|
|
||||||
daemon_fill_info (&info, context->priv->daemon);
|
|
||||||
cb (context, &info, user_data);
|
|
||||||
daemon_clear_info (&info);
|
|
||||||
|
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
client_fill_info (PinosClientInfo *info, GDBusProxy *proxy)
|
|
||||||
{
|
|
||||||
GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties");
|
|
||||||
|
|
||||||
info->id = proxy;
|
|
||||||
info->client_path = g_dbus_proxy_get_object_path (proxy);
|
|
||||||
SET_STRING ("Sender", sender, 0);
|
|
||||||
|
|
||||||
info->change_mask = 0;
|
|
||||||
SET_PROPERTIES ("Properties", properties, 0);
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
g_hash_table_remove_all (changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
client_clear_info (PinosClientInfo *info)
|
|
||||||
{
|
|
||||||
if (info->properties)
|
|
||||||
pinos_properties_free (info->properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_context_list_client_info:
|
|
||||||
* @context: a connected #PinosContext
|
|
||||||
* @flags: extra #PinosClientInfoFlags
|
|
||||||
* @cb: a #PinosClientInfoCallback
|
|
||||||
* @cancelable: a #GCancellable
|
|
||||||
* @callback: a #GAsyncReadyCallback to call when the operation is finished
|
|
||||||
* @user_data: user data passed to @cb
|
|
||||||
*
|
|
||||||
* Call @cb for each client.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pinos_context_list_client_info (PinosContext *context,
|
|
||||||
PinosClientInfoFlags flags,
|
|
||||||
PinosClientInfoCallback cb,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosContextPrivate *priv;
|
|
||||||
GList *walk;
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_CONTEXT (context));
|
|
||||||
g_return_if_fail (cb != NULL);
|
|
||||||
|
|
||||||
task = g_task_new (context, cancellable, callback, user_data);
|
|
||||||
|
|
||||||
priv = context->priv;
|
|
||||||
|
|
||||||
for (walk = priv->clients; walk; walk = g_list_next (walk)) {
|
|
||||||
GDBusProxy *proxy = walk->data;
|
|
||||||
PinosClientInfo info;
|
|
||||||
|
|
||||||
client_fill_info (&info, proxy);
|
|
||||||
cb (context, &info, user_data);
|
|
||||||
client_clear_info (&info);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_context_get_client_info_by_id:
|
|
||||||
* @context: a connected #PinosContext
|
|
||||||
* @id: a client id
|
|
||||||
* @flags: extra #PinosClientInfoFlags
|
|
||||||
* @cb: a #PinosClientInfoCallback
|
|
||||||
* @cancelable: a #GCancellable
|
|
||||||
* @callback: a #GAsyncReadyCallback to call when the operation is finished
|
|
||||||
* @user_data: user data passed to @cb
|
|
||||||
*
|
|
||||||
* Call @cb for the client with @id.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pinos_context_get_client_info_by_id (PinosContext *context,
|
|
||||||
gpointer id,
|
|
||||||
PinosClientInfoFlags flags,
|
|
||||||
PinosClientInfoCallback cb,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosClientInfo info;
|
|
||||||
GDBusProxy *proxy;
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_CONTEXT (context));
|
|
||||||
g_return_if_fail (id != NULL);
|
|
||||||
g_return_if_fail (cb != NULL);
|
|
||||||
|
|
||||||
task = g_task_new (context, cancellable, callback, user_data);
|
|
||||||
|
|
||||||
proxy = G_DBUS_PROXY (id);
|
|
||||||
|
|
||||||
client_fill_info (&info, proxy);
|
|
||||||
cb (context, &info, user_data);
|
|
||||||
client_clear_info (&info);
|
|
||||||
|
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pinos_node_state_as_string:
|
* pinos_node_state_as_string:
|
||||||
* @state: a #PinosNodeeState
|
* @state: a #PinosNodeeState
|
||||||
|
|
@ -294,124 +32,24 @@ pinos_context_get_client_info_by_id (PinosContext *context,
|
||||||
*
|
*
|
||||||
* Returns: the string representation of @state.
|
* Returns: the string representation of @state.
|
||||||
*/
|
*/
|
||||||
const gchar *
|
const char *
|
||||||
pinos_node_state_as_string (PinosNodeState state)
|
pinos_node_state_as_string (PinosNodeState state)
|
||||||
{
|
{
|
||||||
GEnumValue *val;
|
switch (state) {
|
||||||
|
case PINOS_NODE_STATE_ERROR:
|
||||||
val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (PINOS_TYPE_NODE_STATE)),
|
return "error";
|
||||||
state);
|
case PINOS_NODE_STATE_CREATING:
|
||||||
|
return "creating";
|
||||||
return val == NULL ? "invalid-state" : val->value_nick;
|
case PINOS_NODE_STATE_SUSPENDED:
|
||||||
}
|
return "suspended";
|
||||||
|
case PINOS_NODE_STATE_INITIALIZING:
|
||||||
static void
|
return "initializing";
|
||||||
node_fill_info (PinosNodeInfo *info, GDBusProxy *proxy)
|
case PINOS_NODE_STATE_IDLE:
|
||||||
{
|
return "idle";
|
||||||
GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties");
|
case PINOS_NODE_STATE_RUNNING:
|
||||||
|
return "running";
|
||||||
info->id = proxy;
|
|
||||||
info->node_path = g_dbus_proxy_get_object_path (proxy);
|
|
||||||
SET_STRING ("Owner", owner, 0);
|
|
||||||
|
|
||||||
info->change_mask = 0;
|
|
||||||
SET_STRING ("Name", name, 0);
|
|
||||||
SET_PROPERTIES ("Properties", properties, 1);
|
|
||||||
SET_UINT32 ("State", state, 2, PINOS_NODE_STATE_ERROR);
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
g_hash_table_remove_all (changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
node_clear_info (PinosNodeInfo *info)
|
|
||||||
{
|
|
||||||
if (info->properties)
|
|
||||||
pinos_properties_free (info->properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_context_list_node_info:
|
|
||||||
* @context: a connected #PinosContext
|
|
||||||
* @flags: extra #PinosNodeInfoFlags
|
|
||||||
* @cb: a #PinosNodeInfoCallback
|
|
||||||
* @cancelable: a #GCancellable
|
|
||||||
* @callback: a #GAsyncReadyCallback to call when the operation is finished
|
|
||||||
* @user_data: user data passed to @cb
|
|
||||||
*
|
|
||||||
* Call @cb for each node.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pinos_context_list_node_info (PinosContext *context,
|
|
||||||
PinosNodeInfoFlags flags,
|
|
||||||
PinosNodeInfoCallback cb,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosContextPrivate *priv;
|
|
||||||
GList *walk;
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_CONTEXT (context));
|
|
||||||
g_return_if_fail (cb != NULL);
|
|
||||||
|
|
||||||
task = g_task_new (context, cancellable, callback, user_data);
|
|
||||||
|
|
||||||
priv = context->priv;
|
|
||||||
|
|
||||||
for (walk = priv->nodes; walk; walk = g_list_next (walk)) {
|
|
||||||
GDBusProxy *proxy = walk->data;
|
|
||||||
PinosNodeInfo info;
|
|
||||||
|
|
||||||
node_fill_info (&info, proxy);
|
|
||||||
cb (context, &info, user_data);
|
|
||||||
node_clear_info (&info);
|
|
||||||
}
|
}
|
||||||
|
return "invalid-state";
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_context_get_node_info_by_id:
|
|
||||||
* @context: a connected #PinosContext
|
|
||||||
* @id: a node id
|
|
||||||
* @flags: extra #PinosNodeInfoFlags
|
|
||||||
* @cb: a #PinosNodeInfoCallback
|
|
||||||
* @cancelable: a #GCancellable
|
|
||||||
* @callback: a #GAsyncReadyCallback to call when the operation is finished
|
|
||||||
* @user_data: user data passed to @cb
|
|
||||||
*
|
|
||||||
* Call @cb for the node with @id.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pinos_context_get_node_info_by_id (PinosContext *context,
|
|
||||||
gpointer id,
|
|
||||||
PinosNodeInfoFlags flags,
|
|
||||||
PinosNodeInfoCallback cb,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosNodeInfo info;
|
|
||||||
GDBusProxy *proxy;
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_CONTEXT (context));
|
|
||||||
g_return_if_fail (id != NULL);
|
|
||||||
g_return_if_fail (cb != NULL);
|
|
||||||
|
|
||||||
task = g_task_new (context, cancellable, callback, user_data);
|
|
||||||
|
|
||||||
proxy = G_DBUS_PROXY (id);
|
|
||||||
|
|
||||||
node_fill_info (&info, proxy);
|
|
||||||
cb (context, &info, user_data);
|
|
||||||
node_clear_info (&info);
|
|
||||||
|
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -422,15 +60,18 @@ pinos_context_get_node_info_by_id (PinosContext *context,
|
||||||
*
|
*
|
||||||
* Returns: the string representation of @direction.
|
* Returns: the string representation of @direction.
|
||||||
*/
|
*/
|
||||||
const gchar *
|
const char *
|
||||||
pinos_direction_as_string (PinosDirection direction)
|
pinos_direction_as_string (PinosDirection direction)
|
||||||
{
|
{
|
||||||
GEnumValue *val;
|
switch (direction) {
|
||||||
|
case PINOS_DIRECTION_INVALID:
|
||||||
val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (PINOS_TYPE_DIRECTION)),
|
return "invalid";
|
||||||
direction);
|
case PINOS_DIRECTION_INPUT:
|
||||||
|
return "input";
|
||||||
return val == NULL ? "invalid-direction" : val->value_nick;
|
case PINOS_DIRECTION_OUTPUT:
|
||||||
|
return "output";
|
||||||
|
}
|
||||||
|
return "invalid-direction";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -441,121 +82,24 @@ pinos_direction_as_string (PinosDirection direction)
|
||||||
*
|
*
|
||||||
* Returns: the string representation of @state.
|
* Returns: the string representation of @state.
|
||||||
*/
|
*/
|
||||||
const gchar *
|
const char *
|
||||||
pinos_link_state_as_string (PinosLinkState state)
|
pinos_link_state_as_string (PinosLinkState state)
|
||||||
{
|
{
|
||||||
GEnumValue *val;
|
switch (state) {
|
||||||
|
case PINOS_LINK_STATE_ERROR:
|
||||||
val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (PINOS_TYPE_LINK_STATE)),
|
return "error";
|
||||||
state);
|
case PINOS_LINK_STATE_UNLINKED:
|
||||||
|
return "unlinked";
|
||||||
return val == NULL ? "invalid-state" : val->value_nick;
|
case PINOS_LINK_STATE_INIT:
|
||||||
}
|
return "init";
|
||||||
|
case PINOS_LINK_STATE_NEGOTIATING:
|
||||||
|
return "negotiating";
|
||||||
static void
|
case PINOS_LINK_STATE_ALLOCATING:
|
||||||
link_fill_info (PinosLinkInfo *info, GDBusProxy *proxy)
|
return "allocating";
|
||||||
{
|
case PINOS_LINK_STATE_PAUSED:
|
||||||
GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties");
|
return "paused";
|
||||||
|
case PINOS_LINK_STATE_RUNNING:
|
||||||
info->id = proxy;
|
return "running";
|
||||||
info->link_path = g_dbus_proxy_get_object_path (proxy);
|
|
||||||
|
|
||||||
info->change_mask = 0;
|
|
||||||
SET_STRING ("OutputNode", output_node_path, 0);
|
|
||||||
SET_UINT32 ("OutputPort", output_port, 1, -1);
|
|
||||||
SET_STRING ("InputNode", input_node_path, 2);
|
|
||||||
SET_UINT32 ("InputPort", input_port, 3, -1);
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
g_hash_table_remove_all (changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
link_clear_info (PinosLinkInfo *info)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_context_list_link_info:
|
|
||||||
* @context: a connected #PinosContext
|
|
||||||
* @flags: extra #PinosLinkInfoFlags
|
|
||||||
* @cb: a #PinosLinkInfoCallback
|
|
||||||
* @cancelable: a #GCancellable
|
|
||||||
* @callback: a #GAsyncReadyCallback to call when the operation is finished
|
|
||||||
* @user_data: user data passed to @cb
|
|
||||||
*
|
|
||||||
* Call @cb for each link.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pinos_context_list_link_info (PinosContext *context,
|
|
||||||
PinosLinkInfoFlags flags,
|
|
||||||
PinosLinkInfoCallback cb,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosContextPrivate *priv;
|
|
||||||
GList *walk;
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_CONTEXT (context));
|
|
||||||
g_return_if_fail (cb != NULL);
|
|
||||||
|
|
||||||
task = g_task_new (context, cancellable, callback, user_data);
|
|
||||||
|
|
||||||
priv = context->priv;
|
|
||||||
|
|
||||||
for (walk = priv->links; walk; walk = g_list_next (walk)) {
|
|
||||||
GDBusProxy *proxy = walk->data;
|
|
||||||
PinosLinkInfo info;
|
|
||||||
|
|
||||||
link_fill_info (&info, proxy);
|
|
||||||
cb (context, &info, user_data);
|
|
||||||
link_clear_info (&info);
|
|
||||||
}
|
}
|
||||||
|
return "invalid-state";
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_context_get_link_info_by_id:
|
|
||||||
* @context: a connected #PinosContext
|
|
||||||
* @id: a link id
|
|
||||||
* @flags: extra #PinosLinkInfoFlags
|
|
||||||
* @cb: a #PinosLinkInfoCallback
|
|
||||||
* @cancelable: a #GCancellable
|
|
||||||
* @callback: a #GAsyncReadyCallback to call when the operation is finished
|
|
||||||
* @user_data: user data passed to @cb
|
|
||||||
*
|
|
||||||
* Call @cb for the link with @id.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pinos_context_get_link_info_by_id (PinosContext *context,
|
|
||||||
gpointer id,
|
|
||||||
PinosLinkInfoFlags flags,
|
|
||||||
PinosLinkInfoCallback cb,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosLinkInfo info;
|
|
||||||
GDBusProxy *proxy;
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_CONTEXT (context));
|
|
||||||
g_return_if_fail (id != NULL);
|
|
||||||
g_return_if_fail (cb != NULL);
|
|
||||||
|
|
||||||
task = g_task_new (context, cancellable, callback, user_data);
|
|
||||||
|
|
||||||
proxy = G_DBUS_PROXY (id);
|
|
||||||
|
|
||||||
link_fill_info (&info, proxy);
|
|
||||||
cb (context, &info, user_data);
|
|
||||||
link_clear_info (&info);
|
|
||||||
|
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,11 @@
|
||||||
#ifndef __PINOS_INTROSPECT_H__
|
#ifndef __PINOS_INTROSPECT_H__
|
||||||
#define __PINOS_INTROSPECT_H__
|
#define __PINOS_INTROSPECT_H__
|
||||||
|
|
||||||
#include <gio/gio.h>
|
|
||||||
#include <glib-object.h>
|
|
||||||
|
|
||||||
#include <spa/include/spa/defs.h>
|
#include <spa/include/spa/defs.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosNodeState:
|
* PinosNodeState:
|
||||||
|
|
@ -50,7 +49,7 @@ typedef enum {
|
||||||
PINOS_NODE_STATE_RUNNING = 4,
|
PINOS_NODE_STATE_RUNNING = 4,
|
||||||
} PinosNodeState;
|
} PinosNodeState;
|
||||||
|
|
||||||
const gchar * pinos_node_state_as_string (PinosNodeState state);
|
const char * pinos_node_state_as_string (PinosNodeState state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosDirection:
|
* PinosDirection:
|
||||||
|
|
@ -66,7 +65,7 @@ typedef enum {
|
||||||
PINOS_DIRECTION_OUTPUT = SPA_DIRECTION_OUTPUT
|
PINOS_DIRECTION_OUTPUT = SPA_DIRECTION_OUTPUT
|
||||||
} PinosDirection;
|
} PinosDirection;
|
||||||
|
|
||||||
const gchar * pinos_direction_as_string (PinosDirection direction);
|
const char * pinos_direction_as_string (PinosDirection direction);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosLinkState:
|
* PinosLinkState:
|
||||||
|
|
@ -90,19 +89,14 @@ typedef enum {
|
||||||
PINOS_LINK_STATE_RUNNING = 4,
|
PINOS_LINK_STATE_RUNNING = 4,
|
||||||
} PinosLinkState;
|
} PinosLinkState;
|
||||||
|
|
||||||
const gchar * pinos_link_state_as_string (PinosLinkState state);
|
const char * pinos_link_state_as_string (PinosLinkState state);
|
||||||
|
|
||||||
#include <pinos/client/context.h>
|
#include <pinos/client/context.h>
|
||||||
#include <pinos/client/properties.h>
|
#include <pinos/client/properties.h>
|
||||||
|
|
||||||
gboolean pinos_context_info_finish (GObject *object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosDaemonInfo:
|
* PinosDaemonInfo:
|
||||||
* @id: generic id of the daemon
|
* @id: generic id of the daemon
|
||||||
* @daemon-path: unique path of the daemon
|
|
||||||
* @change_mask: bitfield of changed fields since last call
|
* @change_mask: bitfield of changed fields since last call
|
||||||
* @user_name: name of the user that started the daemon
|
* @user_name: name of the user that started the daemon
|
||||||
* @host_name: name of the machine the daemon is running on
|
* @host_name: name of the machine the daemon is running on
|
||||||
|
|
@ -115,25 +109,16 @@ gboolean pinos_context_info_finish (GObject *object,
|
||||||
* versions.
|
* versions.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gpointer id;
|
uint32_t id;
|
||||||
const char *daemon_path;
|
uint64_t change_mask;
|
||||||
guint64 change_mask;
|
|
||||||
const char *user_name;
|
const char *user_name;
|
||||||
const char *host_name;
|
const char *host_name;
|
||||||
const char *version;
|
const char *version;
|
||||||
const char *name;
|
const char *name;
|
||||||
guint32 cookie;
|
uint32_t cookie;
|
||||||
PinosProperties *properties;
|
PinosProperties *properties;
|
||||||
} PinosDaemonInfo;
|
} PinosDaemonInfo;
|
||||||
|
|
||||||
/**PinosDaemonInfoFlags:
|
|
||||||
* @PINOS_DAEMON_INFO_FLAGS_NONE: no flags
|
|
||||||
*
|
|
||||||
* Extra flags that can be passed to pinos_context_get_daemon_info()
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
PINOS_DAEMON_INFO_FLAGS_NONE = 0,
|
|
||||||
} PinosDaemonInfoFlags;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosDaemonInfoCallback:
|
* PinosDaemonInfoCallback:
|
||||||
|
|
@ -144,21 +129,17 @@ typedef enum {
|
||||||
* Callback with information about the Pinos daemon in @info.
|
* Callback with information about the Pinos daemon in @info.
|
||||||
*/
|
*/
|
||||||
typedef void (*PinosDaemonInfoCallback) (PinosContext *c,
|
typedef void (*PinosDaemonInfoCallback) (PinosContext *c,
|
||||||
|
SpaResult res,
|
||||||
const PinosDaemonInfo *info,
|
const PinosDaemonInfo *info,
|
||||||
gpointer user_data);
|
void *user_data);
|
||||||
|
|
||||||
void pinos_context_get_daemon_info (PinosContext *context,
|
void pinos_context_get_daemon_info (PinosContext *context,
|
||||||
PinosDaemonInfoFlags flags,
|
PinosDaemonInfoCallback cb,
|
||||||
PinosDaemonInfoCallback cb,
|
void *user_data);
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosClientInfo:
|
* PinosClientInfo:
|
||||||
* @id: generic id of the client
|
* @id: generic id of the client
|
||||||
* @client_path: unique path of the client
|
|
||||||
* @sender: sender of client
|
|
||||||
* @change_mask: bitfield of changed fields since last call
|
* @change_mask: bitfield of changed fields since last call
|
||||||
* @properties: extra properties
|
* @properties: extra properties
|
||||||
*
|
*
|
||||||
|
|
@ -166,24 +147,11 @@ void pinos_context_get_daemon_info (PinosContext *context,
|
||||||
* versions.
|
* versions.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gpointer id;
|
uint32_t id;
|
||||||
const char *client_path;
|
uint64_t change_mask;
|
||||||
const char *sender;
|
|
||||||
guint64 change_mask;
|
|
||||||
PinosProperties *properties;
|
PinosProperties *properties;
|
||||||
} PinosClientInfo;
|
} PinosClientInfo;
|
||||||
|
|
||||||
/**
|
|
||||||
* PinosClientInfoFlags:
|
|
||||||
* @PINOS_CLIENT_INFO_FLAGS_NONE: no flags
|
|
||||||
*
|
|
||||||
* Extra flags for pinos_context_list_client_info() and
|
|
||||||
* pinos_context_get_client_info_by_id().
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
PINOS_CLIENT_INFO_FLAGS_NONE = 0,
|
|
||||||
} PinosClientInfoFlags;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosClientInfoCallback:
|
* PinosClientInfoCallback:
|
||||||
* @c: a #PinosContext
|
* @c: a #PinosContext
|
||||||
|
|
@ -193,28 +161,21 @@ typedef enum {
|
||||||
* Callback with information about the Pinos client in @info.
|
* Callback with information about the Pinos client in @info.
|
||||||
*/
|
*/
|
||||||
typedef void (*PinosClientInfoCallback) (PinosContext *c,
|
typedef void (*PinosClientInfoCallback) (PinosContext *c,
|
||||||
|
SpaResult res,
|
||||||
const PinosClientInfo *info,
|
const PinosClientInfo *info,
|
||||||
gpointer user_data);
|
void *user_data);
|
||||||
|
|
||||||
void pinos_context_list_client_info (PinosContext *context,
|
void pinos_context_list_client_info (PinosContext *context,
|
||||||
PinosClientInfoFlags flags,
|
PinosClientInfoCallback cb,
|
||||||
PinosClientInfoCallback cb,
|
void *user_data);
|
||||||
GCancellable *cancellable,
|
void pinos_context_get_client_info_by_id (PinosContext *context,
|
||||||
GAsyncReadyCallback callback,
|
uint32_t id,
|
||||||
gpointer user_data);
|
PinosClientInfoCallback cb,
|
||||||
void pinos_context_get_client_info_by_id (PinosContext *context,
|
void *user_data);
|
||||||
gpointer id,
|
|
||||||
PinosClientInfoFlags flags,
|
|
||||||
PinosClientInfoCallback cb,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosNodeInfo:
|
* PinosNodeInfo:
|
||||||
* @id: generic id of the node
|
* @id: generic id of the node
|
||||||
* @node_path: the unique path of the node
|
|
||||||
* @owner: the unique name of the owner
|
|
||||||
* @change_mask: bitfield of changed fields since last call
|
* @change_mask: bitfield of changed fields since last call
|
||||||
* @name: name the node, suitable for display
|
* @name: name the node, suitable for display
|
||||||
* @properties: the properties of the node
|
* @properties: the properties of the node
|
||||||
|
|
@ -224,25 +185,13 @@ void pinos_context_get_client_info_by_id (PinosContext *context,
|
||||||
* versions.
|
* versions.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gpointer id;
|
uint32_t id;
|
||||||
const char *node_path;
|
uint64_t change_mask;
|
||||||
const char *owner;
|
|
||||||
guint64 change_mask;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
PinosProperties *properties;
|
PinosProperties *properties;
|
||||||
PinosNodeState state;
|
PinosNodeState state;
|
||||||
} PinosNodeInfo;
|
} PinosNodeInfo;
|
||||||
|
|
||||||
/**
|
|
||||||
* PinosNodeInfoFlags:
|
|
||||||
* @PINOS_NODE_INFO_FLAGS_NONE: no flags
|
|
||||||
*
|
|
||||||
* Extra flags to pass to pinos_context_get_node_info_list.
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
PINOS_NODE_INFO_FLAGS_NONE = 0,
|
|
||||||
} PinosNodeInfoFlags;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosNodeInfoCallback:
|
* PinosNodeInfoCallback:
|
||||||
* @c: a #PinosContext
|
* @c: a #PinosContext
|
||||||
|
|
@ -252,28 +201,22 @@ typedef enum {
|
||||||
* Callback with information about the Pinos node in @info.
|
* Callback with information about the Pinos node in @info.
|
||||||
*/
|
*/
|
||||||
typedef void (*PinosNodeInfoCallback) (PinosContext *c,
|
typedef void (*PinosNodeInfoCallback) (PinosContext *c,
|
||||||
|
SpaResult res,
|
||||||
const PinosNodeInfo *info,
|
const PinosNodeInfo *info,
|
||||||
gpointer user_data);
|
void *user_data);
|
||||||
|
|
||||||
void pinos_context_list_node_info (PinosContext *context,
|
void pinos_context_list_node_info (PinosContext *context,
|
||||||
PinosNodeInfoFlags flags,
|
PinosNodeInfoCallback cb,
|
||||||
PinosNodeInfoCallback cb,
|
void *user_data);
|
||||||
GCancellable *cancellable,
|
void pinos_context_get_node_info_by_id (PinosContext *context,
|
||||||
GAsyncReadyCallback callback,
|
uint32_t id,
|
||||||
gpointer user_data);
|
PinosNodeInfoCallback cb,
|
||||||
void pinos_context_get_node_info_by_id (PinosContext *context,
|
void *user_data);
|
||||||
gpointer id,
|
|
||||||
PinosNodeInfoFlags flags,
|
|
||||||
PinosNodeInfoCallback cb,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosLinkInfo:
|
* PinosLinkInfo:
|
||||||
* @id: generic id of the link
|
* @id: generic id of the link
|
||||||
* @link_path: the unique path of the link
|
|
||||||
* @change_mask: bitfield of changed fields since last call
|
* @change_mask: bitfield of changed fields since last call
|
||||||
* @output_node_path: the output node
|
* @output_node_path: the output node
|
||||||
* @output_port: the output port
|
* @output_port: the output port
|
||||||
|
|
@ -284,25 +227,14 @@ void pinos_context_get_node_info_by_id (PinosContext *context,
|
||||||
* versions.
|
* versions.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gpointer id;
|
uint32_t id;
|
||||||
const char *link_path;
|
uint64_t change_mask;
|
||||||
guint64 change_mask;
|
uint32_t output_node_id;
|
||||||
const char *output_node_path;
|
uint32_t output_port_id;
|
||||||
guint output_port;
|
uint32_t input_node_id;
|
||||||
const char *input_node_path;
|
uint32_t input_port_id;
|
||||||
guint input_port;
|
|
||||||
} PinosLinkInfo;
|
} PinosLinkInfo;
|
||||||
|
|
||||||
/**
|
|
||||||
* PinosLinkInfoFlags:
|
|
||||||
* @PINOS_LINK_INFO_FLAGS_NONE: no flags
|
|
||||||
*
|
|
||||||
* Extra flags to pass to pinos_context_list_link_info() and
|
|
||||||
* pinos_context_get_link_info_by_id().
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
PINOS_LINK_INFO_FLAGS_NONE = 0,
|
|
||||||
} PinosLinkInfoFlags;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosLinkInfoCallback:
|
* PinosLinkInfoCallback:
|
||||||
|
|
@ -312,23 +244,21 @@ typedef enum {
|
||||||
*
|
*
|
||||||
* Callback with information about the Pinos link in @info.
|
* Callback with information about the Pinos link in @info.
|
||||||
*/
|
*/
|
||||||
typedef void (*PinosLinkInfoCallback) (PinosContext *c,
|
typedef void (*PinosLinkInfoCallback) (PinosContext *c,
|
||||||
|
SpaResult res,
|
||||||
const PinosLinkInfo *info,
|
const PinosLinkInfo *info,
|
||||||
gpointer user_data);
|
void *user_data);
|
||||||
|
|
||||||
void pinos_context_list_link_info (PinosContext *context,
|
void pinos_context_list_link_info (PinosContext *context,
|
||||||
PinosLinkInfoFlags flags,
|
PinosLinkInfoCallback cb,
|
||||||
PinosLinkInfoCallback cb,
|
void *user_data);
|
||||||
GCancellable *cancellable,
|
void pinos_context_get_link_info_by_id (PinosContext *context,
|
||||||
GAsyncReadyCallback callback,
|
uint32_t id,
|
||||||
gpointer user_data);
|
PinosLinkInfoCallback cb,
|
||||||
void pinos_context_get_link_info_by_id (PinosContext *context,
|
void *user_data);
|
||||||
gpointer id,
|
|
||||||
PinosLinkInfoFlags flags,
|
#ifdef __cplusplus
|
||||||
PinosLinkInfoCallback cb,
|
}
|
||||||
GCancellable *cancellable,
|
#endif
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data);
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __PINOS_INTROSPECT_H__ */
|
#endif /* __PINOS_INTROSPECT_H__ */
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ pinos_headers = [
|
||||||
'mem.h',
|
'mem.h',
|
||||||
'pinos.h',
|
'pinos.h',
|
||||||
'properties.h',
|
'properties.h',
|
||||||
|
'proxy.h',
|
||||||
'rtkit.h',
|
'rtkit.h',
|
||||||
'stream.h',
|
'stream.h',
|
||||||
'subscribe.h',
|
'subscribe.h',
|
||||||
|
|
@ -27,11 +28,11 @@ pinos_sources = [
|
||||||
'mapper.c',
|
'mapper.c',
|
||||||
'mem.c',
|
'mem.c',
|
||||||
'properties.c',
|
'properties.c',
|
||||||
|
'proxy.c',
|
||||||
'serialize.c',
|
'serialize.c',
|
||||||
'stream.c',
|
'stream.c',
|
||||||
'pinos.c',
|
'pinos.c',
|
||||||
'rtkit.c',
|
'rtkit.c',
|
||||||
'subscribe.c',
|
|
||||||
'thread-mainloop.c',
|
'thread-mainloop.c',
|
||||||
'transport.c',
|
'transport.c',
|
||||||
'utils.c',
|
'utils.c',
|
||||||
|
|
@ -67,7 +68,6 @@ libpinos_c_args = [
|
||||||
pinos_gen_sources = [enumtypes_h]
|
pinos_gen_sources = [enumtypes_h]
|
||||||
|
|
||||||
libpinos = shared_library('pinos', pinos_sources,
|
libpinos = shared_library('pinos', pinos_sources,
|
||||||
enumtypes_h, enumtypes_c,
|
|
||||||
version : libversion,
|
version : libversion,
|
||||||
soversion : soversion,
|
soversion : soversion,
|
||||||
c_args : libpinos_c_args,
|
c_args : libpinos_c_args,
|
||||||
|
|
|
||||||
|
|
@ -17,22 +17,11 @@
|
||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glib.h>
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "pinos/client/pinos.h"
|
#include "pinos/client/pinos.h"
|
||||||
|
|
||||||
const gchar g_log_domain_pinos[] = "Pinos";
|
|
||||||
|
|
||||||
GQuark
|
|
||||||
pinos_error_quark (void)
|
|
||||||
{
|
|
||||||
static GQuark quark = 0;
|
|
||||||
if (!quark)
|
|
||||||
quark = g_quark_from_static_string ("pinos-error-quark");
|
|
||||||
return quark;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pinos_init:
|
* pinos_init:
|
||||||
* @argc: pointer to argc
|
* @argc: pointer to argc
|
||||||
|
|
@ -46,22 +35,48 @@ pinos_init (int *argc, char **argv[])
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
pinos_get_application_name (void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
pinos_get_prgname (void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
pinos_get_user_name (void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
pinos_get_host_name (void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pinos_client_name:
|
* pinos_client_name:
|
||||||
*
|
*
|
||||||
* Make a new pinos client name that can be used to construct a context.
|
* Make a new pinos client name that can be used to construct a context.
|
||||||
*/
|
*/
|
||||||
gchar *
|
char *
|
||||||
pinos_client_name (void)
|
pinos_client_name (void)
|
||||||
{
|
{
|
||||||
const char *c;
|
char *c;
|
||||||
|
|
||||||
if ((c = g_get_application_name ()))
|
if ((c = pinos_get_application_name ()))
|
||||||
return g_strdup (c);
|
return strdup (c);
|
||||||
else if ((c = g_get_prgname ()))
|
else if ((c = pinos_get_prgname ()))
|
||||||
return g_strdup (c);
|
return strdup (c);
|
||||||
else
|
else {
|
||||||
return g_strdup_printf ("pinos-pid-%lu", (gulong) getpid ());
|
asprintf (&c, "pinos-pid-%zd", (size_t) getpid ());
|
||||||
|
return c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -73,34 +88,26 @@ pinos_client_name (void)
|
||||||
void
|
void
|
||||||
pinos_fill_context_properties (PinosProperties *properties)
|
pinos_fill_context_properties (PinosProperties *properties)
|
||||||
{
|
{
|
||||||
g_return_if_fail (properties != NULL);
|
|
||||||
|
|
||||||
if (!pinos_properties_get (properties, "application.name"))
|
if (!pinos_properties_get (properties, "application.name"))
|
||||||
pinos_properties_set (properties, "application.name", g_get_application_name ());
|
pinos_properties_set (properties, "application.name", pinos_get_application_name ());
|
||||||
|
|
||||||
if (!pinos_properties_get (properties, "application.prgname"))
|
if (!pinos_properties_get (properties, "application.prgname"))
|
||||||
pinos_properties_set (properties, "application.prgname", g_get_prgname ());
|
pinos_properties_set (properties, "application.prgname", pinos_get_prgname ());
|
||||||
|
|
||||||
if (!pinos_properties_get (properties, "application.language")) {
|
if (!pinos_properties_get (properties, "application.language")) {
|
||||||
const gchar *str = g_getenv ("LANG");
|
pinos_properties_set (properties, "application.language", getenv ("LANG"));
|
||||||
if (str)
|
|
||||||
pinos_properties_set (properties, "application.language", str);
|
|
||||||
}
|
}
|
||||||
if (!pinos_properties_get (properties, "application.process.id")) {
|
if (!pinos_properties_get (properties, "application.process.id")) {
|
||||||
gchar *str = g_strdup_printf ("%lu", (gulong) getpid());
|
pinos_properties_setf (properties, "application.process.id", "%zd", (size_t) getpid ());
|
||||||
pinos_properties_set (properties, "application.process.id", str);
|
|
||||||
g_free (str);
|
|
||||||
}
|
}
|
||||||
if (!pinos_properties_get (properties, "application.process.user"))
|
if (!pinos_properties_get (properties, "application.process.user"))
|
||||||
pinos_properties_set (properties, "application.process.user", g_get_user_name ());
|
pinos_properties_set (properties, "application.process.user", pinos_get_user_name ());
|
||||||
|
|
||||||
if (!pinos_properties_get (properties, "application.process.host"))
|
if (!pinos_properties_get (properties, "application.process.host"))
|
||||||
pinos_properties_set (properties, "application.process.host", g_get_host_name ());
|
pinos_properties_set (properties, "application.process.host", pinos_get_host_name ());
|
||||||
|
|
||||||
if (!pinos_properties_get (properties, "application.process.session_id")) {
|
if (!pinos_properties_get (properties, "application.process.session_id")) {
|
||||||
const gchar *str = g_getenv ("XDG_SESSION_ID");
|
pinos_properties_set (properties, "application.process.session_id", getenv ("XDG_SESSION_ID"));
|
||||||
if (str)
|
|
||||||
pinos_properties_set (properties, "application.process.session_id", str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,7 +120,6 @@ pinos_fill_context_properties (PinosProperties *properties)
|
||||||
void
|
void
|
||||||
pinos_fill_stream_properties (PinosProperties *properties)
|
pinos_fill_stream_properties (PinosProperties *properties)
|
||||||
{
|
{
|
||||||
g_return_if_fail (properties != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PinosDirection
|
PinosDirection
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,11 @@
|
||||||
#ifndef __PINOS_H__
|
#ifndef __PINOS_H__
|
||||||
#define __PINOS_H__
|
#define __PINOS_H__
|
||||||
|
|
||||||
extern const char g_log_domain_pinos[];
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <pinos/client/context.h>
|
#include <pinos/client/context.h>
|
||||||
#include <pinos/client/enumtypes.h>
|
|
||||||
#include <pinos/client/introspect.h>
|
#include <pinos/client/introspect.h>
|
||||||
#include <pinos/client/log.h>
|
#include <pinos/client/log.h>
|
||||||
#include <pinos/client/loop.h>
|
#include <pinos/client/loop.h>
|
||||||
|
|
@ -43,21 +44,9 @@ extern const char g_log_domain_pinos[];
|
||||||
#define PINOS_DBUS_OBJECT_NODE PINOS_DBUS_OBJECT_PREFIX "/node"
|
#define PINOS_DBUS_OBJECT_NODE PINOS_DBUS_OBJECT_PREFIX "/node"
|
||||||
#define PINOS_DBUS_OBJECT_LINK PINOS_DBUS_OBJECT_PREFIX "/link"
|
#define PINOS_DBUS_OBJECT_LINK PINOS_DBUS_OBJECT_PREFIX "/link"
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PINOS_ERROR_FAILED,
|
|
||||||
PINOS_ERROR_FORMAT_NEGOTIATION,
|
|
||||||
PINOS_ERROR_BUFFER_ALLOCATION,
|
|
||||||
PINOS_ERROR_NODE_STATE,
|
|
||||||
PINOS_ERROR_NODE_PORT,
|
|
||||||
PINOS_ERROR_NODE_LINK,
|
|
||||||
} PinosErrorEnum;
|
|
||||||
|
|
||||||
GQuark pinos_error_quark (void);
|
|
||||||
#define PINOS_ERROR pinos_error_quark()
|
|
||||||
|
|
||||||
void pinos_init (int *argc, char **argv[]);
|
void pinos_init (int *argc, char **argv[]);
|
||||||
|
|
||||||
gchar *pinos_client_name (void);
|
char * pinos_client_name (void);
|
||||||
|
|
||||||
void pinos_fill_context_properties (PinosProperties *properties);
|
void pinos_fill_context_properties (PinosProperties *properties);
|
||||||
void pinos_fill_stream_properties (PinosProperties *properties);
|
void pinos_fill_stream_properties (PinosProperties *properties);
|
||||||
|
|
@ -66,4 +55,8 @@ PinosDirection pinos_direction_reverse (PinosDirection direction);
|
||||||
|
|
||||||
SpaIDMap * pinos_id_map_get_default (void);
|
SpaIDMap * pinos_id_map_get_default (void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __PINOS_H__ */
|
#endif /* __PINOS_H__ */
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
/* Pinos
|
|
||||||
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct _PinosContextPrivate
|
|
||||||
{
|
|
||||||
GMainContext *context;
|
|
||||||
|
|
||||||
gchar *name;
|
|
||||||
PinosProperties *properties;
|
|
||||||
|
|
||||||
guint id;
|
|
||||||
GDBusConnection *connection;
|
|
||||||
|
|
||||||
PinosContextFlags flags;
|
|
||||||
|
|
||||||
PinosContextState state;
|
|
||||||
GError *error;
|
|
||||||
|
|
||||||
GDBusProxy *daemon;
|
|
||||||
gboolean disconnecting;
|
|
||||||
|
|
||||||
PinosSubscriptionFlags subscription_mask;
|
|
||||||
PinosSubscribe *subscribe;
|
|
||||||
|
|
||||||
GList *clients;
|
|
||||||
GList *nodes;
|
|
||||||
GList *links;
|
|
||||||
};
|
|
||||||
|
|
||||||
void pinos_subscribe_get_proxy (PinosSubscribe *subscribe,
|
|
||||||
const gchar *name,
|
|
||||||
const gchar *object_path,
|
|
||||||
const gchar *interface_name,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data);
|
|
||||||
GDBusProxy * pinos_subscribe_get_proxy_finish (PinosSubscribe *subscribe,
|
|
||||||
GAsyncResult *res,
|
|
||||||
GError **error);
|
|
||||||
|
|
@ -27,7 +27,7 @@ struct _PinosProperties {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
copy_func (const gchar *key, const gchar *value, GHashTable *copy)
|
copy_func (const char *key, const char *value, GHashTable *copy)
|
||||||
{
|
{
|
||||||
g_hash_table_insert (copy, g_strdup (key), g_strdup (value));
|
g_hash_table_insert (copy, g_strdup (key), g_strdup (value));
|
||||||
}
|
}
|
||||||
|
|
@ -42,20 +42,20 @@ copy_func (const gchar *key, const gchar *value, GHashTable *copy)
|
||||||
* Returns: a new #PinosProperties
|
* Returns: a new #PinosProperties
|
||||||
*/
|
*/
|
||||||
PinosProperties *
|
PinosProperties *
|
||||||
pinos_properties_new (const gchar *key, ...)
|
pinos_properties_new (const char *key, ...)
|
||||||
{
|
{
|
||||||
PinosProperties *props;
|
PinosProperties *props;
|
||||||
va_list varargs;
|
va_list varargs;
|
||||||
const gchar *value;
|
const char *value;
|
||||||
|
|
||||||
props = g_new (PinosProperties, 1);
|
props = g_new (PinosProperties, 1);
|
||||||
props->hashtable = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
props->hashtable = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||||
|
|
||||||
va_start (varargs, key);
|
va_start (varargs, key);
|
||||||
while (key != NULL) {
|
while (key != NULL) {
|
||||||
value = va_arg (varargs, gchar *);
|
value = va_arg (varargs, char *);
|
||||||
copy_func (key, value, props->hashtable);
|
copy_func (key, value, props->hashtable);
|
||||||
key = va_arg (varargs, gchar *);
|
key = va_arg (varargs, char *);
|
||||||
}
|
}
|
||||||
va_end (varargs);
|
va_end (varargs);
|
||||||
|
|
||||||
|
|
@ -97,8 +97,8 @@ pinos_properties_merge (PinosProperties *oldprops,
|
||||||
} else if (newprops == NULL) {
|
} else if (newprops == NULL) {
|
||||||
res = pinos_properties_copy (oldprops);
|
res = pinos_properties_copy (oldprops);
|
||||||
} else {
|
} else {
|
||||||
const gchar *key;
|
const char *key;
|
||||||
gpointer state = NULL;
|
void * state = NULL;
|
||||||
|
|
||||||
res = pinos_properties_copy (oldprops);
|
res = pinos_properties_copy (oldprops);
|
||||||
while ((key = pinos_properties_iterate (newprops, &state))) {
|
while ((key = pinos_properties_iterate (newprops, &state))) {
|
||||||
|
|
@ -137,8 +137,8 @@ pinos_properties_free (PinosProperties *properties)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
pinos_properties_set (PinosProperties *properties,
|
pinos_properties_set (PinosProperties *properties,
|
||||||
const gchar *key,
|
const char *key,
|
||||||
const gchar *value)
|
const char *value)
|
||||||
{
|
{
|
||||||
g_return_if_fail (properties != NULL);
|
g_return_if_fail (properties != NULL);
|
||||||
g_return_if_fail (key != NULL);
|
g_return_if_fail (key != NULL);
|
||||||
|
|
@ -161,8 +161,8 @@ pinos_properties_set (PinosProperties *properties,
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
pinos_properties_setf (PinosProperties *properties,
|
pinos_properties_setf (PinosProperties *properties,
|
||||||
const gchar *key,
|
const char *key,
|
||||||
const gchar *format,
|
const char *format,
|
||||||
...)
|
...)
|
||||||
{
|
{
|
||||||
va_list varargs;
|
va_list varargs;
|
||||||
|
|
@ -187,9 +187,9 @@ pinos_properties_setf (PinosProperties *properties,
|
||||||
*
|
*
|
||||||
* Returns: the property for @key or %NULL when the key was not found
|
* Returns: the property for @key or %NULL when the key was not found
|
||||||
*/
|
*/
|
||||||
const gchar *
|
const char *
|
||||||
pinos_properties_get (PinosProperties *properties,
|
pinos_properties_get (PinosProperties *properties,
|
||||||
const gchar *key)
|
const char *key)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (properties != NULL, NULL);
|
g_return_val_if_fail (properties != NULL, NULL);
|
||||||
g_return_val_if_fail (key != NULL, NULL);
|
g_return_val_if_fail (key != NULL, NULL);
|
||||||
|
|
@ -211,12 +211,12 @@ pinos_properties_get (PinosProperties *properties,
|
||||||
*
|
*
|
||||||
* Returns: The next key or %NULL when there are no more keys to iterate.
|
* Returns: The next key or %NULL when there are no more keys to iterate.
|
||||||
*/
|
*/
|
||||||
const gchar *
|
const char *
|
||||||
pinos_properties_iterate (PinosProperties *properties,
|
pinos_properties_iterate (PinosProperties *properties,
|
||||||
gpointer *state)
|
void **state)
|
||||||
{
|
{
|
||||||
static gpointer dummy = GINT_TO_POINTER (1);
|
static void * dummy = GINT_TO_POINTER (1);
|
||||||
const gchar *res = NULL;
|
const char *res = NULL;
|
||||||
GList *items;
|
GList *items;
|
||||||
|
|
||||||
g_return_val_if_fail (properties != NULL, NULL);
|
g_return_val_if_fail (properties != NULL, NULL);
|
||||||
|
|
@ -241,84 +241,3 @@ pinos_properties_iterate (PinosProperties *properties,
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
add_to_variant (const gchar *key, const gchar *value, GVariantBuilder *b)
|
|
||||||
{
|
|
||||||
g_variant_builder_add (b, "{sv}", key, g_variant_new_string (value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_properties_init_builder:
|
|
||||||
* @properties: a #PinosProperties
|
|
||||||
* @builder: a #GVariantBuilder
|
|
||||||
*
|
|
||||||
* Initialize the @builder of type a{sv} and add @properties to it.
|
|
||||||
*
|
|
||||||
* Returns: %TRUE if @builder could be initialized.
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
pinos_properties_init_builder (PinosProperties *properties,
|
|
||||||
GVariantBuilder *builder)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (properties != NULL, FALSE);
|
|
||||||
g_return_val_if_fail (builder != NULL, FALSE);
|
|
||||||
|
|
||||||
g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sv}"));
|
|
||||||
g_hash_table_foreach (properties->hashtable, (GHFunc) add_to_variant, builder);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_properties_to_variant:
|
|
||||||
* @properties: a #PinosProperties
|
|
||||||
*
|
|
||||||
* Convert @properties to a #GVariant of type a{sv}
|
|
||||||
*
|
|
||||||
* Returns: a new #GVariant of @properties. use g_variant_unref() after
|
|
||||||
* use.
|
|
||||||
*/
|
|
||||||
GVariant *
|
|
||||||
pinos_properties_to_variant (PinosProperties *properties)
|
|
||||||
{
|
|
||||||
GVariantBuilder builder;
|
|
||||||
|
|
||||||
if (!pinos_properties_init_builder (properties, &builder))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return g_variant_builder_end (&builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_properties_from_variant:
|
|
||||||
* @variant: a #GVariant
|
|
||||||
*
|
|
||||||
* Convert @variant to a #PinosProperties
|
|
||||||
*
|
|
||||||
* Returns: a new #PinosProperties of @variant. use pinos_properties_free()
|
|
||||||
* after use.
|
|
||||||
*/
|
|
||||||
PinosProperties *
|
|
||||||
pinos_properties_from_variant (GVariant *variant)
|
|
||||||
{
|
|
||||||
PinosProperties *props;
|
|
||||||
GVariantIter iter;
|
|
||||||
GVariant *value;
|
|
||||||
gchar *key;
|
|
||||||
|
|
||||||
g_return_val_if_fail (variant != NULL, NULL);
|
|
||||||
|
|
||||||
props = pinos_properties_new (NULL, NULL);
|
|
||||||
|
|
||||||
g_variant_iter_init (&iter, variant);
|
|
||||||
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
|
|
||||||
g_hash_table_replace (props->hashtable,
|
|
||||||
g_strdup (key),
|
|
||||||
g_variant_dup_string (value, NULL));
|
|
||||||
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
G_DEFINE_BOXED_TYPE (PinosProperties, pinos_properties,
|
|
||||||
pinos_properties_copy, pinos_properties_free);
|
|
||||||
|
|
|
||||||
|
|
@ -20,40 +20,33 @@
|
||||||
#ifndef __PINOS_PROPERTIES_H__
|
#ifndef __PINOS_PROPERTIES_H__
|
||||||
#define __PINOS_PROPERTIES_H__
|
#define __PINOS_PROPERTIES_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
G_BEGIN_DECLS
|
#endif
|
||||||
|
|
||||||
typedef struct _PinosProperties PinosProperties;
|
typedef struct _PinosProperties PinosProperties;
|
||||||
|
|
||||||
#define PINOS_TYPE_PROPERTIES (pinos_properties_get_type())
|
PinosProperties * pinos_properties_new (const char *key, ...);
|
||||||
GType pinos_properties_get_type (void);
|
|
||||||
|
|
||||||
PinosProperties * pinos_properties_new (const gchar *key, ...) G_GNUC_NULL_TERMINATED;
|
|
||||||
PinosProperties * pinos_properties_copy (PinosProperties *properties);
|
PinosProperties * pinos_properties_copy (PinosProperties *properties);
|
||||||
PinosProperties * pinos_properties_merge (PinosProperties *oldprops,
|
PinosProperties * pinos_properties_merge (PinosProperties *oldprops,
|
||||||
PinosProperties *newprops);
|
PinosProperties *newprops);
|
||||||
void pinos_properties_free (PinosProperties *properties);
|
void pinos_properties_free (PinosProperties *properties);
|
||||||
|
|
||||||
void pinos_properties_set (PinosProperties *properties,
|
void pinos_properties_set (PinosProperties *properties,
|
||||||
const gchar *key,
|
const char *key,
|
||||||
const gchar *value);
|
const char *value);
|
||||||
void pinos_properties_setf (PinosProperties *properties,
|
void pinos_properties_setf (PinosProperties *properties,
|
||||||
const gchar *key,
|
const char *key,
|
||||||
const gchar *format,
|
const char *format,
|
||||||
...) G_GNUC_PRINTF (3, 4);
|
...) SPA_PRINTF_FUNC (3, 4);
|
||||||
const gchar * pinos_properties_get (PinosProperties *properties,
|
const char * pinos_properties_get (PinosProperties *properties,
|
||||||
const gchar *key);
|
const char *key);
|
||||||
|
|
||||||
const gchar * pinos_properties_iterate (PinosProperties *properties,
|
const char * pinos_properties_iterate (PinosProperties *properties,
|
||||||
gpointer *state);
|
void **state);
|
||||||
|
|
||||||
gboolean pinos_properties_init_builder (PinosProperties *properties,
|
#ifdef __cplusplus
|
||||||
GVariantBuilder *builder);
|
}
|
||||||
GVariant * pinos_properties_to_variant (PinosProperties *properties);
|
#endif
|
||||||
PinosProperties * pinos_properties_from_variant (GVariant *variant);
|
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __PINOS_PROPERTIES_H__ */
|
#endif /* __PINOS_PROPERTIES_H__ */
|
||||||
|
|
|
||||||
76
pinos/client/proxy.c
Normal file
76
pinos/client/proxy.c
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* Pinos
|
||||||
|
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pinos/client/log.h>
|
||||||
|
#include <pinos/client/proxy.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PinosProxy this;
|
||||||
|
} PinosProxyImpl;
|
||||||
|
|
||||||
|
PinosProxy *
|
||||||
|
pinos_proxy_new (PinosContext *context,
|
||||||
|
uint32_t id,
|
||||||
|
uint32_t type)
|
||||||
|
{
|
||||||
|
PinosProxyImpl *impl;
|
||||||
|
PinosProxy *this;
|
||||||
|
|
||||||
|
impl = calloc (1, sizeof (PinosProxyImpl));
|
||||||
|
this = &impl->this;
|
||||||
|
|
||||||
|
this->context = context;
|
||||||
|
this->type = type;
|
||||||
|
this->send_func = context->send_func;
|
||||||
|
this->send_data = context->send_data;
|
||||||
|
|
||||||
|
pinos_signal_init (&this->destroy_signal);
|
||||||
|
|
||||||
|
this->id = pinos_map_insert_new (&context->objects, this);
|
||||||
|
|
||||||
|
spa_list_insert (&this->context->proxy_list, &this->link);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pinos_proxy_destroy (PinosProxy *proxy)
|
||||||
|
{
|
||||||
|
PinosProxyImpl *impl = SPA_CONTAINER_OF (proxy, PinosProxyImpl, this);
|
||||||
|
|
||||||
|
pinos_signal_emit (&proxy->destroy_signal, proxy);
|
||||||
|
|
||||||
|
pinos_map_remove (&proxy->context->objects, proxy->id);
|
||||||
|
spa_list_remove (&proxy->link);
|
||||||
|
free (impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpaResult
|
||||||
|
pinos_proxy_send_message (PinosProxy *proxy,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
bool flush)
|
||||||
|
{
|
||||||
|
if (proxy->send_func)
|
||||||
|
return proxy->send_func (proxy, proxy->id, type, message, flush, proxy->send_data);
|
||||||
|
|
||||||
|
pinos_log_error ("proxy %p: send func not implemented", proxy);
|
||||||
|
|
||||||
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
75
pinos/client/proxy.h
Normal file
75
pinos/client/proxy.h
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* Pinos
|
||||||
|
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PINOS_PROXY_H__
|
||||||
|
#define __PINOS_PROXY_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pinos/client/connection.h>
|
||||||
|
|
||||||
|
typedef struct _PinosProxy PinosProxy;
|
||||||
|
|
||||||
|
typedef SpaResult (*PinosSendFunc) (void *object,
|
||||||
|
uint32_t id,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
bool flush,
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
typedef SpaResult (*PinosDispatchFunc) (void *object,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
void *data);
|
||||||
|
#include <pinos/client/context.h>
|
||||||
|
|
||||||
|
struct _PinosProxy {
|
||||||
|
PinosContext *context;
|
||||||
|
SpaList link;
|
||||||
|
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t type;
|
||||||
|
|
||||||
|
PinosSendFunc send_func;
|
||||||
|
void *send_data;
|
||||||
|
PinosDispatchFunc dispatch_func;
|
||||||
|
void *dispatch_data;
|
||||||
|
|
||||||
|
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
||||||
|
PinosProxy *proxy));
|
||||||
|
};
|
||||||
|
|
||||||
|
PinosProxy * pinos_proxy_new (PinosContext *context,
|
||||||
|
uint32_t id,
|
||||||
|
uint32_t type);
|
||||||
|
void pinos_proxy_destroy (PinosProxy *proxy);
|
||||||
|
|
||||||
|
SpaResult pinos_proxy_send_message (PinosProxy *proxy,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
bool flush);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __PINOS_PROXY_H__ */
|
||||||
|
|
@ -352,3 +352,91 @@ pinos_serialize_props_copy_into (void *dest, const SpaProps *props)
|
||||||
pinos_serialize_props_serialize (dest, props);
|
pinos_serialize_props_serialize (dest, props);
|
||||||
return pinos_serialize_props_deserialize (dest, 0);
|
return pinos_serialize_props_deserialize (dest, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
pinos_serialize_dict_get_size (const SpaDict *dict)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (dict == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = sizeof (SpaDict);
|
||||||
|
len += dict->n_items * sizeof (SpaDictItem);
|
||||||
|
for (i = 0; i < dict->n_items; i++) {
|
||||||
|
SpaDictItem *di = &dict->items[i];
|
||||||
|
len += di->key ? strlen (di->key) + 1 : 0;
|
||||||
|
len += di->value ? strlen (di->value) + 1 : 0;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
pinos_serialize_dict_serialize (void *p, const SpaDict *dict)
|
||||||
|
{
|
||||||
|
SpaDict *pi;
|
||||||
|
SpaDictItem *di;
|
||||||
|
int i;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (dict == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pi = p;
|
||||||
|
memcpy (pi, dict, sizeof (SpaDict));
|
||||||
|
|
||||||
|
di = SPA_MEMBER (pi, sizeof (SpaDict), SpaDictItem);
|
||||||
|
if (dict->n_items)
|
||||||
|
pi->items = SPA_INT_TO_PTR (SPA_PTRDIFF (di, pi));
|
||||||
|
else
|
||||||
|
pi->items = 0;
|
||||||
|
|
||||||
|
p = SPA_MEMBER (di, sizeof (SpaDictItem) * dict->n_items, void);
|
||||||
|
|
||||||
|
for (i = 0; i < dict->n_items; i++) {
|
||||||
|
if (dict->items[i].key) {
|
||||||
|
len = strlen (dict->items[i].key) + 1;
|
||||||
|
memcpy (p, dict->items[i].key, len);
|
||||||
|
di[i].key = SPA_INT_TO_PTR (SPA_PTRDIFF (p, pi));
|
||||||
|
p += len;
|
||||||
|
} else {
|
||||||
|
di[i].key = NULL;
|
||||||
|
}
|
||||||
|
if (dict->items[i].value) {
|
||||||
|
len = strlen (dict->items[i].value) + 1;
|
||||||
|
memcpy (p, dict->items[i].value, len);
|
||||||
|
di[i].value = SPA_INT_TO_PTR (SPA_PTRDIFF (p, pi));
|
||||||
|
p += len;
|
||||||
|
} else {
|
||||||
|
di[i].value = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SPA_PTRDIFF (p, pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpaDict *
|
||||||
|
pinos_serialize_dict_deserialize (void *p, off_t offset)
|
||||||
|
{
|
||||||
|
SpaDict *pi;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
pi = SPA_MEMBER (p, offset, SpaDict);
|
||||||
|
if (pi->items)
|
||||||
|
pi->items = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->items), SpaDictItem);
|
||||||
|
for (i = 0; i < pi->n_items; i++) {
|
||||||
|
pi->items[i].key = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->items[i].key), char);
|
||||||
|
pi->items[i].value = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->items[i].value), char);
|
||||||
|
}
|
||||||
|
return pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpaDict *
|
||||||
|
pinos_serialize_dict_copy_into (void *dest, const SpaDict *dict)
|
||||||
|
{
|
||||||
|
if (dict == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pinos_serialize_dict_serialize (dest, dict);
|
||||||
|
return pinos_serialize_dict_deserialize (dest, 0);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,11 @@ size_t pinos_serialize_props_serialize (void *dest, const SpaProp
|
||||||
SpaProps * pinos_serialize_props_deserialize (void *src, off_t offset);
|
SpaProps * pinos_serialize_props_deserialize (void *src, off_t offset);
|
||||||
SpaProps * pinos_serialize_props_copy_into (void *dest, const SpaProps *props);
|
SpaProps * pinos_serialize_props_copy_into (void *dest, const SpaProps *props);
|
||||||
|
|
||||||
|
size_t pinos_serialize_dict_get_size (const SpaDict *dict);
|
||||||
|
size_t pinos_serialize_dict_serialize (void *dest, const SpaDict *dict);
|
||||||
|
SpaDict * pinos_serialize_dict_deserialize (void *src, off_t offset);
|
||||||
|
SpaDict * pinos_serialize_dict_copy_into (void *dest, const SpaDict *dict);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -41,19 +41,19 @@ struct _PinosSignal {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PINOS_SIGNAL(name,func) \
|
#define PINOS_SIGNAL(name,func) \
|
||||||
union { \
|
union { \
|
||||||
SpaList listeners; \
|
SpaList listeners; \
|
||||||
void (*notify) func; \
|
void (*notify) func; \
|
||||||
} name;
|
} name;
|
||||||
|
|
||||||
#define pinos_signal_init(signal) \
|
#define pinos_signal_init(signal) \
|
||||||
spa_list_init (&(signal)->listeners);
|
spa_list_init (&(signal)->listeners);
|
||||||
|
|
||||||
#define pinos_signal_add(signal,listener,func) \
|
#define pinos_signal_add(signal,listener,func) \
|
||||||
do { \
|
do { \
|
||||||
__typeof__((signal)->notify) n = (func); \
|
__typeof__((signal)->notify) n = (func); \
|
||||||
(listener)->notify = (void (*) (void *)) n; \
|
(listener)->notify = (void (*) (void *)) n; \
|
||||||
spa_list_insert ((signal)->listeners.prev, &(listener)->link); \
|
spa_list_insert ((signal)->listeners.prev, &(listener)->link); \
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ pinos_signal_remove (PinosListener *listener)
|
||||||
do { \
|
do { \
|
||||||
PinosListener *l, *next; \
|
PinosListener *l, *next; \
|
||||||
spa_list_for_each_safe (l, next, &(signal)->listeners, link) \
|
spa_list_for_each_safe (l, next, &(signal)->listeners, link) \
|
||||||
((__typeof__((signal)->notify))l->notify) (l,__VA_ARGS__); \
|
((__typeof__((signal)->notify))l->notify) (l,__VA_ARGS__); \
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -20,28 +20,16 @@
|
||||||
#ifndef __PINOS_STREAM_H__
|
#ifndef __PINOS_STREAM_H__
|
||||||
#define __PINOS_STREAM_H__
|
#define __PINOS_STREAM_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
|
||||||
|
|
||||||
#include <spa/include/spa/buffer.h>
|
#include <spa/include/spa/buffer.h>
|
||||||
#include <spa/include/spa/format.h>
|
#include <spa/include/spa/format.h>
|
||||||
|
|
||||||
#include <pinos/client/context.h>
|
#include <pinos/client/context.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
G_BEGIN_DECLS
|
extern "C" {
|
||||||
|
#endif
|
||||||
#define PINOS_TYPE_STREAM (pinos_stream_get_type ())
|
|
||||||
#define PINOS_IS_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_STREAM))
|
|
||||||
#define PINOS_IS_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_STREAM))
|
|
||||||
#define PINOS_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_STREAM, PinosStreamClass))
|
|
||||||
#define PINOS_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_STREAM, PinosStream))
|
|
||||||
#define PINOS_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_STREAM, PinosStreamClass))
|
|
||||||
#define PINOS_STREAM_CAST(obj) ((PinosStream*)(obj))
|
|
||||||
#define PINOS_STREAM_CLASS_CAST(klass) ((PinosStreamClass*)(klass))
|
|
||||||
|
|
||||||
typedef struct _PinosStream PinosStream;
|
typedef struct _PinosStream PinosStream;
|
||||||
typedef struct _PinosStreamClass PinosStreamClass;
|
|
||||||
typedef struct _PinosStreamPrivate PinosStreamPrivate;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PINOS_STREAM_STATE_ERROR = -1,
|
PINOS_STREAM_STATE_ERROR = -1,
|
||||||
|
|
@ -53,7 +41,7 @@ typedef enum {
|
||||||
PINOS_STREAM_STATE_STREAMING = 5
|
PINOS_STREAM_STATE_STREAMING = 5
|
||||||
} PinosStreamState;
|
} PinosStreamState;
|
||||||
|
|
||||||
const gchar * pinos_stream_state_as_string (PinosStreamState state);
|
const char * pinos_stream_state_as_string (PinosStreamState state);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PINOS_STREAM_FLAG_NONE = 0,
|
PINOS_STREAM_FLAG_NONE = 0,
|
||||||
|
|
@ -66,8 +54,8 @@ typedef enum {
|
||||||
} PinosStreamMode;
|
} PinosStreamMode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gint64 ticks;
|
int64_t ticks;
|
||||||
gint32 rate;
|
int32_t rate;
|
||||||
} PinosTime;
|
} PinosTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,57 +64,71 @@ typedef struct {
|
||||||
* Pinos stream object class.
|
* Pinos stream object class.
|
||||||
*/
|
*/
|
||||||
struct _PinosStream {
|
struct _PinosStream {
|
||||||
GObject object;
|
PinosContext *context;
|
||||||
|
SpaList link;
|
||||||
|
|
||||||
PinosStreamPrivate *priv;
|
char *name;
|
||||||
|
PinosProperties *properties;
|
||||||
|
|
||||||
|
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
||||||
|
PinosStream *stream));
|
||||||
|
|
||||||
|
PinosStreamState state;
|
||||||
|
char *error;
|
||||||
|
PINOS_SIGNAL (state_changed, (PinosListener *listener,
|
||||||
|
PinosStream *stream));
|
||||||
|
|
||||||
|
PINOS_SIGNAL (format_changed, (PinosListener *listener,
|
||||||
|
PinosStream *stream,
|
||||||
|
SpaFormat *format));
|
||||||
|
|
||||||
|
PINOS_SIGNAL (add_buffer, (PinosListener *listener,
|
||||||
|
PinosStream *stream,
|
||||||
|
uint32_t id));
|
||||||
|
PINOS_SIGNAL (remove_buffer, (PinosListener *listener,
|
||||||
|
PinosStream *stream,
|
||||||
|
uint32_t id));
|
||||||
|
PINOS_SIGNAL (new_buffer, (PinosListener *listener,
|
||||||
|
PinosStream *stream,
|
||||||
|
uint32_t id));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* PinosStreamClass:
|
|
||||||
*
|
|
||||||
* Pinos stream object class.
|
|
||||||
*/
|
|
||||||
struct _PinosStreamClass {
|
|
||||||
GObjectClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* normal GObject stuff */
|
|
||||||
GType pinos_stream_get_type (void);
|
|
||||||
|
|
||||||
|
|
||||||
PinosStream * pinos_stream_new (PinosContext *context,
|
PinosStream * pinos_stream_new (PinosContext *context,
|
||||||
const gchar *name,
|
const char *name,
|
||||||
PinosProperties *props);
|
PinosProperties *props);
|
||||||
|
void pinos_stream_destroy (PinosStream *stream);
|
||||||
|
|
||||||
PinosStreamState pinos_stream_get_state (PinosStream *stream);
|
bool pinos_stream_connect (PinosStream *stream,
|
||||||
const GError * pinos_stream_get_error (PinosStream *stream);
|
|
||||||
|
|
||||||
gboolean pinos_stream_connect (PinosStream *stream,
|
|
||||||
PinosDirection direction,
|
PinosDirection direction,
|
||||||
PinosStreamMode mode,
|
PinosStreamMode mode,
|
||||||
const gchar *port_path,
|
const char *port_path,
|
||||||
PinosStreamFlags flags,
|
PinosStreamFlags flags,
|
||||||
GPtrArray *possible_formats);
|
unsigned int n_possible_formats,
|
||||||
gboolean pinos_stream_disconnect (PinosStream *stream);
|
SpaFormat **possible_formats);
|
||||||
|
bool pinos_stream_disconnect (PinosStream *stream);
|
||||||
|
|
||||||
gboolean pinos_stream_finish_format (PinosStream *stream,
|
bool pinos_stream_finish_format (PinosStream *stream,
|
||||||
SpaResult res,
|
SpaResult res,
|
||||||
SpaAllocParam **params,
|
SpaAllocParam **params,
|
||||||
unsigned int n_params);
|
unsigned int n_params);
|
||||||
|
|
||||||
gboolean pinos_stream_start (PinosStream *stream);
|
|
||||||
gboolean pinos_stream_stop (PinosStream *stream);
|
|
||||||
|
|
||||||
gboolean pinos_stream_get_time (PinosStream *stream,
|
|
||||||
|
bool pinos_stream_start (PinosStream *stream);
|
||||||
|
bool pinos_stream_stop (PinosStream *stream);
|
||||||
|
|
||||||
|
bool pinos_stream_get_time (PinosStream *stream,
|
||||||
PinosTime *time);
|
PinosTime *time);
|
||||||
|
|
||||||
guint pinos_stream_get_empty_buffer (PinosStream *stream);
|
uint32_t pinos_stream_get_empty_buffer (PinosStream *stream);
|
||||||
gboolean pinos_stream_recycle_buffer (PinosStream *stream,
|
bool pinos_stream_recycle_buffer (PinosStream *stream,
|
||||||
guint id);
|
uint32_t id);
|
||||||
SpaBuffer * pinos_stream_peek_buffer (PinosStream *stream,
|
SpaBuffer * pinos_stream_peek_buffer (PinosStream *stream,
|
||||||
guint id);
|
uint32_t id);
|
||||||
gboolean pinos_stream_send_buffer (PinosStream *stream,
|
bool pinos_stream_send_buffer (PinosStream *stream,
|
||||||
guint id);
|
uint32_t id);
|
||||||
G_END_DECLS
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __PINOS_STREAM_H__ */
|
#endif /* __PINOS_STREAM_H__ */
|
||||||
|
|
|
||||||
|
|
@ -1,819 +0,0 @@
|
||||||
/* Pinos
|
|
||||||
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gio/gio.h>
|
|
||||||
|
|
||||||
#include "pinos/client/pinos.h"
|
|
||||||
#include "pinos/client/enumtypes.h"
|
|
||||||
#include "pinos/client/private.h"
|
|
||||||
|
|
||||||
struct _PinosSubscribePrivate
|
|
||||||
{
|
|
||||||
gchar *service;
|
|
||||||
PinosSubscriptionFlags subscription_mask;
|
|
||||||
|
|
||||||
GDBusConnection *connection;
|
|
||||||
GCancellable *cancellable;
|
|
||||||
|
|
||||||
GDBusProxy *manager_proxy;
|
|
||||||
guint owner_id;
|
|
||||||
guint signal_id;
|
|
||||||
|
|
||||||
guint pending_proxies;
|
|
||||||
GList *objects;
|
|
||||||
|
|
||||||
PinosSubscriptionState state;
|
|
||||||
GError *error;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
PinosSubscribe *subscribe;
|
|
||||||
gchar *sender_name;
|
|
||||||
gchar *object_path;
|
|
||||||
gchar *interface_name;
|
|
||||||
gboolean pending;
|
|
||||||
GDBusProxy *proxy;
|
|
||||||
guint prop_id;
|
|
||||||
GList *tasks;
|
|
||||||
gboolean removed;
|
|
||||||
} PinosObjectData;
|
|
||||||
|
|
||||||
|
|
||||||
#define PINOS_SUBSCRIBE_GET_PRIVATE(obj) \
|
|
||||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_SUBSCRIBE, PinosSubscribePrivate))
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (PinosSubscribe, pinos_subscribe, G_TYPE_OBJECT);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_CONNECTION,
|
|
||||||
PROP_SERVICE,
|
|
||||||
PROP_SUBSCRIPTION_MASK,
|
|
||||||
PROP_STATE,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
SIGNAL_SUBSCRIPTION_EVENT,
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
static guint signals[LAST_SIGNAL] = { 0 };
|
|
||||||
|
|
||||||
static void
|
|
||||||
subscription_set_state (PinosSubscribe *subscribe,
|
|
||||||
PinosSubscriptionState state)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
|
|
||||||
if (state != priv->state) {
|
|
||||||
priv->state = state;
|
|
||||||
g_object_notify (G_OBJECT (subscribe), "state");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
notify_event (PinosSubscribe *subscribe,
|
|
||||||
PinosObjectData *data,
|
|
||||||
PinosSubscriptionEvent event)
|
|
||||||
{
|
|
||||||
const gchar *interface_name;
|
|
||||||
PinosSubscriptionFlags flags = 0;
|
|
||||||
|
|
||||||
interface_name = g_dbus_proxy_get_interface_name (data->proxy);
|
|
||||||
if (g_strcmp0 (interface_name, "org.pinos.Daemon1") == 0) {
|
|
||||||
flags = PINOS_SUBSCRIPTION_FLAG_DAEMON;
|
|
||||||
}
|
|
||||||
if (g_strcmp0 (interface_name, "org.pinos.Client1") == 0) {
|
|
||||||
flags = PINOS_SUBSCRIPTION_FLAG_CLIENT;
|
|
||||||
}
|
|
||||||
else if (g_strcmp0 (interface_name, "org.pinos.Node1") == 0) {
|
|
||||||
flags = PINOS_SUBSCRIPTION_FLAG_NODE;
|
|
||||||
}
|
|
||||||
else if (g_strcmp0 (interface_name, "org.pinos.Link1") == 0) {
|
|
||||||
flags = PINOS_SUBSCRIPTION_FLAG_LINK;
|
|
||||||
}
|
|
||||||
g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0,
|
|
||||||
event, flags, data->proxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_proxy_properties_changed (GDBusProxy *proxy,
|
|
||||||
GVariant *changed_properties,
|
|
||||||
GStrv invalidated_properties,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosObjectData *data = user_data;
|
|
||||||
GVariantIter iter;
|
|
||||||
GVariant *value;
|
|
||||||
gchar *key;
|
|
||||||
GHashTable *props;
|
|
||||||
gboolean need_notify = FALSE;
|
|
||||||
|
|
||||||
props = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties");
|
|
||||||
|
|
||||||
g_variant_iter_init (&iter, changed_properties);
|
|
||||||
while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) {
|
|
||||||
if (!g_hash_table_contains (props, key))
|
|
||||||
g_hash_table_add (props, g_strdup (key));
|
|
||||||
need_notify = TRUE;
|
|
||||||
}
|
|
||||||
if (need_notify)
|
|
||||||
notify_event (data->subscribe, data, PINOS_SUBSCRIPTION_EVENT_CHANGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
object_data_free (PinosObjectData *data)
|
|
||||||
{
|
|
||||||
g_signal_handler_disconnect (data->proxy, data->prop_id);
|
|
||||||
g_object_unref (data->proxy);
|
|
||||||
g_free (data->sender_name);
|
|
||||||
g_free (data->object_path);
|
|
||||||
g_free (data->interface_name);
|
|
||||||
g_free (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remove_data (PinosSubscribe *subscribe,
|
|
||||||
PinosObjectData *data)
|
|
||||||
{
|
|
||||||
if (data->pending) {
|
|
||||||
data->removed = TRUE;
|
|
||||||
} else {
|
|
||||||
GHashTable *props = g_object_get_data (G_OBJECT (data->proxy), "pinos-changed-properties");
|
|
||||||
|
|
||||||
g_hash_table_remove_all (props);
|
|
||||||
notify_event (subscribe, data, PINOS_SUBSCRIPTION_EVENT_REMOVE);
|
|
||||||
object_data_free (data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remove_all_data (PinosSubscribe *subscribe)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
GList *walk;
|
|
||||||
|
|
||||||
for (walk = priv->objects; walk; walk = g_list_next (walk)) {
|
|
||||||
PinosObjectData *data = walk->data;
|
|
||||||
remove_data (subscribe, data);
|
|
||||||
}
|
|
||||||
g_list_free (priv->objects);
|
|
||||||
priv->objects = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_proxy_created (GObject *source_object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosObjectData *data = user_data;
|
|
||||||
PinosSubscribe *subscribe = data->subscribe;
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
GError *error = NULL;
|
|
||||||
GList *walk;
|
|
||||||
|
|
||||||
data->pending = FALSE;
|
|
||||||
|
|
||||||
data->proxy = g_dbus_proxy_new_finish (res, &error);
|
|
||||||
if (data->proxy == NULL) {
|
|
||||||
priv->objects = g_list_remove (priv->objects, data);
|
|
||||||
pinos_log_warn ("could not create proxy: %s", error->message);
|
|
||||||
subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_ERROR);
|
|
||||||
priv->error = error;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->prop_id = g_signal_connect (data->proxy,
|
|
||||||
"g-properties-changed",
|
|
||||||
(GCallback) on_proxy_properties_changed,
|
|
||||||
data);
|
|
||||||
|
|
||||||
notify_event (subscribe, data, PINOS_SUBSCRIPTION_EVENT_NEW);
|
|
||||||
|
|
||||||
g_object_set_data_full (G_OBJECT (data->proxy),
|
|
||||||
"pinos-changed-properties",
|
|
||||||
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL),
|
|
||||||
(GDestroyNotify) g_hash_table_unref);
|
|
||||||
|
|
||||||
for (walk = data->tasks; walk; walk = g_list_next (walk)) {
|
|
||||||
GTask *task = walk->data;
|
|
||||||
g_task_return_pointer (task, g_object_ref (data->proxy), g_object_unref);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
g_list_free (data->tasks);
|
|
||||||
data->tasks = NULL;
|
|
||||||
|
|
||||||
if (--priv->pending_proxies == 0)
|
|
||||||
subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_READY);
|
|
||||||
|
|
||||||
if (data->removed) {
|
|
||||||
priv->objects = g_list_remove (priv->objects, data);
|
|
||||||
remove_data (subscribe, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
add_interface (PinosSubscribe *subscribe,
|
|
||||||
const gchar *object_path,
|
|
||||||
const gchar *interface_name,
|
|
||||||
GVariant *properties)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
PinosObjectData *data;
|
|
||||||
|
|
||||||
data = g_new0 (PinosObjectData, 1);
|
|
||||||
data->subscribe = subscribe;
|
|
||||||
data->sender_name = g_strdup (priv->service);
|
|
||||||
data->object_path = g_strdup (object_path);
|
|
||||||
data->interface_name = g_strdup (interface_name);
|
|
||||||
data->pending = TRUE;
|
|
||||||
|
|
||||||
priv->objects = g_list_prepend (priv->objects, data);
|
|
||||||
priv->pending_proxies++;
|
|
||||||
|
|
||||||
g_dbus_proxy_new (priv->connection,
|
|
||||||
G_DBUS_PROXY_FLAGS_NONE,
|
|
||||||
NULL, /* GDBusInterfaceInfo* */
|
|
||||||
priv->service,
|
|
||||||
object_path,
|
|
||||||
interface_name,
|
|
||||||
priv->cancellable,
|
|
||||||
on_proxy_created,
|
|
||||||
data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remove_interface (PinosSubscribe *subscribe,
|
|
||||||
const gchar *object_path,
|
|
||||||
const gchar *interface_name)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
GList *walk;
|
|
||||||
|
|
||||||
for (walk = priv->objects; walk; walk = g_list_next (walk)) {
|
|
||||||
PinosObjectData *data = walk->data;
|
|
||||||
|
|
||||||
if (g_strcmp0 (data->object_path, object_path) == 0 &&
|
|
||||||
g_strcmp0 (data->interface_name, interface_name) == 0) {
|
|
||||||
priv->objects = g_list_remove (priv->objects, data);
|
|
||||||
remove_data (subscribe, data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
add_ifaces_and_properties (PinosSubscribe *subscribe,
|
|
||||||
const gchar *object_path,
|
|
||||||
GVariant *ifaces_and_properties)
|
|
||||||
{
|
|
||||||
GVariantIter iter;
|
|
||||||
const gchar *interface_name;
|
|
||||||
GVariant *properties;
|
|
||||||
|
|
||||||
g_variant_iter_init (&iter, ifaces_and_properties);
|
|
||||||
while (g_variant_iter_next (&iter,
|
|
||||||
"{&s@a{sv}}",
|
|
||||||
&interface_name,
|
|
||||||
&properties)) {
|
|
||||||
|
|
||||||
add_interface (subscribe, object_path, interface_name, properties);
|
|
||||||
|
|
||||||
g_variant_unref (properties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remove_ifaces (PinosSubscribe *subscribe,
|
|
||||||
const gchar *object_path,
|
|
||||||
const gchar **ifaces)
|
|
||||||
{
|
|
||||||
while (*ifaces) {
|
|
||||||
remove_interface (subscribe, object_path, *ifaces);
|
|
||||||
|
|
||||||
ifaces++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_manager_proxy_signal (GDBusProxy *proxy,
|
|
||||||
const gchar *sender_name,
|
|
||||||
const gchar *signal_name,
|
|
||||||
GVariant *parameters,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosSubscribe *subscribe = user_data;
|
|
||||||
const gchar *object_path;
|
|
||||||
|
|
||||||
if (g_strcmp0 (signal_name, "InterfacesAdded") == 0) {
|
|
||||||
GVariant *ifaces_and_properties;
|
|
||||||
|
|
||||||
g_variant_get (parameters,
|
|
||||||
"(&o@a{sa{sv}})",
|
|
||||||
&object_path,
|
|
||||||
&ifaces_and_properties);
|
|
||||||
|
|
||||||
add_ifaces_and_properties (subscribe, object_path, ifaces_and_properties);
|
|
||||||
|
|
||||||
g_variant_unref (ifaces_and_properties);
|
|
||||||
} else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0) {
|
|
||||||
const gchar **ifaces;
|
|
||||||
g_variant_get (parameters,
|
|
||||||
"(&o^a&s)",
|
|
||||||
&object_path,
|
|
||||||
&ifaces);
|
|
||||||
|
|
||||||
remove_ifaces (subscribe, object_path, ifaces);
|
|
||||||
|
|
||||||
g_free (ifaces);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_managed_objects_ready (GObject *source_object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosSubscribe *subscribe = user_data;
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
GError *error = NULL;
|
|
||||||
GVariant *objects;
|
|
||||||
GVariant *arg0;
|
|
||||||
const gchar *object_path;
|
|
||||||
GVariant *ifaces_and_properties;
|
|
||||||
GVariantIter object_iter;
|
|
||||||
|
|
||||||
objects = g_dbus_proxy_call_finish (priv->manager_proxy, res, &error);
|
|
||||||
if (objects == NULL) {
|
|
||||||
pinos_log_warn ("could not get objects: %s", error->message);
|
|
||||||
subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_ERROR);
|
|
||||||
priv->error = error;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
arg0 = g_variant_get_child_value (objects, 0);
|
|
||||||
g_variant_iter_init (&object_iter, arg0);
|
|
||||||
while (g_variant_iter_next (&object_iter,
|
|
||||||
"{&o@a{sa{sv}}}",
|
|
||||||
&object_path,
|
|
||||||
&ifaces_and_properties)) {
|
|
||||||
|
|
||||||
add_ifaces_and_properties (subscribe, object_path, ifaces_and_properties);
|
|
||||||
|
|
||||||
g_variant_unref (ifaces_and_properties);
|
|
||||||
}
|
|
||||||
g_variant_unref (arg0);
|
|
||||||
g_variant_unref (objects);
|
|
||||||
|
|
||||||
if (priv->pending_proxies == 0)
|
|
||||||
subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_READY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
manager_proxy_appeared (PinosSubscribe *subscribe)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
|
|
||||||
g_dbus_proxy_call (priv->manager_proxy,
|
|
||||||
"GetManagedObjects",
|
|
||||||
NULL, /* parameters */
|
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
|
||||||
-1,
|
|
||||||
priv->cancellable,
|
|
||||||
on_managed_objects_ready,
|
|
||||||
subscribe);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
manager_proxy_disappeared (PinosSubscribe *subscribe)
|
|
||||||
{
|
|
||||||
remove_all_data (subscribe);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_manager_proxy_name_owner (GObject *object,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosSubscribe *subscribe = user_data;
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
gchar *name_owner;
|
|
||||||
|
|
||||||
g_object_get (priv->manager_proxy, "g-name-owner", &name_owner, NULL);
|
|
||||||
|
|
||||||
if (name_owner) {
|
|
||||||
manager_proxy_appeared (subscribe);
|
|
||||||
g_free (name_owner);
|
|
||||||
} else {
|
|
||||||
manager_proxy_disappeared (subscribe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
connect_client_signals (PinosSubscribe *subscribe)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
|
|
||||||
priv->owner_id = g_signal_connect (priv->manager_proxy, "notify::g-name-owner",
|
|
||||||
(GCallback) on_manager_proxy_name_owner, subscribe);
|
|
||||||
|
|
||||||
priv->signal_id = g_signal_connect (priv->manager_proxy, "g-signal",
|
|
||||||
(GCallback) on_manager_proxy_signal, subscribe);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_manager_proxy_ready (GObject *source_object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosSubscribe *subscribe = user_data;
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
priv->manager_proxy = g_dbus_proxy_new_finish (res, &error);
|
|
||||||
if (priv->manager_proxy == NULL)
|
|
||||||
goto manager_error;
|
|
||||||
|
|
||||||
connect_client_signals (subscribe);
|
|
||||||
|
|
||||||
on_manager_proxy_name_owner (G_OBJECT (priv->manager_proxy), NULL, subscribe);
|
|
||||||
g_object_unref (subscribe);
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* ERRORS */
|
|
||||||
manager_error:
|
|
||||||
{
|
|
||||||
pinos_log_warn ("could not create client manager: %s", error->message);
|
|
||||||
subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_ERROR);
|
|
||||||
priv->error = error;
|
|
||||||
g_object_unref (subscribe);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
install_subscription (PinosSubscribe *subscribe)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
|
|
||||||
subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_CONNECTING);
|
|
||||||
|
|
||||||
g_dbus_proxy_new (priv->connection,
|
|
||||||
G_DBUS_PROXY_FLAGS_NONE,
|
|
||||||
NULL, /* GDBusInterfaceInfo* */
|
|
||||||
priv->service,
|
|
||||||
PINOS_DBUS_OBJECT_PREFIX,
|
|
||||||
"org.freedesktop.DBus.ObjectManager",
|
|
||||||
priv->cancellable,
|
|
||||||
on_manager_proxy_ready,
|
|
||||||
g_object_ref (subscribe));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
uninstall_subscription (PinosSubscribe *subscribe)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
|
|
||||||
if (priv->manager_proxy) {
|
|
||||||
g_signal_handler_disconnect (priv->manager_proxy, priv->owner_id);
|
|
||||||
g_signal_handler_disconnect (priv->manager_proxy, priv->signal_id);
|
|
||||||
g_clear_object (&priv->manager_proxy);
|
|
||||||
}
|
|
||||||
g_clear_error (&priv->error);
|
|
||||||
subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_UNCONNECTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_subscribe_get_property (GObject *_object,
|
|
||||||
guint prop_id,
|
|
||||||
GValue *value,
|
|
||||||
GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
PinosSubscribe *subscribe = PINOS_SUBSCRIBE (_object);
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_CONNECTION:
|
|
||||||
g_value_set_object (value, priv->connection);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_SERVICE:
|
|
||||||
g_value_set_string (value, priv->service);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_SUBSCRIPTION_MASK:
|
|
||||||
g_value_set_flags (value, priv->subscription_mask);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_STATE:
|
|
||||||
g_value_set_enum (value, priv->state);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (subscribe, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_subscribe_set_property (GObject *_object,
|
|
||||||
guint prop_id,
|
|
||||||
const GValue *value,
|
|
||||||
GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
PinosSubscribe *subscribe = PINOS_SUBSCRIBE (_object);
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_CONNECTION:
|
|
||||||
{
|
|
||||||
uninstall_subscription (subscribe);
|
|
||||||
if (priv->connection)
|
|
||||||
g_object_unref (priv->connection);
|
|
||||||
priv->connection = g_value_dup_object (value);
|
|
||||||
if (priv->connection)
|
|
||||||
install_subscription (subscribe);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PROP_SERVICE:
|
|
||||||
g_free (priv->service);
|
|
||||||
priv->service = g_value_dup_string (value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_SUBSCRIPTION_MASK:
|
|
||||||
priv->subscription_mask = g_value_get_flags (value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (subscribe, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_subscribe_finalize (GObject * object)
|
|
||||||
{
|
|
||||||
PinosSubscribe *subscribe = PINOS_SUBSCRIBE (object);
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv;
|
|
||||||
|
|
||||||
remove_all_data (subscribe);
|
|
||||||
|
|
||||||
g_cancellable_cancel (priv->cancellable);
|
|
||||||
if (priv->manager_proxy)
|
|
||||||
g_object_unref (priv->manager_proxy);
|
|
||||||
g_object_unref (priv->cancellable);
|
|
||||||
g_free (priv->service);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (pinos_subscribe_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_subscribe_class_init (PinosSubscribeClass * klass)
|
|
||||||
{
|
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
||||||
|
|
||||||
g_type_class_add_private (klass, sizeof (PinosSubscribePrivate));
|
|
||||||
|
|
||||||
gobject_class->finalize = pinos_subscribe_finalize;
|
|
||||||
gobject_class->set_property = pinos_subscribe_set_property;
|
|
||||||
gobject_class->get_property = pinos_subscribe_get_property;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PinosSubscribe:connection
|
|
||||||
*
|
|
||||||
* The connection of the subscribe.
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_CONNECTION,
|
|
||||||
g_param_spec_object ("connection",
|
|
||||||
"Connection",
|
|
||||||
"The DBus connection",
|
|
||||||
G_TYPE_DBUS_CONNECTION,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosSubscribe:service
|
|
||||||
*
|
|
||||||
* The service of the subscribe.
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_SERVICE,
|
|
||||||
g_param_spec_string ("service",
|
|
||||||
"Service",
|
|
||||||
"The service",
|
|
||||||
PINOS_DBUS_SERVICE,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosSubscribe:subscription-mask
|
|
||||||
*
|
|
||||||
* A mask for what object notifications will be signaled with
|
|
||||||
* PinosSubscribe:subscription-event
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_SUBSCRIPTION_MASK,
|
|
||||||
g_param_spec_flags ("subscription-mask",
|
|
||||||
"Subscription Mask",
|
|
||||||
"The object to receive subscription events of",
|
|
||||||
PINOS_TYPE_SUBSCRIPTION_FLAGS,
|
|
||||||
0,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosSubscribe:state
|
|
||||||
*
|
|
||||||
* The state of the subscription
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_STATE,
|
|
||||||
g_param_spec_enum ("state",
|
|
||||||
"State",
|
|
||||||
"The state",
|
|
||||||
PINOS_TYPE_SUBSCRIPTION_STATE,
|
|
||||||
PINOS_SUBSCRIPTION_STATE_UNCONNECTED,
|
|
||||||
G_PARAM_READABLE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosSubscribe:subscription-event
|
|
||||||
* @subscribe: The #PinosSubscribe emitting the signal.
|
|
||||||
* @event: A #PinosSubscriptionEvent
|
|
||||||
* @flags: #PinosSubscriptionFlags indicating the object
|
|
||||||
* @id: the unique and opaque object id
|
|
||||||
*
|
|
||||||
* Notify about a new object that was added/removed/modified.
|
|
||||||
*/
|
|
||||||
signals[SIGNAL_SUBSCRIPTION_EVENT] = g_signal_new ("subscription-event",
|
|
||||||
G_TYPE_FROM_CLASS (klass),
|
|
||||||
G_SIGNAL_RUN_LAST,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
g_cclosure_marshal_generic,
|
|
||||||
G_TYPE_NONE,
|
|
||||||
3,
|
|
||||||
PINOS_TYPE_SUBSCRIPTION_EVENT,
|
|
||||||
PINOS_TYPE_SUBSCRIPTION_FLAGS,
|
|
||||||
G_TYPE_POINTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_subscribe_init (PinosSubscribe * subscribe)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv = subscribe->priv = PINOS_SUBSCRIBE_GET_PRIVATE (subscribe);
|
|
||||||
|
|
||||||
priv->service = g_strdup (PINOS_DBUS_SERVICE);
|
|
||||||
priv->state = PINOS_SUBSCRIPTION_STATE_UNCONNECTED;
|
|
||||||
priv->cancellable = g_cancellable_new ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_subscribe_new:
|
|
||||||
* @name: an application name
|
|
||||||
* @properties: optional properties
|
|
||||||
*
|
|
||||||
* Make a new unconnected #PinosSubscribe
|
|
||||||
*
|
|
||||||
* Returns: a new unconnected #PinosSubscribe
|
|
||||||
*/
|
|
||||||
PinosSubscribe *
|
|
||||||
pinos_subscribe_new (void)
|
|
||||||
{
|
|
||||||
return g_object_new (PINOS_TYPE_SUBSCRIBE, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
PinosSubscriptionState
|
|
||||||
pinos_subscribe_get_state (PinosSubscribe *subscribe)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv;
|
|
||||||
|
|
||||||
g_return_val_if_fail (PINOS_IS_SUBSCRIBE (subscribe), PINOS_SUBSCRIPTION_STATE_ERROR);
|
|
||||||
priv = subscribe->priv;
|
|
||||||
|
|
||||||
return priv->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
GError *
|
|
||||||
pinos_subscribe_get_error (PinosSubscribe *subscribe)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv;
|
|
||||||
|
|
||||||
g_return_val_if_fail (PINOS_IS_SUBSCRIBE (subscribe), NULL);
|
|
||||||
priv = subscribe->priv;
|
|
||||||
|
|
||||||
return priv->error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
compare_data (PinosObjectData *data,
|
|
||||||
const gchar *name,
|
|
||||||
const gchar *object_path,
|
|
||||||
const gchar *interface_name)
|
|
||||||
{
|
|
||||||
gint res;
|
|
||||||
|
|
||||||
if ((res = g_strcmp0 (data->sender_name, name)) != 0)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
if ((res = g_strcmp0 (data->object_path, object_path)) != 0)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
return g_strcmp0 (data->interface_name, interface_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_subscribe_get_proxy:
|
|
||||||
* @subscribe: a #PinosSubscribe
|
|
||||||
* @name: the owner name
|
|
||||||
* @object_path: the object path
|
|
||||||
* @interface_name: the interface name
|
|
||||||
* @cancellable: a #GCancellable
|
|
||||||
* @callback: a #GAsyncReadyCallback
|
|
||||||
* @user_data: extra user data
|
|
||||||
*
|
|
||||||
* Asyncronously get a #GDBusProxy for the object with the given
|
|
||||||
* @name/@object_path/@interface.
|
|
||||||
*
|
|
||||||
* Use pinos_subscribe_get_proxy_finish() to get the result or error in
|
|
||||||
* @callback.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pinos_subscribe_get_proxy (PinosSubscribe *subscribe,
|
|
||||||
const gchar *name,
|
|
||||||
const gchar *object_path,
|
|
||||||
const gchar *interface_name,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PinosSubscribePrivate *priv;
|
|
||||||
GList *walk;
|
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_SUBSCRIBE (subscribe));
|
|
||||||
priv = subscribe->priv;
|
|
||||||
|
|
||||||
for (walk = priv->objects; walk; walk = g_list_next (walk)) {
|
|
||||||
PinosObjectData *data = walk->data;
|
|
||||||
|
|
||||||
if (compare_data (data, name, object_path, interface_name) == 0) {
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
task = g_task_new (subscribe,
|
|
||||||
cancellable,
|
|
||||||
callback,
|
|
||||||
user_data);
|
|
||||||
|
|
||||||
if (data->pending) {
|
|
||||||
data->tasks = g_list_prepend (data->tasks, task);
|
|
||||||
} else {
|
|
||||||
if (data->proxy)
|
|
||||||
g_task_return_pointer (task, g_object_ref (data->proxy), g_object_unref);
|
|
||||||
else
|
|
||||||
g_task_return_error (task, NULL);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_subscribe_get_proxy_finish:
|
|
||||||
* @subscribe: a #PinosSubscribe
|
|
||||||
* @res: a #GAsyncResult
|
|
||||||
* @error: a #GError or %NULL
|
|
||||||
*
|
|
||||||
* Get the requested #GDBusProxy. This function should be called in the callback
|
|
||||||
* of pinos_subscribe_get_proxy() to get the result or error.
|
|
||||||
*
|
|
||||||
* Returns: the requested #GDBusProxy. If %NULL is returned, @error will
|
|
||||||
* be set.
|
|
||||||
*/
|
|
||||||
GDBusProxy *
|
|
||||||
pinos_subscribe_get_proxy_finish (PinosSubscribe *subscribe,
|
|
||||||
GAsyncResult *res,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
return g_task_propagate_pointer (G_TASK (res), error);
|
|
||||||
}
|
|
||||||
|
|
@ -20,22 +20,11 @@
|
||||||
#ifndef __PINOS_SUBSCRIBE_H__
|
#ifndef __PINOS_SUBSCRIBE_H__
|
||||||
#define __PINOS_SUBSCRIBE_H__
|
#define __PINOS_SUBSCRIBE_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
#define PINOS_TYPE_SUBSCRIBE (pinos_subscribe_get_type ())
|
#endif
|
||||||
#define PINOS_IS_SUBSCRIBE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_SUBSCRIBE))
|
|
||||||
#define PINOS_IS_SUBSCRIBE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_SUBSCRIBE))
|
|
||||||
#define PINOS_SUBSCRIBE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_SUBSCRIBE, PinosSubscribeClass))
|
|
||||||
#define PINOS_SUBSCRIBE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_SUBSCRIBE, PinosSubscribe))
|
|
||||||
#define PINOS_SUBSCRIBE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_SUBSCRIBE, PinosSubscribeClass))
|
|
||||||
#define PINOS_SUBSCRIBE_CAST(obj) ((PinosSubscribe*)(obj))
|
|
||||||
#define PINOS_SUBSCRIBE_CLASS_CAST(klass) ((PinosSubscribeClass*)(klass))
|
|
||||||
|
|
||||||
typedef struct _PinosSubscribe PinosSubscribe;
|
|
||||||
typedef struct _PinosSubscribeClass PinosSubscribeClass;
|
|
||||||
typedef struct _PinosSubscribePrivate PinosSubscribePrivate;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PINOS_SUBSCRIPTION_STATE_UNCONNECTED = 0,
|
PINOS_SUBSCRIPTION_STATE_UNCONNECTED = 0,
|
||||||
|
|
@ -59,34 +48,19 @@ typedef enum {
|
||||||
PINOS_SUBSCRIPTION_EVENT_REMOVE = 2,
|
PINOS_SUBSCRIPTION_EVENT_REMOVE = 2,
|
||||||
} PinosSubscriptionEvent;
|
} PinosSubscriptionEvent;
|
||||||
|
|
||||||
/**
|
typedef void (*PinosSubscriptionFunc) (PinosContext *context,
|
||||||
* PinosSubscribe:
|
PinosSubscriptionFlags flags,
|
||||||
*
|
PinosSubscriptionEvent event,
|
||||||
* Pinos subscribe object class.
|
uint32_t id,
|
||||||
*/
|
void *data);
|
||||||
struct _PinosSubscribe {
|
|
||||||
GObject object;
|
|
||||||
|
|
||||||
PinosSubscribePrivate *priv;
|
void pinos_context_subscribe (PinosContext *context,
|
||||||
};
|
PinosSubscriptionFlags mask,
|
||||||
|
PinosSubscriptionFunc func,
|
||||||
|
void *data);
|
||||||
|
|
||||||
/**
|
#ifdef __cplusplus
|
||||||
* PinosSubscribeClass:
|
}
|
||||||
*
|
#endif
|
||||||
* Pinos subscribe object class.
|
|
||||||
*/
|
|
||||||
struct _PinosSubscribeClass {
|
|
||||||
GObjectClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* normal GObject stuff */
|
|
||||||
GType pinos_subscribe_get_type (void);
|
|
||||||
|
|
||||||
PinosSubscribe * pinos_subscribe_new (void);
|
|
||||||
|
|
||||||
PinosSubscriptionState pinos_subscribe_get_state (PinosSubscribe *subscribe);
|
|
||||||
GError * pinos_subscribe_get_error (PinosSubscribe *subscribe);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __PINOS_SUBSCRIBE_H__ */
|
#endif /* __PINOS_SUBSCRIBE_H__ */
|
||||||
|
|
|
||||||
|
|
@ -17,185 +17,51 @@
|
||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#include "pinos.h"
|
#include "pinos.h"
|
||||||
#include "thread-mainloop.h"
|
#include "thread-mainloop.h"
|
||||||
|
|
||||||
struct _PinosThreadMainLoopPrivate
|
typedef struct {
|
||||||
{
|
PinosThreadMainLoop this;
|
||||||
GMainContext *maincontext;
|
|
||||||
GMainLoop *mainloop;
|
|
||||||
|
|
||||||
gchar *name;
|
char *name;
|
||||||
|
|
||||||
GPollFunc poll_func;
|
pthread_mutex_t lock;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
pthread_cond_t accept_cond;
|
||||||
|
|
||||||
GMutex lock;
|
bool running;
|
||||||
GCond cond;
|
pthread_t thread;
|
||||||
GCond accept_cond;
|
|
||||||
GThread *thread;
|
|
||||||
|
|
||||||
gint n_waiting;
|
SpaSource *event;
|
||||||
gint n_waiting_for_accept;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PINOS_THREAD_MAIN_LOOP_GET_PRIVATE(obj) \
|
int n_waiting;
|
||||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_THREAD_MAIN_LOOP, PinosThreadMainLoopPrivate))
|
int n_waiting_for_accept;
|
||||||
|
} PinosThreadMainLoopImpl;
|
||||||
G_DEFINE_TYPE (PinosThreadMainLoop, pinos_thread_main_loop, G_TYPE_OBJECT);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MAIN_CONTEXT,
|
|
||||||
PROP_NAME,
|
|
||||||
PROP_MAIN_LOOP,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pinos_thread_main_loop_get_property (GObject *_object,
|
pre_hook (SpaLoopControl *ctrl,
|
||||||
guint prop_id,
|
void *data)
|
||||||
GValue *value,
|
|
||||||
GParamSpec *pspec)
|
|
||||||
{
|
{
|
||||||
PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (_object);
|
PinosThreadMainLoopImpl *impl = data;
|
||||||
PinosThreadMainLoopPrivate *priv = loop->priv;
|
pthread_mutex_unlock (&impl->lock);
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MAIN_CONTEXT:
|
|
||||||
g_value_set_boxed (value, priv->maincontext);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_NAME:
|
|
||||||
g_value_set_string (value, priv->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_MAIN_LOOP:
|
|
||||||
g_value_set_boxed (value, priv->mainloop);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (loop, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pinos_thread_main_loop_set_property (GObject *_object,
|
post_hook (SpaLoopControl *ctrl,
|
||||||
guint prop_id,
|
void *data)
|
||||||
const GValue *value,
|
|
||||||
GParamSpec *pspec)
|
|
||||||
{
|
{
|
||||||
PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (_object);
|
PinosThreadMainLoopImpl *impl = data;
|
||||||
PinosThreadMainLoopPrivate *priv = loop->priv;
|
pthread_mutex_lock (&impl->lock);
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MAIN_CONTEXT:
|
|
||||||
priv->maincontext = g_value_dup_boxed (value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_NAME:
|
|
||||||
priv->name = g_value_dup_string (value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (loop, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pinos_thread_main_loop_constructed (GObject * object)
|
do_stop (SpaSource *source,
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (object);
|
PinosThreadMainLoopImpl *impl = data;
|
||||||
PinosThreadMainLoopPrivate *priv = loop->priv;
|
impl->running = false;
|
||||||
|
|
||||||
priv->mainloop = g_main_loop_new (priv->maincontext, FALSE);
|
|
||||||
pinos_log_debug ("thread-mainloop %p: contructed %p %p", loop, priv->maincontext, priv->mainloop);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (pinos_thread_main_loop_parent_class)->constructed (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_thread_main_loop_finalize (GObject * object)
|
|
||||||
{
|
|
||||||
PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (object);
|
|
||||||
PinosThreadMainLoopPrivate *priv = loop->priv;
|
|
||||||
|
|
||||||
if (priv->maincontext)
|
|
||||||
g_main_context_unref (priv->maincontext);
|
|
||||||
g_main_loop_unref (priv->mainloop);
|
|
||||||
|
|
||||||
g_free (priv->name);
|
|
||||||
g_mutex_clear (&priv->lock);
|
|
||||||
g_cond_clear (&priv->cond);
|
|
||||||
g_cond_clear (&priv->accept_cond);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (pinos_thread_main_loop_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_thread_main_loop_class_init (PinosThreadMainLoopClass * klass)
|
|
||||||
{
|
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
||||||
|
|
||||||
g_type_class_add_private (klass, sizeof (PinosThreadMainLoopPrivate));
|
|
||||||
|
|
||||||
gobject_class->constructed = pinos_thread_main_loop_constructed;
|
|
||||||
gobject_class->finalize = pinos_thread_main_loop_finalize;
|
|
||||||
gobject_class->set_property = pinos_thread_main_loop_set_property;
|
|
||||||
gobject_class->get_property = pinos_thread_main_loop_get_property;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PinosThreadMainLoop:main-context
|
|
||||||
*
|
|
||||||
* The GMainContext of the loop.
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_MAIN_CONTEXT,
|
|
||||||
g_param_spec_boxed ("main-context",
|
|
||||||
"Main Context",
|
|
||||||
"The GMainContext of the loop",
|
|
||||||
G_TYPE_MAIN_CONTEXT,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_CONSTRUCT_ONLY |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosThreadMainLoop:name
|
|
||||||
*
|
|
||||||
* The name of the loop as specified at construction time.
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_NAME,
|
|
||||||
g_param_spec_string ("name",
|
|
||||||
"Name",
|
|
||||||
"The name of the loop thread",
|
|
||||||
NULL,
|
|
||||||
G_PARAM_READWRITE |
|
|
||||||
G_PARAM_CONSTRUCT_ONLY |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
/**
|
|
||||||
* PinosThreadMainLoop:main-loop
|
|
||||||
*
|
|
||||||
* The GMainLoop of the loop.
|
|
||||||
*/
|
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_MAIN_LOOP,
|
|
||||||
g_param_spec_boxed ("main-loop",
|
|
||||||
"Main Loop",
|
|
||||||
"The GMainLoop",
|
|
||||||
G_TYPE_MAIN_LOOP,
|
|
||||||
G_PARAM_READABLE |
|
|
||||||
G_PARAM_STATIC_STRINGS));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pinos_thread_main_loop_init (PinosThreadMainLoop * loop)
|
|
||||||
{
|
|
||||||
PinosThreadMainLoopPrivate *priv = loop->priv = PINOS_THREAD_MAIN_LOOP_GET_PRIVATE (loop);
|
|
||||||
|
|
||||||
g_mutex_init (&priv->lock);
|
|
||||||
g_cond_init (&priv->cond);
|
|
||||||
g_cond_init (&priv->accept_cond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -209,101 +75,100 @@ pinos_thread_main_loop_init (PinosThreadMainLoop * loop)
|
||||||
* Returns: a #PinosThreadMainLoop
|
* Returns: a #PinosThreadMainLoop
|
||||||
*/
|
*/
|
||||||
PinosThreadMainLoop *
|
PinosThreadMainLoop *
|
||||||
pinos_thread_main_loop_new (GMainContext * context, const gchar *name)
|
pinos_thread_main_loop_new (PinosLoop *loop,
|
||||||
|
const char *name)
|
||||||
{
|
{
|
||||||
PinosThreadMainLoop *loop;
|
PinosThreadMainLoopImpl *impl;
|
||||||
|
PinosThreadMainLoop *this;
|
||||||
|
|
||||||
loop = g_object_new (PINOS_TYPE_THREAD_MAIN_LOOP,
|
impl = calloc (1, sizeof (PinosThreadMainLoopImpl));
|
||||||
"main-context", context,
|
this = &impl->this;
|
||||||
"name", name,
|
pinos_log_debug ("thread-mainloop %p: new", impl);
|
||||||
NULL);
|
|
||||||
return loop;
|
this->loop = loop;
|
||||||
|
if (name)
|
||||||
|
this->name = strdup (name);
|
||||||
|
|
||||||
|
pinos_loop_set_hooks (loop,
|
||||||
|
pre_hook,
|
||||||
|
post_hook,
|
||||||
|
impl);
|
||||||
|
|
||||||
|
pinos_signal_init (&this->destroy_signal);
|
||||||
|
|
||||||
|
pthread_mutex_init (&impl->lock, NULL);
|
||||||
|
pthread_cond_init (&impl->cond, NULL);
|
||||||
|
pthread_cond_init (&impl->accept_cond, NULL);
|
||||||
|
|
||||||
|
impl->event = pinos_loop_add_event (this->loop,
|
||||||
|
do_stop,
|
||||||
|
impl);
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void
|
||||||
* pinos_thread_main_loop_get_impl:
|
pinos_thread_main_loop_destroy (PinosThreadMainLoop *loop)
|
||||||
* @loop: a #PinosThreadMainLoop
|
|
||||||
*
|
|
||||||
* Get the #GMainLoop used by @loop.
|
|
||||||
*
|
|
||||||
* Returns: the #GMainLoop used by @loop. It remains valid as long as
|
|
||||||
* @loop is valid.
|
|
||||||
*/
|
|
||||||
GMainLoop *
|
|
||||||
pinos_thread_main_loop_get_impl (PinosThreadMainLoop *loop)
|
|
||||||
{
|
{
|
||||||
PinosThreadMainLoopPrivate *priv;
|
PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
|
||||||
|
|
||||||
g_return_val_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop), NULL);
|
pinos_signal_emit (&loop->destroy_signal, loop);
|
||||||
|
|
||||||
priv = loop->priv;
|
if (loop->name)
|
||||||
|
free (loop->name);
|
||||||
|
pthread_mutex_destroy (&impl->lock);
|
||||||
|
pthread_cond_destroy (&impl->cond);
|
||||||
|
pthread_cond_destroy (&impl->accept_cond);
|
||||||
|
|
||||||
return priv->mainloop;
|
free (impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GPrivate loop_key;
|
static void *
|
||||||
|
do_loop (void *user_data)
|
||||||
static gint
|
|
||||||
do_poll (GPollFD *ufds, guint nfsd, gint timeout_)
|
|
||||||
{
|
{
|
||||||
gint res;
|
PinosThreadMainLoopImpl *impl = user_data;
|
||||||
PinosThreadMainLoop *loop = g_private_get (&loop_key);
|
PinosThreadMainLoop *this = &impl->this;
|
||||||
PinosThreadMainLoopPrivate *priv = loop->priv;
|
SpaResult res;
|
||||||
|
|
||||||
g_mutex_unlock (&priv->lock);
|
pthread_mutex_lock (&impl->lock);
|
||||||
res = priv->poll_func (ufds, nfsd, timeout_);
|
pinos_log_debug ("thread-mainloop %p: enter thread", this);
|
||||||
g_mutex_lock (&priv->lock);
|
pinos_loop_enter (this->loop);
|
||||||
|
|
||||||
return res;
|
while (impl->running) {
|
||||||
}
|
if ((res = pinos_loop_iterate (this->loop, -1)) < 0)
|
||||||
|
pinos_log_warn ("thread-mainloop %p: iterate error %d", this, res);
|
||||||
static gpointer
|
}
|
||||||
handle_mainloop (PinosThreadMainLoop *loop)
|
pinos_log_debug ("thread-mainloop %p: leave thread", this);
|
||||||
{
|
pinos_loop_leave (this->loop);
|
||||||
PinosThreadMainLoopPrivate *priv = loop->priv;
|
pthread_mutex_unlock (&impl->lock);
|
||||||
|
|
||||||
g_mutex_lock (&priv->lock);
|
|
||||||
g_private_set (&loop_key, loop);
|
|
||||||
|
|
||||||
priv->poll_func = g_main_context_get_poll_func (priv->maincontext);
|
|
||||||
g_main_context_set_poll_func (priv->maincontext, do_poll);
|
|
||||||
|
|
||||||
g_main_context_push_thread_default (priv->maincontext);
|
|
||||||
pinos_log_debug ("thread-mainloop %p: run mainloop %p context %p", loop, priv->mainloop, priv->maincontext);
|
|
||||||
g_main_loop_run (priv->mainloop);
|
|
||||||
pinos_log_debug ("thread-mainloop %p: done", loop);
|
|
||||||
g_main_context_pop_thread_default (priv->maincontext);
|
|
||||||
|
|
||||||
g_main_context_set_poll_func (priv->maincontext, priv->poll_func);
|
|
||||||
|
|
||||||
g_mutex_unlock (&priv->lock);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pinos_thread_main_loop_start:
|
* pinos_thread_main_loop_start:
|
||||||
* @loop: a #PinosThreadMainLoop
|
* @loop: a #PinosThreadMainLoop
|
||||||
* @error: am optional #GError
|
|
||||||
*
|
*
|
||||||
* Start the thread to handle @loop.
|
* Start the thread to handle @loop.
|
||||||
*
|
*
|
||||||
* Returns: %TRUE on success. %FALSE will be returned when an error occured
|
* Returns: %SPA_RESULT_OK on success.
|
||||||
* and @error will contain more information.
|
|
||||||
*/
|
*/
|
||||||
gboolean
|
SpaResult
|
||||||
pinos_thread_main_loop_start (PinosThreadMainLoop *loop, GError **error)
|
pinos_thread_main_loop_start (PinosThreadMainLoop *loop)
|
||||||
{
|
{
|
||||||
PinosThreadMainLoopPrivate *priv;
|
PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
|
||||||
|
|
||||||
g_return_val_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop), FALSE);
|
if (!impl->running) {
|
||||||
priv = loop->priv;
|
int err;
|
||||||
g_return_val_if_fail (priv->thread == NULL, FALSE);
|
|
||||||
|
|
||||||
priv->thread = g_thread_try_new (priv->name, (GThreadFunc) handle_mainloop, loop, error);
|
impl->running = true;
|
||||||
|
if ((err = pthread_create (&impl->thread, NULL, do_loop, impl)) != 0) {
|
||||||
return priv->thread != NULL;
|
pinos_log_warn ("thread-mainloop %p: can't create thread: %s", impl, strerror (err));
|
||||||
|
impl->running = false;
|
||||||
|
return SPA_RESULT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SPA_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -315,20 +180,11 @@ pinos_thread_main_loop_start (PinosThreadMainLoop *loop, GError **error)
|
||||||
void
|
void
|
||||||
pinos_thread_main_loop_stop (PinosThreadMainLoop *loop)
|
pinos_thread_main_loop_stop (PinosThreadMainLoop *loop)
|
||||||
{
|
{
|
||||||
PinosThreadMainLoopPrivate *priv;
|
PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop));
|
pinos_loop_signal_event (loop->loop, impl->event);
|
||||||
priv = loop->priv;
|
|
||||||
|
|
||||||
g_return_if_fail (priv->thread != NULL);
|
pthread_join (impl->thread, NULL);
|
||||||
g_return_if_fail (!pinos_thread_main_loop_in_thread (loop));
|
|
||||||
|
|
||||||
g_mutex_lock (&priv->lock);
|
|
||||||
g_main_loop_quit (priv->mainloop);
|
|
||||||
g_mutex_unlock (&priv->lock);
|
|
||||||
|
|
||||||
g_thread_join (priv->thread);
|
|
||||||
priv->thread = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -340,13 +196,8 @@ pinos_thread_main_loop_stop (PinosThreadMainLoop *loop)
|
||||||
void
|
void
|
||||||
pinos_thread_main_loop_lock (PinosThreadMainLoop *loop)
|
pinos_thread_main_loop_lock (PinosThreadMainLoop *loop)
|
||||||
{
|
{
|
||||||
PinosThreadMainLoopPrivate *priv;
|
PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
|
||||||
|
pthread_mutex_lock (&impl->lock);
|
||||||
g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop));
|
|
||||||
priv = loop->priv;
|
|
||||||
g_return_if_fail (!pinos_thread_main_loop_in_thread (loop));
|
|
||||||
|
|
||||||
g_mutex_lock (&priv->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -358,13 +209,8 @@ pinos_thread_main_loop_lock (PinosThreadMainLoop *loop)
|
||||||
void
|
void
|
||||||
pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop)
|
pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop)
|
||||||
{
|
{
|
||||||
PinosThreadMainLoopPrivate *priv;
|
PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
|
||||||
|
pthread_mutex_unlock (&impl->lock);
|
||||||
g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop));
|
|
||||||
priv = loop->priv;
|
|
||||||
g_return_if_fail (!pinos_thread_main_loop_in_thread (loop));
|
|
||||||
|
|
||||||
g_mutex_unlock (&priv->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -375,21 +221,19 @@ pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop)
|
||||||
* this function waits until pinos_thread_main_loop_accept() is called.
|
* this function waits until pinos_thread_main_loop_accept() is called.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
pinos_thread_main_loop_signal (PinosThreadMainLoop *loop, gboolean wait_for_accept)
|
pinos_thread_main_loop_signal (PinosThreadMainLoop *loop,
|
||||||
|
bool wait_for_accept)
|
||||||
{
|
{
|
||||||
PinosThreadMainLoopPrivate *priv;
|
PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop));
|
if (impl->n_waiting > 0)
|
||||||
priv = loop->priv;
|
pthread_cond_broadcast (&impl->cond);
|
||||||
|
|
||||||
if (priv->n_waiting > 0)
|
|
||||||
g_cond_broadcast (&priv->cond);
|
|
||||||
|
|
||||||
if (wait_for_accept) {
|
if (wait_for_accept) {
|
||||||
priv->n_waiting_for_accept++;
|
impl->n_waiting_for_accept++;
|
||||||
|
|
||||||
while (priv->n_waiting_for_accept > 0)
|
while (impl->n_waiting_for_accept > 0)
|
||||||
g_cond_wait (&priv->accept_cond, &priv->lock);
|
pthread_cond_wait (&impl->accept_cond, &impl->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -402,18 +246,12 @@ pinos_thread_main_loop_signal (PinosThreadMainLoop *loop, gboolean wait_for_acce
|
||||||
void
|
void
|
||||||
pinos_thread_main_loop_wait (PinosThreadMainLoop *loop)
|
pinos_thread_main_loop_wait (PinosThreadMainLoop *loop)
|
||||||
{
|
{
|
||||||
PinosThreadMainLoopPrivate *priv;
|
PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop));
|
impl->n_waiting++;
|
||||||
priv = loop->priv;
|
|
||||||
g_return_if_fail (!pinos_thread_main_loop_in_thread (loop));
|
|
||||||
|
|
||||||
priv->n_waiting ++;
|
pthread_cond_wait (&impl->cond, &impl->lock);
|
||||||
|
impl->n_waiting --;
|
||||||
g_cond_wait (&priv->cond, &priv->lock);
|
|
||||||
|
|
||||||
g_assert (priv->n_waiting > 0);
|
|
||||||
priv->n_waiting --;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -425,16 +263,10 @@ pinos_thread_main_loop_wait (PinosThreadMainLoop *loop)
|
||||||
void
|
void
|
||||||
pinos_thread_main_loop_accept (PinosThreadMainLoop *loop)
|
pinos_thread_main_loop_accept (PinosThreadMainLoop *loop)
|
||||||
{
|
{
|
||||||
PinosThreadMainLoopPrivate *priv;
|
PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
|
||||||
|
|
||||||
g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop));
|
impl->n_waiting_for_accept--;
|
||||||
priv = loop->priv;
|
pthread_cond_signal (&impl->accept_cond);
|
||||||
g_return_if_fail (!pinos_thread_main_loop_in_thread (loop));
|
|
||||||
|
|
||||||
g_assert (priv->n_waiting_for_accept > 0);
|
|
||||||
priv->n_waiting_for_accept--;
|
|
||||||
|
|
||||||
g_cond_signal (&priv->accept_cond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -445,10 +277,9 @@ pinos_thread_main_loop_accept (PinosThreadMainLoop *loop)
|
||||||
*
|
*
|
||||||
* Returns: %TRUE when called inside the thread of @loop.
|
* Returns: %TRUE when called inside the thread of @loop.
|
||||||
*/
|
*/
|
||||||
gboolean
|
bool
|
||||||
pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop)
|
pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop), FALSE);
|
PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
|
||||||
|
return pthread_self() == impl->thread;
|
||||||
return g_thread_self() == loop->priv->thread;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,23 +20,13 @@
|
||||||
#ifndef __PINOS_THREAD_MAIN_LOOP_H__
|
#ifndef __PINOS_THREAD_MAIN_LOOP_H__
|
||||||
#define __PINOS_THREAD_MAIN_LOOP_H__
|
#define __PINOS_THREAD_MAIN_LOOP_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <pinos/client/loop.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
#define PINOS_TYPE_THREAD_MAIN_LOOP (pinos_thread_main_loop_get_type ())
|
#endif
|
||||||
#define PINOS_IS_THREAD_MAIN_LOOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_THREAD_MAIN_LOOP))
|
|
||||||
#define PINOS_IS_THREAD_MAIN_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_THREAD_MAIN_LOOP))
|
|
||||||
#define PINOS_THREAD_MAIN_LOOP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_THREAD_MAIN_LOOP, PinosThreadMainLoopClass))
|
|
||||||
#define PINOS_THREAD_MAIN_LOOP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_THREAD_MAIN_LOOP, PinosThreadMainLoop))
|
|
||||||
#define PINOS_THREAD_MAIN_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_THREAD_MAIN_LOOP, PinosThreadMainLoopClass))
|
|
||||||
#define PINOS_THREAD_MAIN_LOOP_CAST(obj) ((PinosThreadMainLoop*)(obj))
|
|
||||||
#define PINOS_THREAD_MAIN_LOOP_CLASS_CAST(klass) ((PinosThreadMainLoopClass*)(klass))
|
|
||||||
|
|
||||||
typedef struct _PinosThreadMainLoop PinosThreadMainLoop;
|
typedef struct _PinosThreadMainLoop PinosThreadMainLoop;
|
||||||
typedef struct _PinosThreadMainLoopClass PinosThreadMainLoopClass;
|
|
||||||
typedef struct _PinosThreadMainLoopPrivate PinosThreadMainLoopPrivate;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosThreadMainLoop:
|
* PinosThreadMainLoop:
|
||||||
|
|
@ -44,41 +34,32 @@ typedef struct _PinosThreadMainLoopPrivate PinosThreadMainLoopPrivate;
|
||||||
* Pinos main loop object class.
|
* Pinos main loop object class.
|
||||||
*/
|
*/
|
||||||
struct _PinosThreadMainLoop {
|
struct _PinosThreadMainLoop {
|
||||||
GObject object;
|
PinosLoop *loop;
|
||||||
|
char *name;
|
||||||
|
|
||||||
PinosThreadMainLoopPrivate *priv;
|
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
||||||
|
PinosThreadMainLoop *loop));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
PinosThreadMainLoop * pinos_thread_main_loop_new (PinosLoop *loop,
|
||||||
* PinosThreadMainLoopClass:
|
const char *name);
|
||||||
*
|
void pinos_thread_main_loop_destroy (PinosThreadMainLoop *loop);
|
||||||
* Pinos main loop object class.
|
|
||||||
*/
|
|
||||||
struct _PinosThreadMainLoopClass {
|
|
||||||
GObjectClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* normal GObject stuff */
|
SpaResult pinos_thread_main_loop_start (PinosThreadMainLoop *loop);
|
||||||
GType pinos_thread_main_loop_get_type (void);
|
|
||||||
|
|
||||||
PinosThreadMainLoop * pinos_thread_main_loop_new (GMainContext * context,
|
|
||||||
const gchar *name);
|
|
||||||
|
|
||||||
GMainLoop * pinos_thread_main_loop_get_impl (PinosThreadMainLoop *loop);
|
|
||||||
|
|
||||||
gboolean pinos_thread_main_loop_start (PinosThreadMainLoop *loop, GError **error);
|
|
||||||
void pinos_thread_main_loop_stop (PinosThreadMainLoop *loop);
|
void pinos_thread_main_loop_stop (PinosThreadMainLoop *loop);
|
||||||
|
|
||||||
void pinos_thread_main_loop_lock (PinosThreadMainLoop *loop);
|
void pinos_thread_main_loop_lock (PinosThreadMainLoop *loop);
|
||||||
void pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop);
|
void pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop);
|
||||||
|
|
||||||
void pinos_thread_main_loop_wait (PinosThreadMainLoop *loop);
|
void pinos_thread_main_loop_wait (PinosThreadMainLoop *loop);
|
||||||
void pinos_thread_main_loop_signal (PinosThreadMainLoop *loop, gboolean wait_for_accept);
|
void pinos_thread_main_loop_signal (PinosThreadMainLoop *loop,
|
||||||
|
bool wait_for_accept);
|
||||||
void pinos_thread_main_loop_accept (PinosThreadMainLoop *loop);
|
void pinos_thread_main_loop_accept (PinosThreadMainLoop *loop);
|
||||||
|
|
||||||
gboolean pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop);
|
bool pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
G_END_DECLS
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __PINOS_THREAD_MAIN_LOOP_H__ */
|
#endif /* __PINOS_THREAD_MAIN_LOOP_H__ */
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include <pinos/client/log.h>
|
||||||
#include <pinos/client/transport.h>
|
#include <pinos/client/transport.h>
|
||||||
|
|
||||||
#define INPUT_BUFFER_SIZE (1<<12)
|
#define INPUT_BUFFER_SIZE (1<<12)
|
||||||
|
|
@ -131,6 +132,11 @@ pinos_transport_new_from_info (PinosTransportInfo *info)
|
||||||
impl->mem.fd = info->memfd;
|
impl->mem.fd = info->memfd;
|
||||||
impl->mem.size = info->size;
|
impl->mem.size = info->size;
|
||||||
impl->mem.ptr = mmap (NULL, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, info->memfd, info->offset);
|
impl->mem.ptr = mmap (NULL, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, info->memfd, info->offset);
|
||||||
|
if (impl->mem.ptr == MAP_FAILED) {
|
||||||
|
pinos_log_warn ("transport %p: failed to map fd %d", impl, info->memfd);
|
||||||
|
goto mmap_failed;
|
||||||
|
}
|
||||||
|
|
||||||
impl->offset = info->offset;
|
impl->offset = info->offset;
|
||||||
|
|
||||||
transport_setup_area (impl->mem.ptr, trans);
|
transport_setup_area (impl->mem.ptr, trans);
|
||||||
|
|
@ -144,6 +150,10 @@ pinos_transport_new_from_info (PinosTransportInfo *info)
|
||||||
trans->input_data = tmp;
|
trans->input_data = tmp;
|
||||||
|
|
||||||
return trans;
|
return trans;
|
||||||
|
|
||||||
|
mmap_failed:
|
||||||
|
free (impl);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
#include "pinos/daemon/daemon-config.h"
|
#include "pinos/daemon/daemon-config.h"
|
||||||
|
|
||||||
#define DEFAULT_CONFIG_FILE PINOS_CONFIG_DIR G_DIR_SEPARATOR_S "pinos.conf"
|
#define DEFAULT_CONFIG_FILE PINOS_CONFIG_DIR "/pinos.conf"
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_line (PinosDaemonConfig *config,
|
parse_line (PinosDaemonConfig *config,
|
||||||
|
|
@ -165,7 +165,7 @@ bool
|
||||||
pinos_daemon_config_load (PinosDaemonConfig *config,
|
pinos_daemon_config_load (PinosDaemonConfig *config,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
const gchar *filename;
|
const char *filename;
|
||||||
|
|
||||||
filename = getenv ("PINOS_CONFIG_FILE");
|
filename = getenv ("PINOS_CONFIG_FILE");
|
||||||
if (filename != NULL && *filename != '\0') {
|
if (filename != NULL && *filename != '\0') {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ main (int argc, char *argv[])
|
||||||
/* parse configuration */
|
/* parse configuration */
|
||||||
config = pinos_daemon_config_new ();
|
config = pinos_daemon_config_new ();
|
||||||
if (!pinos_daemon_config_load (config, &err)) {
|
if (!pinos_daemon_config_load (config, &err)) {
|
||||||
g_error ("failed to parse config: %s", err);
|
pinos_log_error ("failed to parse config: %s", err);
|
||||||
free (err);
|
free (err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
load-module libpinos-module-protocol-dbus
|
#load-module libpinos-module-protocol-dbus
|
||||||
load-module libpinos-module-protocol-native
|
load-module libpinos-module-protocol-native
|
||||||
load-module libpinos-module-suspend-on-idle
|
load-module libpinos-module-suspend-on-idle
|
||||||
load-module libpinos-module-spa
|
load-module libpinos-module-spa
|
||||||
|
|
|
||||||
|
|
@ -39,19 +39,18 @@ G_DEFINE_TYPE (GstPinosDevice, gst_pinos_device, GST_TYPE_DEVICE);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_PATH = 1,
|
PROP_ID = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static GstDevice *
|
static GstDevice *
|
||||||
gst_pinos_device_new (gpointer id, const gchar * device_name,
|
gst_pinos_device_new (uint32_t id, const gchar * device_name,
|
||||||
GstCaps * caps, const gchar * path, const gchar *klass,
|
GstCaps * caps, const gchar *klass,
|
||||||
GstPinosDeviceType type, GstStructure *props)
|
GstPinosDeviceType type, GstStructure *props)
|
||||||
{
|
{
|
||||||
GstPinosDevice *gstdev;
|
GstPinosDevice *gstdev;
|
||||||
const gchar *element = NULL;
|
const gchar *element = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (device_name, NULL);
|
g_return_val_if_fail (device_name, NULL);
|
||||||
g_return_val_if_fail (path, NULL);
|
|
||||||
g_return_val_if_fail (caps, NULL);
|
g_return_val_if_fail (caps, NULL);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
@ -68,7 +67,7 @@ gst_pinos_device_new (gpointer id, const gchar * device_name,
|
||||||
|
|
||||||
gstdev = g_object_new (GST_TYPE_PINOS_DEVICE,
|
gstdev = g_object_new (GST_TYPE_PINOS_DEVICE,
|
||||||
"display-name", device_name, "caps", caps, "device-class", klass,
|
"display-name", device_name, "caps", caps, "device-class", klass,
|
||||||
"path", path, "properties", props, NULL);
|
"id", id, "properties", props, NULL);
|
||||||
|
|
||||||
gstdev->id = id;
|
gstdev->id = id;
|
||||||
gstdev->type = type;
|
gstdev->type = type;
|
||||||
|
|
@ -84,7 +83,7 @@ gst_pinos_device_create_element (GstDevice * device, const gchar * name)
|
||||||
GstElement *elem;
|
GstElement *elem;
|
||||||
|
|
||||||
elem = gst_element_factory_make (pinos_dev->element, name);
|
elem = gst_element_factory_make (pinos_dev->element, name);
|
||||||
g_object_set (elem, "path", pinos_dev->path, NULL);
|
g_object_set (elem, "path", pinos_dev->id, NULL);
|
||||||
|
|
||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +103,7 @@ gst_pinos_device_reconfigure_element (GstDevice * device, GstElement * element)
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_set (element, "path", pinos_dev->path, NULL);
|
g_object_set (element, "path", pinos_dev->id, NULL);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -119,8 +118,8 @@ gst_pinos_device_get_property (GObject * object, guint prop_id,
|
||||||
device = GST_PINOS_DEVICE_CAST (object);
|
device = GST_PINOS_DEVICE_CAST (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_PATH:
|
case PROP_ID:
|
||||||
g_value_set_string (value, device->path);
|
g_value_set_uint (value, device->id);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
|
@ -137,8 +136,8 @@ gst_pinos_device_set_property (GObject * object, guint prop_id,
|
||||||
device = GST_PINOS_DEVICE_CAST (object);
|
device = GST_PINOS_DEVICE_CAST (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_PATH:
|
case PROP_ID:
|
||||||
device->path = g_value_dup_string (value);
|
device->id = g_value_get_uint (value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
|
@ -149,10 +148,6 @@ gst_pinos_device_set_property (GObject * object, guint prop_id,
|
||||||
static void
|
static void
|
||||||
gst_pinos_device_finalize (GObject * object)
|
gst_pinos_device_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstPinosDevice *device = GST_PINOS_DEVICE (object);
|
|
||||||
|
|
||||||
g_free (device->path);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (gst_pinos_device_parent_class)->finalize (object);
|
G_OBJECT_CLASS (gst_pinos_device_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,9 +164,9 @@ gst_pinos_device_class_init (GstPinosDeviceClass * klass)
|
||||||
object_class->set_property = gst_pinos_device_set_property;
|
object_class->set_property = gst_pinos_device_set_property;
|
||||||
object_class->finalize = gst_pinos_device_finalize;
|
object_class->finalize = gst_pinos_device_finalize;
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_PATH,
|
g_object_class_install_property (object_class, PROP_ID,
|
||||||
g_param_spec_string ("path", "Path",
|
g_param_spec_uint ("id", "Id",
|
||||||
"The internal path of the Pinos device", "",
|
"The internal id of the Pinos device", 0, G_MAXUINT32, SPA_ID_INVALID,
|
||||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,7 +220,6 @@ new_node (const PinosNodeInfo *info)
|
||||||
return gst_pinos_device_new (info->id,
|
return gst_pinos_device_new (info->id,
|
||||||
info->name,
|
info->name,
|
||||||
caps,
|
caps,
|
||||||
info->node_path,
|
|
||||||
klass,
|
klass,
|
||||||
GST_PINOS_DEVICE_TYPE_SOURCE,
|
GST_PINOS_DEVICE_TYPE_SOURCE,
|
||||||
props);
|
props);
|
||||||
|
|
@ -233,19 +227,22 @@ new_node (const PinosNodeInfo *info)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_node_info_cb (PinosContext *context,
|
get_node_info_cb (PinosContext *context,
|
||||||
|
SpaResult res,
|
||||||
const PinosNodeInfo *info,
|
const PinosNodeInfo *info,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GstPinosDeviceProvider *self = user_data;
|
GstPinosDeviceProvider *self = user_data;
|
||||||
GstDevice *dev;
|
|
||||||
|
|
||||||
dev = new_node (info);
|
if (info) {
|
||||||
if (dev)
|
GstDevice *dev;
|
||||||
gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev);
|
dev = new_node (info);
|
||||||
|
if (dev)
|
||||||
|
gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstPinosDevice *
|
static GstPinosDevice *
|
||||||
find_device (GstDeviceProvider *provider, gpointer id)
|
find_device (GstDeviceProvider *provider, uint32_t id)
|
||||||
{
|
{
|
||||||
GList *item;
|
GList *item;
|
||||||
GstPinosDevice *dev = NULL;
|
GstPinosDevice *dev = NULL;
|
||||||
|
|
@ -266,10 +263,10 @@ find_device (GstDeviceProvider *provider, gpointer id)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
context_subscribe_cb (PinosContext *context,
|
context_subscribe_cb (PinosContext *context,
|
||||||
PinosSubscriptionEvent type,
|
|
||||||
PinosSubscriptionFlags flags,
|
PinosSubscriptionFlags flags,
|
||||||
gpointer id,
|
PinosSubscriptionEvent type,
|
||||||
gpointer user_data)
|
uint32_t id,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
GstPinosDeviceProvider *self = user_data;
|
GstPinosDeviceProvider *self = user_data;
|
||||||
GstDeviceProvider *provider = user_data;
|
GstDeviceProvider *provider = user_data;
|
||||||
|
|
@ -284,10 +281,7 @@ context_subscribe_cb (PinosContext *context,
|
||||||
if (flags == PINOS_SUBSCRIPTION_FLAG_NODE && dev == NULL)
|
if (flags == PINOS_SUBSCRIPTION_FLAG_NODE && dev == NULL)
|
||||||
pinos_context_get_node_info_by_id (context,
|
pinos_context_get_node_info_by_id (context,
|
||||||
id,
|
id,
|
||||||
PINOS_NODE_INFO_FLAGS_NONE,
|
|
||||||
get_node_info_cb,
|
get_node_info_cb,
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
self);
|
self);
|
||||||
} else if (type == PINOS_SUBSCRIPTION_EVENT_REMOVE) {
|
} else if (type == PINOS_SUBSCRIPTION_EVENT_REMOVE) {
|
||||||
if (flags == PINOS_SUBSCRIPTION_FLAG_NODE && dev != NULL) {
|
if (flags == PINOS_SUBSCRIPTION_FLAG_NODE && dev != NULL) {
|
||||||
|
|
@ -306,31 +300,23 @@ typedef struct {
|
||||||
|
|
||||||
static void
|
static void
|
||||||
list_node_info_cb (PinosContext *c,
|
list_node_info_cb (PinosContext *c,
|
||||||
|
SpaResult res,
|
||||||
const PinosNodeInfo *info,
|
const PinosNodeInfo *info,
|
||||||
gpointer user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
InfoData *data = user_data;
|
InfoData *data = user_data;
|
||||||
|
if (info) {
|
||||||
*data->devices = g_list_prepend (*data->devices, gst_object_ref_sink (new_node (info)));
|
*data->devices = g_list_prepend (*data->devices, gst_object_ref_sink (new_node (info)));
|
||||||
}
|
} else {
|
||||||
|
data->end = TRUE;
|
||||||
static void
|
|
||||||
list_node_info_end_cb (GObject *source_object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
InfoData *data = user_data;
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
if (!pinos_context_info_finish (source_object, res, &error)) {
|
|
||||||
GST_WARNING_OBJECT (source_object, "failed to list nodes: %s", error->message);
|
|
||||||
g_clear_error (&error);
|
|
||||||
}
|
}
|
||||||
data->end = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_daemon_info_cb (PinosContext *c, const PinosDaemonInfo *info, gpointer user_data)
|
get_daemon_info_cb (PinosContext *c,
|
||||||
|
SpaResult res,
|
||||||
|
const PinosDaemonInfo *info,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
GstDeviceProvider *provider = user_data;
|
GstDeviceProvider *provider = user_data;
|
||||||
const gchar *value;
|
const gchar *value;
|
||||||
|
|
@ -353,30 +339,27 @@ static GList *
|
||||||
gst_pinos_device_provider_probe (GstDeviceProvider * provider)
|
gst_pinos_device_provider_probe (GstDeviceProvider * provider)
|
||||||
{
|
{
|
||||||
GstPinosDeviceProvider *self = GST_PINOS_DEVICE_PROVIDER (provider);
|
GstPinosDeviceProvider *self = GST_PINOS_DEVICE_PROVIDER (provider);
|
||||||
GMainContext *m = NULL;
|
PinosLoop *l = NULL;
|
||||||
PinosContext *c = NULL;
|
PinosContext *c = NULL;
|
||||||
InfoData data;
|
InfoData data;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "starting probe");
|
GST_DEBUG_OBJECT (self, "starting probe");
|
||||||
|
|
||||||
if (!(m = g_main_context_new ()))
|
if (!(l = pinos_loop_new ()))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!(c = pinos_context_new (m, self->client_name, NULL)))
|
if (!(c = pinos_context_new (l, self->client_name, NULL)))
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
g_main_context_push_thread_default (m);
|
pinos_context_connect (c);
|
||||||
|
|
||||||
pinos_context_connect (c, PINOS_CONTEXT_FLAGS_NONE);
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
PinosContextState state;
|
PinosContextState state;
|
||||||
|
|
||||||
state = pinos_context_get_state (c);
|
state = c->state;
|
||||||
|
|
||||||
if (state <= 0) {
|
if (state <= 0) {
|
||||||
GST_ERROR_OBJECT (self, "Failed to connect: %s",
|
GST_ERROR_OBJECT (self, "Failed to connect: %s", c->error);
|
||||||
pinos_context_get_error (c)->message);
|
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -384,59 +367,47 @@ gst_pinos_device_provider_probe (GstDeviceProvider * provider)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Wait until something happens */
|
/* Wait until something happens */
|
||||||
g_main_context_iteration (m, TRUE);
|
pinos_loop_iterate (l, -1);
|
||||||
}
|
}
|
||||||
GST_DEBUG_OBJECT (self, "connected");
|
GST_DEBUG_OBJECT (self, "connected");
|
||||||
|
|
||||||
pinos_context_get_daemon_info (c,
|
pinos_context_get_daemon_info (c,
|
||||||
PINOS_DAEMON_INFO_FLAGS_NONE,
|
|
||||||
get_daemon_info_cb,
|
get_daemon_info_cb,
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
self);
|
self);
|
||||||
|
|
||||||
|
|
||||||
data.end = FALSE;
|
data.end = FALSE;
|
||||||
data.devices = NULL;
|
data.devices = NULL;
|
||||||
pinos_context_list_node_info (c,
|
pinos_context_list_node_info (c,
|
||||||
PINOS_NODE_INFO_FLAGS_NONE,
|
|
||||||
list_node_info_cb,
|
list_node_info_cb,
|
||||||
NULL,
|
|
||||||
list_node_info_end_cb,
|
|
||||||
&data);
|
&data);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (pinos_context_get_state (c) <= 0)
|
if (c->state <= 0)
|
||||||
break;
|
break;
|
||||||
if (data.end)
|
if (data.end)
|
||||||
break;
|
break;
|
||||||
g_main_context_iteration (m, TRUE);
|
pinos_loop_iterate (l, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pinos_context_disconnect (c);
|
pinos_context_disconnect (c);
|
||||||
g_clear_object (&c);
|
pinos_context_destroy (c);
|
||||||
|
pinos_loop_destroy (l);
|
||||||
g_main_context_pop_thread_default (m);
|
|
||||||
g_main_context_unref (m);
|
|
||||||
|
|
||||||
return *data.devices;
|
return *data.devices;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
g_main_context_pop_thread_default (m);
|
pinos_loop_destroy (l);
|
||||||
g_main_context_unref (m);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
context_state_notify (GObject *gobject,
|
on_context_state_changed (PinosListener *listener,
|
||||||
GParamSpec *pspec,
|
PinosContext *context)
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
GstPinosDeviceProvider *self = user_data;
|
GstPinosDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPinosDeviceProvider, ctx_state_changed);
|
||||||
PinosContext *context = PINOS_CONTEXT (gobject);
|
|
||||||
PinosContextState state;
|
PinosContextState state;
|
||||||
|
|
||||||
state= pinos_context_get_state (context);
|
state= context->state;
|
||||||
|
|
||||||
GST_DEBUG ("got context state %d", state);
|
GST_DEBUG ("got context state %d", state);
|
||||||
|
|
||||||
|
|
@ -447,67 +418,53 @@ context_state_notify (GObject *gobject,
|
||||||
case PINOS_CONTEXT_STATE_CONNECTED:
|
case PINOS_CONTEXT_STATE_CONNECTED:
|
||||||
break;
|
break;
|
||||||
case PINOS_CONTEXT_STATE_ERROR:
|
case PINOS_CONTEXT_STATE_ERROR:
|
||||||
GST_ERROR_OBJECT (self, "context error: %s",
|
GST_ERROR_OBJECT (self, "context error: %s", context->error);
|
||||||
pinos_context_get_error (context)->message);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_signal (self->loop, FALSE);
|
pinos_thread_main_loop_signal (self->main_loop, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_pinos_device_provider_start (GstDeviceProvider * provider)
|
gst_pinos_device_provider_start (GstDeviceProvider * provider)
|
||||||
{
|
{
|
||||||
GstPinosDeviceProvider *self = GST_PINOS_DEVICE_PROVIDER (provider);
|
GstPinosDeviceProvider *self = GST_PINOS_DEVICE_PROVIDER (provider);
|
||||||
GError *error = NULL;
|
|
||||||
GMainContext *c;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "starting provider");
|
GST_DEBUG_OBJECT (self, "starting provider");
|
||||||
|
|
||||||
c = g_main_context_new ();
|
self->loop = pinos_loop_new ();
|
||||||
|
|
||||||
if (!(self->loop = pinos_thread_main_loop_new (c, "pinos-device-monitor"))) {
|
if (!(self->main_loop = pinos_thread_main_loop_new (self->loop, "pinos-device-monitor"))) {
|
||||||
GST_ERROR_OBJECT (self, "Could not create pinos mainloop");
|
GST_ERROR_OBJECT (self, "Could not create pinos mainloop");
|
||||||
goto failed;
|
goto failed_main_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pinos_thread_main_loop_start (self->loop, &error)) {
|
if (pinos_thread_main_loop_start (self->main_loop) != SPA_RESULT_OK) {
|
||||||
GST_ERROR_OBJECT (self, "Could not start pinos mainloop: %s", error->message);
|
GST_ERROR_OBJECT (self, "Could not start pinos mainloop");
|
||||||
g_clear_object (&self->loop);
|
goto failed_start;
|
||||||
goto failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (self->loop);
|
pinos_thread_main_loop_lock (self->main_loop);
|
||||||
|
|
||||||
if (!(self->context = pinos_context_new (c, self->client_name, NULL))) {
|
if (!(self->context = pinos_context_new (self->loop, self->client_name, NULL))) {
|
||||||
GST_ERROR_OBJECT (self, "Failed to create context");
|
GST_ERROR_OBJECT (self, "Failed to create context");
|
||||||
pinos_thread_main_loop_unlock (self->loop);
|
goto failed_context;
|
||||||
pinos_thread_main_loop_stop (self->loop);
|
|
||||||
g_clear_object (&self->loop);
|
|
||||||
goto failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_signal_connect (self->context,
|
pinos_signal_add (&self->context->state_changed, &self->ctx_state_changed, on_context_state_changed);
|
||||||
"notify::state",
|
|
||||||
(GCallback) context_state_notify,
|
|
||||||
self);
|
|
||||||
|
|
||||||
g_object_set (self->context,
|
pinos_context_subscribe (self->context,
|
||||||
"subscription-mask", PINOS_SUBSCRIPTION_FLAGS_ALL,
|
PINOS_SUBSCRIPTION_FLAGS_ALL,
|
||||||
NULL);
|
context_subscribe_cb,
|
||||||
g_signal_connect (self->context,
|
self);
|
||||||
"subscription-event",
|
|
||||||
(GCallback) context_subscribe_cb,
|
|
||||||
self);
|
|
||||||
|
|
||||||
pinos_context_connect (self->context, PINOS_CONTEXT_FLAGS_NONE);
|
pinos_context_connect (self->context);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
PinosContextState state;
|
PinosContextState state;
|
||||||
|
|
||||||
state = pinos_context_get_state (self->context);
|
state = self->context->state;
|
||||||
|
|
||||||
if (state <= 0) {
|
if (state <= 0) {
|
||||||
GST_WARNING_OBJECT (self, "Failed to connect: %s",
|
GST_WARNING_OBJECT (self, "Failed to connect: %s", self->context->error);
|
||||||
pinos_context_get_error (self->context)->message);
|
|
||||||
goto not_running;
|
goto not_running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -515,34 +472,28 @@ gst_pinos_device_provider_start (GstDeviceProvider * provider)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Wait until something happens */
|
/* Wait until something happens */
|
||||||
pinos_thread_main_loop_wait (self->loop);
|
pinos_thread_main_loop_wait (self->main_loop);
|
||||||
}
|
}
|
||||||
GST_DEBUG_OBJECT (self, "connected");
|
GST_DEBUG_OBJECT (self, "connected");
|
||||||
pinos_context_get_daemon_info (self->context,
|
pinos_context_get_daemon_info (self->context,
|
||||||
PINOS_DAEMON_INFO_FLAGS_NONE,
|
|
||||||
get_daemon_info_cb,
|
get_daemon_info_cb,
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
self);
|
self);
|
||||||
pinos_thread_main_loop_unlock (self->loop);
|
pinos_thread_main_loop_unlock (self->main_loop);
|
||||||
|
|
||||||
g_main_context_unref (c);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
failed:
|
|
||||||
{
|
|
||||||
g_main_context_unref (c);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
not_running:
|
not_running:
|
||||||
{
|
pinos_context_destroy (self->context);
|
||||||
pinos_thread_main_loop_unlock (self->loop);
|
self->context = NULL;
|
||||||
pinos_thread_main_loop_stop (self->loop);
|
failed_context:
|
||||||
g_clear_object (&self->context);
|
pinos_thread_main_loop_unlock (self->main_loop);
|
||||||
g_clear_object (&self->loop);
|
failed_start:
|
||||||
return TRUE;
|
pinos_thread_main_loop_destroy (self->main_loop);
|
||||||
}
|
self->main_loop = NULL;
|
||||||
|
failed_main_loop:
|
||||||
|
pinos_loop_destroy (self->loop);
|
||||||
|
self->loop = NULL;
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -552,12 +503,17 @@ gst_pinos_device_provider_stop (GstDeviceProvider * provider)
|
||||||
|
|
||||||
if (self->context) {
|
if (self->context) {
|
||||||
pinos_context_disconnect (self->context);
|
pinos_context_disconnect (self->context);
|
||||||
|
pinos_context_destroy (self->context);
|
||||||
|
self->context = NULL;
|
||||||
|
}
|
||||||
|
if (self->main_loop) {
|
||||||
|
pinos_thread_main_loop_destroy (self->main_loop);
|
||||||
|
self->main_loop = NULL;
|
||||||
}
|
}
|
||||||
if (self->loop) {
|
if (self->loop) {
|
||||||
pinos_thread_main_loop_stop (self->loop);
|
pinos_loop_destroy (self->loop);
|
||||||
|
self->loop = NULL;
|
||||||
}
|
}
|
||||||
g_clear_object (&self->context);
|
|
||||||
g_clear_object (&self->loop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,7 @@ struct _GstPinosDevice {
|
||||||
GstDevice parent;
|
GstDevice parent;
|
||||||
|
|
||||||
GstPinosDeviceType type;
|
GstPinosDeviceType type;
|
||||||
gpointer id;
|
uint32_t id;
|
||||||
gchar *path;
|
|
||||||
const gchar *element;
|
const gchar *element;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -81,10 +80,11 @@ struct _GstPinosDeviceProvider {
|
||||||
|
|
||||||
gchar *client_name;
|
gchar *client_name;
|
||||||
|
|
||||||
GMainContext *maincontext;
|
PinosLoop *loop;
|
||||||
PinosThreadMainLoop *loop;
|
PinosThreadMainLoop *main_loop;
|
||||||
|
|
||||||
PinosContext *context;
|
PinosContext *context;
|
||||||
|
PinosListener ctx_state_changed;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstPinosDeviceProviderClass {
|
struct _GstPinosDeviceProviderClass {
|
||||||
|
|
|
||||||
|
|
@ -348,11 +348,11 @@ process_mem_data_destroy (gpointer user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_add_buffer (GObject *gobject,
|
on_add_buffer (PinosListener *listener,
|
||||||
guint id,
|
PinosStream *stream,
|
||||||
gpointer user_data)
|
uint32_t id)
|
||||||
{
|
{
|
||||||
GstPinosSink *pinossink = user_data;
|
GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_add_buffer);
|
||||||
SpaBuffer *b;
|
SpaBuffer *b;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
@ -415,15 +415,15 @@ on_add_buffer (GObject *gobject,
|
||||||
gst_pinos_pool_add_buffer (pinossink->pool, buf);
|
gst_pinos_pool_add_buffer (pinossink->pool, buf);
|
||||||
g_hash_table_insert (pinossink->buf_ids, GINT_TO_POINTER (id), buf);
|
g_hash_table_insert (pinossink->buf_ids, GINT_TO_POINTER (id), buf);
|
||||||
|
|
||||||
pinos_thread_main_loop_signal (pinossink->loop, FALSE);
|
pinos_thread_main_loop_signal (pinossink->main_loop, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_remove_buffer (GObject *gobject,
|
on_remove_buffer (PinosListener *listener,
|
||||||
guint id,
|
PinosStream *stream,
|
||||||
gpointer user_data)
|
uint32_t id)
|
||||||
{
|
{
|
||||||
GstPinosSink *pinossink = user_data;
|
GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_remove_buffer);
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
|
|
||||||
GST_LOG_OBJECT (pinossink, "remove buffer");
|
GST_LOG_OBJECT (pinossink, "remove buffer");
|
||||||
|
|
@ -435,11 +435,11 @@ on_remove_buffer (GObject *gobject,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_new_buffer (GObject *gobject,
|
on_new_buffer (PinosListener *listener,
|
||||||
guint id,
|
PinosStream *stream,
|
||||||
gpointer user_data)
|
uint32_t id)
|
||||||
{
|
{
|
||||||
GstPinosSink *pinossink = user_data;
|
GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_new_buffer);
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
|
|
||||||
GST_LOG_OBJECT (pinossink, "got new buffer");
|
GST_LOG_OBJECT (pinossink, "got new buffer");
|
||||||
|
|
@ -451,20 +451,18 @@ on_new_buffer (GObject *gobject,
|
||||||
|
|
||||||
if (buf) {
|
if (buf) {
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
pinos_thread_main_loop_signal (pinossink->loop, FALSE);
|
pinos_thread_main_loop_signal (pinossink->main_loop, FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_stream_notify (GObject *gobject,
|
on_state_changed (PinosListener *listener,
|
||||||
GParamSpec *pspec,
|
PinosStream *stream)
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
|
GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_state_changed);
|
||||||
PinosStreamState state;
|
PinosStreamState state;
|
||||||
PinosStream *stream = PINOS_STREAM (gobject);
|
|
||||||
GstPinosSink *pinossink = user_data;
|
|
||||||
|
|
||||||
state = pinos_stream_get_state (stream);
|
state = stream->state;
|
||||||
GST_DEBUG ("got stream state %d", state);
|
GST_DEBUG ("got stream state %d", state);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
|
@ -477,20 +475,19 @@ on_stream_notify (GObject *gobject,
|
||||||
break;
|
break;
|
||||||
case PINOS_STREAM_STATE_ERROR:
|
case PINOS_STREAM_STATE_ERROR:
|
||||||
GST_ELEMENT_ERROR (pinossink, RESOURCE, FAILED,
|
GST_ELEMENT_ERROR (pinossink, RESOURCE, FAILED,
|
||||||
("stream error: %s",
|
("stream error: %s", stream->error), (NULL));
|
||||||
pinos_stream_get_error (stream)->message), (NULL));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_signal (pinossink->loop, FALSE);
|
pinos_thread_main_loop_signal (pinossink->main_loop, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_format_notify (GObject *gobject,
|
on_format_changed (PinosListener *listener,
|
||||||
GParamSpec *pspec,
|
PinosStream *stream,
|
||||||
gpointer user_data)
|
SpaFormat *format)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
GstPinosSink *pinossink = user_data;
|
GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_format_changed);
|
||||||
GstStructure *config;
|
GstStructure *config;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
guint size;
|
guint size;
|
||||||
|
|
@ -532,8 +529,8 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
|
|
||||||
possible = gst_caps_to_format_all (caps);
|
possible = gst_caps_to_format_all (caps);
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossink->loop);
|
pinos_thread_main_loop_lock (pinossink->main_loop);
|
||||||
state = pinos_stream_get_state (pinossink->stream);
|
state = pinossink->stream->state;
|
||||||
|
|
||||||
if (state == PINOS_STREAM_STATE_ERROR)
|
if (state == PINOS_STREAM_STATE_ERROR)
|
||||||
goto start_error;
|
goto start_error;
|
||||||
|
|
@ -549,10 +546,11 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
PINOS_STREAM_MODE_BUFFER,
|
PINOS_STREAM_MODE_BUFFER,
|
||||||
pinossink->path,
|
pinossink->path,
|
||||||
flags,
|
flags,
|
||||||
possible);
|
possible->len,
|
||||||
|
(SpaFormat **) possible->pdata);
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
state = pinos_stream_get_state (pinossink->stream);
|
state = pinossink->stream->state;
|
||||||
|
|
||||||
if (state == PINOS_STREAM_STATE_READY)
|
if (state == PINOS_STREAM_STATE_READY)
|
||||||
break;
|
break;
|
||||||
|
|
@ -560,7 +558,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
if (state == PINOS_STREAM_STATE_ERROR)
|
if (state == PINOS_STREAM_STATE_ERROR)
|
||||||
goto start_error;
|
goto start_error;
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (pinossink->loop);
|
pinos_thread_main_loop_wait (pinossink->main_loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
|
|
@ -570,7 +568,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
res = pinos_stream_start (pinossink->stream);
|
res = pinos_stream_start (pinossink->stream);
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
state = pinos_stream_get_state (pinossink->stream);
|
state = pinossink->stream->state;
|
||||||
|
|
||||||
if (state == PINOS_STREAM_STATE_STREAMING)
|
if (state == PINOS_STREAM_STATE_STREAMING)
|
||||||
break;
|
break;
|
||||||
|
|
@ -578,11 +576,11 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
if (state == PINOS_STREAM_STATE_ERROR)
|
if (state == PINOS_STREAM_STATE_ERROR)
|
||||||
goto start_error;
|
goto start_error;
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (pinossink->loop);
|
pinos_thread_main_loop_wait (pinossink->main_loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
pinos_thread_main_loop_unlock (pinossink->loop);
|
pinos_thread_main_loop_unlock (pinossink->main_loop);
|
||||||
|
|
||||||
pinossink->negotiated = res;
|
pinossink->negotiated = res;
|
||||||
|
|
||||||
|
|
@ -591,7 +589,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
start_error:
|
start_error:
|
||||||
{
|
{
|
||||||
GST_ERROR ("could not start stream");
|
GST_ERROR ("could not start stream");
|
||||||
pinos_thread_main_loop_unlock (pinossink->loop);
|
pinos_thread_main_loop_unlock (pinossink->main_loop);
|
||||||
g_ptr_array_unref (possible);
|
g_ptr_array_unref (possible);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
@ -610,8 +608,8 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
||||||
if (!pinossink->negotiated)
|
if (!pinossink->negotiated)
|
||||||
goto not_negotiated;
|
goto not_negotiated;
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossink->loop);
|
pinos_thread_main_loop_lock (pinossink->main_loop);
|
||||||
if (pinos_stream_get_state (pinossink->stream) != PINOS_STREAM_STATE_STREAMING)
|
if (pinossink->stream->state != PINOS_STREAM_STATE_STREAMING)
|
||||||
goto done;
|
goto done;
|
||||||
// goto streaming_error;
|
// goto streaming_error;
|
||||||
|
|
||||||
|
|
@ -645,7 +643,7 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
||||||
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
pinos_thread_main_loop_unlock (pinossink->loop);
|
pinos_thread_main_loop_unlock (pinossink->main_loop);
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
|
|
@ -655,7 +653,7 @@ not_negotiated:
|
||||||
}
|
}
|
||||||
//streaming_error:
|
//streaming_error:
|
||||||
// {
|
// {
|
||||||
// pinos_thread_main_loop_unlock (pinossink->loop);
|
// pinos_thread_main_loop_unlock (pinossink->main_loop);
|
||||||
// return GST_FLOW_ERROR;
|
// return GST_FLOW_ERROR;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
@ -689,15 +687,16 @@ gst_pinos_sink_start (GstBaseSink * basesink)
|
||||||
props = NULL;
|
props = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossink->loop);
|
pinos_thread_main_loop_lock (pinossink->main_loop);
|
||||||
pinossink->stream = pinos_stream_new (pinossink->ctx, pinossink->client_name, props);
|
pinossink->stream = pinos_stream_new (pinossink->ctx, pinossink->client_name, props);
|
||||||
pinossink->pool->stream = pinossink->stream;
|
pinossink->pool->stream = pinossink->stream;
|
||||||
g_signal_connect (pinossink->stream, "notify::state", (GCallback) on_stream_notify, pinossink);
|
|
||||||
g_signal_connect (pinossink->stream, "notify::format", (GCallback) on_format_notify, pinossink);
|
pinos_signal_add (&pinossink->stream->state_changed, &pinossink->stream_state_changed, on_state_changed);
|
||||||
g_signal_connect (pinossink->stream, "add-buffer", (GCallback) on_add_buffer, pinossink);
|
pinos_signal_add (&pinossink->stream->format_changed, &pinossink->stream_format_changed, on_format_changed);
|
||||||
g_signal_connect (pinossink->stream, "remove-buffer", (GCallback) on_remove_buffer, pinossink);
|
pinos_signal_add (&pinossink->stream->add_buffer, &pinossink->stream_add_buffer, on_add_buffer);
|
||||||
g_signal_connect (pinossink->stream, "new-buffer", (GCallback) on_new_buffer, pinossink);
|
pinos_signal_add (&pinossink->stream->remove_buffer, &pinossink->stream_remove_buffer, on_remove_buffer);
|
||||||
pinos_thread_main_loop_unlock (pinossink->loop);
|
pinos_signal_add (&pinossink->stream->new_buffer, &pinossink->stream_new_buffer, on_new_buffer);
|
||||||
|
pinos_thread_main_loop_unlock (pinossink->main_loop);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -707,14 +706,14 @@ gst_pinos_sink_stop (GstBaseSink * basesink)
|
||||||
{
|
{
|
||||||
GstPinosSink *pinossink = GST_PINOS_SINK (basesink);
|
GstPinosSink *pinossink = GST_PINOS_SINK (basesink);
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossink->loop);
|
pinos_thread_main_loop_lock (pinossink->main_loop);
|
||||||
if (pinossink->stream) {
|
if (pinossink->stream) {
|
||||||
pinos_stream_stop (pinossink->stream);
|
pinos_stream_stop (pinossink->stream);
|
||||||
pinos_stream_disconnect (pinossink->stream);
|
pinos_stream_disconnect (pinossink->stream);
|
||||||
g_clear_object (&pinossink->stream);
|
g_clear_object (&pinossink->stream);
|
||||||
pinossink->pool->stream = NULL;
|
pinossink->pool->stream = NULL;
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_unlock (pinossink->loop);
|
pinos_thread_main_loop_unlock (pinossink->main_loop);
|
||||||
|
|
||||||
pinossink->negotiated = FALSE;
|
pinossink->negotiated = FALSE;
|
||||||
|
|
||||||
|
|
@ -722,15 +721,13 @@ gst_pinos_sink_stop (GstBaseSink * basesink)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_context_notify (GObject *gobject,
|
on_ctx_state_changed (PinosListener *listener,
|
||||||
GParamSpec *pspec,
|
PinosContext *ctx)
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
GstPinosSink *pinossink = user_data;
|
GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, ctx_state_changed);
|
||||||
PinosContext *ctx = PINOS_CONTEXT (gobject);
|
|
||||||
PinosContextState state;
|
PinosContextState state;
|
||||||
|
|
||||||
state = pinos_context_get_state (ctx);
|
state = ctx->state;
|
||||||
GST_DEBUG ("got context state %d", state);
|
GST_DEBUG ("got context state %d", state);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
|
@ -740,33 +737,31 @@ on_context_notify (GObject *gobject,
|
||||||
break;
|
break;
|
||||||
case PINOS_CONTEXT_STATE_ERROR:
|
case PINOS_CONTEXT_STATE_ERROR:
|
||||||
GST_ELEMENT_ERROR (pinossink, RESOURCE, FAILED,
|
GST_ELEMENT_ERROR (pinossink, RESOURCE, FAILED,
|
||||||
("context error: %s",
|
("context error: %s", ctx->error), (NULL));
|
||||||
pinos_context_get_error (pinossink->ctx)->message), (NULL));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_signal (pinossink->loop, FALSE);
|
pinos_thread_main_loop_signal (pinossink->main_loop, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_pinos_sink_open (GstPinosSink * pinossink)
|
gst_pinos_sink_open (GstPinosSink * pinossink)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
pinossink->loop = pinos_loop_new ();
|
||||||
|
GST_DEBUG ("loop %p", pinossink->loop);
|
||||||
|
|
||||||
pinossink->context = g_main_context_new ();
|
pinossink->main_loop = pinos_thread_main_loop_new (pinossink->loop, "pinos-sink-loop");
|
||||||
GST_DEBUG ("context %p", pinossink->context);
|
if (pinos_thread_main_loop_start (pinossink->main_loop) != SPA_RESULT_OK)
|
||||||
|
|
||||||
pinossink->loop = pinos_thread_main_loop_new (pinossink->context, "pinos-sink-loop");
|
|
||||||
if (!pinos_thread_main_loop_start (pinossink->loop, &error))
|
|
||||||
goto mainloop_error;
|
goto mainloop_error;
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossink->loop);
|
pinos_thread_main_loop_lock (pinossink->main_loop);
|
||||||
pinossink->ctx = pinos_context_new (pinossink->context, g_get_application_name (), NULL);
|
pinossink->ctx = pinos_context_new (pinossink->loop, g_get_application_name (), NULL);
|
||||||
g_signal_connect (pinossink->ctx, "notify::state", (GCallback) on_context_notify, pinossink);
|
|
||||||
|
|
||||||
pinos_context_connect(pinossink->ctx, PINOS_CONTEXT_FLAGS_NONE);
|
pinos_signal_add (&pinossink->ctx->state_changed, &pinossink->ctx_state_changed, on_ctx_state_changed);
|
||||||
|
|
||||||
|
pinos_context_connect(pinossink->ctx);
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
PinosContextState state = pinos_context_get_state (pinossink->ctx);
|
PinosContextState state = pinossink->ctx->state;
|
||||||
|
|
||||||
if (state == PINOS_CONTEXT_STATE_CONNECTED)
|
if (state == PINOS_CONTEXT_STATE_CONNECTED)
|
||||||
break;
|
break;
|
||||||
|
|
@ -774,9 +769,9 @@ gst_pinos_sink_open (GstPinosSink * pinossink)
|
||||||
if (state == PINOS_CONTEXT_STATE_ERROR)
|
if (state == PINOS_CONTEXT_STATE_ERROR)
|
||||||
goto connect_error;
|
goto connect_error;
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (pinossink->loop);
|
pinos_thread_main_loop_wait (pinossink->main_loop);
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_unlock (pinossink->loop);
|
pinos_thread_main_loop_unlock (pinossink->main_loop);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
|
@ -784,12 +779,12 @@ gst_pinos_sink_open (GstPinosSink * pinossink)
|
||||||
mainloop_error:
|
mainloop_error:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (pinossink, RESOURCE, FAILED,
|
GST_ELEMENT_ERROR (pinossink, RESOURCE, FAILED,
|
||||||
("Failed to start mainloop: %s", error->message), (NULL));
|
("Failed to start mainloop"), (NULL));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
connect_error:
|
connect_error:
|
||||||
{
|
{
|
||||||
pinos_thread_main_loop_unlock (pinossink->loop);
|
pinos_thread_main_loop_unlock (pinossink->main_loop);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -797,7 +792,7 @@ connect_error:
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_pinos_sink_close (GstPinosSink * pinossink)
|
gst_pinos_sink_close (GstPinosSink * pinossink)
|
||||||
{
|
{
|
||||||
pinos_thread_main_loop_lock (pinossink->loop);
|
pinos_thread_main_loop_lock (pinossink->main_loop);
|
||||||
if (pinossink->stream) {
|
if (pinossink->stream) {
|
||||||
pinos_stream_disconnect (pinossink->stream);
|
pinos_stream_disconnect (pinossink->stream);
|
||||||
}
|
}
|
||||||
|
|
@ -805,7 +800,7 @@ gst_pinos_sink_close (GstPinosSink * pinossink)
|
||||||
pinos_context_disconnect (pinossink->ctx);
|
pinos_context_disconnect (pinossink->ctx);
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
PinosContextState state = pinos_context_get_state (pinossink->ctx);
|
PinosContextState state = pinossink->ctx->state;
|
||||||
|
|
||||||
if (state == PINOS_CONTEXT_STATE_UNCONNECTED)
|
if (state == PINOS_CONTEXT_STATE_UNCONNECTED)
|
||||||
break;
|
break;
|
||||||
|
|
@ -813,16 +808,17 @@ gst_pinos_sink_close (GstPinosSink * pinossink)
|
||||||
if (state == PINOS_CONTEXT_STATE_ERROR)
|
if (state == PINOS_CONTEXT_STATE_ERROR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (pinossink->loop);
|
pinos_thread_main_loop_wait (pinossink->main_loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_unlock (pinossink->loop);
|
pinos_thread_main_loop_unlock (pinossink->main_loop);
|
||||||
|
|
||||||
pinos_thread_main_loop_stop (pinossink->loop);
|
pinos_thread_main_loop_stop (pinossink->main_loop);
|
||||||
g_clear_object (&pinossink->loop);
|
pinos_thread_main_loop_destroy (pinossink->main_loop);
|
||||||
g_clear_object (&pinossink->stream);
|
pinos_stream_destroy (pinossink->stream);
|
||||||
g_clear_object (&pinossink->ctx);
|
pinos_context_destroy (pinossink->ctx);
|
||||||
g_main_context_unref (pinossink->context);
|
pinos_loop_destroy (pinossink->loop);
|
||||||
|
pinossink->loop = NULL;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,10 +77,19 @@ struct _GstPinosSink {
|
||||||
/* video state */
|
/* video state */
|
||||||
gboolean negotiated;
|
gboolean negotiated;
|
||||||
|
|
||||||
GMainContext *context;
|
PinosLoop *loop;
|
||||||
PinosThreadMainLoop *loop;
|
PinosThreadMainLoop *main_loop;
|
||||||
|
|
||||||
PinosContext *ctx;
|
PinosContext *ctx;
|
||||||
|
PinosListener ctx_state_changed;
|
||||||
|
|
||||||
PinosStream *stream;
|
PinosStream *stream;
|
||||||
|
PinosListener stream_state_changed;
|
||||||
|
PinosListener stream_format_changed;
|
||||||
|
PinosListener stream_add_buffer;
|
||||||
|
PinosListener stream_remove_buffer;
|
||||||
|
PinosListener stream_new_buffer;
|
||||||
|
|
||||||
GstAllocator *allocator;
|
GstAllocator *allocator;
|
||||||
GstStructure *properties;
|
GstStructure *properties;
|
||||||
GstPinosSinkMode mode;
|
GstPinosSinkMode mode;
|
||||||
|
|
|
||||||
|
|
@ -354,19 +354,19 @@ buffer_recycle (GstMiniObject *obj)
|
||||||
src = data->src;
|
src = data->src;
|
||||||
|
|
||||||
GST_LOG_OBJECT (obj, "recycle buffer");
|
GST_LOG_OBJECT (obj, "recycle buffer");
|
||||||
pinos_thread_main_loop_lock (src->loop);
|
pinos_thread_main_loop_lock (src->main_loop);
|
||||||
pinos_stream_recycle_buffer (src->stream, data->id);
|
pinos_stream_recycle_buffer (src->stream, data->id);
|
||||||
pinos_thread_main_loop_unlock (src->loop);
|
pinos_thread_main_loop_unlock (src->main_loop);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_add_buffer (GObject *gobject,
|
on_add_buffer (PinosListener *listener,
|
||||||
guint id,
|
PinosStream *stream,
|
||||||
gpointer user_data)
|
guint id)
|
||||||
{
|
{
|
||||||
GstPinosSrc *pinossrc = user_data;
|
GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_add_buffer);
|
||||||
SpaBuffer *b;
|
SpaBuffer *b;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
@ -430,11 +430,11 @@ on_add_buffer (GObject *gobject,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_remove_buffer (GObject *gobject,
|
on_remove_buffer (PinosListener *listener,
|
||||||
guint id,
|
PinosStream *stream,
|
||||||
gpointer user_data)
|
guint id)
|
||||||
{
|
{
|
||||||
GstPinosSrc *pinossrc = user_data;
|
GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_remove_buffer);
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
|
|
||||||
GST_LOG_OBJECT (pinossrc, "remove buffer");
|
GST_LOG_OBJECT (pinossrc, "remove buffer");
|
||||||
|
|
@ -445,11 +445,11 @@ on_remove_buffer (GObject *gobject,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_new_buffer (GObject *gobject,
|
on_new_buffer (PinosListener *listener,
|
||||||
guint id,
|
PinosStream *stream,
|
||||||
gpointer user_data)
|
guint id)
|
||||||
{
|
{
|
||||||
GstPinosSrc *pinossrc = user_data;
|
GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_new_buffer);
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
ProcessMemData *data;
|
ProcessMemData *data;
|
||||||
SpaMetaHeader *h;
|
SpaMetaHeader *h;
|
||||||
|
|
@ -483,17 +483,16 @@ on_new_buffer (GObject *gobject,
|
||||||
}
|
}
|
||||||
g_queue_push_tail (&pinossrc->queue, buf);
|
g_queue_push_tail (&pinossrc->queue, buf);
|
||||||
|
|
||||||
pinos_thread_main_loop_signal (pinossrc->loop, FALSE);
|
pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_stream_notify (GObject *gobject,
|
on_state_changed (PinosListener *listener,
|
||||||
GParamSpec *pspec,
|
PinosStream *stream)
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
GstPinosSrc *pinossrc = user_data;
|
GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_state_changed);
|
||||||
PinosStreamState state = pinos_stream_get_state (pinossrc->stream);
|
PinosStreamState state = stream->state;
|
||||||
|
|
||||||
GST_DEBUG ("got stream state %s", pinos_stream_state_as_string (state));
|
GST_DEBUG ("got stream state %s", pinos_stream_state_as_string (state));
|
||||||
|
|
||||||
|
|
@ -507,11 +506,10 @@ on_stream_notify (GObject *gobject,
|
||||||
break;
|
break;
|
||||||
case PINOS_STREAM_STATE_ERROR:
|
case PINOS_STREAM_STATE_ERROR:
|
||||||
GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED,
|
GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED,
|
||||||
("stream error: %s",
|
("stream error: %s", stream->error), (NULL));
|
||||||
pinos_stream_get_error (pinossrc->stream)->message), (NULL));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_signal (pinossrc->loop, FALSE);
|
pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -540,13 +538,12 @@ static gboolean
|
||||||
gst_pinos_src_stream_start (GstPinosSrc *pinossrc)
|
gst_pinos_src_stream_start (GstPinosSrc *pinossrc)
|
||||||
{
|
{
|
||||||
gboolean res;
|
gboolean res;
|
||||||
PinosProperties *props;
|
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossrc->loop);
|
pinos_thread_main_loop_lock (pinossrc->main_loop);
|
||||||
GST_DEBUG_OBJECT (pinossrc, "doing stream start");
|
GST_DEBUG_OBJECT (pinossrc, "doing stream start");
|
||||||
res = pinos_stream_start (pinossrc->stream);
|
res = pinos_stream_start (pinossrc->stream);
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
PinosStreamState state = pinos_stream_get_state (pinossrc->stream);
|
PinosStreamState state = pinossrc->stream->state;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pinossrc, "waiting for STREAMING, now %s", pinos_stream_state_as_string (state));
|
GST_DEBUG_OBJECT (pinossrc, "waiting for STREAMING, now %s", pinos_stream_state_as_string (state));
|
||||||
if (state == PINOS_STREAM_STATE_STREAMING)
|
if (state == PINOS_STREAM_STATE_STREAMING)
|
||||||
|
|
@ -555,27 +552,24 @@ gst_pinos_src_stream_start (GstPinosSrc *pinossrc)
|
||||||
if (state == PINOS_STREAM_STATE_ERROR)
|
if (state == PINOS_STREAM_STATE_ERROR)
|
||||||
goto start_error;
|
goto start_error;
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (pinossrc->loop);
|
pinos_thread_main_loop_wait (pinossrc->main_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_get (pinossrc->stream, "properties", &props, NULL);
|
parse_stream_properties (pinossrc, pinossrc->stream->properties);
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
|
|
||||||
parse_stream_properties (pinossrc, props);
|
pinos_thread_main_loop_lock (pinossrc->main_loop);
|
||||||
pinos_properties_free (props);
|
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossrc->loop);
|
|
||||||
GST_DEBUG_OBJECT (pinossrc, "signal started");
|
GST_DEBUG_OBJECT (pinossrc, "signal started");
|
||||||
pinossrc->started = TRUE;
|
pinossrc->started = TRUE;
|
||||||
pinos_thread_main_loop_signal (pinossrc->loop, FALSE);
|
pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE);
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
start_error:
|
start_error:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (pinossrc, "error starting stream");
|
GST_DEBUG_OBJECT (pinossrc, "error starting stream");
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -585,9 +579,9 @@ wait_negotiated (GstPinosSrc *this)
|
||||||
{
|
{
|
||||||
PinosStreamState state;
|
PinosStreamState state;
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (this->loop);
|
pinos_thread_main_loop_lock (this->main_loop);
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
state = pinos_stream_get_state (this->stream);
|
state = this->stream->state;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (this, "waiting for started signal, state now %s",
|
GST_DEBUG_OBJECT (this, "waiting for started signal, state now %s",
|
||||||
pinos_stream_state_as_string (state));
|
pinos_stream_state_as_string (state));
|
||||||
|
|
@ -597,10 +591,10 @@ wait_negotiated (GstPinosSrc *this)
|
||||||
if (this->started)
|
if (this->started)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (this->loop);
|
pinos_thread_main_loop_wait (this->main_loop);
|
||||||
}
|
}
|
||||||
GST_DEBUG_OBJECT (this, "got started signal");
|
GST_DEBUG_OBJECT (this, "got started signal");
|
||||||
pinos_thread_main_loop_unlock (this->loop);
|
pinos_thread_main_loop_unlock (this->main_loop);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
@ -645,12 +639,12 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc)
|
||||||
possible = gst_caps_to_format_all (caps);
|
possible = gst_caps_to_format_all (caps);
|
||||||
|
|
||||||
/* first disconnect */
|
/* first disconnect */
|
||||||
pinos_thread_main_loop_lock (pinossrc->loop);
|
pinos_thread_main_loop_lock (pinossrc->main_loop);
|
||||||
if (pinos_stream_get_state (pinossrc->stream) != PINOS_STREAM_STATE_UNCONNECTED) {
|
if (pinossrc->stream->state != PINOS_STREAM_STATE_UNCONNECTED) {
|
||||||
GST_DEBUG_OBJECT (basesrc, "disconnect capture");
|
GST_DEBUG_OBJECT (basesrc, "disconnect capture");
|
||||||
pinos_stream_disconnect (pinossrc->stream);
|
pinos_stream_disconnect (pinossrc->stream);
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
PinosStreamState state = pinos_stream_get_state (pinossrc->stream);
|
PinosStreamState state = pinossrc->stream->state;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (basesrc, "waiting for UNCONNECTED, now %s", pinos_stream_state_as_string (state));
|
GST_DEBUG_OBJECT (basesrc, "waiting for UNCONNECTED, now %s", pinos_stream_state_as_string (state));
|
||||||
if (state == PINOS_STREAM_STATE_UNCONNECTED)
|
if (state == PINOS_STREAM_STATE_UNCONNECTED)
|
||||||
|
|
@ -661,7 +655,7 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc)
|
||||||
goto connect_error;
|
goto connect_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (pinossrc->loop);
|
pinos_thread_main_loop_wait (pinossrc->main_loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -671,10 +665,11 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc)
|
||||||
PINOS_STREAM_MODE_BUFFER,
|
PINOS_STREAM_MODE_BUFFER,
|
||||||
pinossrc->path,
|
pinossrc->path,
|
||||||
PINOS_STREAM_FLAG_AUTOCONNECT,
|
PINOS_STREAM_FLAG_AUTOCONNECT,
|
||||||
possible);
|
possible->len,
|
||||||
|
(SpaFormat **)possible->pdata);
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
PinosStreamState state = pinos_stream_get_state (pinossrc->stream);
|
PinosStreamState state = pinossrc->stream->state;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (basesrc, "waiting for PAUSED, now %s", pinos_stream_state_as_string (state));
|
GST_DEBUG_OBJECT (basesrc, "waiting for PAUSED, now %s", pinos_stream_state_as_string (state));
|
||||||
if (state == PINOS_STREAM_STATE_PAUSED ||
|
if (state == PINOS_STREAM_STATE_PAUSED ||
|
||||||
|
|
@ -684,9 +679,9 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc)
|
||||||
if (state == PINOS_STREAM_STATE_ERROR)
|
if (state == PINOS_STREAM_STATE_ERROR)
|
||||||
goto connect_error;
|
goto connect_error;
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (pinossrc->loop);
|
pinos_thread_main_loop_wait (pinossrc->main_loop);
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
|
|
||||||
result = gst_pinos_src_stream_start (pinossrc);
|
result = gst_pinos_src_stream_start (pinossrc);
|
||||||
|
|
||||||
|
|
@ -721,23 +716,20 @@ no_common_caps:
|
||||||
}
|
}
|
||||||
connect_error:
|
connect_error:
|
||||||
{
|
{
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_format_notify (GObject *gobject,
|
on_format_changed (PinosListener *listener,
|
||||||
GParamSpec *pspec,
|
PinosStream *stream,
|
||||||
gpointer user_data)
|
SpaFormat *format)
|
||||||
{
|
{
|
||||||
GstPinosSrc *pinossrc = user_data;
|
GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_format_changed);
|
||||||
SpaFormat *format;
|
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
gboolean res;
|
gboolean res;
|
||||||
|
|
||||||
g_object_get (gobject, "format", &format, NULL);
|
|
||||||
|
|
||||||
caps = gst_caps_from_format (format);
|
caps = gst_caps_from_format (format);
|
||||||
GST_DEBUG_OBJECT (pinossrc, "we got format %" GST_PTR_FORMAT, caps);
|
GST_DEBUG_OBJECT (pinossrc, "we got format %" GST_PTR_FORMAT, caps);
|
||||||
res = gst_base_src_set_caps (GST_BASE_SRC (pinossrc), caps);
|
res = gst_base_src_set_caps (GST_BASE_SRC (pinossrc), caps);
|
||||||
|
|
@ -765,11 +757,11 @@ gst_pinos_src_unlock (GstBaseSrc * basesrc)
|
||||||
{
|
{
|
||||||
GstPinosSrc *pinossrc = GST_PINOS_SRC (basesrc);
|
GstPinosSrc *pinossrc = GST_PINOS_SRC (basesrc);
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossrc->loop);
|
pinos_thread_main_loop_lock (pinossrc->main_loop);
|
||||||
GST_DEBUG_OBJECT (pinossrc, "setting flushing");
|
GST_DEBUG_OBJECT (pinossrc, "setting flushing");
|
||||||
pinossrc->flushing = TRUE;
|
pinossrc->flushing = TRUE;
|
||||||
pinos_thread_main_loop_signal (pinossrc->loop, FALSE);
|
pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE);
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -779,10 +771,10 @@ gst_pinos_src_unlock_stop (GstBaseSrc * basesrc)
|
||||||
{
|
{
|
||||||
GstPinosSrc *pinossrc = GST_PINOS_SRC (basesrc);
|
GstPinosSrc *pinossrc = GST_PINOS_SRC (basesrc);
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossrc->loop);
|
pinos_thread_main_loop_lock (pinossrc->main_loop);
|
||||||
GST_DEBUG_OBJECT (pinossrc, "unsetting flushing");
|
GST_DEBUG_OBJECT (pinossrc, "unsetting flushing");
|
||||||
pinossrc->flushing = FALSE;
|
pinossrc->flushing = FALSE;
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -868,14 +860,14 @@ gst_pinos_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
|
||||||
if (!pinossrc->negotiated)
|
if (!pinossrc->negotiated)
|
||||||
goto not_negotiated;
|
goto not_negotiated;
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossrc->loop);
|
pinos_thread_main_loop_lock (pinossrc->main_loop);
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
PinosStreamState state;
|
PinosStreamState state;
|
||||||
|
|
||||||
if (pinossrc->flushing)
|
if (pinossrc->flushing)
|
||||||
goto streaming_stopped;
|
goto streaming_stopped;
|
||||||
|
|
||||||
state = pinos_stream_get_state (pinossrc->stream);
|
state = pinossrc->stream->state;
|
||||||
if (state == PINOS_STREAM_STATE_ERROR)
|
if (state == PINOS_STREAM_STATE_ERROR)
|
||||||
goto streaming_error;
|
goto streaming_error;
|
||||||
|
|
||||||
|
|
@ -886,9 +878,9 @@ gst_pinos_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
|
||||||
if (*buffer != NULL)
|
if (*buffer != NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (pinossrc->loop);
|
pinos_thread_main_loop_wait (pinossrc->main_loop);
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
|
|
||||||
if (pinossrc->is_live)
|
if (pinossrc->is_live)
|
||||||
base_time = GST_ELEMENT_CAST (psrc)->base_time;
|
base_time = GST_ELEMENT_CAST (psrc)->base_time;
|
||||||
|
|
@ -919,12 +911,12 @@ not_negotiated:
|
||||||
}
|
}
|
||||||
streaming_error:
|
streaming_error:
|
||||||
{
|
{
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
streaming_stopped:
|
streaming_stopped:
|
||||||
{
|
{
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
return GST_FLOW_FLUSHING;
|
return GST_FLOW_FLUSHING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -949,20 +941,19 @@ gst_pinos_src_stop (GstBaseSrc * basesrc)
|
||||||
|
|
||||||
pinossrc = GST_PINOS_SRC (basesrc);
|
pinossrc = GST_PINOS_SRC (basesrc);
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossrc->loop);
|
pinos_thread_main_loop_lock (pinossrc->main_loop);
|
||||||
clear_queue (pinossrc);
|
clear_queue (pinossrc);
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_context_notify (GObject *gobject,
|
on_ctx_state_changed (PinosListener *listener,
|
||||||
GParamSpec *pspec,
|
PinosContext *ctx)
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
GstPinosSrc *pinossrc = user_data;
|
GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, ctx_state_changed);
|
||||||
PinosContextState state = pinos_context_get_state (pinossrc->ctx);
|
PinosContextState state = ctx->state;
|
||||||
|
|
||||||
GST_DEBUG ("got context state %s", pinos_context_state_as_string (state));
|
GST_DEBUG ("got context state %s", pinos_context_state_as_string (state));
|
||||||
|
|
||||||
|
|
@ -973,11 +964,10 @@ on_context_notify (GObject *gobject,
|
||||||
break;
|
break;
|
||||||
case PINOS_CONTEXT_STATE_ERROR:
|
case PINOS_CONTEXT_STATE_ERROR:
|
||||||
GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED,
|
GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED,
|
||||||
("context error: %s",
|
("context error: %s", ctx->error), (NULL));
|
||||||
pinos_context_get_error (pinossrc->ctx)->message), (NULL));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pinos_thread_main_loop_signal (pinossrc->loop, FALSE);
|
pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
@ -997,24 +987,24 @@ copy_properties (GQuark field_id,
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_pinos_src_open (GstPinosSrc * pinossrc)
|
gst_pinos_src_open (GstPinosSrc * pinossrc)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
|
||||||
PinosProperties *props;
|
PinosProperties *props;
|
||||||
|
|
||||||
pinossrc->context = g_main_context_new ();
|
pinossrc->loop = pinos_loop_new ();
|
||||||
GST_DEBUG ("context %p", pinossrc->context);
|
GST_DEBUG ("loop %p", pinossrc->loop);
|
||||||
|
|
||||||
pinossrc->loop = pinos_thread_main_loop_new (pinossrc->context, "pinos-main-loop");
|
pinossrc->main_loop = pinos_thread_main_loop_new (pinossrc->loop, "pinos-main-loop");
|
||||||
if (!pinos_thread_main_loop_start (pinossrc->loop, &error))
|
if (pinos_thread_main_loop_start (pinossrc->main_loop) != SPA_RESULT_OK)
|
||||||
goto mainloop_failed;
|
goto mainloop_failed;
|
||||||
|
|
||||||
pinos_thread_main_loop_lock (pinossrc->loop);
|
pinos_thread_main_loop_lock (pinossrc->main_loop);
|
||||||
pinossrc->ctx = pinos_context_new (pinossrc->context, g_get_application_name (), NULL);
|
pinossrc->ctx = pinos_context_new (pinossrc->loop, g_get_application_name (), NULL);
|
||||||
g_signal_connect (pinossrc->ctx, "notify::state", (GCallback) on_context_notify, pinossrc);
|
|
||||||
|
|
||||||
pinos_context_connect (pinossrc->ctx, PINOS_CONTEXT_FLAGS_NONE);
|
pinos_signal_add (&pinossrc->ctx->state_changed, &pinossrc->ctx_state_changed, on_ctx_state_changed);
|
||||||
|
|
||||||
|
pinos_context_connect (pinossrc->ctx);
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
PinosContextState state = pinos_context_get_state (pinossrc->ctx);
|
PinosContextState state = pinossrc->ctx->state;
|
||||||
|
|
||||||
GST_DEBUG ("waiting for CONNECTED, now %s", pinos_context_state_as_string (state));
|
GST_DEBUG ("waiting for CONNECTED, now %s", pinos_context_state_as_string (state));
|
||||||
if (state == PINOS_CONTEXT_STATE_CONNECTED)
|
if (state == PINOS_CONTEXT_STATE_CONNECTED)
|
||||||
|
|
@ -1023,7 +1013,7 @@ gst_pinos_src_open (GstPinosSrc * pinossrc)
|
||||||
if (state == PINOS_CONTEXT_STATE_ERROR)
|
if (state == PINOS_CONTEXT_STATE_ERROR)
|
||||||
goto connect_error;
|
goto connect_error;
|
||||||
|
|
||||||
pinos_thread_main_loop_wait (pinossrc->loop);
|
pinos_thread_main_loop_wait (pinossrc->main_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pinossrc->properties) {
|
if (pinossrc->properties) {
|
||||||
|
|
@ -1034,26 +1024,27 @@ gst_pinos_src_open (GstPinosSrc * pinossrc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pinossrc->stream = pinos_stream_new (pinossrc->ctx, pinossrc->client_name, props);
|
pinossrc->stream = pinos_stream_new (pinossrc->ctx, pinossrc->client_name, props);
|
||||||
g_signal_connect (pinossrc->stream, "notify::state", (GCallback) on_stream_notify, pinossrc);
|
|
||||||
g_signal_connect (pinossrc->stream, "notify::format", (GCallback) on_format_notify, pinossrc);
|
pinos_signal_add (&pinossrc->stream->state_changed, &pinossrc->stream_state_changed, on_state_changed);
|
||||||
g_signal_connect (pinossrc->stream, "add-buffer", (GCallback) on_add_buffer, pinossrc);
|
pinos_signal_add (&pinossrc->stream->format_changed, &pinossrc->stream_format_changed, on_format_changed);
|
||||||
g_signal_connect (pinossrc->stream, "remove-buffer", (GCallback) on_remove_buffer, pinossrc);
|
pinos_signal_add (&pinossrc->stream->add_buffer, &pinossrc->stream_add_buffer, on_add_buffer);
|
||||||
g_signal_connect (pinossrc->stream, "new-buffer", (GCallback) on_new_buffer, pinossrc);
|
pinos_signal_add (&pinossrc->stream->remove_buffer, &pinossrc->stream_remove_buffer, on_remove_buffer);
|
||||||
|
pinos_signal_add (&pinossrc->stream->new_buffer, &pinossrc->stream_new_buffer, on_new_buffer);
|
||||||
|
|
||||||
pinossrc->clock = gst_pinos_clock_new (pinossrc->stream);
|
pinossrc->clock = gst_pinos_clock_new (pinossrc->stream);
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
mainloop_failed:
|
mainloop_failed:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED,
|
GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED, ("error starting mainloop"), (NULL));
|
||||||
("mainloop error: %s", error->message), (NULL));
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
connect_error:
|
connect_error:
|
||||||
{
|
{
|
||||||
pinos_thread_main_loop_unlock (pinossrc->loop);
|
pinos_thread_main_loop_unlock (pinossrc->main_loop);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1061,10 +1052,16 @@ connect_error:
|
||||||
static void
|
static void
|
||||||
gst_pinos_src_close (GstPinosSrc * pinossrc)
|
gst_pinos_src_close (GstPinosSrc * pinossrc)
|
||||||
{
|
{
|
||||||
pinos_thread_main_loop_stop (pinossrc->loop);
|
pinos_thread_main_loop_stop (pinossrc->main_loop);
|
||||||
g_clear_object (&pinossrc->loop);
|
pinos_thread_main_loop_destroy (pinossrc->main_loop);
|
||||||
g_clear_object (&pinossrc->ctx);
|
pinossrc->main_loop = NULL;
|
||||||
g_main_context_unref (pinossrc->context);
|
|
||||||
|
pinos_context_destroy (pinossrc->ctx);
|
||||||
|
pinossrc->ctx = NULL;
|
||||||
|
|
||||||
|
pinos_loop_destroy (pinossrc->loop);
|
||||||
|
pinossrc->loop = NULL;
|
||||||
|
|
||||||
GST_OBJECT_LOCK (pinossrc);
|
GST_OBJECT_LOCK (pinossrc);
|
||||||
g_clear_object (&pinossrc->clock);
|
g_clear_object (&pinossrc->clock);
|
||||||
g_clear_object (&pinossrc->stream);
|
g_clear_object (&pinossrc->stream);
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,19 @@ struct _GstPinosSrc {
|
||||||
GstClockTime min_latency;
|
GstClockTime min_latency;
|
||||||
GstClockTime max_latency;
|
GstClockTime max_latency;
|
||||||
|
|
||||||
GMainContext *context;
|
PinosLoop *loop;
|
||||||
PinosThreadMainLoop *loop;
|
PinosThreadMainLoop *main_loop;
|
||||||
|
|
||||||
PinosContext *ctx;
|
PinosContext *ctx;
|
||||||
|
PinosListener ctx_state_changed;
|
||||||
|
|
||||||
PinosStream *stream;
|
PinosStream *stream;
|
||||||
|
PinosListener stream_state_changed;
|
||||||
|
PinosListener stream_format_changed;
|
||||||
|
PinosListener stream_add_buffer;
|
||||||
|
PinosListener stream_remove_buffer;
|
||||||
|
PinosListener stream_new_buffer;
|
||||||
|
|
||||||
GstAllocator *fd_allocator;
|
GstAllocator *fd_allocator;
|
||||||
GstStructure *properties;
|
GstStructure *properties;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,18 +26,11 @@
|
||||||
#include "pinos/server/core.h"
|
#include "pinos/server/core.h"
|
||||||
#include "pinos/server/module.h"
|
#include "pinos/server/module.h"
|
||||||
|
|
||||||
#define MODULE_URI "http://pinos.org/ns/module-autolink"
|
|
||||||
#define MODULE_PREFIX MODULE_URI "#"
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PinosCore *core;
|
PinosCore *core;
|
||||||
PinosProperties *properties;
|
PinosProperties *properties;
|
||||||
PinosGlobal *global;
|
PinosGlobal *global;
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t module;
|
|
||||||
} uri;
|
|
||||||
|
|
||||||
PinosListener global_added;
|
PinosListener global_added;
|
||||||
PinosListener global_removed;
|
PinosListener global_removed;
|
||||||
PinosListener port_added;
|
PinosListener port_added;
|
||||||
|
|
@ -57,8 +50,10 @@ try_link_port (PinosNode *node, PinosPort *port, ModuleImpl *impl)
|
||||||
PinosLink *link;
|
PinosLink *link;
|
||||||
|
|
||||||
props = node->properties;
|
props = node->properties;
|
||||||
if (props == NULL)
|
if (props == NULL) {
|
||||||
|
pinos_log_debug ("module %p: node has no properties", impl);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
path = pinos_properties_get (props, "pinos.target.node");
|
path = pinos_properties_get (props, "pinos.target.node");
|
||||||
|
|
||||||
|
|
@ -275,10 +270,8 @@ module_new (PinosCore *core,
|
||||||
pinos_signal_add (&core->port_unlinked, &impl->port_unlinked, on_link_port_unlinked);
|
pinos_signal_add (&core->port_unlinked, &impl->port_unlinked, on_link_port_unlinked);
|
||||||
pinos_signal_add (&core->link_state_changed, &impl->link_state_changed, on_link_state_changed);
|
pinos_signal_add (&core->link_state_changed, &impl->link_state_changed, on_link_state_changed);
|
||||||
|
|
||||||
impl->uri.module = spa_id_map_get_id (core->uri.map, MODULE_URI);
|
|
||||||
|
|
||||||
impl->global = pinos_core_add_global (core,
|
impl->global = pinos_core_add_global (core,
|
||||||
impl->uri.module,
|
core->uri.module,
|
||||||
impl);
|
impl);
|
||||||
return impl;
|
return impl;
|
||||||
}
|
}
|
||||||
|
|
@ -306,5 +299,5 @@ bool
|
||||||
pinos__module_init (PinosModule * module, const char * args)
|
pinos__module_init (PinosModule * module, const char * args)
|
||||||
{
|
{
|
||||||
module_new (module->core, NULL);
|
module_new (module->core, NULL);
|
||||||
return TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
#include <gio/gunixfdlist.h>
|
#include <gio/gunixfdlist.h>
|
||||||
|
|
@ -34,6 +35,7 @@
|
||||||
#include "pinos/server/module.h"
|
#include "pinos/server/module.h"
|
||||||
#include "pinos/server/client-node.h"
|
#include "pinos/server/client-node.h"
|
||||||
#include "pinos/server/client.h"
|
#include "pinos/server/client.h"
|
||||||
|
#include "pinos/server/resource.h"
|
||||||
#include "pinos/server/link.h"
|
#include "pinos/server/link.h"
|
||||||
#include "pinos/server/node-factory.h"
|
#include "pinos/server/node-factory.h"
|
||||||
#include "pinos/server/data-loop.h"
|
#include "pinos/server/data-loop.h"
|
||||||
|
|
@ -41,9 +43,6 @@
|
||||||
|
|
||||||
#include "pinos/dbus/org-pinos.h"
|
#include "pinos/dbus/org-pinos.h"
|
||||||
|
|
||||||
#define PINOS_PROTOCOL_DBUS_URI "http://pinos.org/ns/protocol-dbus"
|
|
||||||
#define PINOS_PROTOCOL_DBUS_PREFIX PINOS_PROTOCOL_DBUS_URI "#"
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PinosCore *core;
|
PinosCore *core;
|
||||||
SpaList link;
|
SpaList link;
|
||||||
|
|
@ -51,10 +50,6 @@ typedef struct {
|
||||||
|
|
||||||
PinosProperties *properties;
|
PinosProperties *properties;
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t protocol_dbus;
|
|
||||||
} uri;
|
|
||||||
|
|
||||||
GDBusConnection *connection;
|
GDBusConnection *connection;
|
||||||
GDBusObjectManagerServer *server_manager;
|
GDBusObjectManagerServer *server_manager;
|
||||||
|
|
||||||
|
|
@ -162,6 +157,51 @@ find_object (PinosProtocolDBus *impl,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct _PinosProperties {
|
||||||
|
GHashTable *hashtable;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_to_variant (const gchar *key, const gchar *value, GVariantBuilder *b)
|
||||||
|
{
|
||||||
|
g_variant_builder_add (b, "{sv}", key, g_variant_new_string (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pinos_properties_init_builder (PinosProperties *properties,
|
||||||
|
GVariantBuilder *builder)
|
||||||
|
{
|
||||||
|
g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sv}"));
|
||||||
|
g_hash_table_foreach (properties->hashtable, (GHFunc) add_to_variant, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariant *
|
||||||
|
pinos_properties_to_variant (PinosProperties *properties)
|
||||||
|
{
|
||||||
|
GVariantBuilder builder;
|
||||||
|
pinos_properties_init_builder (properties, &builder);
|
||||||
|
return g_variant_builder_end (&builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PinosProperties *
|
||||||
|
pinos_properties_from_variant (GVariant *variant)
|
||||||
|
{
|
||||||
|
PinosProperties *props;
|
||||||
|
GVariantIter iter;
|
||||||
|
GVariant *value;
|
||||||
|
gchar *key;
|
||||||
|
|
||||||
|
props = pinos_properties_new (NULL, NULL);
|
||||||
|
|
||||||
|
g_variant_iter_init (&iter, variant);
|
||||||
|
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
|
||||||
|
g_hash_table_replace (props->hashtable,
|
||||||
|
g_strdup (key),
|
||||||
|
g_variant_dup_string (value, NULL));
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
client_name_appeared_handler (GDBusConnection *connection,
|
client_name_appeared_handler (GDBusConnection *connection,
|
||||||
const gchar *name,
|
const gchar *name,
|
||||||
|
|
@ -176,8 +216,10 @@ client_name_appeared_handler (GDBusConnection *connection,
|
||||||
static void
|
static void
|
||||||
client_destroy (PinosProtocolDBusClient *this)
|
client_destroy (PinosProtocolDBusClient *this)
|
||||||
{
|
{
|
||||||
spa_list_remove (&this->link);
|
if (this->sender) {
|
||||||
free (this->sender);
|
spa_list_remove (&this->link);
|
||||||
|
free (this->sender);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -279,10 +321,11 @@ handle_create_node (PinosDaemon1 *interface,
|
||||||
if (object == NULL)
|
if (object == NULL)
|
||||||
goto object_failed;
|
goto object_failed;
|
||||||
|
|
||||||
pinos_client_add_resource (client,
|
pinos_resource_new (client,
|
||||||
impl->core->uri.node,
|
SPA_ID_INVALID,
|
||||||
node,
|
impl->core->uri.node,
|
||||||
(PinosDestroy) pinos_node_destroy);
|
node,
|
||||||
|
(PinosDestroy) pinos_node_destroy);
|
||||||
|
|
||||||
object_path = object->object_path;
|
object_path = object->object_path;
|
||||||
pinos_log_debug ("protocol-dbus %p: added node %p with path %s", impl, node, object_path);
|
pinos_log_debug ("protocol-dbus %p: added node %p with path %s", impl, node, object_path);
|
||||||
|
|
@ -350,6 +393,7 @@ handle_create_client_node (PinosDaemon1 *interface,
|
||||||
int ctrl_fd, data_fd;
|
int ctrl_fd, data_fd;
|
||||||
int ctrl_idx, data_idx;
|
int ctrl_idx, data_idx;
|
||||||
PinosProtocolDBusObject *object;
|
PinosProtocolDBusObject *object;
|
||||||
|
int fd[2];
|
||||||
|
|
||||||
sender = g_dbus_method_invocation_get_sender (invocation);
|
sender = g_dbus_method_invocation_get_sender (invocation);
|
||||||
client = sender_get_client (impl, sender, TRUE);
|
client = sender_get_client (impl, sender, TRUE);
|
||||||
|
|
@ -364,8 +408,13 @@ handle_create_client_node (PinosDaemon1 *interface,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, fd) != 0)
|
||||||
|
goto no_socket_pair;
|
||||||
|
|
||||||
node = pinos_client_node_new (impl->core,
|
ctrl_fd = fd[1];
|
||||||
|
|
||||||
|
node = pinos_client_node_new (client,
|
||||||
|
SPA_ID_INVALID,
|
||||||
arg_name,
|
arg_name,
|
||||||
props);
|
props);
|
||||||
|
|
||||||
|
|
@ -373,17 +422,9 @@ handle_create_client_node (PinosDaemon1 *interface,
|
||||||
if (object == NULL)
|
if (object == NULL)
|
||||||
goto object_failed;
|
goto object_failed;
|
||||||
|
|
||||||
if ((res = pinos_client_node_get_ctrl_socket (node, &ctrl_fd)) < 0)
|
|
||||||
goto no_socket;
|
|
||||||
|
|
||||||
if ((res = pinos_client_node_get_data_socket (node, &data_fd)) < 0)
|
if ((res = pinos_client_node_get_data_socket (node, &data_fd)) < 0)
|
||||||
goto no_socket;
|
goto no_socket;
|
||||||
|
|
||||||
pinos_client_add_resource (client,
|
|
||||||
impl->core->uri.client_node,
|
|
||||||
node,
|
|
||||||
(PinosDestroy) pinos_client_node_destroy);
|
|
||||||
|
|
||||||
object_path = object->object_path;
|
object_path = object->object_path;
|
||||||
pinos_log_debug ("protocol-dbus %p: add client-node %p, %s", impl, node, object_path);
|
pinos_log_debug ("protocol-dbus %p: add client-node %p, %s", impl, node, object_path);
|
||||||
|
|
||||||
|
|
@ -402,6 +443,11 @@ object_failed:
|
||||||
pinos_log_debug ("protocol-dbus %p: could not create object", impl);
|
pinos_log_debug ("protocol-dbus %p: could not create object", impl);
|
||||||
goto exit_error;
|
goto exit_error;
|
||||||
}
|
}
|
||||||
|
no_socket_pair:
|
||||||
|
{
|
||||||
|
pinos_log_debug ("protocol-dbus %p: could not create socketpair: %s", impl, strerror (errno));
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
no_socket:
|
no_socket:
|
||||||
{
|
{
|
||||||
pinos_log_debug ("protocol-dbus %p: could not create socket: %s", impl, strerror (errno));
|
pinos_log_debug ("protocol-dbus %p: could not create socket: %s", impl, strerror (errno));
|
||||||
|
|
@ -519,7 +565,7 @@ on_global_added (PinosListener *listener,
|
||||||
true,
|
true,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
else if (global->type == impl->uri.protocol_dbus) {
|
else if (global->object == impl) {
|
||||||
PinosProtocolDBus *proto = global->object;
|
PinosProtocolDBus *proto = global->object;
|
||||||
PinosProtocolDBusServer *server;
|
PinosProtocolDBusServer *server;
|
||||||
PinosDaemon1 *iface;
|
PinosDaemon1 *iface;
|
||||||
|
|
@ -631,10 +677,8 @@ pinos_protocol_dbus_new (PinosCore *core,
|
||||||
|
|
||||||
impl->server_manager = g_dbus_object_manager_server_new (PINOS_DBUS_OBJECT_PREFIX);
|
impl->server_manager = g_dbus_object_manager_server_new (PINOS_DBUS_OBJECT_PREFIX);
|
||||||
|
|
||||||
impl->uri.protocol_dbus = spa_id_map_get_id (core->uri.map, PINOS_PROTOCOL_DBUS_URI);
|
|
||||||
|
|
||||||
impl->global = pinos_core_add_global (core,
|
impl->global = pinos_core_add_global (core,
|
||||||
impl->uri.protocol_dbus,
|
core->uri.module,
|
||||||
impl);
|
impl);
|
||||||
return impl;
|
return impl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
@ -36,14 +37,12 @@
|
||||||
#include "pinos/server/module.h"
|
#include "pinos/server/module.h"
|
||||||
#include "pinos/server/client-node.h"
|
#include "pinos/server/client-node.h"
|
||||||
#include "pinos/server/client.h"
|
#include "pinos/server/client.h"
|
||||||
|
#include "pinos/server/resource.h"
|
||||||
#include "pinos/server/link.h"
|
#include "pinos/server/link.h"
|
||||||
#include "pinos/server/node-factory.h"
|
#include "pinos/server/node-factory.h"
|
||||||
#include "pinos/server/data-loop.h"
|
#include "pinos/server/data-loop.h"
|
||||||
#include "pinos/server/main-loop.h"
|
#include "pinos/server/main-loop.h"
|
||||||
|
|
||||||
#define PINOS_PROTOCOL_NATIVE_URI "http://pinos.org/ns/protocol-native"
|
|
||||||
#define PINOS_PROTOCOL_NATIVE_PREFIX PINOS_PROTOCOL_NATIVE_URI "#"
|
|
||||||
|
|
||||||
#ifndef UNIX_PATH_MAX
|
#ifndef UNIX_PATH_MAX
|
||||||
#define UNIX_PATH_MAX 108
|
#define UNIX_PATH_MAX 108
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -69,10 +68,6 @@ typedef struct {
|
||||||
|
|
||||||
PinosProperties *properties;
|
PinosProperties *properties;
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t protocol_native;
|
|
||||||
} uri;
|
|
||||||
|
|
||||||
SpaList socket_list;
|
SpaList socket_list;
|
||||||
|
|
||||||
SpaList client_list;
|
SpaList client_list;
|
||||||
|
|
@ -102,6 +97,7 @@ typedef struct {
|
||||||
struct ucred ucred;
|
struct ucred ucred;
|
||||||
SpaSource *source;
|
SpaSource *source;
|
||||||
PinosConnection *connection;
|
PinosConnection *connection;
|
||||||
|
PinosResource *core_resource;
|
||||||
} PinosProtocolNativeClient;
|
} PinosProtocolNativeClient;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -153,9 +149,120 @@ static void
|
||||||
client_destroy (PinosProtocolNativeClient *this)
|
client_destroy (PinosProtocolNativeClient *this)
|
||||||
{
|
{
|
||||||
spa_list_remove (&this->link);
|
spa_list_remove (&this->link);
|
||||||
|
pinos_loop_destroy_source (this->parent.impl->core->main_loop->loop,
|
||||||
|
this->source);
|
||||||
|
pinos_connection_destroy (this->connection);
|
||||||
close (this->fd);
|
close (this->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SpaResult
|
||||||
|
core_dispatch_func (void *object,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
PinosProtocolNativeClient *client = data;
|
||||||
|
PinosProtocolNative *impl = client->parent.impl;
|
||||||
|
PinosClient *c = client->parent.global->object;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case PINOS_MESSAGE_SUBSCRIBE:
|
||||||
|
{
|
||||||
|
PinosMessageSubscribe *m = message;
|
||||||
|
PinosGlobal *global;
|
||||||
|
PinosMessageNotifyDone nd;
|
||||||
|
|
||||||
|
spa_list_for_each (global, &impl->core->global_list, link) {
|
||||||
|
PinosMessageNotifyGlobal ng;
|
||||||
|
|
||||||
|
ng.id = global->id;
|
||||||
|
ng.type = spa_id_map_get_uri (impl->core->uri.map, global->type);
|
||||||
|
pinos_resource_send_message (client->core_resource,
|
||||||
|
PINOS_MESSAGE_NOTIFY_GLOBAL,
|
||||||
|
&ng,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
nd.seq = m->seq;
|
||||||
|
pinos_resource_send_message (client->core_resource,
|
||||||
|
PINOS_MESSAGE_NOTIFY_DONE,
|
||||||
|
&nd,
|
||||||
|
true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PINOS_MESSAGE_CREATE_CLIENT_NODE:
|
||||||
|
{
|
||||||
|
PinosMessageCreateClientNode *m = message;
|
||||||
|
PinosClientNode *node;
|
||||||
|
SpaResult res;
|
||||||
|
int data_fd, i;
|
||||||
|
PinosMessageCreateClientNodeDone r;
|
||||||
|
PinosProperties *props;
|
||||||
|
|
||||||
|
props = pinos_properties_new (NULL, NULL);
|
||||||
|
for (i = 0; i < m->props->n_items; i++) {
|
||||||
|
pinos_properties_set (props, m->props->items[i].key,
|
||||||
|
m->props->items[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
node = pinos_client_node_new (c,
|
||||||
|
m->id,
|
||||||
|
m->name,
|
||||||
|
props);
|
||||||
|
|
||||||
|
if ((res = pinos_client_node_get_data_socket (node, &data_fd)) < 0) {
|
||||||
|
pinos_log_error ("can't get data fd");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
r.seq = m->seq;
|
||||||
|
r.datafd = data_fd;
|
||||||
|
pinos_resource_send_message (node->resource,
|
||||||
|
PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE,
|
||||||
|
&r,
|
||||||
|
true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
pinos_log_error ("unhandled message %d", type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SpaResult
|
||||||
|
client_send_func (void *object,
|
||||||
|
uint32_t id,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
bool flush,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
PinosProtocolNativeClient *client = data;
|
||||||
|
|
||||||
|
pinos_log_debug ("protocol-native %p: sending message %d to %u", client->parent.impl, type, id);
|
||||||
|
|
||||||
|
pinos_connection_add_message (client->connection,
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
message);
|
||||||
|
if (flush)
|
||||||
|
pinos_connection_flush (client->connection);
|
||||||
|
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PinosResource *
|
||||||
|
find_resource (PinosClient *client, uint32_t id)
|
||||||
|
{
|
||||||
|
PinosResource *resource;
|
||||||
|
|
||||||
|
spa_list_for_each (resource, &client->resource_list, link) {
|
||||||
|
if (resource->id == id)
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_data (SpaSource *source,
|
connection_data (SpaSource *source,
|
||||||
int fd,
|
int fd,
|
||||||
|
|
@ -164,15 +271,36 @@ connection_data (SpaSource *source,
|
||||||
{
|
{
|
||||||
PinosProtocolNativeClient *client = data;
|
PinosProtocolNativeClient *client = data;
|
||||||
PinosConnection *conn = client->connection;
|
PinosConnection *conn = client->connection;
|
||||||
|
PinosMessageType type;
|
||||||
|
uint32_t id;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
while (pinos_connection_has_next (conn)) {
|
if (mask & (SPA_IO_ERR | SPA_IO_HUP)) {
|
||||||
PinosMessageType type = pinos_connection_get_type (conn);
|
pinos_client_destroy (client->parent.global->object);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (type) {
|
while (pinos_connection_get_next (conn, &type, &id, &size)) {
|
||||||
default:
|
PinosResource *resource;
|
||||||
pinos_log_error ("unhandled message %d", type);
|
void *message = alloca (size);
|
||||||
break;
|
|
||||||
|
pinos_log_debug ("protocol-native %p: got message %d from %u", client->parent.impl, type, id);
|
||||||
|
|
||||||
|
if (!pinos_connection_parse_message (conn, message)) {
|
||||||
|
pinos_log_error ("protocol-native %p: failed to parse message", client->parent.impl);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource = find_resource (client->parent.global->object, id);
|
||||||
|
if (resource == NULL) {
|
||||||
|
pinos_log_error ("protocol-native %p: unknown resource %u", client->parent.impl, id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
resource->dispatch_func (resource,
|
||||||
|
type,
|
||||||
|
message,
|
||||||
|
resource->dispatch_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,11 +318,22 @@ client_new (PinosProtocolNative *impl,
|
||||||
close (fd);
|
close (fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
client->send_func = client_send_func;
|
||||||
|
client->send_data = this;
|
||||||
|
|
||||||
|
this->core_resource = pinos_resource_new (client,
|
||||||
|
0,
|
||||||
|
impl->core->uri.core,
|
||||||
|
impl->core,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
this->core_resource->dispatch_func = core_dispatch_func;
|
||||||
|
this->core_resource->dispatch_data = this;
|
||||||
|
|
||||||
this->fd = fd;
|
this->fd = fd;
|
||||||
this->source = pinos_loop_add_io (impl->core->main_loop->loop,
|
this->source = pinos_loop_add_io (impl->core->main_loop->loop,
|
||||||
this->fd,
|
this->fd,
|
||||||
SPA_IO_IN,
|
SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP,
|
||||||
false,
|
false,
|
||||||
connection_data,
|
connection_data,
|
||||||
this);
|
this);
|
||||||
|
|
@ -224,7 +363,10 @@ on_global_added (PinosListener *listener,
|
||||||
global,
|
global,
|
||||||
(PinosDestroy) client_destroy);
|
(PinosDestroy) client_destroy);
|
||||||
} else if (global->type == impl->core->uri.node) {
|
} else if (global->type == impl->core->uri.node) {
|
||||||
} else if (global->type == impl->uri.protocol_native) {
|
object_new (sizeof (PinosProtocolNativeNode),
|
||||||
|
impl,
|
||||||
|
global,
|
||||||
|
NULL);
|
||||||
} else if (global->type == impl->core->uri.link) {
|
} else if (global->type == impl->core->uri.link) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -234,7 +376,7 @@ on_global_removed (PinosListener *listener,
|
||||||
PinosCore *core,
|
PinosCore *core,
|
||||||
PinosGlobal *global)
|
PinosGlobal *global)
|
||||||
{
|
{
|
||||||
PinosProtocolNative *impl = SPA_CONTAINER_OF (listener, PinosProtocolNative, global_added);
|
PinosProtocolNative *impl = SPA_CONTAINER_OF (listener, PinosProtocolNative, global_removed);
|
||||||
PinosProtocolNativeObject *object;
|
PinosProtocolNativeObject *object;
|
||||||
|
|
||||||
if ((object = find_object (impl, global->object))) {
|
if ((object = find_object (impl, global->object))) {
|
||||||
|
|
@ -284,7 +426,7 @@ init_socket_name (Socket *s, const char *name)
|
||||||
|
|
||||||
s->addr.sun_family = AF_LOCAL;
|
s->addr.sun_family = AF_LOCAL;
|
||||||
name_size = snprintf (s->addr.sun_path, sizeof (s->addr.sun_path),
|
name_size = snprintf (s->addr.sun_path, sizeof (s->addr.sun_path),
|
||||||
"%s/%s", runtime_dir, name) + 1;
|
"%s/%s", runtime_dir, name) + 1;
|
||||||
|
|
||||||
s->core_name = (s->addr.sun_path + name_size - 1) - strlen (name);
|
s->core_name = (s->addr.sun_path + name_size - 1) - strlen (name);
|
||||||
|
|
||||||
|
|
@ -434,10 +576,8 @@ pinos_protocol_native_new (PinosCore *core,
|
||||||
pinos_signal_add (&core->global_added, &impl->global_added, on_global_added);
|
pinos_signal_add (&core->global_added, &impl->global_added, on_global_added);
|
||||||
pinos_signal_add (&core->global_removed, &impl->global_removed, on_global_removed);
|
pinos_signal_add (&core->global_removed, &impl->global_removed, on_global_removed);
|
||||||
|
|
||||||
impl->uri.protocol_native = spa_id_map_get_id (core->uri.map, PINOS_PROTOCOL_NATIVE_URI);
|
|
||||||
|
|
||||||
impl->global = pinos_core_add_global (core,
|
impl->global = pinos_core_add_global (core,
|
||||||
impl->uri.protocol_native,
|
core->uri.module,
|
||||||
impl);
|
impl);
|
||||||
return impl;
|
return impl;
|
||||||
|
|
||||||
|
|
@ -472,5 +612,5 @@ bool
|
||||||
pinos__module_init (PinosModule * module, const char * args)
|
pinos__module_init (PinosModule * module, const char * args)
|
||||||
{
|
{
|
||||||
pinos_protocol_native_new (module->core, NULL);
|
pinos_protocol_native_new (module->core, NULL);
|
||||||
return TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,18 +26,11 @@
|
||||||
#include "pinos/server/core.h"
|
#include "pinos/server/core.h"
|
||||||
#include "pinos/server/module.h"
|
#include "pinos/server/module.h"
|
||||||
|
|
||||||
#define MODULE_URI "http://pinos.org/ns/module-suspend-on-idle"
|
|
||||||
#define MODULE_PREFIX MODULE_URI "#"
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PinosCore *core;
|
PinosCore *core;
|
||||||
PinosProperties *properties;
|
PinosProperties *properties;
|
||||||
PinosGlobal *global;
|
PinosGlobal *global;
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t module;
|
|
||||||
} uri;
|
|
||||||
|
|
||||||
PinosListener global_added;
|
PinosListener global_added;
|
||||||
PinosListener global_removed;
|
PinosListener global_removed;
|
||||||
PinosListener node_state_request;
|
PinosListener node_state_request;
|
||||||
|
|
@ -196,10 +189,8 @@ module_new (PinosCore *core,
|
||||||
pinos_signal_add (&core->node_state_request, &impl->node_state_request, on_node_state_request);
|
pinos_signal_add (&core->node_state_request, &impl->node_state_request, on_node_state_request);
|
||||||
pinos_signal_add (&core->node_state_changed, &impl->node_state_changed, on_node_state_changed);
|
pinos_signal_add (&core->node_state_changed, &impl->node_state_changed, on_node_state_changed);
|
||||||
|
|
||||||
impl->uri.module = spa_id_map_get_id (core->uri.map, MODULE_URI);
|
|
||||||
|
|
||||||
impl->global = pinos_core_add_global (core,
|
impl->global = pinos_core_add_global (core,
|
||||||
impl->uri.module,
|
core->uri.module,
|
||||||
impl);
|
impl);
|
||||||
return impl;
|
return impl;
|
||||||
}
|
}
|
||||||
|
|
@ -221,5 +212,5 @@ bool
|
||||||
pinos__module_init (PinosModule * module, const char * args)
|
pinos__module_init (PinosModule * module, const char * args)
|
||||||
{
|
{
|
||||||
module_new (module->core, NULL);
|
module_new (module->core, NULL);
|
||||||
return TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,5 +89,5 @@ pinos__module_init (PinosModule * module, const char * args)
|
||||||
"videotestsrc",
|
"videotestsrc",
|
||||||
video_props);
|
video_props);
|
||||||
|
|
||||||
return TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@
|
||||||
#include <sys/eventfd.h>
|
#include <sys/eventfd.h>
|
||||||
|
|
||||||
#include "pinos/client/pinos.h"
|
#include "pinos/client/pinos.h"
|
||||||
#include "pinos/client/private.h"
|
|
||||||
#include "pinos/client/connection.h"
|
#include "pinos/client/connection.h"
|
||||||
#include "pinos/client/serialize.h"
|
#include "pinos/client/serialize.h"
|
||||||
#include "pinos/client/transport.h"
|
#include "pinos/client/transport.h"
|
||||||
|
|
@ -99,8 +98,7 @@ struct _SpaProxy
|
||||||
SpaNodeEventCallback event_cb;
|
SpaNodeEventCallback event_cb;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
|
|
||||||
SpaSource ctrl_source;
|
PinosResource *resource;
|
||||||
PinosConnection *conn;
|
|
||||||
|
|
||||||
SpaSource data_source;
|
SpaSource data_source;
|
||||||
|
|
||||||
|
|
@ -125,7 +123,6 @@ typedef struct
|
||||||
PinosListener transport_changed;
|
PinosListener transport_changed;
|
||||||
PinosListener loop_changed;
|
PinosListener loop_changed;
|
||||||
|
|
||||||
int ctrl_fd;
|
|
||||||
int data_fd;
|
int data_fd;
|
||||||
} PinosClientNodeImpl;
|
} PinosClientNodeImpl;
|
||||||
|
|
||||||
|
|
@ -195,13 +192,11 @@ spa_proxy_node_send_command (SpaNode *node,
|
||||||
/* send start */
|
/* send start */
|
||||||
cnc.seq = this->seq++;
|
cnc.seq = this->seq++;
|
||||||
cnc.command = command;
|
cnc.command = command;
|
||||||
pinos_connection_add_message (this->conn, PINOS_MESSAGE_NODE_COMMAND, &cnc);
|
pinos_resource_send_message (this->resource,
|
||||||
|
PINOS_MESSAGE_NODE_COMMAND,
|
||||||
if (!pinos_connection_flush (this->conn)) {
|
&cnc,
|
||||||
spa_log_error (this->log, "proxy %p: error writing connection", this);
|
true);
|
||||||
res = SPA_RESULT_ERROR;
|
res = SPA_RESULT_RETURN_ASYNC (cnc.seq);
|
||||||
} else
|
|
||||||
res = SPA_RESULT_RETURN_ASYNC (cnc.seq);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,12 +206,10 @@ spa_proxy_node_send_command (SpaNode *node,
|
||||||
|
|
||||||
/* send start */
|
/* send start */
|
||||||
cnc.command = command;
|
cnc.command = command;
|
||||||
pinos_connection_add_message (this->conn, PINOS_MESSAGE_NODE_COMMAND, &cnc);
|
pinos_resource_send_message (this->resource,
|
||||||
|
PINOS_MESSAGE_NODE_COMMAND,
|
||||||
if (!pinos_connection_flush (this->conn)) {
|
&cnc,
|
||||||
spa_log_error (this->log, "proxy %p: error writing connection", this);
|
true);
|
||||||
res = SPA_RESULT_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -489,11 +482,10 @@ spa_proxy_node_port_set_format (SpaNode *node,
|
||||||
sf.port_id = port_id;
|
sf.port_id = port_id;
|
||||||
sf.flags = flags;
|
sf.flags = flags;
|
||||||
sf.format = (SpaFormat *) format;
|
sf.format = (SpaFormat *) format;
|
||||||
pinos_connection_add_message (this->conn, PINOS_MESSAGE_SET_FORMAT, &sf);
|
pinos_resource_send_message (this->resource,
|
||||||
|
PINOS_MESSAGE_SET_FORMAT,
|
||||||
if (!pinos_connection_flush (this->conn))
|
&sf,
|
||||||
spa_log_error (this->log, "proxy %p: error writing connection", this);
|
true);
|
||||||
|
|
||||||
return SPA_RESULT_RETURN_ASYNC (sf.seq);
|
return SPA_RESULT_RETURN_ASYNC (sf.seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -668,12 +660,14 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
|
||||||
am.port_id = port_id;
|
am.port_id = port_id;
|
||||||
am.mem_id = n_mem;
|
am.mem_id = n_mem;
|
||||||
am.type = d->type;
|
am.type = d->type;
|
||||||
am.fd_index = pinos_connection_add_fd (this->conn, d->fd, false);
|
am.memfd = d->fd;
|
||||||
am.flags = d->flags;
|
am.flags = d->flags;
|
||||||
am.offset = d->offset;
|
am.offset = d->offset;
|
||||||
am.size = d->maxsize;
|
am.size = d->maxsize;
|
||||||
pinos_connection_add_message (this->conn, PINOS_MESSAGE_ADD_MEM, &am);
|
pinos_resource_send_message (this->resource,
|
||||||
|
PINOS_MESSAGE_ADD_MEM,
|
||||||
|
&am,
|
||||||
|
false);
|
||||||
b->buffer.datas[j].type = SPA_DATA_TYPE_ID;
|
b->buffer.datas[j].type = SPA_DATA_TYPE_ID;
|
||||||
b->buffer.datas[j].data = SPA_UINT32_TO_PTR (n_mem);
|
b->buffer.datas[j].data = SPA_UINT32_TO_PTR (n_mem);
|
||||||
n_mem++;
|
n_mem++;
|
||||||
|
|
@ -732,11 +726,14 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
|
||||||
am.port_id = port_id;
|
am.port_id = port_id;
|
||||||
am.mem_id = port->buffer_mem_id;
|
am.mem_id = port->buffer_mem_id;
|
||||||
am.type = SPA_DATA_TYPE_MEMFD;
|
am.type = SPA_DATA_TYPE_MEMFD;
|
||||||
am.fd_index = pinos_connection_add_fd (this->conn, port->buffer_mem.fd, false);
|
am.memfd = port->buffer_mem.fd;
|
||||||
am.flags = 0;
|
am.flags = 0;
|
||||||
am.offset = 0;
|
am.offset = 0;
|
||||||
am.size = size;
|
am.size = size;
|
||||||
pinos_connection_add_message (this->conn, PINOS_MESSAGE_ADD_MEM, &am);
|
pinos_resource_send_message (this->resource,
|
||||||
|
PINOS_MESSAGE_ADD_MEM,
|
||||||
|
&am,
|
||||||
|
false);
|
||||||
|
|
||||||
memref = alloca (n_buffers * sizeof (PinosMessageMemRef));
|
memref = alloca (n_buffers * sizeof (PinosMessageMemRef));
|
||||||
for (i = 0; i < n_buffers; i++) {
|
for (i = 0; i < n_buffers; i++) {
|
||||||
|
|
@ -754,11 +751,10 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
|
||||||
ub.port_id = port_id;
|
ub.port_id = port_id;
|
||||||
ub.n_buffers = n_buffers;
|
ub.n_buffers = n_buffers;
|
||||||
ub.buffers = memref;
|
ub.buffers = memref;
|
||||||
pinos_connection_add_message (this->conn, PINOS_MESSAGE_USE_BUFFERS, &ub);
|
pinos_resource_send_message (this->resource,
|
||||||
|
PINOS_MESSAGE_USE_BUFFERS,
|
||||||
if (!pinos_connection_flush (this->conn))
|
&ub,
|
||||||
spa_log_error (this->log, "proxy %p: error writing connection", this);
|
true);
|
||||||
|
|
||||||
return SPA_RESULT_RETURN_ASYNC (ub.seq);
|
return SPA_RESULT_RETURN_ASYNC (ub.seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -983,118 +979,95 @@ handle_node_event (SpaProxy *this,
|
||||||
}
|
}
|
||||||
|
|
||||||
static SpaResult
|
static SpaResult
|
||||||
parse_connection (SpaProxy *this)
|
client_node_dispatch_func (void *object,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
PinosConnection *conn = this->conn;
|
PinosClientNode *node = data;
|
||||||
|
PinosClientNodeImpl *impl = SPA_CONTAINER_OF (node, PinosClientNodeImpl, this);
|
||||||
|
SpaProxy *this = &impl->proxy;
|
||||||
|
|
||||||
while (pinos_connection_has_next (conn)) {
|
switch (type) {
|
||||||
PinosMessageType type = pinos_connection_get_type (conn);
|
case PINOS_MESSAGE_INVALID:
|
||||||
|
case PINOS_MESSAGE_ADD_PORT:
|
||||||
|
case PINOS_MESSAGE_REMOVE_PORT:
|
||||||
|
case PINOS_MESSAGE_SET_FORMAT:
|
||||||
|
case PINOS_MESSAGE_SET_PROPERTY:
|
||||||
|
case PINOS_MESSAGE_NODE_COMMAND:
|
||||||
|
case PINOS_MESSAGE_PORT_COMMAND:
|
||||||
|
case PINOS_MESSAGE_TRANSPORT_UPDATE:
|
||||||
|
spa_log_error (this->log, "proxy %p: got unexpected command %d", this, type);
|
||||||
|
break;
|
||||||
|
|
||||||
switch (type) {
|
case PINOS_MESSAGE_NODE_UPDATE:
|
||||||
case PINOS_MESSAGE_INVALID:
|
{
|
||||||
case PINOS_MESSAGE_ADD_PORT:
|
PinosMessageNodeUpdate *nu = message;
|
||||||
case PINOS_MESSAGE_REMOVE_PORT:
|
|
||||||
case PINOS_MESSAGE_SET_FORMAT:
|
if (nu->change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_INPUTS)
|
||||||
case PINOS_MESSAGE_SET_PROPERTY:
|
this->max_inputs = nu->max_input_ports;
|
||||||
case PINOS_MESSAGE_NODE_COMMAND:
|
if (nu->change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_OUTPUTS)
|
||||||
case PINOS_MESSAGE_PORT_COMMAND:
|
this->max_outputs = nu->max_output_ports;
|
||||||
case PINOS_MESSAGE_PROCESS_BUFFER:
|
|
||||||
case PINOS_MESSAGE_TRANSPORT_UPDATE:
|
spa_log_info (this->log, "proxy %p: got node update %d, max_in %u, max_out %u", this, type,
|
||||||
spa_log_error (this->log, "proxy %p: got unexpected command %d", this, type);
|
this->max_inputs, this->max_outputs);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PINOS_MESSAGE_PORT_UPDATE:
|
||||||
|
{
|
||||||
|
PinosMessagePortUpdate *pu = message;
|
||||||
|
bool remove;
|
||||||
|
|
||||||
|
spa_log_info (this->log, "proxy %p: got port update %d", this, type);
|
||||||
|
if (!CHECK_PORT_ID (this, pu->direction, pu->port_id))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_NODE_UPDATE:
|
remove = (pu->change_mask == 0);
|
||||||
{
|
|
||||||
PinosMessageNodeUpdate nu;
|
|
||||||
|
|
||||||
if (!pinos_connection_parse_message (conn, &nu))
|
if (remove) {
|
||||||
break;
|
do_uninit_port (this, pu->direction, pu->port_id);
|
||||||
|
} else {
|
||||||
if (nu.change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_INPUTS)
|
do_update_port (this, pu);
|
||||||
this->max_inputs = nu.max_input_ports;
|
|
||||||
if (nu.change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_OUTPUTS)
|
|
||||||
this->max_outputs = nu.max_output_ports;
|
|
||||||
|
|
||||||
spa_log_info (this->log, "proxy %p: got node update %d, max_in %u, max_out %u", this, type,
|
|
||||||
this->max_inputs, this->max_outputs);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PINOS_MESSAGE_PORT_UPDATE:
|
case PINOS_MESSAGE_PORT_STATUS_CHANGE:
|
||||||
{
|
{
|
||||||
PinosMessagePortUpdate pu;
|
spa_log_warn (this->log, "proxy %p: command not implemented %d", this, type);
|
||||||
bool remove;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
spa_log_info (this->log, "proxy %p: got port update %d", this, type);
|
case PINOS_MESSAGE_NODE_STATE_CHANGE:
|
||||||
if (!pinos_connection_parse_message (conn, &pu))
|
{
|
||||||
break;
|
PinosMessageNodeStateChange *sc = message;
|
||||||
|
SpaNodeState old = this->node.state;
|
||||||
|
|
||||||
if (!CHECK_PORT_ID (this, pu.direction, pu.port_id))
|
spa_log_info (this->log, "proxy %p: got node state change %d -> %d", this, old, sc->state);
|
||||||
break;
|
this->node.state = sc->state;
|
||||||
|
if (old == SPA_NODE_STATE_INIT)
|
||||||
|
send_async_complete (this, 0, SPA_RESULT_OK);
|
||||||
|
|
||||||
remove = (pu.change_mask == 0);
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (remove) {
|
case PINOS_MESSAGE_ADD_MEM:
|
||||||
do_uninit_port (this, pu.direction, pu.port_id);
|
break;
|
||||||
} else {
|
case PINOS_MESSAGE_USE_BUFFERS:
|
||||||
do_update_port (this, &pu);
|
break;
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PINOS_MESSAGE_PORT_STATUS_CHANGE:
|
case PINOS_MESSAGE_NODE_EVENT:
|
||||||
{
|
{
|
||||||
spa_log_warn (this->log, "proxy %p: command not implemented %d", this, type);
|
PinosMessageNodeEvent *cne = message;
|
||||||
break;
|
handle_node_event (this, cne->event);
|
||||||
}
|
break;
|
||||||
|
|
||||||
case PINOS_MESSAGE_NODE_STATE_CHANGE:
|
|
||||||
{
|
|
||||||
PinosMessageNodeStateChange sc;
|
|
||||||
SpaNodeState old = this->node.state;
|
|
||||||
|
|
||||||
if (!pinos_connection_parse_message (conn, &sc))
|
|
||||||
break;
|
|
||||||
|
|
||||||
spa_log_info (this->log, "proxy %p: got node state change %d -> %d", this, old, sc.state);
|
|
||||||
this->node.state = sc.state;
|
|
||||||
if (old == SPA_NODE_STATE_INIT)
|
|
||||||
send_async_complete (this, 0, SPA_RESULT_OK);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PINOS_MESSAGE_ADD_MEM:
|
|
||||||
break;
|
|
||||||
case PINOS_MESSAGE_USE_BUFFERS:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PINOS_MESSAGE_NODE_EVENT:
|
|
||||||
{
|
|
||||||
PinosMessageNodeEvent cne;
|
|
||||||
|
|
||||||
if (!pinos_connection_parse_message (conn, &cne))
|
|
||||||
break;
|
|
||||||
|
|
||||||
handle_node_event (this, cne.event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SPA_RESULT_OK;
|
return SPA_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
proxy_on_fd_events (SpaSource *source)
|
|
||||||
{
|
|
||||||
SpaProxy *this = source->data;
|
|
||||||
|
|
||||||
if (source->rmask & SPA_IO_IN)
|
|
||||||
parse_connection (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
proxy_on_data_fd_events (SpaSource *source)
|
proxy_on_data_fd_events (SpaSource *source)
|
||||||
{
|
{
|
||||||
|
|
@ -1184,16 +1157,10 @@ proxy_init (SpaProxy *this,
|
||||||
|
|
||||||
this->node = proxy_node;
|
this->node = proxy_node;
|
||||||
|
|
||||||
this->ctrl_source.func = proxy_on_fd_events;
|
|
||||||
this->ctrl_source.data = this;
|
|
||||||
this->ctrl_source.fd = -1;
|
|
||||||
this->ctrl_source.mask = SPA_IO_IN | SPA_IO_ERR;
|
|
||||||
this->ctrl_source.rmask = 0;
|
|
||||||
|
|
||||||
this->data_source.func = proxy_on_data_fd_events;
|
this->data_source.func = proxy_on_data_fd_events;
|
||||||
this->data_source.data = this;
|
this->data_source.data = this;
|
||||||
this->data_source.fd = -1;
|
this->data_source.fd = -1;
|
||||||
this->data_source.mask = SPA_IO_IN | SPA_IO_ERR;
|
this->data_source.mask = SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP;
|
||||||
this->data_source.rmask = 0;
|
this->data_source.rmask = 0;
|
||||||
|
|
||||||
return SPA_RESULT_RETURN_ASYNC (this->seq++);
|
return SPA_RESULT_RETURN_ASYNC (this->seq++);
|
||||||
|
|
@ -1207,17 +1174,16 @@ on_transport_changed (PinosListener *listener,
|
||||||
PinosClientNode *this = &impl->this;
|
PinosClientNode *this = &impl->this;
|
||||||
PinosTransportInfo info;
|
PinosTransportInfo info;
|
||||||
PinosMessageTransportUpdate tu;
|
PinosMessageTransportUpdate tu;
|
||||||
PinosConnection *conn = impl->proxy.conn;
|
|
||||||
|
|
||||||
pinos_transport_get_info (node->transport, &info);
|
pinos_transport_get_info (node->transport, &info);
|
||||||
|
|
||||||
tu.memfd_index = pinos_connection_add_fd (conn, info.memfd, false);
|
tu.memfd = info.memfd;
|
||||||
tu.offset = info.offset;
|
tu.offset = info.offset;
|
||||||
tu.size = info.size;
|
tu.size = info.size;
|
||||||
pinos_connection_add_message (conn, PINOS_MESSAGE_TRANSPORT_UPDATE, &tu);
|
pinos_resource_send_message (this->resource,
|
||||||
|
PINOS_MESSAGE_TRANSPORT_UPDATE,
|
||||||
if (!pinos_connection_flush (conn))
|
&tu,
|
||||||
pinos_log_error ("client-node %p: error writing connection", this);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -1241,10 +1207,6 @@ proxy_clear (SpaProxy *this)
|
||||||
if (this->out_ports[i].valid)
|
if (this->out_ports[i].valid)
|
||||||
clear_port (this, &this->out_ports[i], SPA_DIRECTION_OUTPUT, i);
|
clear_port (this, &this->out_ports[i], SPA_DIRECTION_OUTPUT, i);
|
||||||
}
|
}
|
||||||
if (this->ctrl_source.fd != -1) {
|
|
||||||
spa_loop_remove_source (this->main_loop, &this->ctrl_source);
|
|
||||||
close (this->ctrl_source.fd);
|
|
||||||
}
|
|
||||||
if (this->data_source.fd != -1) {
|
if (this->data_source.fd != -1) {
|
||||||
spa_loop_remove_source (this->data_loop, &this->data_source);
|
spa_loop_remove_source (this->data_loop, &this->data_source);
|
||||||
close (this->data_source.fd);
|
close (this->data_source.fd);
|
||||||
|
|
@ -1264,25 +1226,25 @@ proxy_clear (SpaProxy *this)
|
||||||
* Returns: a new #PinosNode
|
* Returns: a new #PinosNode
|
||||||
*/
|
*/
|
||||||
PinosClientNode *
|
PinosClientNode *
|
||||||
pinos_client_node_new (PinosCore *core,
|
pinos_client_node_new (PinosClient *client,
|
||||||
const gchar *name,
|
uint32_t id,
|
||||||
|
const char *name,
|
||||||
PinosProperties *properties)
|
PinosProperties *properties)
|
||||||
{
|
{
|
||||||
PinosClientNodeImpl *impl;
|
PinosClientNodeImpl *impl;
|
||||||
PinosClientNode *this;
|
PinosClientNode *this;
|
||||||
|
|
||||||
impl = calloc (1, sizeof (PinosClientNodeImpl));
|
impl = calloc (1, sizeof (PinosClientNodeImpl));
|
||||||
impl->core = core;
|
|
||||||
impl->ctrl_fd = -1;
|
|
||||||
impl->data_fd = -1;
|
|
||||||
this = &impl->this;
|
this = &impl->this;
|
||||||
|
impl->core = client->core;
|
||||||
|
impl->data_fd = -1;
|
||||||
pinos_log_debug ("client-node %p: new", impl);
|
pinos_log_debug ("client-node %p: new", impl);
|
||||||
|
|
||||||
pinos_signal_init (&this->destroy_signal);
|
pinos_signal_init (&this->destroy_signal);
|
||||||
|
|
||||||
proxy_init (&impl->proxy, NULL, core->support, core->n_support);
|
proxy_init (&impl->proxy, NULL, client->core->support, client->core->n_support);
|
||||||
|
|
||||||
this->node = pinos_node_new (core,
|
this->node = pinos_node_new (client->core,
|
||||||
name,
|
name,
|
||||||
&impl->proxy.node,
|
&impl->proxy.node,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
@ -1298,12 +1260,22 @@ pinos_client_node_new (PinosCore *core,
|
||||||
&impl->loop_changed,
|
&impl->loop_changed,
|
||||||
on_loop_changed);
|
on_loop_changed);
|
||||||
|
|
||||||
|
this->resource = pinos_resource_new (client,
|
||||||
|
id,
|
||||||
|
client->core->uri.client_node,
|
||||||
|
this,
|
||||||
|
(PinosDestroy) pinos_client_node_destroy);
|
||||||
|
impl->proxy.resource = this->resource;
|
||||||
|
|
||||||
|
this->resource->dispatch_func = client_node_dispatch_func;
|
||||||
|
this->resource->dispatch_data = this;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_node_remove (PinosNode *node,
|
on_node_remove (PinosNode *node,
|
||||||
gpointer data,
|
void *data,
|
||||||
SpaResult res)
|
SpaResult res)
|
||||||
{
|
{
|
||||||
PinosClientNode *this = data;
|
PinosClientNode *this = data;
|
||||||
|
|
@ -1312,8 +1284,6 @@ on_node_remove (PinosNode *node,
|
||||||
pinos_log_debug ("client-node %p: finalize", node);
|
pinos_log_debug ("client-node %p: finalize", node);
|
||||||
proxy_clear (&impl->proxy);
|
proxy_clear (&impl->proxy);
|
||||||
|
|
||||||
if (impl->ctrl_fd != -1)
|
|
||||||
close (impl->ctrl_fd);
|
|
||||||
if (impl->data_fd != -1)
|
if (impl->data_fd != -1)
|
||||||
close (impl->data_fd);
|
close (impl->data_fd);
|
||||||
free (impl);
|
free (impl);
|
||||||
|
|
@ -1340,37 +1310,6 @@ pinos_client_node_destroy (PinosClientNode * this)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* pinos_client_node_get_ctrl_socket:
|
|
||||||
* @node: a #PinosClientNode
|
|
||||||
* @fd: a result socket
|
|
||||||
*
|
|
||||||
* Create or return a previously create socket pair for @node. The
|
|
||||||
* socket for the other end is returned.
|
|
||||||
*
|
|
||||||
* Returns: %SPA_RESULT_OK on success
|
|
||||||
*/
|
|
||||||
SpaResult
|
|
||||||
pinos_client_node_get_ctrl_socket (PinosClientNode *this,
|
|
||||||
int *fd)
|
|
||||||
{
|
|
||||||
PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, this);
|
|
||||||
|
|
||||||
if (impl->ctrl_fd == -1) {
|
|
||||||
int fd[2];
|
|
||||||
|
|
||||||
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, fd) != 0)
|
|
||||||
return SPA_RESULT_ERRNO;
|
|
||||||
|
|
||||||
impl->proxy.ctrl_source.fd = fd[0];
|
|
||||||
impl->proxy.conn = pinos_connection_new (impl->proxy.ctrl_source.fd);
|
|
||||||
spa_loop_add_source (impl->proxy.main_loop, &impl->proxy.ctrl_source);
|
|
||||||
impl->ctrl_fd = fd[1];
|
|
||||||
}
|
|
||||||
*fd = impl->ctrl_fd;
|
|
||||||
return SPA_RESULT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pinos_client_node_get_data_socket:
|
* pinos_client_node_get_data_socket:
|
||||||
* @node: a #PinosClientNode
|
* @node: a #PinosClientNode
|
||||||
|
|
@ -1390,11 +1329,12 @@ pinos_client_node_get_data_socket (PinosClientNode *this,
|
||||||
if (impl->data_fd == -1) {
|
if (impl->data_fd == -1) {
|
||||||
int fd[2];
|
int fd[2];
|
||||||
|
|
||||||
if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) != 0)
|
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fd) != 0)
|
||||||
return SPA_RESULT_ERRNO;
|
return SPA_RESULT_ERRNO;
|
||||||
|
|
||||||
impl->proxy.data_source.fd = fd[0];
|
impl->proxy.data_source.fd = fd[0];
|
||||||
spa_loop_add_source (impl->proxy.data_loop, &impl->proxy.data_source);
|
spa_loop_add_source (impl->proxy.data_loop, &impl->proxy.data_source);
|
||||||
|
pinos_log_debug ("client-node %p: add data fd %d", this, fd[0]);
|
||||||
impl->data_fd = fd[1];
|
impl->data_fd = fd[1];
|
||||||
}
|
}
|
||||||
*fd = impl->data_fd;
|
*fd = impl->data_fd;
|
||||||
|
|
|
||||||
|
|
@ -39,18 +39,25 @@ typedef struct _PinosClientNode PinosClientNode;
|
||||||
struct _PinosClientNode {
|
struct _PinosClientNode {
|
||||||
PinosNode *node;
|
PinosNode *node;
|
||||||
|
|
||||||
|
PinosClient *client;
|
||||||
|
PinosResource *resource;
|
||||||
|
|
||||||
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
||||||
PinosClientNode *node));
|
PinosClientNode *node));
|
||||||
};
|
};
|
||||||
|
|
||||||
PinosClientNode * pinos_client_node_new (PinosCore *core,
|
PinosClientNode * pinos_client_node_new (PinosClient *client,
|
||||||
const gchar *name,
|
uint32_t id,
|
||||||
|
const char *name,
|
||||||
PinosProperties *properties);
|
PinosProperties *properties);
|
||||||
SpaResult pinos_client_node_destroy (PinosClientNode *node);
|
SpaResult pinos_client_node_destroy (PinosClientNode *node);
|
||||||
|
|
||||||
SpaResult pinos_client_node_get_ctrl_socket (PinosClientNode *node, int *fd);
|
|
||||||
SpaResult pinos_client_node_get_data_socket (PinosClientNode *node, int *fd);
|
SpaResult pinos_client_node_get_data_socket (PinosClientNode *node, int *fd);
|
||||||
|
|
||||||
|
SpaResult pinos_client_node_dispatch_message (PinosClientNode *node,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -21,55 +21,13 @@
|
||||||
#include "pinos/client/pinos.h"
|
#include "pinos/client/pinos.h"
|
||||||
|
|
||||||
#include "pinos/server/client.h"
|
#include "pinos/server/client.h"
|
||||||
|
#include "pinos/server/resource.h"
|
||||||
#include "pinos/dbus/org-pinos.h"
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
PinosClient this;
|
PinosClient this;
|
||||||
} PinosClientImpl;
|
} PinosClientImpl;
|
||||||
|
|
||||||
PinosResource *
|
|
||||||
pinos_client_add_resource (PinosClient *client,
|
|
||||||
uint32_t type,
|
|
||||||
void *object,
|
|
||||||
PinosDestroy destroy)
|
|
||||||
{
|
|
||||||
PinosResource *resource;
|
|
||||||
|
|
||||||
resource = calloc (1, sizeof (PinosResource));
|
|
||||||
resource->core = client->core;
|
|
||||||
resource->client = client;
|
|
||||||
resource->id = 0;
|
|
||||||
resource->type = type;
|
|
||||||
resource->object = object;
|
|
||||||
resource->destroy = destroy;
|
|
||||||
|
|
||||||
pinos_signal_init (&resource->destroy_signal);
|
|
||||||
|
|
||||||
pinos_log_debug ("client %p: add resource %p", client, resource);
|
|
||||||
|
|
||||||
spa_list_insert (client->resource_list.prev, &resource->link);
|
|
||||||
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
SpaResult
|
|
||||||
pinos_resource_destroy (PinosResource *resource)
|
|
||||||
{
|
|
||||||
pinos_log_debug ("resource %p: destroy", resource);
|
|
||||||
pinos_signal_emit (&resource->destroy_signal, resource);
|
|
||||||
|
|
||||||
spa_list_remove (&resource->link);
|
|
||||||
|
|
||||||
if (resource->destroy)
|
|
||||||
resource->destroy (resource->object);
|
|
||||||
|
|
||||||
free (resource);
|
|
||||||
|
|
||||||
return SPA_RESULT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pinos_client_new:
|
* pinos_client_new:
|
||||||
* @daemon: a #PinosDaemon
|
* @daemon: a #PinosDaemon
|
||||||
|
|
|
||||||
|
|
@ -28,26 +28,9 @@ extern "C" {
|
||||||
#define PINOS_CLIENT_PREFIX PINOS_CLIENT_URI "#"
|
#define PINOS_CLIENT_PREFIX PINOS_CLIENT_URI "#"
|
||||||
|
|
||||||
typedef struct _PinosClient PinosClient;
|
typedef struct _PinosClient PinosClient;
|
||||||
typedef struct _PinosResource PinosResource;
|
|
||||||
|
|
||||||
typedef void (*PinosDestroy) (void *object);
|
|
||||||
|
|
||||||
#include <pinos/server/core.h>
|
#include <pinos/server/core.h>
|
||||||
|
#include <pinos/server/resource.h>
|
||||||
struct _PinosResource {
|
|
||||||
PinosCore *core;
|
|
||||||
SpaList link;
|
|
||||||
|
|
||||||
PinosClient *client;
|
|
||||||
|
|
||||||
uint32_t id;
|
|
||||||
uint32_t type;
|
|
||||||
void *object;
|
|
||||||
PinosDestroy destroy;
|
|
||||||
|
|
||||||
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
|
||||||
PinosResource *resource));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PinosClient:
|
* PinosClient:
|
||||||
|
|
@ -63,6 +46,9 @@ struct _PinosClient {
|
||||||
|
|
||||||
SpaList resource_list;
|
SpaList resource_list;
|
||||||
|
|
||||||
|
PinosSendFunc send_func;
|
||||||
|
void *send_data;
|
||||||
|
|
||||||
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
||||||
PinosClient *client));
|
PinosClient *client));
|
||||||
};
|
};
|
||||||
|
|
@ -71,14 +57,6 @@ PinosClient * pinos_client_new (PinosCore *core,
|
||||||
PinosProperties *properties);
|
PinosProperties *properties);
|
||||||
SpaResult pinos_client_destroy (PinosClient *client);
|
SpaResult pinos_client_destroy (PinosClient *client);
|
||||||
|
|
||||||
|
|
||||||
PinosResource * pinos_client_add_resource (PinosClient *client,
|
|
||||||
uint32_t type,
|
|
||||||
void *object,
|
|
||||||
PinosDestroy destroy);
|
|
||||||
|
|
||||||
SpaResult pinos_resource_destroy (PinosResource *resource);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,17 @@
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
|
||||||
typedef bool (*PinosCommandFunc) (PinosCommand *command,
|
typedef bool (*PinosCommandFunc) (PinosCommand *command,
|
||||||
PinosCore *core,
|
PinosCore *core,
|
||||||
char **err);
|
char **err);
|
||||||
|
|
||||||
static bool execute_command_module_load (PinosCommand *command,
|
static bool execute_command_module_load (PinosCommand *command,
|
||||||
PinosCore *core,
|
PinosCore *core,
|
||||||
|
char **err);
|
||||||
|
|
||||||
|
typedef PinosCommand * (*PinosCommandParseFunc) (const char *line,
|
||||||
char **err);
|
char **err);
|
||||||
|
|
||||||
typedef PinosCommand * (*PinosCommandParseFunc) (const gchar *line,
|
static PinosCommand * parse_command_module_load (const char *line,
|
||||||
char **err);
|
|
||||||
|
|
||||||
static PinosCommand * parse_command_module_load (const gchar *line,
|
|
||||||
char **err);
|
char **err);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
@ -51,7 +51,7 @@ typedef struct
|
||||||
|
|
||||||
typedef struct _CommandParse
|
typedef struct _CommandParse
|
||||||
{
|
{
|
||||||
const gchar *name;
|
const char *name;
|
||||||
PinosCommandParseFunc func;
|
PinosCommandParseFunc func;
|
||||||
} CommandParse;
|
} CommandParse;
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ static const CommandParse parsers[] = {
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const gchar whitespace[] = " \t";
|
static const char whitespace[] = " \t";
|
||||||
|
|
||||||
static PinosCommand *
|
static PinosCommand *
|
||||||
parse_command_module_load (const char * line, char ** err)
|
parse_command_module_load (const char * line, char ** err)
|
||||||
|
|
@ -130,8 +130,8 @@ pinos_command_parse (const char *line,
|
||||||
{
|
{
|
||||||
PinosCommand *command = NULL;
|
PinosCommand *command = NULL;
|
||||||
const CommandParse *parse;
|
const CommandParse *parse;
|
||||||
gchar *name;
|
char *name;
|
||||||
gsize len;
|
size_t len;
|
||||||
|
|
||||||
len = strcspn (line, whitespace);
|
len = strcspn (line, whitespace);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,10 @@ pinos_core_new (PinosMainLoop *main_loop)
|
||||||
pinos_signal_init (&this->node_unlink);
|
pinos_signal_init (&this->node_unlink);
|
||||||
pinos_signal_init (&this->node_unlink_done);
|
pinos_signal_init (&this->node_unlink_done);
|
||||||
|
|
||||||
|
this->global = pinos_core_add_global (this,
|
||||||
|
this->uri.core,
|
||||||
|
this);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ extern "C" {
|
||||||
typedef struct _PinosCore PinosCore;
|
typedef struct _PinosCore PinosCore;
|
||||||
typedef struct _PinosGlobal PinosGlobal;
|
typedef struct _PinosGlobal PinosGlobal;
|
||||||
|
|
||||||
|
#define PINOS_CORE_URI "http://pinos.org/ns/core"
|
||||||
|
#define PINOS_CORE_PREFIX PINOS_CORE_URI "#"
|
||||||
|
|
||||||
#include <spa/include/spa/log.h>
|
#include <spa/include/spa/log.h>
|
||||||
|
|
||||||
#include <pinos/server/main-loop.h>
|
#include <pinos/server/main-loop.h>
|
||||||
|
|
@ -53,6 +56,8 @@ struct _PinosGlobal {
|
||||||
* Pinos core object class.
|
* Pinos core object class.
|
||||||
*/
|
*/
|
||||||
struct _PinosCore {
|
struct _PinosCore {
|
||||||
|
PinosGlobal *global;
|
||||||
|
|
||||||
PinosURI uri;
|
PinosURI uri;
|
||||||
|
|
||||||
PinosMap objects;
|
PinosMap objects;
|
||||||
|
|
|
||||||
|
|
@ -95,9 +95,21 @@ do_add_source (SpaLoop *loop,
|
||||||
GIOChannel *channel;
|
GIOChannel *channel;
|
||||||
GSource *s;
|
GSource *s;
|
||||||
LoopData *data;
|
LoopData *data;
|
||||||
|
GIOCondition cond;
|
||||||
|
|
||||||
channel = g_io_channel_unix_new (source->fd);
|
channel = g_io_channel_unix_new (source->fd);
|
||||||
s = g_io_create_watch (channel, G_IO_IN);
|
|
||||||
|
cond = 0;
|
||||||
|
if (source->mask & SPA_IO_IN)
|
||||||
|
cond |= G_IO_IN;
|
||||||
|
if (source->mask & SPA_IO_OUT)
|
||||||
|
cond |= G_IO_OUT;
|
||||||
|
if (source->mask & SPA_IO_ERR)
|
||||||
|
cond |= G_IO_ERR;
|
||||||
|
if (source->mask & SPA_IO_HUP)
|
||||||
|
cond |= G_IO_HUP;
|
||||||
|
|
||||||
|
s = g_io_create_watch (channel, cond);
|
||||||
g_io_channel_unref (channel);
|
g_io_channel_unref (channel);
|
||||||
|
|
||||||
data = g_new0 (LoopData, 1);
|
data = g_new0 (LoopData, 1);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ pinoscore_headers = [
|
||||||
'node.h',
|
'node.h',
|
||||||
'node-factory.h',
|
'node-factory.h',
|
||||||
'port.h',
|
'port.h',
|
||||||
|
'resource.h',
|
||||||
'uri.h',
|
'uri.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -25,6 +26,7 @@ pinoscore_sources = [
|
||||||
'node.c',
|
'node.c',
|
||||||
'node-factory.c',
|
'node-factory.c',
|
||||||
'port.c',
|
'port.c',
|
||||||
|
'resource.c',
|
||||||
'uri.c',
|
'uri.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
#include "pinos/client/pinos.h"
|
#include "pinos/client/pinos.h"
|
||||||
#include "pinos/client/utils.h"
|
#include "pinos/client/utils.h"
|
||||||
|
|
@ -40,7 +41,7 @@ typedef struct
|
||||||
static char *
|
static char *
|
||||||
find_module (const char * path, const char *name)
|
find_module (const char * path, const char *name)
|
||||||
{
|
{
|
||||||
gchar *filename;
|
char *filename;
|
||||||
GDir *dir;
|
GDir *dir;
|
||||||
const gchar *entry;
|
const gchar *entry;
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ extern "C" {
|
||||||
|
|
||||||
#include <pinos/server/core.h>
|
#include <pinos/server/core.h>
|
||||||
|
|
||||||
|
#define PINOS_MODULE_URI "http://pinos.org/ns/module"
|
||||||
|
#define PINOS_MODULE_PREFIX PINOS_MODULE_URI "#"
|
||||||
|
|
||||||
typedef struct _PinosModule PinosModule;
|
typedef struct _PinosModule PinosModule;
|
||||||
|
|
||||||
struct _PinosModule {
|
struct _PinosModule {
|
||||||
|
|
@ -52,8 +55,8 @@ struct _PinosModule {
|
||||||
typedef bool (*PinosModuleInitFunc) (PinosModule *module, char *args);
|
typedef bool (*PinosModuleInitFunc) (PinosModule *module, char *args);
|
||||||
|
|
||||||
PinosModule * pinos_module_load (PinosCore *core,
|
PinosModule * pinos_module_load (PinosCore *core,
|
||||||
const gchar *name,
|
const char *name,
|
||||||
const gchar *args,
|
const char *args,
|
||||||
char **err);
|
char **err);
|
||||||
void pinos_module_destroy (PinosModule *module);
|
void pinos_module_destroy (PinosModule *module);
|
||||||
|
|
||||||
|
|
|
||||||
86
pinos/server/resource.c
Normal file
86
pinos/server/resource.c
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
/* Pinos
|
||||||
|
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "pinos/server/resource.h"
|
||||||
|
|
||||||
|
PinosResource *
|
||||||
|
pinos_resource_new (PinosClient *client,
|
||||||
|
uint32_t id,
|
||||||
|
uint32_t type,
|
||||||
|
void *object,
|
||||||
|
PinosDestroy destroy)
|
||||||
|
{
|
||||||
|
PinosResource *resource;
|
||||||
|
|
||||||
|
resource = calloc (1, sizeof (PinosResource));
|
||||||
|
pinos_log_debug ("resource %p: new for client %p", resource, client);
|
||||||
|
|
||||||
|
resource->core = client->core;
|
||||||
|
resource->client = client;
|
||||||
|
resource->id = id;
|
||||||
|
resource->type = type;
|
||||||
|
resource->object = object;
|
||||||
|
resource->destroy = destroy;
|
||||||
|
|
||||||
|
resource->send_func = client->send_func;
|
||||||
|
resource->send_data = client->send_data;
|
||||||
|
|
||||||
|
pinos_signal_init (&resource->destroy_signal);
|
||||||
|
|
||||||
|
spa_list_insert (client->resource_list.prev, &resource->link);
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpaResult
|
||||||
|
pinos_resource_destroy (PinosResource *resource)
|
||||||
|
{
|
||||||
|
pinos_log_debug ("resource %p: destroy", resource);
|
||||||
|
pinos_signal_emit (&resource->destroy_signal, resource);
|
||||||
|
|
||||||
|
spa_list_remove (&resource->link);
|
||||||
|
|
||||||
|
if (resource->destroy)
|
||||||
|
resource->destroy (resource->object);
|
||||||
|
|
||||||
|
free (resource);
|
||||||
|
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpaResult
|
||||||
|
pinos_resource_send_message (PinosResource *resource,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
bool flush)
|
||||||
|
{
|
||||||
|
if (resource->send_func)
|
||||||
|
return resource->send_func (resource,
|
||||||
|
resource->id,
|
||||||
|
type,
|
||||||
|
message,
|
||||||
|
flush,
|
||||||
|
resource->send_data);
|
||||||
|
|
||||||
|
pinos_log_error ("resource %p: send func not implemented", resource);
|
||||||
|
|
||||||
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
84
pinos/server/resource.h
Normal file
84
pinos/server/resource.h
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
/* Pinos
|
||||||
|
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PINOS_RESOURCE_H__
|
||||||
|
#define __PINOS_RESOURCE_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PINOS_RESOURCE_URI "http://pinos.org/ns/resource"
|
||||||
|
#define PINOS_RESOURCE_PREFIX PINOS_RESOURCE_URI "#"
|
||||||
|
|
||||||
|
typedef struct _PinosResource PinosResource;
|
||||||
|
|
||||||
|
#include <pinos/server/core.h>
|
||||||
|
|
||||||
|
typedef void (*PinosDestroy) (void *object);
|
||||||
|
|
||||||
|
typedef SpaResult (*PinosSendFunc) (void *object,
|
||||||
|
uint32_t id,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
bool flush,
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
typedef SpaResult (*PinosDispatchFunc) (void *object,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
struct _PinosResource {
|
||||||
|
PinosCore *core;
|
||||||
|
SpaList link;
|
||||||
|
|
||||||
|
PinosClient *client;
|
||||||
|
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t type;
|
||||||
|
void *object;
|
||||||
|
PinosDestroy destroy;
|
||||||
|
|
||||||
|
PinosSendFunc send_func;
|
||||||
|
void *send_data;
|
||||||
|
PinosDispatchFunc dispatch_func;
|
||||||
|
void *dispatch_data;
|
||||||
|
|
||||||
|
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
|
||||||
|
PinosResource *resource));
|
||||||
|
};
|
||||||
|
|
||||||
|
PinosResource * pinos_resource_new (PinosClient *client,
|
||||||
|
uint32_t id,
|
||||||
|
uint32_t type,
|
||||||
|
void *object,
|
||||||
|
PinosDestroy destroy);
|
||||||
|
SpaResult pinos_resource_destroy (PinosResource *resource);
|
||||||
|
|
||||||
|
SpaResult pinos_resource_send_message (PinosResource *resource,
|
||||||
|
PinosMessageType type,
|
||||||
|
void *message,
|
||||||
|
bool flush);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __PINOS_RESOURCE_H__ */
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "pinos/server/node-factory.h"
|
#include "pinos/server/node-factory.h"
|
||||||
#include "pinos/server/client.h"
|
#include "pinos/server/client.h"
|
||||||
#include "pinos/server/client-node.h"
|
#include "pinos/server/client-node.h"
|
||||||
|
#include "pinos/server/module.h"
|
||||||
|
|
||||||
#include "spa/include/spa/monitor.h"
|
#include "spa/include/spa/monitor.h"
|
||||||
|
|
||||||
|
|
@ -34,11 +35,13 @@ pinos_uri_init (PinosURI *uri)
|
||||||
{
|
{
|
||||||
uri->map = pinos_id_map_get_default();
|
uri->map = pinos_id_map_get_default();
|
||||||
|
|
||||||
|
uri->core = spa_id_map_get_id (uri->map, PINOS_CORE_URI);
|
||||||
uri->node = spa_id_map_get_id (uri->map, PINOS_NODE_URI);
|
uri->node = spa_id_map_get_id (uri->map, PINOS_NODE_URI);
|
||||||
uri->node_factory = spa_id_map_get_id (uri->map, PINOS_NODE_FACTORY_URI);
|
uri->node_factory = spa_id_map_get_id (uri->map, PINOS_NODE_FACTORY_URI);
|
||||||
uri->link = spa_id_map_get_id (uri->map, PINOS_LINK_URI);
|
uri->link = spa_id_map_get_id (uri->map, PINOS_LINK_URI);
|
||||||
uri->client = spa_id_map_get_id (uri->map, PINOS_CLIENT_URI);
|
uri->client = spa_id_map_get_id (uri->map, PINOS_CLIENT_URI);
|
||||||
uri->client_node = spa_id_map_get_id (uri->map, PINOS_CLIENT_NODE_URI);
|
uri->client_node = spa_id_map_get_id (uri->map, PINOS_CLIENT_NODE_URI);
|
||||||
|
uri->module = spa_id_map_get_id (uri->map, PINOS_MODULE_URI);
|
||||||
|
|
||||||
uri->spa_node = spa_id_map_get_id (uri->map, SPA_NODE_URI);
|
uri->spa_node = spa_id_map_get_id (uri->map, SPA_NODE_URI);
|
||||||
uri->spa_clock = spa_id_map_get_id (uri->map, SPA_CLOCK_URI);
|
uri->spa_clock = spa_id_map_get_id (uri->map, SPA_CLOCK_URI);
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,13 @@ typedef struct _PinosURI PinosURI;
|
||||||
struct _PinosURI {
|
struct _PinosURI {
|
||||||
SpaIDMap *map;
|
SpaIDMap *map;
|
||||||
|
|
||||||
|
uint32_t core;
|
||||||
uint32_t node;
|
uint32_t node;
|
||||||
uint32_t node_factory;
|
uint32_t node_factory;
|
||||||
uint32_t link;
|
uint32_t link;
|
||||||
uint32_t client;
|
uint32_t client;
|
||||||
uint32_t client_node;
|
uint32_t client_node;
|
||||||
|
uint32_t module;
|
||||||
|
|
||||||
uint32_t spa_node;
|
uint32_t spa_node;
|
||||||
uint32_t spa_clock;
|
uint32_t spa_clock;
|
||||||
|
|
|
||||||
|
|
@ -17,218 +17,192 @@
|
||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pinos/client/pinos.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
static GMainLoop *loop;
|
#include <pinos/client/pinos.h>
|
||||||
|
#include <pinos/client/signal.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool running;
|
||||||
|
PinosLoop *loop;
|
||||||
|
PinosContext *context;
|
||||||
|
|
||||||
|
PinosListener on_state_changed;
|
||||||
|
} Data;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_properties (PinosProperties *props, gchar mark)
|
print_properties (PinosProperties *props, char mark)
|
||||||
{
|
{
|
||||||
gpointer state = NULL;
|
void *state = NULL;
|
||||||
const gchar *key;
|
const char *key;
|
||||||
|
|
||||||
if (props == NULL)
|
if (props == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_print ("%c\tproperties:\n", mark);
|
printf ("%c\tproperties:\n", mark);
|
||||||
while ((key = pinos_properties_iterate (props, &state))) {
|
while ((key = pinos_properties_iterate (props, &state))) {
|
||||||
g_print ("%c\t\t%s = \"%s\"\n", mark, key, pinos_properties_get (props, key));
|
printf ("%c\t\t%s = \"%s\"\n", mark, key, pinos_properties_get (props, key));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
info_ready (GObject *o, GAsyncResult *res, gpointer user_data)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
if (!pinos_context_info_finish (o, res, &error)) {
|
|
||||||
g_printerr ("introspection failure: %s\n", error->message);
|
|
||||||
g_clear_error (&error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gboolean print_mark;
|
bool print_mark;
|
||||||
gboolean print_all;
|
bool print_all;
|
||||||
} DumpData;
|
} DumpData;
|
||||||
|
|
||||||
#define MARK_CHANGE(f) ((data->print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ')
|
#define MARK_CHANGE(f) ((data->print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ')
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_daemon_info (PinosContext *c, const PinosDaemonInfo *info, gpointer user_data)
|
dump_daemon_info (PinosContext *c, const PinosDaemonInfo *info, void * user_data)
|
||||||
{
|
{
|
||||||
DumpData *data = user_data;
|
DumpData *data = user_data;
|
||||||
|
|
||||||
g_print ("\tid: %p\n", info->id);
|
printf ("\tid: %u\n", info->id);
|
||||||
g_print ("\tdaemon-path: \"%s\"\n", info->daemon_path);
|
|
||||||
if (data->print_all) {
|
if (data->print_all) {
|
||||||
g_print ("%c\tuser-name: \"%s\"\n", MARK_CHANGE (0), info->user_name);
|
printf ("%c\tuser-name: \"%s\"\n", MARK_CHANGE (0), info->user_name);
|
||||||
g_print ("%c\thost-name: \"%s\"\n", MARK_CHANGE (1), info->host_name);
|
printf ("%c\thost-name: \"%s\"\n", MARK_CHANGE (1), info->host_name);
|
||||||
g_print ("%c\tversion: \"%s\"\n", MARK_CHANGE (2), info->version);
|
printf ("%c\tversion: \"%s\"\n", MARK_CHANGE (2), info->version);
|
||||||
g_print ("%c\tname: \"%s\"\n", MARK_CHANGE (3), info->name);
|
printf ("%c\tname: \"%s\"\n", MARK_CHANGE (3), info->name);
|
||||||
g_print ("%c\tcookie: %u\n", MARK_CHANGE (4), info->cookie);
|
printf ("%c\tcookie: %u\n", MARK_CHANGE (4), info->cookie);
|
||||||
print_properties (info->properties, MARK_CHANGE (5));
|
print_properties (info->properties, MARK_CHANGE (5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_client_info (PinosContext *c, const PinosClientInfo *info, gpointer user_data)
|
dump_client_info (PinosContext *c, const PinosClientInfo *info, void * user_data)
|
||||||
{
|
{
|
||||||
DumpData *data = user_data;
|
DumpData *data = user_data;
|
||||||
|
|
||||||
g_print ("\tid: %p\n", info->id);
|
printf ("\tid: %u\n", info->id);
|
||||||
g_print ("\tclient-path: \"%s\"\n", info->client_path);
|
|
||||||
if (data->print_all) {
|
if (data->print_all) {
|
||||||
g_print ("\tsender: \"%s\"\n", info->sender);
|
|
||||||
print_properties (info->properties, MARK_CHANGE (0));
|
print_properties (info->properties, MARK_CHANGE (0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_node_info (PinosContext *c, const PinosNodeInfo *info, gpointer user_data)
|
dump_node_info (PinosContext *c, const PinosNodeInfo *info, void * user_data)
|
||||||
{
|
{
|
||||||
DumpData *data = user_data;
|
DumpData *data = user_data;
|
||||||
|
|
||||||
g_print ("\tid: %p\n", info->id);
|
printf ("\tid: %u\n", info->id);
|
||||||
g_print ("\tnode-path: \"%s\"\n", info->node_path);
|
|
||||||
if (data->print_all) {
|
if (data->print_all) {
|
||||||
g_print ("%c\towner: \"%s\"\n", MARK_CHANGE (0), info->owner);
|
printf ("%c\tname: \"%s\"\n", MARK_CHANGE (0), info->name);
|
||||||
g_print ("%c\tname: \"%s\"\n", MARK_CHANGE (0), info->name);
|
|
||||||
print_properties (info->properties, MARK_CHANGE (1));
|
print_properties (info->properties, MARK_CHANGE (1));
|
||||||
g_print ("%c\tstate: \"%s\"\n", MARK_CHANGE (2), pinos_node_state_as_string (info->state));
|
printf ("%c\tstate: \"%s\"\n", MARK_CHANGE (2), pinos_node_state_as_string (info->state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_link_info (PinosContext *c, const PinosLinkInfo *info, gpointer user_data)
|
dump_link_info (PinosContext *c, const PinosLinkInfo *info, void * user_data)
|
||||||
{
|
{
|
||||||
DumpData *data = user_data;
|
DumpData *data = user_data;
|
||||||
|
|
||||||
g_print ("\tid: %p\n", info->id);
|
printf ("\tid: %u\n", info->id);
|
||||||
g_print ("\tlink-path: \"%s\"\n", info->link_path);
|
|
||||||
if (data->print_all) {
|
if (data->print_all) {
|
||||||
g_print ("%c\toutput-node-path: \"%s\"\n", MARK_CHANGE (0), info->output_node_path);
|
printf ("%c\toutput-node-id: %u\n", MARK_CHANGE (0), info->output_node_id);
|
||||||
g_print ("%c\toutput-port: %u\n", MARK_CHANGE (1), info->output_port);
|
printf ("%c\toutput-port-id: %u\n", MARK_CHANGE (1), info->output_port_id);
|
||||||
g_print ("%c\tinput-node-path: \"%s\"\n", MARK_CHANGE (2), info->input_node_path);
|
printf ("%c\tinput-node-id: %u\n", MARK_CHANGE (2), info->input_node_id);
|
||||||
g_print ("%c\tinput-port: %u\n", MARK_CHANGE (3), info->input_port);
|
printf ("%c\tinput-port-id: %u\n", MARK_CHANGE (3), info->input_port_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_object (PinosContext *context, gpointer id, PinosSubscriptionFlags flags,
|
dump_object (PinosContext *context,
|
||||||
DumpData *data)
|
uint32_t id,
|
||||||
|
PinosSubscriptionFlags flags,
|
||||||
|
DumpData *data)
|
||||||
{
|
{
|
||||||
if (flags & PINOS_SUBSCRIPTION_FLAG_DAEMON) {
|
if (flags & PINOS_SUBSCRIPTION_FLAG_DAEMON) {
|
||||||
pinos_context_get_daemon_info (context,
|
|
||||||
PINOS_DAEMON_INFO_FLAGS_NONE,
|
|
||||||
dump_daemon_info,
|
|
||||||
NULL,
|
|
||||||
info_ready,
|
|
||||||
data);
|
|
||||||
}
|
}
|
||||||
else if (flags & PINOS_SUBSCRIPTION_FLAG_CLIENT) {
|
else if (flags & PINOS_SUBSCRIPTION_FLAG_CLIENT) {
|
||||||
pinos_context_get_client_info_by_id (context,
|
|
||||||
id,
|
|
||||||
PINOS_CLIENT_INFO_FLAGS_NONE,
|
|
||||||
dump_client_info,
|
|
||||||
NULL,
|
|
||||||
info_ready,
|
|
||||||
data);
|
|
||||||
}
|
}
|
||||||
else if (flags & PINOS_SUBSCRIPTION_FLAG_NODE) {
|
else if (flags & PINOS_SUBSCRIPTION_FLAG_NODE) {
|
||||||
pinos_context_get_node_info_by_id (context,
|
|
||||||
id,
|
|
||||||
PINOS_NODE_INFO_FLAGS_NONE,
|
|
||||||
dump_node_info,
|
|
||||||
NULL,
|
|
||||||
info_ready,
|
|
||||||
data);
|
|
||||||
}
|
}
|
||||||
else if (flags & PINOS_SUBSCRIPTION_FLAG_LINK) {
|
else if (flags & PINOS_SUBSCRIPTION_FLAG_LINK) {
|
||||||
pinos_context_get_link_info_by_id (context,
|
|
||||||
id,
|
|
||||||
PINOS_LINK_INFO_FLAGS_NONE,
|
|
||||||
dump_link_info,
|
|
||||||
NULL,
|
|
||||||
info_ready,
|
|
||||||
data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
subscription_cb (PinosContext *context,
|
subscription_cb (PinosContext *context,
|
||||||
PinosSubscriptionEvent type,
|
|
||||||
PinosSubscriptionFlags flags,
|
PinosSubscriptionFlags flags,
|
||||||
gpointer id,
|
PinosSubscriptionEvent type,
|
||||||
gpointer user_data)
|
uint32_t id,
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
DumpData data;
|
DumpData dd;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PINOS_SUBSCRIPTION_EVENT_NEW:
|
case PINOS_SUBSCRIPTION_EVENT_NEW:
|
||||||
g_print ("added:\n");
|
printf ("added:\n");
|
||||||
data.print_mark = FALSE;
|
dd.print_mark = false;
|
||||||
data.print_all = TRUE;
|
dd.print_all = true;
|
||||||
dump_object (context, id, flags, &data);
|
dump_object (context, id, flags, &dd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_SUBSCRIPTION_EVENT_CHANGE:
|
case PINOS_SUBSCRIPTION_EVENT_CHANGE:
|
||||||
g_print ("changed:\n");
|
printf ("changed:\n");
|
||||||
data.print_mark = TRUE;
|
dd.print_mark = true;
|
||||||
data.print_all = TRUE;
|
dd.print_all = true;
|
||||||
dump_object (context, id, flags, &data);
|
dump_object (context, id, flags, &dd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PINOS_SUBSCRIPTION_EVENT_REMOVE:
|
case PINOS_SUBSCRIPTION_EVENT_REMOVE:
|
||||||
g_print ("removed:\n");
|
printf ("removed:\n");
|
||||||
data.print_mark = FALSE;
|
dd.print_mark = false;
|
||||||
data.print_all = FALSE;
|
dd.print_all = false;
|
||||||
dump_object (context, id, flags, &data);
|
dump_object (context, id, flags, &dd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_state_notify (GObject *gobject,
|
on_state_changed (PinosListener *listener,
|
||||||
GParamSpec *pspec,
|
PinosContext *context)
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
PinosContextState state;
|
Data *data = SPA_CONTAINER_OF (listener, Data, on_state_changed);
|
||||||
PinosContext *c = PINOS_CONTEXT (gobject);
|
|
||||||
const GError *error;
|
|
||||||
|
|
||||||
g_object_get (c, "state", &state, NULL);
|
switch (context->state) {
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case PINOS_CONTEXT_STATE_ERROR:
|
case PINOS_CONTEXT_STATE_ERROR:
|
||||||
error = pinos_context_get_error (c);
|
printf ("context error: %s\n", context->error);
|
||||||
g_print ("context error: %s\n", error->message);
|
data->running = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_print ("context state: \"%s\"\n", pinos_context_state_as_string (state));
|
printf ("context state: \"%s\"\n", pinos_context_state_as_string (context->state));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gint
|
int
|
||||||
main (gint argc, gchar *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
PinosContext *c;
|
Data data;
|
||||||
|
|
||||||
pinos_init (&argc, &argv);
|
pinos_init (&argc, &argv);
|
||||||
|
|
||||||
loop = g_main_loop_new (NULL, FALSE);
|
data.loop = pinos_loop_new ();
|
||||||
|
data.running = true;
|
||||||
|
data.context = pinos_context_new (data.loop, "pinos-monitor", NULL);
|
||||||
|
|
||||||
c = pinos_context_new (NULL, "pinos-monitor", NULL);
|
pinos_signal_add (&data.context->state_changed,
|
||||||
g_signal_connect (c, "notify::state", (GCallback) on_state_notify, c);
|
&data.on_state_changed,
|
||||||
g_object_set (c, "subscription-mask", PINOS_SUBSCRIPTION_FLAGS_ALL, NULL);
|
on_state_changed);
|
||||||
g_signal_connect (c, "subscription-event", (GCallback) subscription_cb, NULL);
|
|
||||||
pinos_context_connect(c, PINOS_CONTEXT_FLAGS_NOFAIL);
|
|
||||||
|
|
||||||
g_main_loop_run (loop);
|
pinos_context_subscribe (data.context,
|
||||||
|
PINOS_SUBSCRIPTION_FLAGS_ALL,
|
||||||
|
subscription_cb,
|
||||||
|
&data);
|
||||||
|
|
||||||
g_object_unref (c);
|
pinos_context_connect (data.context);
|
||||||
|
|
||||||
|
pinos_loop_enter (data.loop);
|
||||||
|
while (data.running) {
|
||||||
|
pinos_loop_iterate (data.loop, -1);
|
||||||
|
}
|
||||||
|
pinos_loop_leave (data.loop);
|
||||||
|
|
||||||
|
pinos_context_destroy (data.context);
|
||||||
|
pinos_loop_destroy (data.loop);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ struct _SpaLoopControl {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define spa_loop_control_get_fd(l) (l)->get_fd(l)
|
#define spa_loop_control_get_fd(l) (l)->get_fd(l)
|
||||||
#define spa_loop_control_set_hooks(l,...) (l)->set_hook((l),__VA_ARGS__)
|
#define spa_loop_control_set_hooks(l,...) (l)->set_hooks((l),__VA_ARGS__)
|
||||||
#define spa_loop_control_enter(l) (l)->enter(l)
|
#define spa_loop_control_enter(l) (l)->enter(l)
|
||||||
#define spa_loop_control_iterate(l,...) (l)->iterate((l),__VA_ARGS__)
|
#define spa_loop_control_iterate(l,...) (l)->iterate((l),__VA_ARGS__)
|
||||||
#define spa_loop_control_leave(l) (l)->leave(l)
|
#define spa_loop_control_leave(l) (l)->leave(l)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue