mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-10-07 08:30:10 +00:00
module: add a netjack2 driver module
The module advertizes itself on multicast and will trigger a new client in the netjack2 manager. Tested with jack2 and 'jack_load netmanager'. The driver will receive and send data (no midi yet) from and to the manager in sync with the manager, without resampling and with a fixed latency.
This commit is contained in:
parent
d9e29e70f3
commit
991a1558dc
|
@ -21,6 +21,7 @@ module_sources = [
|
|||
'module-link-factory.c',
|
||||
'module-loopback.c',
|
||||
'module-metadata.c',
|
||||
'module-netjack2-driver.c',
|
||||
'module-pipe-tunnel.c',
|
||||
'module-portal.c',
|
||||
'module-profiler.c',
|
||||
|
@ -200,6 +201,14 @@ endif
|
|||
|
||||
summary({'ffado-driver': build_module_ffado_driver}, bool_yn: true, section: 'Optional Modules')
|
||||
|
||||
pipewire_module_netjack2_driver = shared_library('pipewire-module-netjack2-driver',
|
||||
[ 'module-netjack2-driver.c' ],
|
||||
include_directories : [configinc],
|
||||
install : true,
|
||||
install_dir : modules_install_dir,
|
||||
install_rpath: modules_install_dir,
|
||||
dependencies : [spa_dep, mathlib, dl_lib, pipewire_dep],
|
||||
)
|
||||
|
||||
pipewire_module_profiler = shared_library('pipewire-module-profiler',
|
||||
[ 'module-profiler.c',
|
||||
|
|
1631
src/modules/module-netjack2-driver.c
Normal file
1631
src/modules/module-netjack2-driver.c
Normal file
File diff suppressed because it is too large
Load diff
127
src/modules/module-netjack2/packets.h
Normal file
127
src/modules/module-netjack2/packets.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans <wim.taymans@gmail.com> */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_NETJACK2_H
|
||||
#define PIPEWIRE_NETJACK2_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define JACK_CLIENT_NAME_SIZE 64
|
||||
#define JACK_SERVER_NAME_SIZE 256
|
||||
|
||||
struct nj2_session_params {
|
||||
char type[8]; /* packet type ('param') */
|
||||
uint32_t version; /* version */
|
||||
#define NJ2_ID_FOLLOWER_AVAILABLE 0 /* a follower is available */
|
||||
#define NJ2_ID_FOLLOWER_SETUP 1 /* follower configuration */
|
||||
#define NJ2_ID_START_DRIVER 2 /* follower is ready, start driver */
|
||||
#define NJ2_ID_START_FOLLOWER 3 /* driver is ready, activate follower */
|
||||
#define NJ2_ID_STOP_DRIVER 4 /* driver must stop */
|
||||
int32_t packet_id; /* indicates the packet type */
|
||||
char name[JACK_CLIENT_NAME_SIZE]; /* follower's name */
|
||||
char driver_name[JACK_SERVER_NAME_SIZE]; /* driver hostname (network) */
|
||||
char follower_name[JACK_SERVER_NAME_SIZE]; /* follower hostname (network) */
|
||||
uint32_t mtu; /* connection mtu */
|
||||
uint32_t id; /* follower's ID */
|
||||
uint32_t transport_sync; /* is the transport synced ? */
|
||||
int32_t send_audio_channels; /* number of driver->follower channels */
|
||||
int32_t recv_audio_channels; /* number of follower->driver channels */
|
||||
int32_t send_midi_channels; /* number of driver->follower midi channels */
|
||||
int32_t recv_midi_channels; /* number of follower->driver midi channels */
|
||||
uint32_t sample_rate; /* session sample rate */
|
||||
uint32_t period_size; /* period size */
|
||||
#define NJ2_ENCODER_FLOAT 0
|
||||
#define NJ2_ENCODER_INT 1
|
||||
#define NJ2_ENCODER_CELT 2
|
||||
#define NJ2_ENCODER_OPUS 3
|
||||
uint32_t sample_encoder; /* samples encoder */
|
||||
uint32_t kbps; /* KB per second for CELT encoder */
|
||||
uint32_t follower_sync_mode; /* is the follower in sync mode ? */
|
||||
uint32_t network_latency; /* network latency */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static inline void nj2_dump_session_params(struct nj2_session_params *params)
|
||||
{
|
||||
pw_log_info("Type: '%s'", params->type);
|
||||
pw_log_info("Version: %u", ntohl(params->version));
|
||||
pw_log_info("packet ID: %d", ntohl(params->packet_id));
|
||||
pw_log_info("Name: '%s'", params->name);
|
||||
pw_log_info("Driver Name: '%s'", params->driver_name);
|
||||
pw_log_info("Follower Name: '%s'", params->follower_name);
|
||||
pw_log_info("MTU: %u", ntohl(params->mtu));
|
||||
pw_log_info("ID: %u", ntohl(params->id));
|
||||
pw_log_info("TransportSync: %u", ntohl(params->transport_sync));
|
||||
pw_log_info("Audio Send: %d", ntohl(params->send_audio_channels));
|
||||
pw_log_info("Audio Recv: %d", ntohl(params->recv_audio_channels));
|
||||
pw_log_info("MIDI Send: %d", ntohl(params->send_midi_channels));
|
||||
pw_log_info("MIDI Recv: %d", ntohl(params->recv_midi_channels));
|
||||
pw_log_info("Sample Rate: %u", ntohl(params->sample_rate));
|
||||
pw_log_info("Period Size: %u", ntohl(params->period_size));
|
||||
pw_log_info("Encoder: %u", ntohl(params->sample_encoder));
|
||||
pw_log_info("KBps: %u", ntohl(params->kbps));
|
||||
pw_log_info("Follower Sync: %u", ntohl(params->follower_sync_mode));
|
||||
pw_log_info("Latency: %u", ntohl(params->network_latency));
|
||||
}
|
||||
|
||||
struct nj2_packet_header {
|
||||
char type[8]; /* packet type ('headr') */
|
||||
uint32_t data_type; /* 'a' for audio, 'm' for midi and 's' for sync */
|
||||
uint32_t data_stream; /* 's' for send, 'r' for return */
|
||||
uint32_t id; /* unique ID of the follower */
|
||||
uint32_t num_packets; /* number of data packets of the cycle */
|
||||
uint32_t packet_size; /* packet size in bytes */
|
||||
uint32_t active_ports; /* number of active ports */
|
||||
uint32_t cycle; /* process cycle counter */
|
||||
uint32_t sub_cycle; /* midi/audio subcycle counter */
|
||||
int32_t frames; /* process cycle size in frames (can be -1 to indicate entire buffer) */
|
||||
uint32_t is_last; /* is it the last packet of a given cycle ('y' or 'n') */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define UDP_HEADER_SIZE 64 /* 40 bytes for IP header in IPV6, 20 in IPV4, 8 for UDP, so take 64 */
|
||||
|
||||
#define PACKET_AVAILABLE_SIZE(mtu) (mtu - UDP_HEADER_SIZE - sizeof(struct nj2_packet_header))
|
||||
|
||||
static inline void nj2_dump_packet_header(struct nj2_packet_header *header)
|
||||
{
|
||||
pw_log_info("Type: %s", header->type);
|
||||
pw_log_info("Data Type: %c", ntohl(header->data_type));
|
||||
pw_log_info("Data Stream: %c", ntohl(header->data_stream));
|
||||
pw_log_info("ID: %u", ntohl(header->id));
|
||||
pw_log_info("Num Packets: %u", ntohl(header->num_packets));
|
||||
pw_log_info("Packet Size: %u", ntohl(header->packet_size));
|
||||
pw_log_info("Active Ports: %u", ntohl(header->active_ports));
|
||||
pw_log_info("Cycle: %u", ntohl(header->cycle));
|
||||
pw_log_info("Sub Cycle: %u", ntohl(header->sub_cycle));
|
||||
pw_log_info("Frames %d", ntohl(header->frames));
|
||||
pw_log_info("Is Last: %u", ntohl(header->is_last));
|
||||
}
|
||||
|
||||
struct nj2_midi_event {
|
||||
uint32_t time; /**< Sample index at which event is valid */
|
||||
uint32_t size; /**< Number of bytes of data in the event */
|
||||
union {
|
||||
uint32_t offset; /**< offset in buffer */
|
||||
uint8_t buffer[4]; /**< Raw inline data */
|
||||
};
|
||||
};
|
||||
|
||||
struct nj2_midi_buffer {
|
||||
#define MIDI_BUFFER_MAGIC 0x900df00d
|
||||
uint32_t magic;
|
||||
int32_t buffer_size;
|
||||
uint32_t nframes;
|
||||
int32_t write_pos;
|
||||
uint32_t event_count;
|
||||
uint32_t lost_events;
|
||||
|
||||
struct nj2_midi_event event[1];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_NETJACK2_H */
|
Loading…
Reference in a new issue