udp://<address>:<port><
at the risk of conflict with other protocols (''MPEG-TS'' or ''Matroska'').
Note: When handling AVTransport files, it is recommended to use the .avt file extension.
+Alternatively, for image-only files, .ati is recommended, and for subtitles,
+the recommendation is .avs.
# Packet structure # {#packet-structure}
@@ -646,6 +648,10 @@ as an AVTransport session. The syntax is as follows:
Multiple session packets may be present in a session, but must remain
bytewise-identical.
+The [=producer_name=] field is a fixed-length string, meaning that
+the field is always 16 bytes. If the name is less than 16 bytes, it must
+be zero-padded.
+
## Stream Session Flags Enumeration (enum SessionFlags) ## {#enum-SessionFlags}
The [=session_flags=] field must be interpreted in the following way:
@@ -731,7 +737,7 @@ The structure of the data in a [[#time-synchronization-packets]] packet is as fo
The ts_clock_freq field is equal to [=ts_clock_freq=] = [=ts_clock_hz=] + [=ts_clock_hz2=]/65536
.
Implementations should prefer to use integer math, and instead have the [=ts_clock_freq=] in increments of 1/65536 Hz.
-Note: if [=ts_clock_freq=] is 0, then the sender should be assumed to be relying entirely on its real-time clock.
+Note: If [=ts_clock_freq=] is 0, then the sender should be assumed to be relying entirely on its real-time clock.
The field defines a strictly monotonic clock signal with a rate of [=ts_clock_freq=], which atomically increments a counter,
[=ts_clock_seq=] on the rising edge of the waveform.
@@ -2165,7 +2171,7 @@ The following structure MUST be followed:
The stream ID for which to make the font available.
- Note: may be set to ''0xffff'' to make the font available for all streams.
+ Note: May be set to ''0xffff'' to make the font available for all streams.
|
@@ -2520,7 +2526,7 @@ The [=colorspace=] field must be interpreted in the following way:
: CSP_XYB = 0x6
:: Video contains XYB color data, as defined by [[ISO18181]].
- Note: [matrix] must be equal to ''0xFF'' and the [=custom_matrix=] must be a valid matrix to transform XYB into RGB.
+ Note: [=matrix=] must be equal to ''0xFF'' and the [=custom_matrix=] must be a valid matrix to transform XYB into RGB.
: CSP_ICTCP = 0x5
:: Video contains [[BT2100]] ICtCp color data.
@@ -2543,7 +2549,7 @@ The [=colorspace=] field must be interpreted in the following way:
: COLOR_RANGE_LIMITED = 0x1
:: Video sample values contains the limited range of the [=bit_depth=].
- Note: this describes the cannonical limited range representation:
+ Note: This describes the cannonical limited range representation:
(219 * E + 16) * 2([=bit_depth=]-8)
,
where E
, the input range, is ''0.0'' to ''1.0'' for luma planes and
''-0.5'' to ''0.5'' for chroma planes. This means, for 8-bits, the luma
@@ -2572,7 +2578,7 @@ to interpret the value of [=field_id=] in stream data packet headers.
: ILACE_PROG = 0x0
:: Video contains progressive data, or interlacing does not apply.
- Note: in this mode, the [=field_id=] bit is free to use by users. Implementations must ignore it, and preserve it.
+ Note: In this mode, the [=field_id=] bit is free to use by users. Implementations must ignore it, and preserve it.
: ILACE_TFF = 0x1
:: Video is interlaced. One [[#stream-data-packets]] packet per field. If the data packet's [=field_id=] bit is unset, indicates the field contained is the top field, otherwise it's the bottom field.
@@ -2683,7 +2689,7 @@ These values are copied verbatim from [[H.273]].
:: SMPTE EG 432-2 (2010)
-Note: this list may not be up to date in this version of the AVTransport specifications.
+Note: This list may not be up to date in this version of the AVTransport specifications.
Users should consult [[H.273]] for up-to-date values and how to interpret them.
@@ -4617,7 +4623,7 @@ The matrices are also listed as standard .alist files, directly usable for analy
#### ldpc_h_matrix_288_224 #### {#ldpc_h_matrix_288_224}
-Note: spaceholder, working and optimal tables to be done
+Note: Spaceholder, working and optimal tables to be done
alist code:
@@ -4707,7 +4713,7 @@ const uint64_t ldpc_h_matrix_288_224[288 /* (64 rows/64) * 288 cols */] = {
#### ldpc_h_matrix_2784_2016 #### {#ldpc_h_matrix_2784_2016}
-Note: spaceholder, working and optimal tables to be done
+Note: Spaceholder, working and optimal tables to be done
alist code:
diff --git a/libavtransport/address.c b/libavtransport/address.c
index dc24c80..dbfa704 100644
--- a/libavtransport/address.c
+++ b/libavtransport/address.c
@@ -112,6 +112,10 @@ int avt_addr_from_url(void *log_ctx, AVTAddress *addr,
/* Unofficial and conflicting, but let's accept it */
addr->proto = AVT_PROTOCOL_UDP;
next += strlen("udp://");
+ } else if (!strncmp(next, "udplite://", strlen("udplite://"))) {
+ /* Unofficial, but let's accept it */
+ addr->proto = AVT_PROTOCOL_UDP_LITE;
+ next += strlen("udplite://");
} else if (!strncmp(next, "quic://", strlen("quic://"))) {
/* Unofficial, but let's accept it */
addr->proto = AVT_PROTOCOL_QUIC;
diff --git a/libavtransport/connection.c b/libavtransport/connection.c
index d2ff44d..6417b98 100644
--- a/libavtransport/connection.c
+++ b/libavtransport/connection.c
@@ -96,25 +96,54 @@ int avt_connection_send(AVTConnection *conn,
{
int err;
- err = avt_pkt_fifo_push(&conn->out_fifo_pre, pkt, pl);
- if (err < 0)
- return err;
+// err = avt_pkt_fifo_push(&conn->out_fifo_pre, pkt, pl);
+// if (err < 0)
+// return err;
err = avt_scheduler_push(&conn->out_scheduler, pkt, pl);
if (err < 0)
return err;
+// AVTPacketFifo *seq;
+// err = avt_scheduler_pop(&conn->out_scheduler, &seq);
+// if (err < 0)
+// return err;
+
+ return 0;
+}
+
+int avt_connection_process(AVTConnection *conn, int64_t timeout)
+{
+ int err;
+
AVTPacketFifo *seq;
err = avt_scheduler_pop(&conn->out_scheduler, &seq);
if (err < 0)
return err;
+ err = conn->p->send_seq(conn->ctx, conn->p_ctx, seq, timeout);
+ if (err < 0)
+ avt_scheduler_done(&conn->out_scheduler, seq);
+
return 0;
}
int avt_connection_flush(AVTConnection *conn, int64_t timeout)
{
- return 0;
+ int err;
+
+ AVTPacketFifo *seq;
+ err = avt_scheduler_flush(&conn->out_scheduler, &seq);
+ if (err < 0)
+ return err;
+
+ if (seq) {
+ err = conn->p->send_seq(conn->ctx, conn->p_ctx, seq, timeout);
+ if (err < 0)
+ avt_scheduler_done(&conn->out_scheduler, seq);
+ }
+
+ return conn->p->flush(conn->ctx, conn->p_ctx, timeout);
}
int avt_connection_destroy(AVTConnection **_conn)
diff --git a/libavtransport/include/avtransport/connection.h b/libavtransport/include/avtransport/connection.h
index a7497f8..672bee5 100644
--- a/libavtransport/include/avtransport/connection.h
+++ b/libavtransport/include/avtransport/connection.h
@@ -126,12 +126,12 @@ typedef struct AVTConnectionInfo {
* NOTE: dup()-licated on success, users can close() this freely */
int fd;
- /* AVT_CONNECTION_NET: opened and bound network socket */
+ /* AVT_CONNECTION_NET: opened and bound/connected network socket */
struct {
/* Bound socket
* NOTE: dup()'d on success, users can close() this freely */
int socket;
- /* Sending: destination IP (IPv4: mapped in IPv6) */
+ /* Sending: destination IP (IPv4 must be always mapped in IPv6) */
uint8_t dst[16];
/* Connection port */
uint16_t port;
diff --git a/libavtransport/io_common.c b/libavtransport/io_common.c
index 0062aa0..0773849 100644
--- a/libavtransport/io_common.c
+++ b/libavtransport/io_common.c
@@ -35,9 +35,8 @@ extern const AVTIO avt_io_fd;
extern const AVTIO avt_io_fd_path;
#endif
-#ifndef _WIN32
extern const AVTIO avt_io_udp;
-#endif
+extern const AVTIO avt_io_udp_lite;
#define MAX_NB_BACKENDS 4
@@ -58,9 +57,10 @@ static const AVTIO *avt_io_list[][MAX_NB_BACKENDS] = {
#endif
},
[AVT_IO_UDP] = {
-#ifndef _WIN32
&avt_io_udp,
-#endif
+ },
+ [AVT_IO_UDP_LITE] = {
+ &avt_io_udp_lite,
},
};
diff --git a/libavtransport/io_common.h b/libavtransport/io_common.h
index 166d017..af09011 100644
--- a/libavtransport/io_common.h
+++ b/libavtransport/io_common.h
@@ -31,10 +31,11 @@
#include "packet_common.h"
enum AVTIOType {
- AVT_IO_FILE, /* Takes a path */
- AVT_IO_FD, /* Takes an integer handle fd */
- AVT_IO_UDP, /* UDP network connection */
- AVT_IO_NULL, /* Takes nothing */
+ AVT_IO_FILE, /* Takes a path */
+ AVT_IO_FD, /* Takes an integer handle fd */
+ AVT_IO_UDP, /* UDP network connection */
+ AVT_IO_UDP_LITE, /* UDP-Lite network connection */
+ AVT_IO_NULL, /* Takes nothing */
};
/* Low level interface */
diff --git a/libavtransport/io_socket_common.c b/libavtransport/io_socket_common.c
index 7446d69..e3d3e79 100644
--- a/libavtransport/io_socket_common.c
+++ b/libavtransport/io_socket_common.c
@@ -99,7 +99,7 @@ int avt_socket_open(void *log_ctx, AVTSocketCommon *sc, AVTAddress *addr)
int ret;
int proto = addr->proto == AVT_PROTOCOL_UDP_LITE ? IPPROTO_UDPLITE : IPPROTO_UDP;
- if ((sc->socket = socket(AF_INET6, SOCK_DGRAM, proto)) < 0) {
+ if ((sc->socket = socket(AF_INET6, SOCK_DGRAM, proto)) < 0) {
ret = avt_handle_errno(log_ctx, "Failed to open socket: %i %s\n");
sc->socket = -1;
return ret;
@@ -154,6 +154,14 @@ int avt_socket_open(void *log_ctx, AVTSocketCommon *sc, AVTAddress *addr)
/* Enable MTU monitoring */
// SET_SOCKET_OPT(log_ctx, sc, IPPROTO_IPV6, IPV6_RECVPATHMTU, (int)1);
+#ifdef IPV6_FREEBIND
+ /* Enable free binding when no interface is given.
+ * This lets us not have to deal with dynamic reconfiguration, new
+ * devices being added, and so on */
+ if (addr->listen && !addr->interface)
+ SET_SOCKET_OPT(log_ctx, sc, IPPROTO_IPV6, IPV6_FREEBIND, (int)1);
+#endif
+
/* Setup binding */
sc->local_addr.sin6_family = AF_INET6;
sc->local_addr.sin6_port = addr->port;
diff --git a/libavtransport/io_udp.c b/libavtransport/io_udp.c
index cd23883..fe4a590 100644
--- a/libavtransport/io_udp.c
+++ b/libavtransport/io_udp.c
@@ -125,7 +125,7 @@ static int64_t udp_write_vec(AVTContext *ctx, AVTIOCtx *io,
AVTPktd *iov, uint32_t nb_iov,
int64_t timeout)
{
- int64_t ret;
+ int64_t ret = 0;
int64_t timeout_per = timeout / nb_iov;
for (int i = 0; i < nb_iov; i++) {
ret = udp_write_pkt(ctx, io, &iov[i], timeout_per);
@@ -138,7 +138,7 @@ static int64_t udp_write_vec(AVTContext *ctx, AVTIOCtx *io,
static int64_t udp_read_input(AVTContext *ctx, AVTIOCtx *io,
AVTBuffer **_buf, size_t len, int64_t timeout)
{
- int ret, err;
+ int ret;
uint8_t *data;
size_t buf_len, off = 0;
AVTBuffer *buf = *_buf;
@@ -166,13 +166,14 @@ static int64_t udp_read_input(AVTContext *ctx, AVTIOCtx *io,
struct sockaddr_in6 remote_addr = { };
socklen_t remote_addr_len = sizeof(remote_addr);
- ret = recvfrom(io->sc.socket, data, buf_len,
+ ret = recvfrom(io->sc.socket, data + off, buf_len,
!timeout ? MSG_DONTWAIT : 0,
&remote_addr, &remote_addr_len);
if (ret < 0)
return avt_handle_errno(io, "Unable to receive message: %s");
/* Adjust new size in case of underreads */
+ [[maybe_unused]] int err;
err = avt_buffer_resize(buf, off + len);
avt_assert2(err >= 0);
@@ -203,3 +204,17 @@ const AVTIO avt_io_udp = {
.flush = NULL,
.close = udp_close,
};
+
+const AVTIO avt_io_udp_lite = {
+ .name = "udp_lite",
+ .type = AVT_IO_UDP_LITE,
+ .init = udp_init,
+ .get_max_pkt_len = udp_max_pkt_len,
+ .read_input = udp_read_input,
+ .write_vec = udp_write_vec,
+ .write_pkt = udp_write_pkt,
+ .rewrite = NULL,
+ .seek = NULL,
+ .flush = NULL,
+ .close = udp_close,
+};
diff --git a/libavtransport/output_packet.c b/libavtransport/output_packet.c
index 4087ce8..92e6557 100644
--- a/libavtransport/output_packet.c
+++ b/libavtransport/output_packet.c
@@ -201,49 +201,6 @@ int avt_send_stream_register(AVTOutput *out, AVTStream *st)
return send_pkt(out, pkt, nullptr);
}
-#define INIT_SEGMENTED(buf, desc) \
- int err; \
- void *series = NULL; \
- size_t maxp = avt_packet_get_max_size(out); \
- size_t payload_size = avt_buffer_get_data_len(buf); \
- size_t pbytes = payload_size; \
- size_t seg_len = AVT_MIN(pbytes, maxp); \
- \
- enum AVTDataCompression data_compression; \
- err = avt_payload_compress(out, &buf, desc, &data_compression); \
- if (err < 0) \
- return err; \
- \
- AVTBuffer tmp; \
- avt_buffer_quick_ref(&tmp, buf, 0, seg_len);
-
-#define SEGMENT(buf, seg_desc) \
- avt_buffer_quick_unref(&tmp); \
- if (err < 0) \
- return err; \
- \
- pbytes -= seg_len; \
- while (pbytes) { \
- const uint32_t seq = atomic_fetch_add(&out->seq, 1ULL) & UINT32_MAX; \
- seg_len = AVT_MIN(pbytes, maxp); \
- avt_buffer_quick_ref(&tmp, buf, payload_size - pbytes, seg_len); \
- union AVTPacketData seg = { .generic_segment = { \
- .generic_segment_descriptor = seg_desc, \
- .stream_id = st->id, \
- .pkt_total_data = payload_size, \
- .seg_offset = payload_size - pbytes, \
- .seg_length = seg_len, \
- }}; \
- \
- avt_buffer_quick_unref(&tmp); \
- if (err < 0) \
- break; \
- \
- pbytes -= seg_len; \
- } while (pbytes); \
- \
- return err;
-
int avt_send_stream_data(AVTOutput *out, AVTStream *st, AVTPacket *pkt)
{
/* Compress payload if necessary */
diff --git a/libavtransport/protocol_common.h b/libavtransport/protocol_common.h
index 986b468..c75c2cc 100644
--- a/libavtransport/protocol_common.h
+++ b/libavtransport/protocol_common.h
@@ -50,12 +50,13 @@ typedef struct AVTProtocol {
/* Send. Returns positive offset on success, otherwise negative error.
* Returns offset to which packet was written to. */
int64_t (*send_packet)(AVTContext *ctx, AVTProtocolCtx *p,
- union AVTPacketData pkt, AVTBuffer *pl);
+ union AVTPacketData pkt, AVTBuffer *pl,
+ int64_t timeout);
/* Send a sequence of packets. Returns positive offset on success,
otherwise negative error */
int64_t (*send_seq)(AVTContext *ctx, AVTProtocolCtx *p,
- AVTPacketFifo *seq);
+ AVTPacketFifo *seq, int64_t timeout);
/* Overwrite a packet at a given offset */
int (*update_packet)(AVTContext *ctx, AVTProtocolCtx *p,
diff --git a/libavtransport/protocol_noop.c b/libavtransport/protocol_noop.c
index fb5f053..c774b52 100644
--- a/libavtransport/protocol_noop.c
+++ b/libavtransport/protocol_noop.c
@@ -66,7 +66,8 @@ static int noop_rm_dst(AVTContext *ctx, AVTProtocolCtx *p, AVTAddress *addr)
}
static int64_t noop_send_packet(AVTContext *ctx, AVTProtocolCtx *p,
- union AVTPacketData pkt, AVTBuffer *pl)
+ union AVTPacketData pkt, AVTBuffer *pl,
+ int64_t timeout)
{
uint8_t hdr[AVT_MAX_HEADER_LEN];
size_t hdr_len = 0;
@@ -78,12 +79,11 @@ static int64_t noop_send_packet(AVTContext *ctx, AVTProtocolCtx *p,
}
static int64_t noop_send_seq(AVTContext *ctx, AVTProtocolCtx *p,
- AVTPacketFifo *seq)
+ AVTPacketFifo *seq, int64_t timeout)
{
- uint8_t hdr[AVT_MAX_HEADER_LEN];
- size_t hdr_len = 0;
+ int err;
- // TODO
+ err = p->io->write_vec(ctx, p->io_ctx, seq->data, seq->nb, timeout);
return 0;
}
diff --git a/libavtransport/scheduler.c b/libavtransport/scheduler.c
index 7c10e31..4e7bf5c 100644
--- a/libavtransport/scheduler.c
+++ b/libavtransport/scheduler.c
@@ -385,6 +385,11 @@ int avt_scheduler_pop(AVTScheduler *s, AVTPacketFifo **seq)
return 0;
}
+int avt_scheduler_flush(AVTScheduler *s, AVTPacketFifo **seq)
+{
+ return 0;
+}
+
int avt_scheduler_done(AVTScheduler *s, AVTPacketFifo *seq)
{
avt_assert1(seq->nb); /* Scheduler FIFO was not fully consumed */
diff --git a/libavtransport/scheduler.h b/libavtransport/scheduler.h
index 0bd7264..3a86d6c 100644
--- a/libavtransport/scheduler.h
+++ b/libavtransport/scheduler.h
@@ -100,6 +100,9 @@ int avt_scheduler_push(AVTScheduler *s,
union AVTPacketData pkt, AVTBuffer *pl);
int avt_scheduler_pop(AVTScheduler *s, AVTPacketFifo **seq);
+
+int avt_scheduler_flush(AVTScheduler *s, AVTPacketFifo **seq);
+
int avt_scheduler_done(AVTScheduler *s, AVTPacketFifo *seq);
void avt_scheduler_free(AVTScheduler *s);
diff --git a/libavtransport/tests/file_io_template.c b/libavtransport/tests/file_io_common.c
similarity index 84%
rename from libavtransport/tests/file_io_template.c
rename to libavtransport/tests/file_io_common.c
index fd9acc0..67937cd 100644
--- a/libavtransport/tests/file_io_template.c
+++ b/libavtransport/tests/file_io_common.c
@@ -24,10 +24,12 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include
#include
-#include
+#include
+
+#include "file_io_common.h"
+#include
#include "packet_common.h"
static int read_fn(AVTContext *avt, const AVTIO *io, AVTIOCtx *io_ctx,
@@ -44,26 +46,26 @@ static int read_fn(AVTContext *avt, const AVTIO *io, AVTIOCtx *io_ctx,
/* Read */
ret = io->read_input(avt, io_ctx, test_buf, bytes, INT64_MAX);
if (ret <= 0) {
- printf("No bytes read\n");
+ avt_log(avt, AVT_LOG_ERROR, "No bytes read\n");
return AVT_ERROR(EINVAL);
}
if ((ret - pre) != bytes) {
- printf("Too few bytes read: got %" PRIi64 "; wanted %i\n", ret, bytes);
+ avt_log(avt, AVT_LOG_ERROR, "Too few bytes read: got %" PRIi64 "; wanted %i\n", ret, bytes);
return AVT_ERROR(EINVAL);
}
/* Check data read */
test_buf_data = avt_buffer_get_data(*test_buf, &test_buf_size);
if (memcmp(test_buf_data, test_pkt->hdr, test_buf_size)) {
- printf("Mismatch between read and written data!\n");
+ avt_log(avt, AVT_LOG_ERROR, "Mismatch between read and written data!\n");
return AVT_ERROR(EINVAL);
}
return 0;
}
-static int test_io(AVTContext *avt, const AVTIO *io, AVTIOCtx *io_ctx)
+int file_io_test(AVTContext *avt, const AVTIO *io, AVTIOCtx *io_ctx)
{
int64_t ret;
@@ -84,12 +86,12 @@ static int test_io(AVTContext *avt, const AVTIO *io, AVTIOCtx *io_ctx)
if (ret < 0) {
goto fail;
} else if (ret == 0) {
- printf("No bytes written\n");
+ avt_log(avt, AVT_LOG_ERROR,"No bytes written\n");
ret = AVT_ERROR(EINVAL);
goto fail;
} else if (ret != sum) {
- printf("Bytes written do not match: got %" PRIi64 "; wanted %" PRIi64 "\n",
- ret, sum);
+ avt_log(avt, AVT_LOG_ERROR,"Bytes written do not match: got %" PRIi64 "; wanted %" PRIi64 "\n",
+ ret, sum);
ret = AVT_ERROR(EINVAL);
goto fail;
}
@@ -110,11 +112,11 @@ static int test_io(AVTContext *avt, const AVTIO *io, AVTIOCtx *io_ctx)
int64_t off = io->read_input(avt, io_ctx, &buf, test_pkt[i].hdr_len,
INT64_MAX);
if (off == 0) {
- printf("No bytes read\n");
+ avt_log(avt, AVT_LOG_ERROR,"No bytes read\n");
ret = AVT_ERROR(EINVAL);
goto fail;
} else if (off < 0) {
- printf("Error reading\n");
+ avt_log(avt, AVT_LOG_ERROR,"Error reading\n");
ret = off;
goto fail;
}
@@ -124,8 +126,8 @@ static int test_io(AVTContext *avt, const AVTIO *io, AVTIOCtx *io_ctx)
if ((diff != test_pkt[i].hdr_len) ||
((i == (AVT_ARRAY_ELEMS(test_pkt) - 1)) && (sum != off))) {
- printf("Too few bytes read: got %" PRIi64 "; wanted %i\n",
- diff, test_pkt[i].hdr_len);
+ avt_log(avt, AVT_LOG_ERROR,"Too few bytes read: got %" PRIi64 "; wanted %i\n",
+ diff, test_pkt[i].hdr_len);
ret = AVT_ERROR(EINVAL);
goto fail;
}
@@ -133,7 +135,7 @@ static int test_io(AVTContext *avt, const AVTIO *io, AVTIOCtx *io_ctx)
size_t test_buf_size;
uint8_t *test_buf_data = avt_buffer_get_data(buf, &test_buf_size);
if (memcmp(test_buf_data, test_pkt[i].hdr, test_buf_size)) {
- printf("Mismatch between read and written data!\n");
+ avt_log(avt, AVT_LOG_ERROR,"Mismatch between read and written data!\n");
goto fail;
}
diff --git a/libavtransport/tests/file_io_common.h b/libavtransport/tests/file_io_common.h
new file mode 100644
index 0000000..33bc992
--- /dev/null
+++ b/libavtransport/tests/file_io_common.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2024, Lynne
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TEST_FILE_IO_COMMON_H
+#define TEST_FILE_IO_COMMON_H
+
+#include "io_common.h"
+
+int file_io_test(AVTContext *avt, const AVTIO *io, AVTIOCtx *io_ctx);
+
+#endif /* TEST_FILE_IO_COMMON_H */
diff --git a/libavtransport/tests/io_fd.c b/libavtransport/tests/io_fd.c
index 6a5c2ff..3760063 100644
--- a/libavtransport/tests/io_fd.c
+++ b/libavtransport/tests/io_fd.c
@@ -29,7 +29,7 @@
#include
#include "io_common.h"
-#include "file_io_template.c"
+#include "file_io_common.h"
extern const AVTIO avt_io_fd_path;
@@ -55,7 +55,7 @@ int main(void)
return AVT_ERROR(ret);
}
- ret = test_io(avt, io, io_ctx);
+ ret = file_io_test(avt, io, io_ctx);
if (ret)
io->close(avt, &io_ctx);
diff --git a/libavtransport/tests/io_file.c b/libavtransport/tests/io_file.c
index ad2197a..25f46b0 100644
--- a/libavtransport/tests/io_file.c
+++ b/libavtransport/tests/io_file.c
@@ -29,7 +29,7 @@
#include
#include "io_common.h"
-#include "file_io_template.c"
+#include "file_io_common.h"
/* Always available, on all platforms */
extern const AVTIO avt_io_file;
@@ -56,7 +56,7 @@ int main(void)
return AVT_ERROR(ret);
}
- ret = test_io(avt, io, io_ctx);
+ ret = file_io_test(avt, io, io_ctx);
if (ret)
io->close(avt, &io_ctx);
diff --git a/libavtransport/tests/io_udp.c b/libavtransport/tests/io_udp.c
index 2860e69..6863b34 100644
--- a/libavtransport/tests/io_udp.c
+++ b/libavtransport/tests/io_udp.c
@@ -24,163 +24,19 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include
-#include
-#include
-#include
-#include
-
-#include "address.h"
-#include "io_common.h"
+#include "net_common.h"
extern const AVTIO avt_io_udp;
-static const AVTIO *io = &avt_io_udp;
-
-typedef struct ThreadCtx {
- AVTContext *avt;
-
- AVTAddress addr;
-
- AVTIOCtx *ioctx;
- AVTPktd test_pkts[16];
- int nb_pkts;
-
- AVTBuffer *output;
-
- int err;
-} ThreadCtx;
-
-static int free_context(thrd_t tctx, ThreadCtx *ctx)
-{
- int ret;
- thrd_join(tctx, &ret);
- avt_addr_free(&ctx->addr);
- avt_buffer_unref(&ctx->output);
- if (ctx->ioctx) {
- if (ret < 0)
- io->close(ctx->avt, &ctx->ioctx);
- else
- ret = io->close(ctx->avt, &ctx->ioctx);
- }
- free(ctx);
-
- return ret;
-}
-
-static int client_fn(void *_ctx)
-{
- int64_t ret;
- ThreadCtx *ctx = _ctx;
-
- /* Write single packet test */
- ret = io->write_pkt(ctx->avt, ctx->ioctx, &ctx->test_pkts[0], INT64_MAX);
- if (ret <= 0)
- printf("Error writing %" PRIi64 "\n", ret);
- else
- printf("Wrote %" PRIi64 " bytes\n", ret);
-
- thrd_exit(ret);
-}
-
-static int server_fn(void *_ctx)
-{
- int64_t ret;
- ThreadCtx *ctx = _ctx;
-
- /* Read */
- ret = io->read_input(ctx->avt, ctx->ioctx, &ctx->output,
- ctx->test_pkts[0].hdr_len,
- INT64_MAX);
- if (ret <= 0) {
- printf("No bytes read\n");
- } else {
- printf("Received %" PRIi64 " bytes\n", ret);
-
- size_t buf_len;
- uint8_t *data = avt_buffer_get_data(ctx->output, &buf_len);
- if (memcmp(data, ctx->test_pkts[0].hdr, ctx->test_pkts[0].hdr_len)) {
- printf("Mismatch between data sent and received!\n");
- ret = AVT_ERROR(EINVAL);
- }
- }
-
- thrd_exit(ret);
-}
int main(void)
{
- int64_t ret;
- AVTContext *avt;
-
- thrd_t server_thread = 0;
- ThreadCtx *server_ctx = calloc(1, sizeof(ThreadCtx));
- if (!server_ctx)
- return AVT_ERROR(ENOMEM);
-
- thrd_t client_thread = 0;
- ThreadCtx *client_ctx = calloc(1, sizeof(ThreadCtx));
- if (!client_ctx) {
- free(server_ctx);
- return AVT_ERROR(ENOMEM);
- }
-
- ret = avt_init(&avt, NULL);
- if (ret < 0)
- goto end;
- server_ctx->avt = avt;
- client_ctx->avt = avt;
-
- /** Server */
- ret = avt_addr_from_url(avt, &server_ctx->addr, true, "udp://[::1]");
- if (ret < 0)
- goto end;
-
- ret = io->init(avt, &server_ctx->ioctx, &server_ctx->addr);
- if (ret < 0)
- goto end;
-
- /** Client */
- ret = avt_addr_from_url(avt, &client_ctx->addr, false, "udp://[::1]");
+ NetTestContext ntc;
+ int ret = net_io_init(&ntc, &avt_io_udp, "udp://[::1]");
if (ret < 0)
- goto end;
-
- ret = io->init(avt, &client_ctx->ioctx, &client_ctx->addr);
- if (ret < 0)
- goto end;
-
- uint32_t mtu = io->get_max_pkt_len(avt, client_ctx->ioctx);
- if (!mtu) {
- ret = AVT_ERROR(EINVAL);
- goto end;
- }
-
- printf("MTU received = %u\n", mtu);
-
- /* Packet data */
- AVTPktd test_pkt[16] = { };
- for (int i = 0; i < AVT_ARRAY_ELEMS(test_pkt); i++) {
- test_pkt[i].hdr_len = sizeof(test_pkt[i].hdr);
- for (int j = 0; j < test_pkt[i].hdr_len; j++)
- test_pkt[i].hdr[j] = (i + j) & 0xFF;
- }
-
- memcpy(server_ctx->test_pkts, test_pkt, sizeof(test_pkt));
- thrd_create(&server_thread, server_fn, server_ctx);
-
- memcpy(client_ctx->test_pkts, test_pkt, sizeof(test_pkt));
- thrd_create(&client_thread, client_fn, client_ctx);
-
-end:
- int err;
-
- err = free_context(client_thread, client_ctx);
- if (ret >= 0)
- ret = err;
+ return AVT_ERROR(ret);
- err = free_context(server_thread, server_ctx);
- if (ret >= 0)
- ret = err;
+ ret = net_io_test(&ntc);
- avt_close(&avt);
+ net_io_free(&ntc);
return AVT_ERROR(ret);
}
diff --git a/libavtransport/tests/io_udp_lite.c b/libavtransport/tests/io_udp_lite.c
new file mode 100644
index 0000000..70c6923
--- /dev/null
+++ b/libavtransport/tests/io_udp_lite.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2024, Lynne
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "net_common.h"
+
+extern const AVTIO avt_io_udp_lite;
+
+int main(void)
+{
+ NetTestContext ntc;
+ int ret = net_io_init(&ntc, &avt_io_udp_lite, "udplite://[::1]");
+ if (ret < 0)
+ return AVT_ERROR(ret);
+
+ ret = net_io_test(&ntc);
+
+ net_io_free(&ntc);
+ return AVT_ERROR(ret);
+}
diff --git a/libavtransport/tests/meson.build b/libavtransport/tests/meson.build
index 68647d7..76f1c26 100644
--- a/libavtransport/tests/meson.build
+++ b/libavtransport/tests/meson.build
@@ -31,7 +31,7 @@ ldpc_encode_test = executable('ldpc_encode',
test('LDPC encoding', ldpc_encode_test)
io_file_test = executable('io_file',
- sources : [ 'io_file.c' ],
+ sources : [ 'file_io_common.c', 'io_file.c' ],
include_directories : [ '../' ],
objects : [ avtransport_lib.extract_objects([ 'buffer.c', 'io_file.c' ]) ],
dependencies : [ avtransport_deps_list, avtransport_dep ],
@@ -40,7 +40,7 @@ test('File I/O', io_file_test)
if host_machine.system() != 'windows'
io_file_test = executable('io_fd',
- sources : [ 'io_fd.c' ],
+ sources : [ 'file_io_common.c', 'io_fd.c' ],
include_directories : [ '../' ],
objects : [ avtransport_lib.extract_objects([ 'buffer.c', 'io_fd.c' ]) ],
dependencies : [ avtransport_deps_list, avtransport_dep ],
@@ -49,13 +49,21 @@ if host_machine.system() != 'windows'
endif
io_udp_test = executable('io_udp',
- sources : [ 'io_udp.c' ],
+ sources : [ 'net_common.c', 'io_udp.c' ],
include_directories : [ '../' ],
objects : [ avtransport_lib.extract_objects([ 'address.c', 'io_udp.c', 'io_socket_common.c', 'buffer.c']) ],
dependencies : [ avtransport_deps_list, avtransport_dep ],
)
test('UDP I/O', io_udp_test)
+io_udp_lite_test = executable('io_udp_lite',
+ sources : [ 'net_common.c', 'io_udp_lite.c' ],
+ include_directories : [ '../' ],
+ objects : [ avtransport_lib.extract_objects([ 'address.c', 'io_udp.c', 'io_socket_common.c', 'buffer.c']) ],
+ dependencies : [ avtransport_deps_list, avtransport_dep ],
+)
+test('UDP-Lite I/O', io_udp_lite_test)
+
address_test = executable('address',
sources : [ 'address.c' ],
include_directories : [ '../' ],
diff --git a/libavtransport/tests/net_common.c b/libavtransport/tests/net_common.c
new file mode 100644
index 0000000..a93a659
--- /dev/null
+++ b/libavtransport/tests/net_common.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright © 2024, Lynne
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+#include
+#include
+
+#include "net_common.h"
+
+#include
+
+typedef struct NetListenerContext {
+ AVTContext *avt;
+ const AVTIO *io;
+ AVTIOCtx *ioctx;
+ AVTBuffer *output;
+ size_t pkt_len;
+ int nb_pkts;
+} NetListenerContext;
+
+static int listener_fn(void *_ctx)
+{
+ int64_t prev = 0, ret = 0;
+ NetListenerContext *ctx = _ctx;
+
+ /* Read */
+ for (int i = 0; i < ctx->nb_pkts; i++) {
+ ret = ctx->io->read_input(ctx->avt, ctx->ioctx, &ctx->output,
+ ctx->pkt_len, INT64_MAX);
+ if (ret < 0) {
+ avt_log(ctx->avt, AVT_LOG_ERROR, "No bytes read\n");
+ thrd_exit(AVT_ERROR(EINVAL));
+ } else if ((ret - prev) != ctx->pkt_len) {
+ avt_log(ctx->avt, AVT_LOG_ERROR, "Read length mismatch: received "
+ "%" PRIi64 " bytes, expected %zu bytes\n", ret, ctx->pkt_len);
+ thrd_exit(AVT_ERROR(EINVAL));
+ } else {
+ avt_log(ctx->avt, AVT_LOG_INFO, "Received %" PRIi64 " bytes\n", ret - prev);
+ }
+ prev = ret;
+ }
+
+ if (ret != avt_buffer_get_data_len(ctx->output)) {
+ avt_log(ctx->avt, AVT_LOG_ERROR, "Read length mismatch: received "
+ "%" PRIi64 " bytes, expected %zu bytes\n",
+ ret, avt_buffer_get_data_len(ctx->output));
+ thrd_exit(AVT_ERROR(EINVAL));
+ }
+
+ thrd_exit(ret);
+}
+
+int net_io_test(NetTestContext *ntc)
+{
+ int64_t ret = 0;
+ int t_err = thrd_success, t_res = 0;
+ thrd_t listener_thread = 0;
+ NetListenerContext listener_ctx = {
+ .avt = ntc->avt,
+ .io = ntc->io,
+ .ioctx = ntc->ioctx_listener,
+ };
+
+ uint32_t mtu = ntc->io->get_max_pkt_len(ntc->avt, ntc->ioctx_sender);
+ if (!mtu) {
+ avt_log(ntc->avt, AVT_LOG_ERROR, "MTU received of zero!\n");
+ ret = AVT_ERROR(EINVAL);
+ goto fail;
+ }
+
+ avt_log(ntc->avt, AVT_LOG_INFO, "MTU received = %u\n", mtu);
+
+ /* Random packet data */
+ int64_t sum = 0;
+ AVTPktd test_pkt[16] = { };
+ for (int i = 0; i < AVT_ARRAY_ELEMS(test_pkt); i++) {
+ test_pkt[i].hdr_len = AVT_MIN(mtu, sizeof(test_pkt[i].hdr));
+ sum += test_pkt[i].hdr_len;
+ for (int j = 0; j < test_pkt[i].hdr_len; j++)
+ test_pkt[i].hdr[j] = (rand() & 0xFF);
+ printf("Shit %i = %x\n", i, test_pkt[i].hdr[0]);
+ }
+
+ listener_ctx.output = NULL;
+ listener_ctx.pkt_len = test_pkt[0].hdr_len;
+ listener_ctx.nb_pkts = AVT_ARRAY_ELEMS(test_pkt);
+ t_err = thrd_create(&listener_thread, listener_fn, &listener_ctx);
+ if (t_err != thrd_success)
+ goto fail;
+
+ /* Write vector test */
+ ret = ntc->io->write_vec(ntc->avt, ntc->ioctx_sender, test_pkt,
+ AVT_ARRAY_ELEMS(test_pkt), INT64_MAX);
+ if (ret < 0) {
+ goto fail;
+ } else if (ret == 0) {
+ avt_log(ntc->avt, AVT_LOG_ERROR,"No bytes written\n");
+ ret = AVT_ERROR(EINVAL);
+ goto fail;
+ } else if (ret != sum) {
+ avt_log(ntc->avt, AVT_LOG_ERROR,"Bytes written do not match: got %" PRIi64 "; wanted %" PRIi64 "\n",
+ ret, sum);
+ ret = AVT_ERROR(EINVAL);
+ goto fail;
+ }
+
+ if (thrd_join(listener_thread, &t_res) != thrd_success)
+ goto fail;
+
+ size_t buf_size;
+ uint8_t *buf_data = avt_buffer_get_data(listener_ctx.output, &buf_size);
+
+ /* Two loops as packets may be received out of order */
+ for (int i = 0; i < listener_ctx.nb_pkts; i++) {
+ bool found = false;
+ for (int j = (listener_ctx.nb_pkts - 1); j >= 0; j--) {
+ if (!memcmp(buf_data, test_pkt[j].hdr, test_pkt[j].hdr_len)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ avt_log(ntc->avt, AVT_LOG_ERROR,"Data written and read does not match (pkt %i)\n", i);
+ ret = AVT_ERROR(EINVAL);
+ goto fail;
+ }
+ buf_data += test_pkt[i].hdr_len;
+ }
+
+fail:
+ if (ret >= 0 && t_res)
+ ret = t_res;
+
+ if (ret >= 0 && (t_err != thrd_success)) {
+ avt_log(ntc->avt, AVT_LOG_ERROR, "Threading error\n");
+ ret = AVT_ERROR(EINVAL);
+ listener_thread = 0;
+ }
+
+ if (listener_thread)
+ thrd_join(listener_thread, NULL);
+
+ avt_buffer_unref(&listener_ctx.output);
+
+ return ret;
+}
+
+int net_io_init(NetTestContext *ntc, const AVTIO *io, const char *url)
+{
+ int ret;
+ AVTAddress listener_addr = { };
+ AVTAddress sender_addr = { };
+
+ memset(ntc, 0, sizeof(*ntc));
+ ntc->io = io;
+
+ ret = avt_init(&ntc->avt, NULL);
+ if (ret < 0)
+ goto fail;
+
+ /* Listener */
+ ret = avt_addr_from_url(ntc->avt, &listener_addr, true, url);
+ if (ret < 0)
+ goto fail;
+
+ ret = ntc->io->init(ntc->avt, &ntc->ioctx_listener, &listener_addr);
+ if (ret < 0)
+ goto fail;
+
+ /* Sender */
+ ret = avt_addr_from_url(ntc->avt, &sender_addr, false, url);
+ if (ret < 0)
+ goto fail;
+
+ ret = ntc->io->init(ntc->avt, &ntc->ioctx_sender, &sender_addr);
+ if (ret < 0)
+ goto fail;
+
+ avt_addr_free(&listener_addr);
+ avt_addr_free(&sender_addr);
+ return ret;
+
+fail:
+ avt_addr_free(&listener_addr);
+ avt_addr_free(&sender_addr);
+ net_io_free(ntc);
+ return ret;
+}
+
+int net_io_free(NetTestContext *ntc)
+{
+ int err = ntc->io->close(ntc->avt, &ntc->ioctx_sender);
+ if (err)
+ ntc->io->close(ntc->avt, &ntc->ioctx_listener);
+ else
+ err = ntc->io->close(ntc->avt, &ntc->ioctx_listener);
+ avt_close(&ntc->avt);
+ return err;
+}
diff --git a/libavtransport/tests/net_common.h b/libavtransport/tests/net_common.h
new file mode 100644
index 0000000..288edff
--- /dev/null
+++ b/libavtransport/tests/net_common.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2024, Lynne
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TEST_NET_COMMON_H
+#define TEST_NET_COMMON_H
+
+#include "io_common.h"
+
+typedef struct NetTestContext {
+ AVTContext *avt;
+
+ const AVTIO *io;
+ AVTIOCtx *ioctx_sender;
+ AVTIOCtx *ioctx_listener;
+} NetTestContext;
+
+int net_io_init(NetTestContext *ntc, const AVTIO *io, const char *url);
+int net_io_test(NetTestContext *ntc);
+int net_io_free(NetTestContext *ntc);
+
+#endif /* TEST_NET_COMMON_H */
diff --git a/libavtransport/tests/udp_common.c b/libavtransport/tests/udp_common.c
new file mode 100644
index 0000000..5e4cfbd
--- /dev/null
+++ b/libavtransport/tests/udp_common.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2024, Lynne
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
diff --git a/meson.build b/meson.build
index 20e627d..306cf79 100644
--- a/meson.build
+++ b/meson.build
@@ -28,12 +28,11 @@ project('avtransport',
license_files: [ 'LICENSE.md' ],
default_options: [
'buildtype=debugoptimized',
- 'c_std=c2x',
-# 'c_std=c23',
+ 'c_std=c23',
'warning_level=1'
],
version: '0.0.4',
- meson_version: '>=1.1.0',
+ meson_version: '>=1.4.0',
)
spec_file = files('draft-avtransport-spec.bs')
diff --git a/tools/README.md b/tools/README.md
index a013007..ae8e6f4 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -12,3 +12,11 @@ anything libavformat supports (mkv, mp4, MPEG-TS).
avcat can combine or append inputs, extract streams, add metadata, reconstruct timestamps,
fix errors, and verify integrity.
+
+
+avtdump
+-------
+
+avtdump is a utility to inspect AVTransport streams and files, logging any issues,
+stream changes, packet sizes and so on. It can also provide such information as a JSON
+stream.
diff --git a/tools/avcat.c b/tools/avcat.c
index f96b3e4..d660cea 100644
--- a/tools/avcat.c
+++ b/tools/avcat.c
@@ -78,21 +78,20 @@ static enum IOMode path_is_avt(const char *path, enum AVTConnectionType *conn_ty
!strncmp(path, "file://", strlen("file://"))) {
*conn_type = AVT_CONNECTION_URL;
return IO_AVT;
- } else if (!strcmp(&path[len - 4], ".avt") || !strcmp(&path[len - 3], ".at")) {
+ } else if (!strcmp(&path[len - 4], ".avt") ||
+ !strcmp(&path[len - 3], ".ati") || /* Images */
+ !strcmp(&path[len - 3], ".ats")) { /* Subtitles */
*conn_type = AVT_CONNECTION_FILE;
return IO_AVT;
} else if (is_out && /* For output, anything that can be concat'd payload */
(!strcmp(&path[len - 5], ".h264") ||
!strcmp(&path[len - 5], ".h265") ||
!strcmp(&path[len - 5], ".hevc") ||
- !strcmp(&path[len - 5], ".tiff") ||
- !strcmp(&path[len - 5], ".jpeg") ||
- !strcmp(&path[len - 4], ".dng") ||
- !strcmp(&path[len - 4], ".png") ||
- !strcmp(&path[len - 4], ".jpg") ||
!strcmp(&path[len - 4], ".aac") ||
!strcmp(&path[len - 4], ".ac3") ||
- !strcmp(&path[len - 4], ".svg"))) {
+ !strcmp(&path[len - 4], ".nal") || /* Raw MPEG NALUs */
+ !strcmp(&path[len - 4], ".obu") || /* Raw AV1 OBUs */
+ !strcmp(&path[len - 4], ".raw"))) { /* Generic raw data */
return IO_RAW;
} else if (!is_out && /* Individual files do not need any framing */
(!strcmp(&path[len - 5], ".tiff") ||
@@ -100,6 +99,7 @@ static enum IOMode path_is_avt(const char *path, enum AVTConnectionType *conn_ty
!strcmp(&path[len - 4], ".dng") ||
!strcmp(&path[len - 4], ".png") ||
!strcmp(&path[len - 4], ".jpg") ||
+ !strcmp(&path[len - 4], ".cbor") ||
!strcmp(&path[len - 4], ".svg"))) {
return IO_RAW;
}
diff --git a/tools/avtdump.c b/tools/avtdump.c
new file mode 100644
index 0000000..cb21a3c
--- /dev/null
+++ b/tools/avtdump.c
@@ -0,0 +1,31 @@
+/* Copyright © 2024, Lynne
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+
+int main(int argc, char **argv)
+{
+ return 0;
+}
diff --git a/tools/meson.build b/tools/meson.build
index cb68714..dcf9879 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -68,3 +68,17 @@ executable('avcat',
summary({
'ffmpeg libs': lavc_dep.found() and lavf_dep.found() and lavu_dep.found(),
}, section: 'avcat', bool_yn: true)
+
+# avtdump
+#============================================================================
+avtdump_sources = files(
+ 'avtdump.c',
+)
+
+executable('avtdump',
+ install: true,
+ sources: avtdump_sources + avtransport_spec_pub_headers,
+
+ include_directories: avtransport_inc,
+ link_with: [ avtransport_lib ]
+)