2023-02-28 16:14:19 +01:00
|
|
|
/* PipeWire */
|
|
|
|
|
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans <wim.taymans@gmail.com> */
|
|
|
|
|
/* SPDX-License-Identifier: MIT */
|
|
|
|
|
|
|
|
|
|
#ifndef PIPEWIRE_RTP_STREAM_H
|
|
|
|
|
#define PIPEWIRE_RTP_STREAM_H
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
struct rtp_stream;
|
|
|
|
|
|
2026-06-19 19:18:33 +02:00
|
|
|
#define DEFAULT_RAW_AUDIO_FORMAT "S16BE"
|
|
|
|
|
#define DEFAULT_RAOP_AUDIO_FORMAT "S16LE"
|
2023-03-02 19:55:44 +01:00
|
|
|
#define DEFAULT_RATE 48000
|
|
|
|
|
#define DEFAULT_CHANNELS 2
|
|
|
|
|
#define DEFAULT_POSITION "[ FL FR ]"
|
2025-10-30 12:29:31 +01:00
|
|
|
#define DEFAULT_LAYOUT "Stereo"
|
2023-03-02 19:55:44 +01:00
|
|
|
|
2024-01-25 15:42:16 +01:00
|
|
|
#define ERROR_MSEC 2.0f
|
|
|
|
|
#define DEFAULT_SESS_LATENCY 100.0f
|
2023-03-02 19:55:44 +01:00
|
|
|
|
2025-01-24 12:43:34 +01:00
|
|
|
#define IP4_HEADER_SIZE 20
|
|
|
|
|
#define IP6_HEADER_SIZE 40
|
|
|
|
|
#define UDP_HEADER_SIZE 8
|
|
|
|
|
/* 12 bytes RTP header */
|
|
|
|
|
#define RTP_HEADER_SIZE 12
|
2024-11-11 11:49:20 +01:00
|
|
|
|
2023-03-02 19:55:44 +01:00
|
|
|
#define DEFAULT_MTU 1280
|
2024-01-25 15:42:16 +01:00
|
|
|
#define DEFAULT_MIN_PTIME 2.0f
|
|
|
|
|
#define DEFAULT_MAX_PTIME 20.0f
|
2023-03-02 19:55:44 +01:00
|
|
|
|
2023-02-28 16:14:19 +01:00
|
|
|
struct rtp_stream_events {
|
|
|
|
|
#define RTP_VERSION_STREAM_EVENTS 0
|
|
|
|
|
uint32_t version;
|
|
|
|
|
|
|
|
|
|
void (*destroy) (void *data);
|
|
|
|
|
|
module-rtp: Replace state_changed callbacks
The state_changed callbacks fulfill multiple roles, which is both a problem
regarding separation of concerns and regarding code clarity. De facto,
these callbacks cover error reporting, opening connections, and closing
connection, all in one, depending on a state that is arguably an internal
stream detail. The code in these callbacks tie these internal states to
assumptions that opening/closing callbacks is directly tied to specific
state changes in a common way, which is not always true. For example,
stopping the stream may not _actually_ stop it if a background send timer
is still running.
The notion of a "state_changed" callback is also problematic because the
pw_streams that are used in rtp-sink and rtp-source also have a callback
for state changes, causing confusion.
Solve this by replacing state_changed with three new callbacks:
1. report_error : Used for reporting nonrecoverable errors to the caller.
Note that currently, no one does such error reporting, but the feature
does exist, so this callback is introduced to preserve said feature.
2. open_connection : Used for opening a connection. Its optional return
value informs about success or failure.
3. close_connection : Used for opening a connection. Its optional return
value informs about success or failure.
Importantly, these callbacks do not export any internal stream state. This
improves encapsulation, and also makes it possible to invoke these
callbacks in situations that may not neatly map to a state change. One
example could be to close the connection as part of a stream_start call
to close any connection(s) left over from a previous run. (Followup commits
will in fact introduce such measures.)
2025-08-21 13:30:11 +02:00
|
|
|
void (*report_error) (void *data, const char *error);
|
|
|
|
|
|
|
|
|
|
/* Requests the network connection to be opened. If result is non-NULL,
|
|
|
|
|
* the call sets it to >0 in case of success, and a negative errno error
|
|
|
|
|
* code in case of failure. (Result value 0 is unused.) */
|
|
|
|
|
void (*open_connection) (void *data, int *result);
|
|
|
|
|
|
|
|
|
|
/* Requests the network connection to be closed. If result is non-NULL,
|
|
|
|
|
* the call sets it to >0 in case of success, 0 if the connection was
|
|
|
|
|
* already closed, and a negative errno error code in case of failure. */
|
|
|
|
|
void (*close_connection) (void *data, int *result);
|
2023-02-28 16:14:19 +01:00
|
|
|
|
2023-10-09 07:21:17 +02:00
|
|
|
void (*param_changed) (void *data, uint32_t id, const struct spa_pod *param);
|
|
|
|
|
|
module-rtp-sink: Add ability to add / remove receivers through commands
This makes it possible to dynamically add / remove receivers, which is
necesary for sending to multiple receivers. Mixed multi- and unicast
receivers are possible. Example pw-cli calls (56 is the ID of the RTP
sink node):
pw-cli c 56 User '{ extra="{ \"command.id\" : \"add-receiver\" , \"destination.ip\" : \"10.42.0.1\", \"destination.port\" : 55001 }" }'
pw-cli c 56 User '{ extra="{ \"command.id\" : \"remove-receiver\", \"destination.ip\" : \"10.42.0.1\" }" }'
pw-cli c 56 User '{ extra="{ \"command.id\" : \"clear-receivers\" }" }'
Commands and their arguments:
* "add-receiver" : Adds a receiver to the sink's list. If the given
IP address <-> port combination was already added, the command is
logged, but otherwise ignored. Arguments:
- "destination.ip" : IP address to send data to. Can be a uni- or
multicast address, but must be a valid address.
- "destination.port" : Port to send data to. Must be valid.
- "local.ifname", "source.ip", "net.ttl", "net.dscp", "net.loop" :
These are all optional, and work just like in the RTP sink
module's properties.
* "remove-receiver" : Removes a receiver from the sink's list. The
receiver is identified by the given IP address. A port can optionally
be specified as well. If it isn't, then the first receiver with that IP
address is removed. If no matching receiver is in the sink's list,
this command does nothing. Arguments:
- "destination.ip" : IP address to send data to. Can be a uni- or
multicast address, but must be a valid address.
- "destination.port" : Port to send data to. This is optional. But, if
it is set, it must be a valid port number.
* "clear-receivers" : Removes all receivers from the sink's list. If the
list is empty, this does nothing. This command has no arguments.
If the RTP sink module is created with the "destination.ip" and
"destination.port" properties set, it behaves as if "add-receiver" were
called right after the module was initialized. This means that if none
of these commands are used, the module behaves just as it did prior to
this patch. Note that the "remove-receivers" command can remove this
initial receiver as well.
If no receivers are added, the module continues to work normally.
Adding and removing receivers mid-operation is supported.
NOTE: "destination.ip") handling in stream_props_changed() is removed,
since it never really did anything other than change the param value.
2026-06-18 22:07:30 +02:00
|
|
|
void (*command) (void *data, const struct spa_command *command);
|
|
|
|
|
|
2023-02-28 16:14:19 +01:00
|
|
|
void (*send_packet) (void *data, struct iovec *iov, size_t iovlen);
|
2023-03-10 10:47:03 +01:00
|
|
|
|
2023-10-09 11:12:21 +02:00
|
|
|
void (*send_feedback) (void *data, uint32_t seqnum);
|
2023-02-28 16:14:19 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct rtp_stream *rtp_stream_new(struct pw_core *core,
|
|
|
|
|
enum pw_direction direction, struct pw_properties *props,
|
|
|
|
|
const struct rtp_stream_events *events, void *data);
|
|
|
|
|
|
|
|
|
|
void rtp_stream_destroy(struct rtp_stream *s);
|
|
|
|
|
|
2024-02-06 15:04:43 +01:00
|
|
|
int rtp_stream_update_properties(struct rtp_stream *s, const struct spa_dict *dict);
|
|
|
|
|
|
2025-10-23 20:08:22 +02:00
|
|
|
int rtp_stream_receive_packet(struct rtp_stream *s, uint8_t *buffer, size_t len,
|
|
|
|
|
uint64_t current_time);
|
|
|
|
|
|
2026-05-19 17:30:28 +02:00
|
|
|
int rtp_stream_resend_packets(struct rtp_stream *s, uint16_t seq, uint16_t num);
|
|
|
|
|
|
2025-10-23 20:08:22 +02:00
|
|
|
uint64_t rtp_stream_get_nsec(struct rtp_stream *s);
|
2023-02-28 16:14:19 +01:00
|
|
|
|
2024-06-27 01:43:44 +02:00
|
|
|
uint64_t rtp_stream_get_time(struct rtp_stream *s, uint32_t *rate);
|
2023-03-07 09:00:40 +01:00
|
|
|
|
2023-10-09 07:22:06 +02:00
|
|
|
uint16_t rtp_stream_get_seq(struct rtp_stream *s);
|
|
|
|
|
|
2024-11-11 12:03:32 +01:00
|
|
|
size_t rtp_stream_get_mtu(struct rtp_stream *s);
|
|
|
|
|
|
2023-10-09 07:22:32 +02:00
|
|
|
void rtp_stream_set_first(struct rtp_stream *s);
|
|
|
|
|
|
2025-01-20 16:44:57 +01:00
|
|
|
int rtp_stream_set_active(struct rtp_stream *s, bool active);
|
2024-03-25 12:22:11 +01:00
|
|
|
void rtp_stream_set_error(struct rtp_stream *s, int res, const char *error);
|
2023-10-09 07:23:02 +02:00
|
|
|
enum pw_stream_state rtp_stream_get_state(struct rtp_stream *s, const char **error);
|
|
|
|
|
|
2023-10-09 07:21:17 +02:00
|
|
|
int rtp_stream_set_param(struct rtp_stream *s, uint32_t id, const struct spa_pod *param);
|
|
|
|
|
|
|
|
|
|
int rtp_stream_update_params(struct rtp_stream *stream,
|
|
|
|
|
const struct spa_pod **params,
|
|
|
|
|
uint32_t n_params);
|
2023-02-28 16:14:19 +01:00
|
|
|
|
2025-09-24 20:18:56 +02:00
|
|
|
void rtp_stream_update_process_latency(struct rtp_stream *stream,
|
|
|
|
|
const struct spa_process_latency_info *process_latency);
|
|
|
|
|
|
module-rtp-sink: Add ability to add / remove receivers through commands
This makes it possible to dynamically add / remove receivers, which is
necesary for sending to multiple receivers. Mixed multi- and unicast
receivers are possible. Example pw-cli calls (56 is the ID of the RTP
sink node):
pw-cli c 56 User '{ extra="{ \"command.id\" : \"add-receiver\" , \"destination.ip\" : \"10.42.0.1\", \"destination.port\" : 55001 }" }'
pw-cli c 56 User '{ extra="{ \"command.id\" : \"remove-receiver\", \"destination.ip\" : \"10.42.0.1\" }" }'
pw-cli c 56 User '{ extra="{ \"command.id\" : \"clear-receivers\" }" }'
Commands and their arguments:
* "add-receiver" : Adds a receiver to the sink's list. If the given
IP address <-> port combination was already added, the command is
logged, but otherwise ignored. Arguments:
- "destination.ip" : IP address to send data to. Can be a uni- or
multicast address, but must be a valid address.
- "destination.port" : Port to send data to. Must be valid.
- "local.ifname", "source.ip", "net.ttl", "net.dscp", "net.loop" :
These are all optional, and work just like in the RTP sink
module's properties.
* "remove-receiver" : Removes a receiver from the sink's list. The
receiver is identified by the given IP address. A port can optionally
be specified as well. If it isn't, then the first receiver with that IP
address is removed. If no matching receiver is in the sink's list,
this command does nothing. Arguments:
- "destination.ip" : IP address to send data to. Can be a uni- or
multicast address, but must be a valid address.
- "destination.port" : Port to send data to. This is optional. But, if
it is set, it must be a valid port number.
* "clear-receivers" : Removes all receivers from the sink's list. If the
list is empty, this does nothing. This command has no arguments.
If the RTP sink module is created with the "destination.ip" and
"destination.port" properties set, it behaves as if "add-receiver" were
called right after the module was initialized. This means that if none
of these commands are used, the module behaves just as it did prior to
this patch. Note that the "remove-receivers" command can remove this
initial receiver as well.
If no receivers are added, the module continues to work normally.
Adding and removing receivers mid-operation is supported.
NOTE: "destination.ip") handling in stream_props_changed() is removed,
since it never really did anything other than change the param value.
2026-06-18 22:07:30 +02:00
|
|
|
int rtp_stream_run_in_data_loop(struct rtp_stream *s, spa_invoke_func_t func,
|
|
|
|
|
uint32_t seq, const void *data, size_t size, void *user_data);
|
|
|
|
|
|
2023-02-28 16:14:19 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#endif /* PIPEWIRE_RTP_STREAM_H */
|