diff --git a/src/modules/module-client-node/v0/client-node.c b/src/modules/module-client-node/v0/client-node.c index 685638ef4..520f14fda 100644 --- a/src/modules/module-client-node/v0/client-node.c +++ b/src/modules/module-client-node/v0/client-node.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -65,6 +66,9 @@ #define CHECK_PORT_BUFFER(this,b,p) (b < p->n_buffers) +extern uint32_t pw_protocol_native0_type_from_v2(struct pw_impl_client *client, uint32_t type); +extern uint32_t pw_protocol_native0_name_to_v2(struct pw_impl_client *client, const char *name); + struct mem { uint32_t id; int ref; @@ -111,6 +115,8 @@ struct node { struct spa_hook_list hooks; struct spa_callbacks callbacks; + struct spa_io_position *position; + struct pw_resource *resource; struct spa_source data_source; @@ -310,7 +316,20 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags, static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size) { - return -ENOTSUP; + struct node *this = object; + int res; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + switch(id) { + case SPA_IO_Position: + this->position = data; + break; + default: + res = -ENOTSUP; + break; + } + return res; } static inline void do_flush(struct node *this) @@ -320,6 +339,36 @@ static inline void do_flush(struct node *this) } +static int send_clock_update(struct node *this) +{ + struct pw_impl_client *client = this->resource->client; + uint32_t type = pw_protocol_native0_name_to_v2(client, SPA_TYPE_INFO_NODE_COMMAND_BASE "ClockUpdate"); + struct timespec ts; + int64_t now; + + clock_gettime(CLOCK_MONOTONIC, &ts); + now = SPA_TIMESPEC_TO_NSEC(&ts); + pw_log_trace(NAME " %p: now %"PRIi64, this, now); + + struct spa_command_node0_clock_update cu = + SPA_COMMAND_NODE0_CLOCK_UPDATE_INIT(type, + SPA_COMMAND_NODE0_CLOCK_UPDATE_TIME | + SPA_COMMAND_NODE0_CLOCK_UPDATE_SCALE | + SPA_COMMAND_NODE0_CLOCK_UPDATE_STATE | + SPA_COMMAND_NODE0_CLOCK_UPDATE_LATENCY, /* change_mask */ + SPA_USEC_PER_SEC, /* rate */ + now / SPA_NSEC_PER_USEC, /* ticks */ + now, /* monotonic_time */ + 0, /* offset */ + (1 << 16) | 1, /* scale */ + SPA_CLOCK0_STATE_RUNNING, /* state */ + SPA_COMMAND_NODE0_CLOCK_UPDATE_FLAG_LIVE, /* flags */ + 0); /* latency */ + + pw_client_node0_resource_command(this->resource, this->seq, (const struct spa_command*)&cu); + return SPA_RESULT_RETURN_ASYNC(this->seq++); +} + static int impl_node_send_command(void *object, const struct spa_command *command) { struct node *this = object; @@ -330,6 +379,10 @@ static int impl_node_send_command(void *object, const struct spa_command *comman if (this->resource == NULL) return -EIO; + if (SPA_NODE_COMMAND_ID(command) == SPA_NODE_COMMAND_Start) { + send_clock_update(this); + } + pw_client_node0_resource_command(this->resource, this->seq, command); return SPA_RESULT_RETURN_ASYNC(this->seq++); } @@ -365,8 +418,6 @@ impl_node_sync(void *object, int seq) return this->init_pending; } -extern uint32_t pw_protocol_native0_type_from_v2(struct pw_impl_client *client, uint32_t type); -extern uint32_t pw_protocol_native0_type_to_v2(struct pw_impl_client *client, uint32_t type); extern struct spa_pod *pw_protocol_native0_pod_from_v2(struct pw_impl_client *client, const struct spa_pod *pod); extern int pw_protocol_native0_pod_to_v2(struct pw_impl_client *client, const struct spa_pod *pod, @@ -1015,7 +1066,14 @@ static void client_node0_event(void *data, struct spa_event *event) { struct impl *impl = data; struct node *this = &impl->node; - spa_node_emit_event(&this->hooks, event); + + switch (SPA_EVENT_TYPE(event)) { + case SPA_NODE0_EVENT_RequestClockUpdate: + send_clock_update(this); + break; + default: + spa_node_emit_event(&this->hooks, event); + } } static struct pw_client_node0_methods client_node0_methods = { diff --git a/src/modules/module-client-node/v0/client-node.h b/src/modules/module-client-node/v0/client-node.h index 34d095e8d..829ae5300 100644 --- a/src/modules/module-client-node/v0/client-node.h +++ b/src/modules/module-client-node/v0/client-node.h @@ -28,6 +28,50 @@ extern "C" { #endif +/** The state of the clock */ +enum spa_clock0_state { + SPA_CLOCK0_STATE_STOPPED, /*< the clock is stopped */ + SPA_CLOCK0_STATE_PAUSED, /*< the clock is paused */ + SPA_CLOCK0_STATE_RUNNING, /*< the clock is running */ +}; + +struct spa_command_node0_clock_update_body { + struct spa_pod_object_body body; +#define SPA_COMMAND_NODE0_CLOCK_UPDATE_TIME (1 << 0) +#define SPA_COMMAND_NODE0_CLOCK_UPDATE_SCALE (1 << 1) +#define SPA_COMMAND_NODE0_CLOCK_UPDATE_STATE (1 << 2) +#define SPA_COMMAND_NODE0_CLOCK_UPDATE_LATENCY (1 << 3) + struct spa_pod_int change_mask SPA_ALIGNED(8); + struct spa_pod_int rate SPA_ALIGNED(8); + struct spa_pod_long ticks SPA_ALIGNED(8); + struct spa_pod_long monotonic_time SPA_ALIGNED(8); + struct spa_pod_long offset SPA_ALIGNED(8); + struct spa_pod_int scale SPA_ALIGNED(8); + struct spa_pod_int state SPA_ALIGNED(8); +#define SPA_COMMAND_NODE0_CLOCK_UPDATE_FLAG_LIVE (1 << 0) + struct spa_pod_int flags SPA_ALIGNED(8); + struct spa_pod_long latency SPA_ALIGNED(8); +}; + +struct spa_command_node0_clock_update { + struct spa_pod pod; + struct spa_command_node0_clock_update_body body; +}; + +#define SPA_COMMAND_NODE0_CLOCK_UPDATE_INIT(type,change_mask,rate,ticks,monotonic_time,offset,scale,state,flags,latency) \ + SPA_COMMAND_INIT_FULL(struct spa_command_node0_clock_update, \ + sizeof(struct spa_command_node0_clock_update_body), 0, type, \ + SPA_POD_INIT_Int(change_mask), \ + SPA_POD_INIT_Int(rate), \ + SPA_POD_INIT_Long(ticks), \ + SPA_POD_INIT_Long(monotonic_time), \ + SPA_POD_INIT_Long(offset), \ + SPA_POD_INIT_Int(scale), \ + SPA_POD_INIT_Int(state), \ + SPA_POD_INIT_Int(flags), \ + SPA_POD_INIT_Long(latency)) + + /** \class pw_impl_client_node0 * * PipeWire client node interface diff --git a/src/modules/module-client-node/v0/protocol-native.c b/src/modules/module-client-node/v0/protocol-native.c index c54f8b873..17ffe835c 100644 --- a/src/modules/module-client-node/v0/protocol-native.c +++ b/src/modules/module-client-node/v0/protocol-native.c @@ -36,6 +36,8 @@ extern uint32_t pw_protocol_native0_find_type(struct pw_impl_client *client, const char *type); extern int pw_protocol_native0_pod_to_v2(struct pw_impl_client *client, const struct spa_pod *pod, struct spa_pod_builder *b); +extern struct spa_pod * pw_protocol_native0_pod_from_v2(struct pw_impl_client *client, + const struct spa_pod *pod); extern uint32_t pw_protocol_native0_type_to_v2(struct pw_impl_client *client, const struct spa_type_info *info, uint32_t type); @@ -137,7 +139,10 @@ client_node_marshal_command(void *object, uint32_t seq, const struct spa_command spa_pod_builder_push_struct(b, &f); spa_pod_builder_add(b, "i", seq, NULL); - pw_protocol_native0_pod_to_v2(client, (struct spa_pod *)command, b); + if (SPA_COMMAND_TYPE(command) == 0) + spa_pod_builder_add(b, "P", command, NULL); + else + pw_protocol_native0_pod_to_v2(client, (struct spa_pod *)command, b); spa_pod_builder_pop(b, &f); pw_protocol_native_end_resource(resource, b); @@ -440,15 +445,22 @@ static int client_node_demarshal_set_active(void *object, const struct pw_protoc static int client_node_demarshal_event_method(void *object, const struct pw_protocol_native_message *msg) { struct pw_resource *resource = object; + struct pw_impl_client *client = pw_resource_get_client(resource); struct spa_pod_parser prs; struct spa_event *event; + int res; spa_pod_parser_init(&prs, msg->data, msg->size); if (spa_pod_parser_get_struct(&prs, "O", &event) < 0) return -EINVAL; - return pw_resource_notify(resource, struct pw_client_node0_methods, event, 0, event); + event = (struct spa_event*)pw_protocol_native0_pod_from_v2(client, (struct spa_pod *)event); + + res = pw_resource_notify(resource, struct pw_client_node0_methods, event, 0, event); + free(event); + + return res; } static int client_node_demarshal_destroy(void *object, const struct pw_protocol_native_message *msg) diff --git a/src/modules/module-protocol-native/v0/protocol-native.c b/src/modules/module-protocol-native/v0/protocol-native.c index 0bf6b360d..6d560e10c 100644 --- a/src/modules/module-protocol-native/v0/protocol-native.c +++ b/src/modules/module-protocol-native/v0/protocol-native.c @@ -350,16 +350,9 @@ const char * pw_protocol_native0_name_from_v2(struct pw_impl_client *client, uin } SPA_EXPORT -uint32_t pw_protocol_native0_type_to_v2(struct pw_impl_client *client, - const struct spa_type_info *info, uint32_t type) +uint32_t pw_protocol_native0_name_to_v2(struct pw_impl_client *client, const char *name) { uint32_t i; - const char *name; - - /** find full name of type in type_info */ - if ((name = spa_debug_type_find_name(info, type)) == NULL) - return SPA_ID_INVALID; - /* match name to type table and return index */ for (i = 0; i < SPA_N_ELEMENTS(type_map); i++) { if (type_map[i].name != NULL && !strcmp(type_map[i].name, name)) @@ -368,6 +361,19 @@ uint32_t pw_protocol_native0_type_to_v2(struct pw_impl_client *client, return SPA_ID_INVALID; } +SPA_EXPORT +uint32_t pw_protocol_native0_type_to_v2(struct pw_impl_client *client, + const struct spa_type_info *info, uint32_t type) +{ + const char *name; + + /** find full name of type in type_info */ + if ((name = spa_debug_type_find_name(info, type)) == NULL) + return SPA_ID_INVALID; + + return pw_protocol_native0_name_to_v2(client, name); +} + struct spa_pod_prop_body0 { uint32_t key; #define SPA_POD_PROP0_RANGE_NONE 0 /**< no range */ @@ -540,7 +546,8 @@ static int remap_to_v2(struct pw_impl_client *client, const struct spa_type_info ti = spa_debug_type_find(info, b->type); ii = ti ? spa_debug_type_find(ti->values, 0) : NULL; - if (b->type == SPA_TYPE_COMMAND_Node) { + if (b->type == SPA_TYPE_COMMAND_Node || + b->type == SPA_TYPE_EVENT_Node) { spa_pod_builder_push_object(builder, &f[0], 0, pw_protocol_native0_type_to_v2(client, ii ? ii->values : NULL, b->id)); } else { @@ -654,7 +661,6 @@ struct spa_pod * pw_protocol_native0_pod_from_v2(struct pw_impl_client *client, return NULL; } copy = spa_pod_copy(b.data); - spa_debug_pod(0, NULL, copy); return copy; } diff --git a/src/modules/module-protocol-native/v0/typemap.h b/src/modules/module-protocol-native/v0/typemap.h index dbebacb92..de671f5e2 100644 --- a/src/modules/module-protocol-native/v0/typemap.h +++ b/src/modules/module-protocol-native/v0/typemap.h @@ -60,10 +60,10 @@ const struct type_info { { "Spa:Enum:DataType:MemPtr", SPA_TYPE_INFO_DATA_BASE "MemPtr", SPA_DATA_MemPtr, }, { "Spa:Enum:DataType:Fd:MemFd", SPA_TYPE_INFO_DATA_FD_BASE "MemFd", SPA_DATA_MemFd, }, { "Spa:Enum:DataType:Fd:DmaBuf", SPA_TYPE_INFO_DATA_FD_BASE "DmaBuf", SPA_DATA_DmaBuf, }, - { "Spa:POD:Object:Event:Node:Error", }, - { "Spa:POD:Object:Event:Node:Buffering", }, - { "Spa:POD:Object:Event:Node:RequestRefresh", }, - { "Spa:POD:Object:Event:Node:RequestClockUpdate", }, + { "Spa:POD:Object:Event:Node:Error", SPA_TYPE_INFO_NODE_EVENT_BASE "Error", SPA_NODE_EVENT_Error, }, + { "Spa:POD:Object:Event:Node:Buffering", SPA_TYPE_INFO_NODE_EVENT_BASE "Buffering", SPA_NODE_EVENT_Buffering, }, + { "Spa:POD:Object:Event:Node:RequestRefresh", SPA_TYPE_INFO_NODE_EVENT_BASE "RequestRefresh", SPA_NODE_EVENT_RequestRefresh, }, + { "Spa:POD:Object:Event:Node:RequestClockUpdate", SPA_TYPE_INFO_NODE_EVENT_BASE "RequestClockUpdate", SPA_NODE0_EVENT_RequestClockUpdate, }, { "Spa:POD:Object:Command:Node", SPA_TYPE_INFO_COMMAND_BASE "Node", SPA_TYPE_COMMAND_Node,}, { "Spa:POD:Object:Command:Node:Suspend", SPA_TYPE_INFO_NODE_COMMAND_BASE "Suspend", SPA_NODE_COMMAND_Suspend,}, { "Spa:POD:Object:Command:Node:Pause", SPA_TYPE_INFO_NODE_COMMAND_BASE "Pause", SPA_NODE_COMMAND_Pause, }, @@ -73,7 +73,7 @@ const struct type_info { { "Spa:POD:Object:Command:Node:Flush", SPA_TYPE_INFO_NODE_COMMAND_BASE "Flush", SPA_NODE_COMMAND_Flush, }, { "Spa:POD:Object:Command:Node:Drain", SPA_TYPE_INFO_NODE_COMMAND_BASE "Drain", SPA_NODE_COMMAND_Drain, }, { "Spa:POD:Object:Command:Node:Marker", SPA_TYPE_INFO_NODE_COMMAND_BASE "Marker", SPA_NODE_COMMAND_Marker, }, - { "Spa:POD:Object:Command:Node:ClockUpdate", }, + { "Spa:POD:Object:Command:Node:ClockUpdate", SPA_TYPE_INFO_NODE_COMMAND_BASE "ClockUpdate", SPA_NODE0_COMMAND_ClockUpdate, }, { "Spa:POD:Object:Event:Monitor:Added", }, { "Spa:POD:Object:Event:Monitor:Removed", }, { "Spa:POD:Object:Event:Monitor:Changed", }, diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index 7d13d8acc..acec3b673 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -1204,6 +1204,7 @@ static void node_event(void *data, const struct spa_event *event) node_update_state(node, PW_NODE_STATE_ERROR, strdup("error")); break; default: + pw_log_debug("unhandled event"); break; } pw_impl_node_emit_event(node, event); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 8280dbba1..0312f5f91 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -97,6 +97,16 @@ typedef uint32_t (*pw_permission_func_t) (struct pw_global *global, #define pw_impl_client_emit_resource_removed(o,r) pw_impl_client_emit(o, resource_removed, 0, r) #define pw_impl_client_emit_busy_changed(o,b) pw_impl_client_emit(o, busy_changed, 0, b) +enum spa_node0_event { + SPA_NODE0_EVENT_START = SPA_TYPE_VENDOR_PipeWire, + SPA_NODE0_EVENT_RequestClockUpdate, +}; + +enum spa_node0_command { + SPA_NODE0_COMMAND_START = SPA_TYPE_VENDOR_PipeWire, + SPA_NODE0_COMMAND_ClockUpdate, +}; + struct protocol_compat_v2 { /* v2 typemap */ struct pw_map types;