diff --git a/src/modules/module-vban-recv.c b/src/modules/module-vban-recv.c index 52cf363a0..516e832ff 100644 --- a/src/modules/module-vban-recv.c +++ b/src/modules/module-vban-recv.c @@ -30,6 +30,7 @@ #include #include +#include #include "network-utils.h" /** \page page_module_vban_recv VBAN receiver @@ -37,6 +38,9 @@ * The `vban-recv` module creates a PipeWire source that receives audio * and midi [VBAN](https://vb-audio.com) packets. * + * The receive will listen on a specific port (6980) and create a stream for each + * VBAN stream received on the port. + * * ## Module Name * * `libpipewire-module-vban-recv` @@ -47,11 +51,9 @@ * * - `local.ifname = `: interface name to use * - `source.ip = `: the source ip address, default 127.0.0.1 - * - `source.port = `: the source port + * - `source.port = `: the source port, default 6980 * - `node.always-process = `: true to receive even when not running * - `sess.latency.msec = `: target network latency in milliseconds, default 100 - * - `sess.ignore-ssrc = `: ignore SSRC, default false - * - `sess.media = `: the media type audio|midi|opus, default audio * - `stream.props = {}`: properties to be passed to the stream * * ## General options @@ -59,9 +61,6 @@ * Options with well-known behavior: * * - \ref PW_KEY_REMOTE_NAME - * - \ref PW_KEY_AUDIO_FORMAT - * - \ref PW_KEY_AUDIO_RATE - * - \ref PW_KEY_AUDIO_CHANNELS * - \ref SPA_KEY_AUDIO_POSITION * - \ref PW_KEY_MEDIA_NAME * - \ref PW_KEY_MEDIA_CLASS @@ -82,12 +81,7 @@ * #source.ip = 127.0.0.1 * #source.port = 6980 * sess.latency.msec = 100 - * #sess.ignore-ssrc = false * #node.always-process = false - * #sess.media = "audio" - * #audio.format = "S16LE" - * #audio.rate = 44100 - * #audio.channels = 2 * #audio.position = [ FL FR ] * stream.props = { * #media.class = "Audio/Source" @@ -114,10 +108,6 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); "( source.ip= ) " \ "( source.port= " \ "( sess.latency.msec= ) "\ - "( sess.media= ) " \ - "( audio.format= ) " \ - "( audio.rate= ) " \ - "( audio.channels= ) " \ "( audio.position= ) " \ "( stream.props= { key=value ... } ) " @@ -146,47 +136,28 @@ struct impl { bool always_process; uint32_t cleanup_interval; - struct spa_source *timer; - struct pw_properties *stream_props; - struct vban_stream *stream; + + struct spa_source *timer; uint16_t src_port; struct sockaddr_storage src_addr; socklen_t src_len; struct spa_source *source; - unsigned receiving:1; + struct spa_list streams; }; -static void -on_vban_io(void *data, int fd, uint32_t mask) -{ - struct impl *impl = data; - ssize_t len; - uint8_t buffer[2048]; +struct stream { + struct spa_list link; + struct impl *impl; - if (mask & SPA_IO_IN) { - if ((len = recv(fd, buffer, sizeof(buffer), 0)) < 0) - goto receive_error; + struct vban_header header; + struct vban_stream *stream; - if (len < 12) - goto short_packet; - - if (SPA_LIKELY(impl->stream)) - vban_stream_receive_packet(impl->stream, buffer, len); - - impl->receiving = true; - } - return; - -receive_error: - pw_log_warn("recv error: %m"); - return; -short_packet: - pw_log_warn("short packet received"); - return; -} + bool active; + bool receiving; +}; static int make_socket(const struct sockaddr* sa, socklen_t salen, char *ifname) { @@ -266,7 +237,184 @@ error: return res; } -static int stream_start(struct impl *impl) +static void stream_destroy(void *d) +{ + struct stream *s = d; + s->stream = NULL; +} + +static void stream_state_changed(void *data, bool started, const char *error) +{ + struct stream *s = data; + struct impl *impl = s->impl; + + if (error) { + pw_log_error("stream error: %s", error); + pw_impl_module_schedule_destroy(impl->module); + } else if (started) { + s->active = true; + } else { + s->active = false; + } +} + +static const struct vban_stream_events stream_events = { + VBAN_VERSION_STREAM_EVENTS, + .destroy = stream_destroy, + .state_changed = stream_state_changed, +}; + +static int +do_setup_stream(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct stream *s = user_data; + struct impl *impl = s->impl; + struct pw_properties *props; + int res; + const char *sess_name; + + props = pw_properties_copy(impl->stream_props); + + pw_properties_setf(props, "sess.name", "%s", s->header.stream_name); + sess_name = pw_properties_get(props, "sess.name"); + + if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL) + pw_properties_setf(props, PW_KEY_NODE_NAME, "vban_session.%s", sess_name); + if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL) + pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "%s", sess_name); + if (pw_properties_get(props, PW_KEY_MEDIA_NAME) == NULL) + pw_properties_setf(props, PW_KEY_MEDIA_NAME, "VBAN Session %s", + sess_name); + + if ((s->header.format_SR & 0xE0) == VBAN_PROTOCOL_AUDIO && + (s->header.format_bit & 0xF0) == VBAN_CODEC_PCM) { + const char *fmt; + pw_properties_set(props, "sess.media", "audio"); + pw_properties_setf(props, PW_KEY_AUDIO_CHANNELS, "%u",s->header.format_nbc + 1); + pw_properties_setf(props, PW_KEY_AUDIO_RATE, "%u", vban_SR[s->header.format_SR & 0x1f]); + switch(s->header.format_bit & 0x07) { + case VBAN_DATATYPE_BYTE8: + fmt = "U8"; + break; + case VBAN_DATATYPE_INT16: + fmt = "S16LE"; + break; + case VBAN_DATATYPE_INT24: + fmt = "S24LE"; + break; + case VBAN_DATATYPE_INT32: + fmt = "S32LE"; + break; + case VBAN_DATATYPE_FLOAT32: + fmt = "F32LE"; + break; + case VBAN_DATATYPE_FLOAT64: + fmt = "F64LE"; + break; + break; + case VBAN_DATATYPE_12BITS: + case VBAN_DATATYPE_10BITS: + default: + pw_log_error("stream format %08x:%08x not supported", + s->header.format_SR, s->header.format_bit); + res = -ENOTSUP; + goto error; + } + pw_properties_set(props, PW_KEY_AUDIO_FORMAT, fmt); + } else if ((s->header.format_SR & 0xE0) == VBAN_PROTOCOL_SERIAL && + (s->header.format_bit & 0xF0) == VBAN_SERIAL_MIDI) { + pw_properties_set(props, "sess.media", "midi"); + } else { + pw_log_error("stream format %08x:%08x not supported", + s->header.format_SR, s->header.format_bit); + res = -ENOTSUP; + goto error; + } + + s->stream = vban_stream_new(impl->core, + PW_DIRECTION_OUTPUT, spa_steal_ptr(props), + &stream_events, s); + if (s->stream == NULL) { + pw_log_error("can't create stream: %m"); + return -errno; + } + return 0; +error: + pw_properties_free(props); + return res; +} + +static struct stream *make_stream(struct impl *impl, const struct vban_header *hdr) +{ + struct stream *stream; + + stream = calloc(1, sizeof(*stream)); + if (stream == NULL) + return NULL; + + stream->impl = impl; + stream->header = *hdr; + spa_list_append(&impl->streams, &stream->link); + + pw_loop_invoke(impl->loop, do_setup_stream, 1, NULL, 0, false, stream); + + return stream; +} + +static struct stream *find_stream(struct impl *impl, const char *name) +{ + struct stream *s; + spa_list_for_each(s, &impl->streams, link) { + if (strncmp(s->header.stream_name, name, VBAN_STREAM_NAME_SIZE) == 0) + return s; + } + return NULL; +} + +static void +on_vban_io(void *data, int fd, uint32_t mask) +{ + struct impl *impl = data; + ssize_t len; + uint8_t buffer[2048]; + + if (mask & SPA_IO_IN) { + struct vban_header *hdr; + struct stream *s; + + if ((len = recv(fd, buffer, sizeof(buffer), 0)) < 0) + goto receive_error; + + if (len < VBAN_HEADER_SIZE) + goto short_packet; + + hdr = (struct vban_header *)buffer; + if (strncmp(hdr->vban, "VBAN", 4)) + goto invalid_version; + + s = find_stream(impl, hdr->stream_name); + if (SPA_UNLIKELY(s == NULL)) + s = make_stream(impl, hdr); + if (SPA_LIKELY(s != NULL && s->active)) { + s->receiving = true; + vban_stream_receive_packet(s->stream, buffer, len); + } + } + return; + +receive_error: + pw_log_warn("recv error: %m"); + return; +short_packet: + pw_log_warn("short packet received"); + return; +invalid_version: + pw_log_warn("invalid VBAN version"); + return; +} + +static int listen_start(struct impl *impl) { int fd; @@ -291,7 +439,7 @@ static int stream_start(struct impl *impl) return 0; } -static void stream_stop(struct impl *impl) +static void listen_stop(struct impl *impl) { if (!impl->source) return; @@ -302,45 +450,29 @@ static void stream_stop(struct impl *impl) impl->source = NULL; } -static void stream_destroy(void *d) + +static void destroy_stream(struct stream *s) { - struct impl *impl = d; - impl->stream = NULL; + spa_list_remove(&s->link); + if (s->stream) + vban_stream_destroy(s->stream); + free(s); } -static void stream_state_changed(void *data, bool started, const char *error) -{ - struct impl *impl = data; - - if (error) { - pw_log_error("stream error: %s", error); - pw_impl_module_schedule_destroy(impl->module); - } else if (started) { - if ((errno = -stream_start(impl)) < 0) - pw_log_error("failed to start VBAN stream: %m"); - } else { - if (!impl->always_process) - stream_stop(impl); - } -} - -static const struct vban_stream_events stream_events = { - VBAN_VERSION_STREAM_EVENTS, - .destroy = stream_destroy, - .state_changed = stream_state_changed, -}; - static void on_timer_event(void *data, uint64_t expirations) { struct impl *impl = data; + struct stream *s; - if (!impl->receiving) { - pw_log_info("timeout, inactive VBAN source"); - //pw_impl_module_schedule_destroy(impl->module); - } else { - pw_log_debug("timeout, keeping active VBAN source"); + spa_list_for_each(s, &impl->streams, link) { + if (!s->receiving) { + pw_log_info("timeout, inactive VBAN source"); + //pw_impl_module_schedule_destroy(impl->module); + } else { + pw_log_debug("timeout, keeping active VBAN source"); + } + s->receiving = false; } - impl->receiving = false; } static void core_destroy(void *d) @@ -357,10 +489,12 @@ static const struct pw_proxy_events core_proxy_events = { static void impl_destroy(struct impl *impl) { - if (impl->stream) - vban_stream_destroy(impl->stream); - if (impl->source) - pw_loop_destroy_source(impl->data_loop, impl->source); + struct stream *s; + + listen_stop(impl); + + spa_list_consume(s, &impl->streams, link) + destroy_stream(s); if (impl->core && impl->do_disconnect) pw_core_disconnect(impl->core); @@ -420,7 +554,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) { struct pw_context *context = pw_impl_module_get_context(module); struct impl *impl; - const char *str, *sess_name; + const char *str; struct timespec value, interval; struct pw_properties *props, *stream_props; int res = 0; @@ -446,26 +580,14 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) impl->context = context; impl->loop = pw_context_get_main_loop(context); impl->data_loop = pw_context_acquire_loop(context, &props->dict); - - if ((sess_name = pw_properties_get(props, "sess.name")) == NULL) - sess_name = pw_get_host_name(); + spa_list_init(&impl->streams); pw_properties_set(props, PW_KEY_NODE_LOOP_NAME, impl->data_loop->name); - if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL) - pw_properties_setf(props, PW_KEY_NODE_NAME, "vban_session.%s", sess_name); - if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL) - pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "%s", sess_name); - if (pw_properties_get(props, PW_KEY_MEDIA_NAME) == NULL) - pw_properties_setf(props, PW_KEY_MEDIA_NAME, "VBAN Session with %s", - sess_name); if ((str = pw_properties_get(props, "stream.props")) != NULL) pw_properties_update_string(stream_props, str, strlen(str)); copy_props(impl, props, PW_KEY_NODE_LOOP_NAME); - copy_props(impl, props, PW_KEY_AUDIO_FORMAT); - copy_props(impl, props, PW_KEY_AUDIO_RATE); - copy_props(impl, props, PW_KEY_AUDIO_CHANNELS); copy_props(impl, props, SPA_KEY_AUDIO_POSITION); copy_props(impl, props, PW_KEY_NODE_NAME); copy_props(impl, props, PW_KEY_NODE_DESCRIPTION); @@ -476,10 +598,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) copy_props(impl, props, PW_KEY_MEDIA_NAME); copy_props(impl, props, PW_KEY_MEDIA_CLASS); copy_props(impl, props, "net.mtu"); - copy_props(impl, props, "sess.media"); - copy_props(impl, props, "sess.name"); - copy_props(impl, props, "sess.min-ptime"); - copy_props(impl, props, "sess.max-ptime"); copy_props(impl, props, "sess.latency.msec"); str = pw_properties_get(props, "local.ifname"); @@ -538,12 +656,8 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) interval.tv_nsec = 0; pw_loop_update_timer(impl->loop, impl->timer, &value, &interval, false); - impl->stream = vban_stream_new(impl->core, - PW_DIRECTION_OUTPUT, pw_properties_copy(stream_props), - &stream_events, impl); - if (impl->stream == NULL) { - res = -errno; - pw_log_error("can't create stream: %m"); + if ((res = listen_start(impl)) < 0) { + pw_log_error("failed to start VBAN stream: %s", spa_strerror(res)); goto out; } diff --git a/src/modules/module-vban-send.c b/src/modules/module-vban-send.c index b0861e9c9..5fc6793a1 100644 --- a/src/modules/module-vban-send.c +++ b/src/modules/module-vban-send.c @@ -26,6 +26,7 @@ #include #include +#include #include "network-utils.h" #ifndef IPTOS_DSCP @@ -354,6 +355,7 @@ SPA_EXPORT int pipewire__module_init(struct pw_impl_module *module, const char *args) { struct pw_context *context = pw_impl_module_get_context(module); + uint32_t id = pw_global_get_id(pw_impl_module_get_global(module)); struct impl *impl; struct pw_properties *props = NULL, *stream_props = NULL; char addr[64]; @@ -382,7 +384,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) stream_props = pw_properties_new(NULL, NULL); if (stream_props == NULL) { res = -errno; - pw_log_error( "can't create properties: %m"); + pw_log_error("can't create properties: %m"); goto out; } impl->stream_props = stream_props; @@ -391,15 +393,22 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) impl->context = context; impl->loop = pw_context_get_main_loop(context); + if ((sess_name = pw_properties_get(props, "sess.name")) == NULL) + pw_properties_setf(props, "sess.name", "%s-%d", + pw_get_host_name(), id); if ((sess_name = pw_properties_get(props, "sess.name")) == NULL) sess_name = pw_get_host_name(); + if (strlen(sess_name) > VBAN_STREAM_NAME_SIZE) + pw_log_warn("session name '%s' will be truncated to %d characters", + sess_name, VBAN_STREAM_NAME_SIZE); + if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL) pw_properties_setf(props, PW_KEY_NODE_NAME, "vban_session.%s", sess_name); if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL) pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "%s", sess_name); if (pw_properties_get(props, PW_KEY_MEDIA_NAME) == NULL) - pw_properties_setf(props, PW_KEY_MEDIA_NAME, "VBAN Session with %s", + pw_properties_setf(props, PW_KEY_MEDIA_NAME, "VBAN Session %s", sess_name); if ((str = pw_properties_get(props, "stream.props")) != NULL) diff --git a/src/modules/module-vban/audio.c b/src/modules/module-vban/audio.c index 4aa0fae98..5e5c85c26 100644 --- a/src/modules/module-vban/audio.c +++ b/src/modules/module-vban/audio.c @@ -92,12 +92,7 @@ static int vban_audio_receive(struct impl *impl, uint8_t *buffer, ssize_t len) uint32_t stride = impl->stride; int32_t filled; - if (len < VBAN_HEADER_SIZE) - goto short_packet; - hdr = (struct vban_header*)buffer; - if (strncmp(hdr->vban, "VBAN", 3)) - goto invalid_version; impl->receiving = true; @@ -155,14 +150,6 @@ static int vban_audio_receive(struct impl *impl, uint8_t *buffer, ssize_t len) spa_ringbuffer_write_update(&impl->ring, write); } return 0; - -short_packet: - pw_log_warn("short packet received"); - return -EINVAL; -invalid_version: - pw_log_warn("invalid VBAN version"); - spa_debug_log_mem(pw_log_get(), SPA_LOG_LEVEL_INFO, 0, buffer, len); - return -EPROTO; } static inline void diff --git a/src/modules/module-vban/midi.c b/src/modules/module-vban/midi.c index 239472a98..f820b6839 100644 --- a/src/modules/module-vban/midi.c +++ b/src/modules/module-vban/midi.c @@ -201,13 +201,7 @@ static int vban_midi_receive(struct impl *impl, uint8_t *buffer, ssize_t len) ssize_t hlen; uint32_t n_frames; - if (len < VBAN_HEADER_SIZE) - goto short_packet; - hdr = (struct vban_header*)buffer; - if (strncmp(hdr->vban, "VBAN", 3)) - goto invalid_version; - hlen = VBAN_HEADER_SIZE; n_frames = hdr->n_frames; @@ -221,14 +215,6 @@ static int vban_midi_receive(struct impl *impl, uint8_t *buffer, ssize_t len) impl->receiving = true; return vban_midi_receive_midi(impl, buffer, hlen, len); - -short_packet: - pw_log_warn("short packet received"); - return -EINVAL; -invalid_version: - pw_log_warn("invalid RTP version"); - spa_debug_log_mem(pw_log_get(), SPA_LOG_LEVEL_INFO, 0, buffer, len); - return -EPROTO; } static void vban_midi_flush_packets(struct impl *impl, diff --git a/src/modules/module-vban/stream.c b/src/modules/module-vban/stream.c index 0862dbc81..59ff351a4 100644 --- a/src/modules/module-vban/stream.c +++ b/src/modules/module-vban/stream.c @@ -94,13 +94,13 @@ struct format_info { }; static const struct format_info audio_format_info[] = { - { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_U8, 1, VBAN_DATATYPE_U8, }, + { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_U8, 1, VBAN_DATATYPE_BYTE8, }, { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S16_LE, 2, VBAN_DATATYPE_INT16, }, { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S24_LE, 3, VBAN_DATATYPE_INT24, }, { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S32_LE, 4, VBAN_DATATYPE_INT32, }, { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_F32_LE, 4, VBAN_DATATYPE_FLOAT32, }, { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_F64_LE, 8, VBAN_DATATYPE_FLOAT64, }, - { SPA_MEDIA_SUBTYPE_control, 0, 1, VBAN_SERIAL_MIDI | VBAN_DATATYPE_U8, }, + { SPA_MEDIA_SUBTYPE_control, 0, 1, VBAN_SERIAL_MIDI | VBAN_DATATYPE_BYTE8, }, }; static void stream_io_changed(void *data, uint32_t id, void *area, uint32_t size) @@ -290,7 +290,7 @@ struct vban_stream *vban_stream_new(struct pw_core *core, if (impl->rate == 0) impl->rate = 10000; - impl->header.format_SR = (0x1 << 5) | 14; /* 115200 */ + impl->header.format_SR = VBAN_PROTOCOL_SERIAL | vban_BPSList[14]; /* 115200 */ impl->header.format_nbs = 0; impl->header.format_nbc = 0; impl->header.format_bit = impl->format_info->format_bit; diff --git a/src/modules/module-vban/vban.h b/src/modules/module-vban/vban.h index bf1299200..7557de23f 100644 --- a/src/modules/module-vban/vban.h +++ b/src/modules/module-vban/vban.h @@ -17,21 +17,30 @@ extern "C" { #define VBAN_SAMPLES_MAX_NB 256 struct vban_header { - char vban[4]; /* contains 'V' 'B', 'A', 'N' */ - uint8_t format_SR; /* SR index */ - uint8_t format_nbs; /* nb sample per frame (1 to 256) */ - uint8_t format_nbc; /* nb channel (1 to 256) */ - uint8_t format_bit; /* bit format */ + char vban[4]; /* contains 'V' 'B', 'A', 'N' */ + uint8_t format_SR; /* SR index */ + uint8_t format_nbs; /* nb sample per frame (1 to 256) */ + uint8_t format_nbc; /* nb channel (1 to 256) */ + uint8_t format_bit; /* bit format */ char stream_name[VBAN_STREAM_NAME_SIZE]; /* stream name */ - uint32_t n_frames; /* growing frame number. */ + uint32_t n_frames; /* growing frame number. */ } __attribute__ ((packed)); +#define VBAN_PROTOCOL_AUDIO 0x00 +#define VBAN_PROTOCOL_SERIAL 0x20 +#define VBAN_PROTOCOL_TXT 0x40 +#define VBAN_PROTOCOL_SERVICE 0x60 +#define VBAN_PROTOCOL_UNDEFINED_1 0x80 +#define VBAN_PROTOCOL_UNDEFINED_2 0xA0 +#define VBAN_PROTOCOL_UNDEFINED_3 0xC0 +#define VBAN_PROTOCOL_USER 0xE0 + #define VBAN_SR_MAXNUMBER 21 -static uint32_t const vban_SR[VBAN_SR_MAXNUMBER] = { - 6000, 12000, 24000, 48000, 96000, 192000, 384000, - 8000, 16000, 32000, 64000, 128000, 256000, 512000, - 11025, 22050, 44100, 88200, 176400, 352800, 705600 +static uint32_t const vban_SR[32] = { + 6000, 12000, 24000, 48000, 96000, 192000, 384000, + 8000, 16000, 32000, 64000, 128000, 256000, 512000, + 11025, 22050, 44100, 88200, 176400, 352800, 705600 }; static inline uint8_t vban_sr_index(uint32_t rate) @@ -44,7 +53,37 @@ static inline uint8_t vban_sr_index(uint32_t rate) return VBAN_SR_MAXNUMBER; } -#define VBAN_DATATYPE_U8 0x00 +#define VBAN_CODEC_PCM 0x00 +#define VBAN_CODEC_VBCA 0x10 //VB-AUDIO AOIP CODEC +#define VBAN_CODEC_VBCV 0x20 //VB-AUDIO VOIP CODEC +#define VBAN_CODEC_UNDEFINED_1 0x30 +#define VBAN_CODEC_UNDEFINED_2 0x40 +#define VBAN_CODEC_UNDEFINED_3 0x50 +#define VBAN_CODEC_UNDEFINED_4 0x60 +#define VBAN_CODEC_UNDEFINED_5 0x70 +#define VBAN_CODEC_UNDEFINED_6 0x80 +#define VBAN_CODEC_UNDEFINED_7 0x90 +#define VBAN_CODEC_UNDEFINED_8 0xA0 +#define VBAN_CODEC_UNDEFINED_9 0xB0 +#define VBAN_CODEC_UNDEFINED_10 0xC0 +#define VBAN_CODEC_UNDEFINED_11 0xD0 +#define VBAN_CODEC_UNDEFINED_12 0xE0 +#define VBAN_CODEC_USER 0xF0 + +#define VBAN_BPS_MAXNUMBER 25 + +static const long vban_BPSList[32] = { + 0, 110, 150, 300, 600, 1200, 2400, 4800, 9600, + 14400, 19200, 31250, 38400, 57600, 115200, 128000, + 230400, 250000, 256000, 460800, 921600, 1000000, + 1500000, 2000000, 3000000 +}; + +#define VBAN_SERIAL_GENERIC 0x00 +#define VBAN_SERIAL_MIDI 0x10 +#define VBAN_SERIAL_USER 0xf0 + +#define VBAN_DATATYPE_BYTE8 0x00 #define VBAN_DATATYPE_INT16 0x01 #define VBAN_DATATYPE_INT24 0x02 #define VBAN_DATATYPE_INT32 0x03 @@ -53,10 +92,6 @@ static inline uint8_t vban_sr_index(uint32_t rate) #define VBAN_DATATYPE_12BITS 0x06 #define VBAN_DATATYPE_10BITS 0x07 -#define VBAN_SERIAL_GENERIC 0x00 -#define VBAN_SERIAL_MIDI 0x10 -#define VBAN_SERIAL_USER 0xf0 - #ifdef __cplusplus } #endif