UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
transmit.cpp File Reference
#include <algorithm>
#include <array>
#include <iostream>
#include <sstream>
#include <vector>
#include "audio/codec.h"
#include "audio/types.h"
#include "audio/utils.h"
#include "control_socket.h"
#include "crypto/openssl_encrypt.h"
#include "debug.h"
#include "host.h"
#include "lib_common.h"
#include "module.h"
#include "rtp/fec.h"
#include "rtp/rtp.h"
#include "rtp/rtp_callback.h"
#include "rtp/rtpenc_h264.h"
#include "transmit.h"
#include "tv.h"
#include "types.h"
#include "utils/jpeg_reader.h"
#include "utils/macros.h"
#include "utils/misc.h"
#include "utils/random.h"
#include "video.h"
#include "video_codec.h"
Include dependency graph for transmit.cpp:

Go to the source code of this file.

Classes

struct  rate_limit_dyn
 
struct  tx
 

Macros

#define CONTROL_PORT_BANDWIDTH_REPORT_INTERVAL_NS   NS_IN_SEC
 
#define FEC_MAX_MULT   10
 
#define GET_DELTA   delta = (long)((double)(stop.QuadPart - start.QuadPart) * 1000 * 1000 * 1000 / freq.QuadPart);
 
#define GET_STARTTIME   {QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&start); }
 
#define GET_STOPTIME   { QueryPerformanceCounter(&stop); }
 
#define MOD_NAME   "[transmit] "
 
#define TRANSMIT_MAGIC   0xe80ab15f
 

Functions

void audio_tx_send (struct tx *tx, struct rtp *rtp_session, const audio_frame2 *buffer)
 
static void audio_tx_send_chan (struct tx *tx, struct rtp *rtp_session, uint32_t timestamp, const audio_frame2 *buffer, int channel, bool send_m)
 
void audio_tx_send_standard (struct tx *tx, struct rtp *rtp_session, const audio_frame2 *buffer)
 
static void check_symbol_size (int fec_symbol_size, int payload_len)
 
static void fec_check_messages (struct tx *tx)
 
void format_audio_header (const audio_frame2 *frame, int channel, int buffer_idx, uint32_t *audio_hdr)
 
static uint32_t format_interl_fps_hdr_row (enum interlacing_t interlacing, double input_fps)
 
void format_video_header (struct video_frame *frame, int tile_idx, int buffer_idx, uint32_t *video_hdr)
 
static long get_packet_rate (struct tx *tx, struct video_frame *frame, int substream, long packet_count)
 
static vector< int > get_packet_sizes (struct video_frame *frame, int substream, int mtu)
 
static int get_tx_hdr_len (bool is_ipv6)
 
static int get_video_pkt_len (int mtu, int symbol_size, int *symbol_offset)
 
static void report_stats (struct tx *tx, struct rtp *rtp_session, long data_sent)
 
static bool set_fec (struct tx *tx, const char *fec)
 
static void tx_done (struct module *tx)
 
int tx_get_buffer_id (struct tx *tx)
 
struct tx * tx_init (struct module *parent, unsigned mtu, enum tx_media_type media_type, const char *fec, const char *encryption, long long int bitrate)
 
void tx_send (struct tx *tx, struct video_frame *frame, struct rtp *rtp_session)
 
static void tx_send_base (struct tx *tx, struct video_frame *frame, struct rtp *rtp_session, uint32_t ts, int send_m, unsigned int substream, int fragment_offset)
 
void tx_send_h264 (struct tx *tx, struct video_frame *frame, struct rtp *rtp_session)
 
void tx_send_jpeg (struct tx *tx, struct video_frame *frame, struct rtp *rtp_session)
 
static void tx_update (struct tx *tx, struct video_frame *frame, int substream)
 
static bool validate_std_audio (const audio_frame2 *buffer, int payload_size)
 

Macro Definition Documentation

◆ CONTROL_PORT_BANDWIDTH_REPORT_INTERVAL_NS

#define CONTROL_PORT_BANDWIDTH_REPORT_INTERVAL_NS   NS_IN_SEC

Definition at line 93 of file transmit.cpp.

Referenced by report_stats().

◆ FEC_MAX_MULT

#define FEC_MAX_MULT   10

Definition at line 91 of file transmit.cpp.

Referenced by set_fec().

◆ GET_DELTA

#define GET_DELTA   delta = (long)((double)(stop.QuadPart - start.QuadPart) * 1000 * 1000 * 1000 / freq.QuadPart);

Definition at line 106 of file transmit.cpp.

Referenced by tx_send_base().

◆ GET_STARTTIME

#define GET_STARTTIME   {QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&start); }

Definition at line 104 of file transmit.cpp.

Referenced by tx_send_base().

◆ GET_STOPTIME

#define GET_STOPTIME   { QueryPerformanceCounter(&stop); }

Definition at line 105 of file transmit.cpp.

Referenced by tx_send_base().

◆ MOD_NAME

#define MOD_NAME   "[transmit] "

Definition at line 88 of file transmit.cpp.

Referenced by audio_tx_send_chan(), check_symbol_size(), tx_init(), and validate_std_audio().

◆ TRANSMIT_MAGIC

#define TRANSMIT_MAGIC   0xe80ab15f

Definition at line 89 of file transmit.cpp.

Referenced by tx_done(), tx_init(), and tx_send_base().

Function Documentation

◆ audio_tx_send()

void audio_tx_send ( struct tx * tx,
struct rtp * rtp_session,
const audio_frame2 * buffer )

Definition at line 799 of file transmit.cpp.

801{
802 if (!rtp_has_receiver(rtp_session)) {
803 return;
804 }
805
807
808 const uint32_t timestamp =
809 buffer->get_timestamp() == -1
811 : get_local_mediatime_offset() + buffer->get_timestamp();
812
813 for (int iter = 0; iter < tx->mult_count; ++iter) {
814 for (int chan = 0; chan < buffer->get_channel_count(); ++chan) {
815 bool send_m = iter == tx->mult_count - 1 &&
816 chan == buffer->get_channel_count() - 1;
817 audio_tx_send_chan(tx, rtp_session, timestamp, buffer,
818 chan, send_m);
819 }
820 }
821
822 tx->buffer++;
823}
int get_channel_count() const
Definition types.cpp:260
int64_t get_timestamp() const
Definition types.cpp:340
bool rtp_has_receiver(struct rtp *session)
Definition rtp.c:4016
int mult_count
Definition transmit.cpp:150
unsigned int buffer
Definition transmit.cpp:143
static void audio_tx_send_chan(struct tx *tx, struct rtp *rtp_session, uint32_t timestamp, const audio_frame2 *buffer, int channel, bool send_m)
Definition transmit.cpp:826
static void fec_check_messages(struct tx *tx)
Definition transmit.cpp:354
uint32_t get_local_mediatime_offset(void)
Definition tv.c:73
uint32_t get_local_mediatime(void)
Definition tv.c:65

References audio_tx_send_chan(), tx::buffer, fec_check_messages(), audio_frame2::get_channel_count(), get_local_mediatime(), get_local_mediatime_offset(), audio_frame2::get_timestamp(), tx::mult_count, and rtp_has_receiver().

Referenced by audio_sender_thread(), and state_audio_mixer::worker().

Here is the call graph for this function:

◆ audio_tx_send_chan()

static void audio_tx_send_chan ( struct tx * tx,
struct rtp * rtp_session,
uint32_t timestamp,
const audio_frame2 * buffer,
int channel,
bool send_m )
static

Definition at line 826 of file transmit.cpp.

828{
829 int pt = fec_pt_from_fec_type(
831 tx->encryption); /* PT set for audio in our packet format */
832 unsigned m = 0U;
833 // see definition in rtp_callback.h
834 uint32_t rtp_hdr[100];
835
836 int rtp_hdr_len = 0;
837 int hdrs_len = get_tx_hdr_len(rtp_is_ipv6(rtp_session));
838 unsigned int fec_symbol_size =
839 buffer->get_fec_params(channel).symbol_size;
840
841 const char *chan_data = buffer->get_data(channel);
842 unsigned pos = 0U;
843
844 if (buffer->get_fec_params(0).type == FEC_NONE) {
845 hdrs_len += (sizeof(audio_payload_hdr_t));
846 rtp_hdr_len = sizeof(audio_payload_hdr_t);
847 format_audio_header(buffer, channel, tx->buffer, rtp_hdr);
848 } else {
849 hdrs_len += (sizeof(fec_payload_hdr_t));
850 rtp_hdr_len = sizeof(fec_payload_hdr_t);
851 uint32_t tmp = channel << 22;
852 tmp |= 0x3fffff & tx->buffer;
853 // see definition in rtp_callback.h
854 rtp_hdr[0] = htonl(tmp);
855 rtp_hdr[2] = htonl(buffer->get_data_len(channel));
856 rtp_hdr[3] = htonl(buffer->get_fec_params(channel).k << 19 |
857 buffer->get_fec_params(channel).m << 6 |
858 buffer->get_fec_params(channel).c);
859 rtp_hdr[4] = htonl(buffer->get_fec_params(channel).seed);
860 }
861
862 if (tx->encryption) {
863 hdrs_len += sizeof(crypto_payload_hdr_t) +
865 rtp_hdr[rtp_hdr_len / sizeof(uint32_t)] =
866 htonl(tx->enc_funcs->get_cipher(tx->encryption) << 24);
867 rtp_hdr_len += sizeof(crypto_payload_hdr_t);
868 }
869
870 if (buffer->get_fec_params(0).type != FEC_NONE) {
871 check_symbol_size(fec_symbol_size, tx->mtu - hdrs_len);
872 }
873
874 long data_sent = 0;
875 const int max_len = tx->mtu - hdrs_len;
876 do {
877 const char *data = chan_data + pos;
878 int data_len = max_len;
879 if (pos + data_len >=
880 (unsigned int) buffer->get_data_len(channel)) {
881 data_len = buffer->get_data_len(channel) - pos;
882 if (send_m) {
883 m = 1;
884 }
885 }
886 rtp_hdr[1] = htonl(pos);
887 pos += data_len;
888
889 char encrypted_data[RTP_MAX_PACKET_LEN + MAX_CRYPTO_EXCEED];
890 if (tx->encryption) {
891 data_len = tx->enc_funcs->encrypt(
892 tx->encryption, const_cast<char *>(data), data_len,
893 (char *) rtp_hdr,
894 rtp_hdr_len - sizeof(crypto_payload_hdr_t),
895 encrypted_data);
896 if (data_len <= 0) {
897 return;
898 }
899 data = encrypted_data;
900 }
901
902 data_sent += data_len + rtp_hdr_len;
903
904 rtp_send_data_hdr(rtp_session, timestamp, pt, m,
905 0, /* contributing sources */
906 0, /* contributing sources length */
907 (char *) rtp_hdr, rtp_hdr_len,
908 const_cast<char *>(data), data_len, 0, 0, 0);
909
910 } while (pos < buffer->get_data_len(channel));
911
912 report_stats(tx, rtp_session, data_sent);
913
914 if (buffer->get_fec_params(0).type == FEC_NONE) {
915 return;
916 }
917 // issue a warning if R-S is inadequate
918 const int packet_count =
919 (buffer->get_data_len(channel) + max_len - 1) / max_len;
920 if (packet_count > 3) {
921 return;
922 }
923 const char *pl_suffix = packet_count == 1 ? "" : "s";
924 log_msg_once(LOG_LEVEL_WARNING, to_fourcc('t', 'x', 'a', 'F'),
926 "[audio] %d packet%s per audio channel may be too low "
927 "for Reed Solomon, consider mult instead!%s\n",
928 packet_count, pl_suffix,
929 packet_count == 3 ? " (Or increase the redundancy.)" : "");
930}
char * get_data(int channel)
Definition types.cpp:218
fec_desc const & get_fec_params(int channel) const
Definition types.cpp:255
size_t get_data_len(int channel) const
Definition types.cpp:228
void log_msg_once(int level, uint32_t id, const char *msg,...)
Definition debug.cpp:137
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
int fec_pt_from_fec_type(enum tx_media_type media_type, enum fec_type fec_type, bool encrypted)
Definition fec.cpp:175
#define to_fourcc(a, b, c, d)
Creates FourCC word.
Definition macros.h:114
#define MAX_CRYPTO_EXCEED
int rtp_send_data_hdr(struct rtp *session, uint32_t rtp_ts, char pt, int m, int cc, const uint32_t *csrc, char *phdr, int phdr_len, char *data, int data_len, char *extn, uint16_t extn_len, uint16_t extn_type)
Definition rtp.c:2752
bool rtp_is_ipv6(struct rtp *session)
Definition rtp.c:4022
#define RTP_MAX_PACKET_LEN
Definition rtp.h:61
uint32_t audio_payload_hdr_t[5]
Definition rtp_types.h:129
uint32_t fec_payload_hdr_t[5]
Definition rtp_types.h:152
uint32_t crypto_payload_hdr_t[1]
Definition rtp_types.h:161
unsigned int k
Definition types.h:209
enum fec_type type
Definition types.h:208
unsigned int m
Definition types.h:209
unsigned int symbol_size
Definition types.h:211
unsigned int c
Definition types.h:209
unsigned int seed
Definition types.h:210
int(* get_overhead)(struct openssl_encrypt *encryption)
int(* encrypt)(struct openssl_encrypt *encryption, char *plaintext, int plaintext_len, char *aad, int aad_len, char *ciphertext)
enum openssl_mode(* get_cipher)(struct openssl_encrypt *encryption)
unsigned mtu
Definition transmit.cpp:137
const struct openssl_encrypt_info * enc_funcs
Definition transmit.cpp:158
struct openssl_encrypt * encryption
Definition transmit.cpp:159
static void report_stats(struct tx *tx, struct rtp *rtp_session, long data_sent)
Definition transmit.cpp:585
static void check_symbol_size(int fec_symbol_size, int payload_len)
Definition transmit.cpp:502
static int get_tx_hdr_len(bool is_ipv6)
Definition transmit.cpp:652
#define MOD_NAME
Definition transmit.cpp:88
void format_audio_header(const audio_frame2 *frame, int channel, int buffer_idx, uint32_t *audio_hdr)
Definition transmit.cpp:460
@ TX_MEDIA_AUDIO
Definition types.h:364
@ FEC_NONE
Definition types.h:201

References tx::buffer, fec_desc::c, check_symbol_size(), tx::enc_funcs, openssl_encrypt_info::encrypt, tx::encryption, FEC_NONE, fec_pt_from_fec_type(), format_audio_header(), openssl_encrypt_info::get_cipher, audio_frame2::get_data(), audio_frame2::get_data_len(), audio_frame2::get_fec_params(), openssl_encrypt_info::get_overhead, get_tx_hdr_len(), fec_desc::k, LOG_LEVEL_WARNING, log_msg_once(), fec_desc::m, MAX_CRYPTO_EXCEED, MOD_NAME, tx::mtu, report_stats(), rtp_is_ipv6(), RTP_MAX_PACKET_LEN, rtp_send_data_hdr(), fec_desc::seed, fec_desc::symbol_size, to_fourcc, TX_MEDIA_AUDIO, and fec_desc::type.

Referenced by audio_tx_send().

Here is the call graph for this function:

◆ audio_tx_send_standard()

void audio_tx_send_standard ( struct tx * tx,
struct rtp * rtp_session,
const audio_frame2 * buffer )

audio_tx_send_standard - Send interleaved channels from the audio_frame2, as the mulaw and A-law standards (dynamic or std PT).

Definition at line 958 of file transmit.cpp.

959 {
960 //TODO to be more abstract in order to accept A-law too and other supported standards with such implementation
961 assert(buffer->get_codec() == AC_MULAW ||
962 buffer->get_codec() == AC_ALAW ||
963 buffer->get_codec() == AC_MP3 ||
964 buffer->get_codec() == AC_OPUS);
965
966 uint32_t ts;
967 static uint32_t ts_prev = 0;
968
969 enum {
970 PCMA_U_BPS = 1, // data BPS - get_bps() is 2 to expand to 16-bit
971 // format on the receiver. The semantic of 2 is
972 // the same as for other codecs like Opus to
973 // asses the decmopressed sample size.
974 };
975 const bool is_pcma_u =
976 buffer->get_codec() == AC_MULAW || buffer->get_codec() == AC_ALAW;
977 // Configure the right Payload type,
978 // 8000 Hz, 1 channel PCMU/A is the ITU-T G.711 standard
979 // Other channels or Hz goes to DynRTP-Type97
980 int pt = PT_DynRTP_Type97;
981 if (is_pcma_u && buffer->get_channel_count() == 1 &&
982 buffer->get_sample_rate() == kHz8) {
983 pt = buffer->get_codec() == AC_MULAW ? PT_ITU_T_G711_PCMU
985 }
986 if (buffer->get_codec() == AC_MP3) {
987 pt = PT_MPA;
988 }
989
990 int data_len = buffer->get_data_len(0); /* Number of samples to send */
991 int payload_size = tx->mtu - 40 - 8 - 12; /* Max size of an RTP payload field (minus IPv6, UDP and RTP header lengths) */
992
993 if (is_pcma_u) { // we may split the data into more packets, compute
994 // chunk size
995 const int frame_size = buffer->get_channel_count() * PCMA_U_BPS;
996 payload_size = payload_size / frame_size * frame_size; // align to frame size
997 // The sizes for the different channels must be the same.
998 for (int i = 1; i < buffer->get_channel_count(); i++) {
999 assert(buffer->get_data_len(0) ==
1000 buffer->get_data_len(i));
1001 }
1002 data_len *= buffer->get_channel_count();
1003 } else if (pt == PT_MPA) {
1004 payload_size -= sizeof(mpa_hdr_t);
1005 }
1006
1007 if (!validate_std_audio(buffer, payload_size)) {
1008 return;
1009 }
1010
1011 int pos = 0;
1012 do {
1013 int pkt_len = std::min(payload_size, data_len - pos);
1014
1015 if (buffer->get_codec() == AC_OPUS) {
1016 memcpy(tx->tmp_packet, buffer->get_data(0), pkt_len);
1017 } else if (buffer->get_codec() == AC_MP3) {
1018 memset(tx->tmp_packet, 0, 2);
1019 const uint16_t offset = htons(pos);
1020 memcpy(tx->tmp_packet + 2, &offset, sizeof offset);
1021 pkt_len += sizeof(mpa_hdr_t);
1022 memcpy(tx->tmp_packet + 4, buffer->get_data(0), pkt_len);
1023 } else { // interleave
1024 for (int ch = 0; ch < buffer->get_channel_count(); ch++) {
1026 tx->tmp_packet,
1027 buffer->get_data(ch) +
1028 pos / buffer->get_channel_count(),
1029 PCMA_U_BPS,
1030 pkt_len / buffer->get_channel_count(), 1,
1031 buffer->get_channel_count(), 0, ch);
1032 }
1033 }
1034
1035 // Update first sample timestamp
1036 if (buffer->get_codec() == AC_OPUS) {
1037 /* OPUS packet will be the whole contained in one packet
1038 * according to RFC 7587. For PCMA/PCMU there may be more
1039 * packets so we cannot use the whole frame duration. */
1040 ts = get_std_audio_local_mediatime(buffer->get_duration(), 48000);
1041 } else {
1042 ts = get_std_audio_local_mediatime((double) pkt_len / (double) buffer->get_channel_count() / (double) buffer->get_sample_rate(), buffer->get_sample_rate());
1043 }
1044 rtp_send_ctrl(rtp_session, ts_prev, 0, get_time_in_ns()); //send RTCP SR
1045 ts_prev = ts;
1046 // Send the packet
1047 rtp_send_data(rtp_session, ts, pt, 0, 0, /* contributing sources */
1048 0, /* contributing sources length */
1049 tx->tmp_packet, pkt_len, 0, 0, 0);
1050 pos += pkt_len;
1051 } while (pos < data_len);
1052}
@ AC_OPUS
Definition types.h:57
@ AC_MULAW
Definition types.h:55
@ AC_MP3
Definition types.h:59
@ AC_ALAW
Definition types.h:54
audio_codec_t get_codec() const
Definition types.cpp:213
double get_duration() const
Definition types.cpp:246
int get_sample_rate() const
Definition types.cpp:275
static __device__ const float offset
Definition cuda_dxt.cu:139
void rtp_send_ctrl(struct rtp *session, uint32_t rtp_ts, rtcp_app_callback appcallback, time_ns_t curr_time)
Definition rtp.c:3409
int rtp_send_data(struct rtp *session, uint32_t rtp_ts, char pt, int m, int cc, const uint32_t *csrc, char *data, int data_len, char *extn, uint16_t extn_len, uint16_t extn_type)
Definition rtp.c:2742
#define PT_DynRTP_Type97
Definition rtp_types.h:79
#define PT_MPA
Definition rtp_types.h:65
#define PT_ITU_T_G711_PCMU
Definition rtp_types.h:63
uint32_t mpa_hdr_t
Definition rtp_types.h:163
#define PT_ITU_T_G711_PCMA
Definition rtp_types.h:64
char tmp_packet[RTP_MAX_MTU]
Definition transmit.cpp:163
uint32_t ts
Definition tfrc.c:101
static bool validate_std_audio(const audio_frame2 *buffer, int payload_size)
Definition transmit.cpp:933
uint32_t get_std_audio_local_mediatime(double samples, int rate)
Definition tv.c:185
static time_ns_t get_time_in_ns()
Definition tv.h:101
@ kHz8
Definition types.h:147
void remux_channel(char *out, const char *in, int bps, int in_len, int in_stream_channels, int out_stream_channels, int pos_in_stream, int pos_out_stream)
Definition utils.cpp:352

References AC_ALAW, AC_MP3, AC_MULAW, AC_OPUS, audio_frame2::get_channel_count(), audio_frame2::get_codec(), audio_frame2::get_data(), audio_frame2::get_data_len(), audio_frame2::get_duration(), audio_frame2::get_sample_rate(), get_std_audio_local_mediatime(), get_time_in_ns(), kHz8, tx::mtu, offset, PT_DynRTP_Type97, PT_ITU_T_G711_PCMA, PT_ITU_T_G711_PCMU, PT_MPA, remux_channel(), rtp_send_ctrl(), rtp_send_data(), tx::tmp_packet, ts, and validate_std_audio().

Referenced by audio_sender_thread().

Here is the call graph for this function:

◆ check_symbol_size()

static void check_symbol_size ( int fec_symbol_size,
int payload_len )
inlinestatic

Definition at line 502 of file transmit.cpp.

503{
504 thread_local static bool status_printed = false;
505
506 if (status_printed && log_level < LOG_LEVEL_DEBUG2) {
507 return;
508 }
509
510 if (fec_symbol_size > payload_len) {
512 "Warning: FEC symbol size exceeds payload size! "
513 "FEC symbol size: " << fec_symbol_size
514 << "\n";
515 } else {
516 const int ll =
517 status_printed ? LOG_LEVEL_DEBUG2 : LOG_LEVEL_INFO;
518 LOG(ll) << MOD_NAME "FEC symbol size: " << fec_symbol_size
519 << ", symbols per packet: "
520 << payload_len / fec_symbol_size << ", payload size: "
521 << payload_len / fec_symbol_size * fec_symbol_size
522 << "\n";
523 }
524 status_printed = true;
525}
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_DEBUG2
Definition debug.h:67
#define LOG(level)
Definition debug.h:313
volatile int log_level
Definition debug.cpp:65

References LOG, log_level, LOG_LEVEL_DEBUG2, LOG_LEVEL_INFO, LOG_LEVEL_WARNING, and MOD_NAME.

Referenced by audio_tx_send_chan(), and get_packet_sizes().

◆ fec_check_messages()

static void fec_check_messages ( struct tx * tx)
static

Definition at line 354 of file transmit.cpp.

355{
356 struct message *msg;
357 while ((msg = check_message(&tx->mod))) {
358 auto *data = reinterpret_cast<struct msg_universal *>(msg);
359 const char *text = data->text;
360 if (strstr(text, MSG_UNIVERSAL_TAG_TX) != text) {
361 LOG(LOG_LEVEL_ERROR) << "[Transmit] Unexpected TX message: " << text << "\n";
362 free_message(msg, new_response(RESPONSE_BAD_REQUEST, "Unexpected message"));
363 continue;
364 }
365 text += strlen(MSG_UNIVERSAL_TAG_TX);
366 struct response *r = nullptr;
367 if (strstr(text, "fec ") == text) {
368 text += strlen("fec ");
369 if (set_fec(tx, text)) {
370 r = new_response(RESPONSE_OK, nullptr);
371 LOG(LOG_LEVEL_NOTICE) << "[Transmit] FEC set to new setting: " << text << "\n";
372 } else {
373 r = new_response(RESPONSE_INT_SERV_ERR, "cannot set FEC");
374 LOG(LOG_LEVEL_ERROR) << "[Transmit] Unable to reconfiure FEC to: " << text << "\n";
375 }
376 } else if (strstr(text, "rate ") == text) {
377 text += strlen("rate ");
378 auto new_rate = unit_evaluate(text, nullptr);
379 if (new_rate >= RATE_MIN) {
380 tx->bitrate = new_rate;
381 r = new_response(RESPONSE_OK, nullptr);
382 LOG(LOG_LEVEL_NOTICE) << "[Transmit] Bitrate set to: " << text << (new_rate > 0 ? "B" : "") << "\n";
383 } else {
384 r = new_response(RESPONSE_BAD_REQUEST, "Wrong value for bitrate");
385 LOG(LOG_LEVEL_ERROR) << "[Transmit] Wrong bitrate: " << text << "\n";
386 }
387 } else {
388 r = new_response(RESPONSE_BAD_REQUEST, "Unknown TX message");
389 LOG(LOG_LEVEL_ERROR) << "[Transmit] Unknown TX message: " << text << "\n";
390 }
391
392 free_message(msg, r);
393 }
394}
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define RATE_MIN
Definition host.h:125
void free_message(struct message *msg, struct response *r)
struct response * new_response(int status, const char *text)
struct message * check_message(struct module *mod)
#define RESPONSE_OK
Definition messaging.h:57
#define RESPONSE_BAD_REQUEST
Definition messaging.h:60
#define RESPONSE_INT_SERV_ERR
Definition messaging.h:63
#define MSG_UNIVERSAL_TAG_TX
Definition messaging.h:160
long long unit_evaluate(const char *str, const char **endptr)
Definition misc.cpp:81
struct msghdr msg
char text[8192]
Definition messaging.h:157
char text[]
Definition messaging.cpp:68
long long int bitrate
Definition transmit.cpp:160
struct module mod
Definition transmit.cpp:133
static bool set_fec(struct tx *tx, const char *fec)
Definition transmit.cpp:263

References tx::bitrate, check_message(), free_message(), LOG, LOG_LEVEL_ERROR, LOG_LEVEL_NOTICE, tx::mod, msg, MSG_UNIVERSAL_TAG_TX, new_response(), RATE_MIN, RESPONSE_BAD_REQUEST, RESPONSE_INT_SERV_ERR, RESPONSE_OK, set_fec(), msg_universal::text, response::text, and unit_evaluate().

Referenced by audio_tx_send(), and tx_send().

Here is the call graph for this function:

◆ format_audio_header()

void format_audio_header ( const audio_frame2 * frame,
int channel,
int buffer_idx,
uint32_t * audio_hdr )

Definition at line 460 of file transmit.cpp.

461{
462 uint32_t tmp = 0;
463 tmp = channel << 22U; /* bits 0-9 */
464 tmp |= buffer_idx; /* bits 10-31 */
465 audio_hdr[0] = htonl(tmp);
466
467 audio_hdr[2] = htonl(frame->get_data_len(channel));
468
469 /* fourth word */
470 tmp = (frame->get_bps() * 8) << 26U;
471 tmp |= frame->get_sample_rate();
472 audio_hdr[3] = htonl(tmp);
473
474 /* fifth word */
475 audio_hdr[4] = htonl(get_audio_tag(frame->get_codec()));
476}
struct video_frame * frame
uint32_t get_audio_tag(audio_codec_t codec)
Definition codec.cpp:455

References frame, and get_audio_tag().

Referenced by audio_tx_send_chan(), and rs::encode().

Here is the call graph for this function:

◆ format_interl_fps_hdr_row()

static uint32_t format_interl_fps_hdr_row ( enum interlacing_t interlacing,
double input_fps )
static
Todo
make use of this value (for now it is always one)

Definition at line 478 of file transmit.cpp.

479{
480 unsigned int fpsd, fd, fps, fi;
481 uint32_t tmp;
482
483 tmp = interlacing << 29;
484 fps = round(input_fps);
485 fpsd = 1;
486 fd = 0;
487 fi = 0;
488 if (input_fps > 1.0 && fabs(input_fps - round(input_fps) / 1.001) < 0.005) { // 29.97 etc.
489 fd = 1;
490 } else if (fps < 1.0) {
491 fps = round(1.0 / input_fps);
492 fi = 1;
493 }
494
495 tmp |= fps << 19;
496 tmp |= fpsd << 15;
497 tmp |= fd << 14;
498 tmp |= fi << 13;
499 return htonl(tmp);
500}
static __device__ vec3 round(const vec3 &v)
Definition cuda_dxt.cu:122

References round().

Referenced by format_video_header().

Here is the call graph for this function:

◆ format_video_header()

void format_video_header ( struct video_frame * frame,
int tile_idx,
int buffer_idx,
uint32_t * video_hdr )

Definition at line 445 of file transmit.cpp.

446{
447 uint32_t tmp;
448
449 video_hdr[3] = htonl(frame->tiles[tile_idx].width << 16 | frame->tiles[tile_idx].height);
450 video_hdr[4] = get_fourcc(frame->color_spec);
451 video_hdr[2] = htonl(frame->tiles[tile_idx].data_len);
452 tmp = tile_idx << 22;
453 tmp |= 0x3fffff & buffer_idx;
454 video_hdr[0] = htonl(tmp);
455
456 /* word 6 */
458}
unsigned int width
Definition types.h:280
unsigned int data_len
length of the data
Definition types.h:288
unsigned int height
Definition types.h:281
enum interlacing_t interlacing
Definition types.h:307
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
double fps
Definition types.h:308
codec_t color_spec
Definition types.h:306
static uint32_t format_interl_fps_hdr_row(enum interlacing_t interlacing, double input_fps)
Definition transmit.cpp:478
uint32_t get_fourcc(codec_t codec)

References video_frame::color_spec, tile::data_len, format_interl_fps_hdr_row(), video_frame::fps, frame, get_fourcc(), tile::height, video_frame::interlacing, video_frame::tiles, and tile::width.

Referenced by rs::encode(), and tx_send_base().

Here is the call graph for this function:

◆ get_packet_rate()

static long get_packet_rate ( struct tx * tx,
struct video_frame * frame,
int substream,
long packet_count )
static

Returns inter-packet interval in nanoseconds.

Definition at line 614 of file transmit.cpp.

615{
616 if (tx->bitrate == RATE_UNLIMITED) {
617 return 0;
618 }
619 double time_for_frame = 1.0 / frame->fps / frame->tile_count;
620 double interval_between_pkts = time_for_frame / tx->mult_count / packet_count;
621 // use only 75% of the time - we less likely overshot the frame time and
622 // can minimize risk of swapping packets between 2 frames (out-of-order ones)
623 interval_between_pkts = interval_between_pkts * 0.75;
624 // prevent bitrate to be "too low", here 1 Mbps at minimum
625 interval_between_pkts = std::min<double>(interval_between_pkts, tx->mtu / 1000'000.0);
626 long packet_rate_auto = interval_between_pkts * 1000'000'000L;
627
628 if (tx->bitrate == RATE_AUTO) { // adaptive (spread packets to 75% frame time)
629 return packet_rate_auto;
630 }
631 if (tx->bitrate == RATE_DYNAMIC) {
634 packet_rate_auto /= 2; // double packet rate for this frame
636 } else {
638 }
640 return packet_rate_auto;
641 }
642 long long int bitrate = tx->bitrate & ~RATE_FLAG_FIXED_RATE;
643 int avg_packet_size = frame->tiles[substream].data_len / packet_count;
644 long packet_rate = 1000'000'000L * avg_packet_size * 8 / bitrate; // fixed rate
645 if ((tx->bitrate & RATE_FLAG_FIXED_RATE) == 0) { // adaptive capped rate
646 packet_rate = std::max(packet_rate, packet_rate_auto);
647 }
648 return packet_rate;
649}
#define RATE_AUTO
spread packets evenly across frame time (currently 3/4)
Definition host.h:123
#define RATE_FLAG_FIXED_RATE
use the bitrate as fixed, not capped
Definition host.h:127
#define RATE_UNLIMITED
Definition host.h:122
#define RATE_DYNAMIC
same as RATE_AUTO but occasional excess frame allowed
Definition host.h:124
long packet_rate
Definition run_tests.c:72
static constexpr int EXCESS_GAP
minimal gap between excessive frames
Definition transmit.cpp:129
long long last_excess
nr of frames last excessive frame was emitted
Definition transmit.cpp:128
unsigned long avg_frame_size
moving average
Definition transmit.cpp:127
struct rate_limit_dyn dyn_rate_limit_state
Definition transmit.cpp:161
unsigned int tile_count
Definition types.h:344

References rate_limit_dyn::avg_frame_size, tx::bitrate, tile::data_len, tx::dyn_rate_limit_state, rate_limit_dyn::EXCESS_GAP, video_frame::fps, frame, rate_limit_dyn::last_excess, tx::mtu, tx::mult_count, packet_rate, RATE_AUTO, RATE_DYNAMIC, RATE_FLAG_FIXED_RATE, RATE_UNLIMITED, video_frame::tile_count, and video_frame::tiles.

Referenced by tx_send_base().

◆ get_packet_sizes()

static vector< int > get_packet_sizes ( struct video_frame * frame,
int substream,
int mtu )
static
Parameters
mtuis tx->mtu - hdrs_len

Definition at line 552 of file transmit.cpp.

552 {
553 if (frame->fec_params.type != FEC_NONE) {
555 }
556
557 unsigned int symbol_size = 1;
558 int symbol_offset = 0;
560 symbol_size = vc_get_linesize(frame->tiles[substream].width, frame->color_spec);
562 assert(pf_block_size <= mtu);
563 mtu = mtu / pf_block_size * pf_block_size;
564 } else if (frame->fec_params.type != FEC_NONE) {
565 symbol_size = frame->fec_params.symbol_size;
566 }
567 vector<int> ret;
568 unsigned pos = 0;
569 do {
570 int len = symbol_size == 1
571 ? mtu
572 : get_video_pkt_len(mtu, symbol_size, &symbol_offset);
573 pos += len;
574 ret.push_back(len);
575 } while (pos < frame->tiles[substream].data_len);
576
577 if (pos > frame->tiles[substream].data_len) {
578 ret[ret.size() - 1] -=
579 (int) (pos - frame->tiles[substream].data_len);
580 }
581 return ret;
582}
int void size_t * len
int vc_get_linesize(unsigned int width, codec_t codec)
struct fec_desc fec_params
Definition types.h:328
static int get_video_pkt_len(int mtu, int symbol_size, int *symbol_offset)
Definition transmit.cpp:536
bool is_codec_opaque(codec_t codec)
int get_pf_block_bytes(codec_t codec)
returns codec_info_t::block_size_bytes
int get_pf_block_pixels(codec_t codec)
returns codec_info_t::block_size_pixels
#define PIX_BLOCK_LCM
least common multiple of all pixfmt block sizes in pixels (codec_info_t::block_size/codec_info_t::bpp...
Definition video_codec.h:66

References check_symbol_size(), video_frame::color_spec, tile::data_len, FEC_NONE, video_frame::fec_params, frame, get_pf_block_bytes(), get_pf_block_pixels(), get_video_pkt_len(), is_codec_opaque(), len, tx::mtu, PIX_BLOCK_LCM, fec_desc::symbol_size, video_frame::tiles, fec_desc::type, vc_get_linesize(), and tile::width.

Referenced by tx_send_base().

Here is the call graph for this function:

◆ get_tx_hdr_len()

static int get_tx_hdr_len ( bool is_ipv6)
static

Definition at line 652 of file transmit.cpp.

653{
654 return (is_ipv6 ? IPV6_HDR_LEN : IPV4_HDR_LEN) + UDP_HDR_LEN +
656}
@ IPV6_HDR_LEN
Definition rtp.h:65
@ IPV4_HDR_LEN
Definition rtp.h:64
@ RTP_HDR_LEN
Definition rtp.h:67
@ UDP_HDR_LEN
Definition rtp.h:66

References IPV4_HDR_LEN, IPV6_HDR_LEN, RTP_HDR_LEN, and UDP_HDR_LEN.

Referenced by audio_tx_send_chan(), and tx_send_base().

◆ get_video_pkt_len()

static int get_video_pkt_len ( int mtu,
int symbol_size,
int * symbol_offset )
inlinestatic

Splits symbol (FEC symbol or uncompressed line) to 1 or more MTUs. Symbol starts always on beginning of packet.

If symbol_size is longer than MTU (more symbols fit one packet), the aligned packet size is always the same.

Parameters
symbol_sizeFEC symbol size or linesize for uncompressed

Definition at line 536 of file transmit.cpp.

538{
539 if (symbol_size > mtu) {
540 if (symbol_size - *symbol_offset <= mtu) {
541 mtu = symbol_size - *symbol_offset;
542 *symbol_offset = 0;
543 } else {
544 *symbol_offset += mtu;
545 }
546 return mtu;
547 }
548 return mtu / symbol_size * symbol_size;
549}

References tx::mtu.

Referenced by get_packet_sizes().

◆ report_stats()

static void report_stats ( struct tx * tx,
struct rtp * rtp_session,
long data_sent )
static

Definition at line 585 of file transmit.cpp.

586{
588 return;
589 }
590
591 tx->sent_since_report += data_sent;
592
593 const time_ns_t current_time_ns = get_time_in_ns();
594 if (current_time_ns - tx->last_stat_report <
596 return;
597 }
598
599 const char *media =
600 tx->media_type == TX_MEDIA_VIDEO ? "video" : "audio";
601 std::ostringstream oss;
602 oss << "tx_send " << std::hex << rtp_my_ssrc(rtp_session) << std::dec
603 << " " << media << " " << tx->sent_since_report;
604
605 control_report_stats(tx->control, oss.str());
606 tx->last_stat_report = current_time_ns;
608}
bool control_stats_enabled(struct control_state *s)
void control_report_stats(struct control_state *s, const std::string &report_line)
uint32_t rtp_my_ssrc(struct rtp *session)
Definition rtp.c:1401
size_t sent_since_report
Definition transmit.cpp:155
enum tx_media_type media_type
Definition transmit.cpp:136
uint64_t last_stat_report
Definition transmit.cpp:156
struct control_state * control
Definition transmit.cpp:154
#define CONTROL_PORT_BANDWIDTH_REPORT_INTERVAL_NS
Definition transmit.cpp:93
long long time_ns_t
Definition tv.h:81
@ TX_MEDIA_VIDEO
Definition types.h:365

References tx::control, CONTROL_PORT_BANDWIDTH_REPORT_INTERVAL_NS, control_report_stats(), control_stats_enabled(), get_time_in_ns(), tx::last_stat_report, tx::media_type, rtp_my_ssrc(), tx::sent_since_report, and TX_MEDIA_VIDEO.

Referenced by audio_tx_send_chan(), and tx_send_base().

Here is the call graph for this function:

◆ set_fec()

static bool set_fec ( struct tx * tx,
const char * fec )
static

Definition at line 263 of file transmit.cpp.

264{
265 char *fec = strdup(fec_const);
266 bool ret = true;
267 bool req_1st_pkt_dup = true;
268
269 // handle ...[:]nodup
270 char *end = fec + MAX(strlen(fec), 5) - 5;
271 if (strcmp(end, "nodup") == 0) {
272 req_1st_pkt_dup = true;
273 *end = '\0';
274 if (end > fec) { // ':'
275 end[-1] = '\0';
276 }
277 }
278
279 const char *fec_cfg = "";
280 if(strchr(fec, ':')) {
281 char *delim = strchr(fec, ':');
282 *delim = '\0';
283 fec_cfg = delim + 1;
284 }
285
286 struct msg_sender *msg = (struct msg_sender *)
287 new_message(sizeof(struct msg_sender));
289
290 snprintf(msg->fec_cfg, sizeof(msg->fec_cfg), "flush");
291
292 tx->mult_count = 1; // default
293 if (strcasecmp(fec, "none") == 0) {
295 } else if(strcasecmp(fec, "mult") == 0) {
297 tx->mult_count = atoi(fec_cfg);
298 if (tx->mult_count <= 0 || tx->mult_count > FEC_MAX_MULT) {
299 MSG(ERROR,
300 "mult count must be between 1 and %d (%d given)!\n",
302 ret = false;
303 }
304 } else if(strcasecmp(fec, "LDGM") == 0) {
305 tx->fec_dup_1st_pkt = req_1st_pkt_dup;
307 fprintf(stderr, "LDGM is not currently supported for audio!\n");
308 ret = false;
309 } else {
310 if (strlen(fec_cfg) == 0 ||
311 (strlen(fec_cfg) > 0 &&
312 strchr(fec_cfg, '%') == nullptr)) {
313 snprintf(msg->fec_cfg, sizeof(msg->fec_cfg),
314 "LDGM cfg %s", fec_cfg);
315 } else { // delay creation until we have avarage frame size
316 tx->max_loss = atof(fec_cfg);
317 }
319 }
320 } else if(strcasecmp(fec, "RS") == 0) {
321 tx->fec_dup_1st_pkt = req_1st_pkt_dup;
322 snprintf(msg->fec_cfg, sizeof(msg->fec_cfg), "RS cfg %s",
323 fec_cfg);
325 } else if(strcasecmp(fec, "help") == 0) {
326 color_printf("Usage:\n");
327 color_printf("\t" TBOLD("-f [A:|V:]{mult:count|ldgm[:params]|"
328 "rs[:params]}[:nodup]") "\n");
329 color_printf("\nIf neither A: or V: is speciefied, FEC is set "
330 "to the video (backward compat).\n\n");
331 ret = false;
332 } else {
333 fprintf(stderr, "Unknown FEC: %s\n", fec);
334 ret = false;
335 }
336
337 if (tx->fec_dup_1st_pkt) {
338 MSG(VERBOSE, "Duplicating 1st packet of every frame for better "
339 "error resiliency.\n");
340 }
341
342 if (ret) {
344 (struct message *) msg);
345 free_response(resp);
346 } else {
347 free_message((struct message *) msg, NULL);
348 }
349
350 free(fec);
351 return ret;
352}
int color_printf(const char *format,...)
#define TBOLD(x)
Definition color_out.h:70
static void new_message(struct module *m)
#define MSG(l, fmt,...)
Definition debug.h:96
struct module * get_parent_module(struct module *node)
Definition module.c:214
#define MAX(a, b)
Definition macros.h:65
struct response * send_message_to_receiver(struct module *receiver, struct message *msg)
void free_response(struct response *r)
@ SENDER_MSG_CHANGE_FEC
Definition messaging.h:90
Definition fec.h:51
char fec_cfg[1024]
Definition messaging.h:104
enum fec_type fec_scheme
Definition transmit.cpp:148
bool fec_dup_1st_pkt
Definition transmit.cpp:149
double max_loss
Definition transmit.cpp:138
#define FEC_MAX_MULT
Definition transmit.cpp:91
@ FEC_LDGM
Definition types.h:203
@ FEC_MULT
Definition types.h:202
@ FEC_RS
Definition types.h:204

References color_printf(), msg_sender::fec_cfg, tx::fec_dup_1st_pkt, FEC_LDGM, FEC_MAX_MULT, FEC_MULT, FEC_NONE, FEC_RS, tx::fec_scheme, free_message(), free_response(), get_parent_module(), MAX, tx::max_loss, tx::media_type, tx::mod, MSG, tx::mult_count, new_message(), send_message_to_receiver(), SENDER_MSG_CHANGE_FEC, TBOLD, and TX_MEDIA_AUDIO.

Referenced by fec_check_messages(), and tx_init().

Here is the call graph for this function:

◆ tx_done()

static void tx_done ( struct module * tx)
static

Definition at line 396 of file transmit.cpp.

397{
398 struct tx *tx = (struct tx *) mod->priv_data;
399 assert(tx->magic == TRANSMIT_MAGIC);
400 free(tx);
401}
void * priv_data
Definition module.h:126
uint32_t magic
Definition transmit.cpp:135
#define TRANSMIT_MAGIC
Definition transmit.cpp:89

References tx::magic, tx::mod, module::priv_data, and TRANSMIT_MAGIC.

Referenced by tx_init().

◆ tx_get_buffer_id()

int tx_get_buffer_id ( struct tx * tx_session)

Returns buffer ID to be sent with next tx_send() call

Definition at line 1240 of file transmit.cpp.

1241{
1242 return tx->buffer;
1243
1244}

References tx::buffer.

◆ tx_init()

struct tx * tx_init ( struct module * parent,
unsigned mtu,
enum tx_media_type media_type,
const char * fec,
const char * encryption,
long long int bitrate )

Definition at line 201 of file transmit.cpp.

203{
204 if (mtu > RTP_MAX_MTU) {
205 log_msg(LOG_LEVEL_ERROR, "Requested MTU exceeds maximal value allowed by RTP library (%d B).\n", RTP_MAX_MTU);
206 return NULL;
207 }
208
209 if (bitrate < RATE_MIN) {
210 log_msg(LOG_LEVEL_ERROR, "Invalid bitrate value %lld passed (either positive bitrate or magic values from %d supported)!\n", bitrate, RATE_MIN);
211 return NULL;
212 }
213
214 struct tx *tx = (struct tx *) calloc(1, sizeof(struct tx));
215 if (tx == nullptr) {
216 return tx;
217 }
220 tx->mod.priv_data = tx;
223
226 tx->mult_count = 1;
227 tx->max_loss = 0.0;
228 tx->mtu = mtu;
229 tx->buffer = ug_rand() & 0x3fffff;
233 if (fec) {
234 if(!set_fec(tx, fec)) {
235 module_done(&tx->mod);
236 return NULL;
237 }
238 }
239 if (strlen(encryption) > 0) {
240 tx->enc_funcs = static_cast<const struct openssl_encrypt_info *>(load_library("openssl_encrypt",
242 if (!tx->enc_funcs) {
243 fprintf(stderr, "UltraGrid was build without OpenSSL support!\n");
244 module_done(&tx->mod);
245 return NULL;
246 }
247 if (tx->enc_funcs->init(&tx->encryption,
248 encryption) != 0) {
249 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to initialize encryption\n");
250 module_done(&tx->mod);
251 return NULL;
252 }
253 }
254
255 tx->bitrate = bitrate;
256
257 if(parent)
258 tx->control = (struct control_state *) get_module(get_root_module(parent), "control");
259
260 return tx;
261}
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
void module_init_default(struct module *module_data)
Definition module.c:48
void module_register(struct module *module_data, struct module *parent)
Definition module.c:82
struct module * get_module(struct module *root, const char *const_path)
Definition module.c:264
void module_done(struct module *module_data)
Definition module.c:93
struct module * get_root_module(struct module *node)
Definition module.c:203
@ MODULE_CLASS_TX
Definition module.h:89
const void * load_library(const char *name, enum library_class cls, int abi_version)
@ LIBRARY_CLASS_UNDEFINED
Definition lib_common.h:74
#define OPENSSL_ENCRYPT_ABI_VERSION
#define RTP_MAX_MTU
Definition rtp.h:60
const char * parent
Definition settings.cpp:198
enum module_class cls
Definition module.h:115
module_deleter_t deleter
Definition module.h:118
int(* init)(struct openssl_encrypt **state, const char *passphrase)
unsigned long int sent_frames
Definition transmit.cpp:144
int32_t avg_len_last
Definition transmit.cpp:146
int32_t avg_len
Definition transmit.cpp:145
int last_frame_fragment_id
Definition transmit.cpp:141
static void tx_done(struct module *tx)
Definition transmit.cpp:396
uint32_t ug_rand(void)
Definition random.c:88

References tx::avg_len, tx::avg_len_last, tx::bitrate, tx::buffer, module::cls, tx::control, module::deleter, tx::enc_funcs, tx::encryption, FEC_NONE, tx::fec_scheme, get_module(), get_root_module(), openssl_encrypt_info::init, tx::last_frame_fragment_id, LIBRARY_CLASS_UNDEFINED, load_library(), LOG_LEVEL_ERROR, log_msg(), tx::magic, tx::max_loss, tx::media_type, tx::mod, MOD_NAME, MODULE_CLASS_TX, module_done(), module_init_default(), module_register(), tx::mtu, tx::mult_count, OPENSSL_ENCRYPT_ABI_VERSION, parent, module::priv_data, RATE_MIN, RTP_MAX_MTU, tx::sent_frames, set_fec(), TRANSMIT_MAGIC, tx_done(), and ug_rand().

Referenced by am_participant::am_participant(), rtp_video_rxtx::rtp_video_rxtx(), and audio_init().

Here is the call graph for this function:

◆ tx_send()

void tx_send ( struct tx * tx,
struct video_frame * frame,
struct rtp * rtp_session )

Definition at line 407 of file transmit.cpp.

408{
409 unsigned int i;
410
411 assert(!frame->fragment || tx->fec_scheme == FEC_NONE); // currently no support for FEC with fragments
412 assert(!frame->fragment || frame->tile_count); // multiple tile are not currently supported for fragmented send
414
415 uint32_t ts =
416 (frame->flags & TIMESTAMP_VALID) == 0
419 if(frame->fragment &&
421 ts = tx->last_ts;
422 } else {
424 tx->last_ts = ts;
425 }
426
427 for(i = 0; i < frame->tile_count; ++i)
428 {
429 int last = FALSE;
430 int fragment_offset = 0;
431
432 if (i == frame->tile_count - 1) {
434 last = TRUE;
435 }
436 if(frame->fragment)
437 fragment_offset = vf_get_tile(frame, i)->offset;
438
439 tx_send_base(tx, frame, rtp_session, ts, last,
440 i, fragment_offset);
441 }
442 tx->buffer++;
443}
#define TRUE
#define FALSE
unsigned int offset
Fragment offset from tile beginning (in bytes). Used only if frame is fragmented.
Definition types.h:292
uint32_t last_ts
Definition transmit.cpp:140
int64_t timestamp
Definition types.h:331
int flags
Definition types.h:329
unsigned int frame_fragment_id
Used only if (fragment == 1). ID of the frame. Fragments of same frame must have the same ID.
Definition types.h:319
unsigned int fragment
Indicates that the tile is fragmented. Normally not used (only for Bluefish444).
Definition types.h:315
unsigned int last_fragment
Used only if (fragment == 1). Indicates this is the last fragment.
Definition types.h:317
static void tx_send_base(struct tx *tx, struct video_frame *frame, struct rtp *rtp_session, uint32_t ts, int send_m, unsigned int substream, int fragment_offset)
Definition transmit.cpp:659
@ TIMESTAMP_VALID
timestamp set by source (in 90 kHz clock)
Definition types.h:223
struct tile * vf_get_tile(struct video_frame *buf, int pos)
Returns pointer to n-th tile from video frame Equivalent to &video_frame::tiles[pos].

References tx::buffer, FALSE, fec_check_messages(), FEC_NONE, tx::fec_scheme, video_frame::flags, video_frame::fragment, frame, video_frame::frame_fragment_id, get_local_mediatime(), get_local_mediatime_offset(), video_frame::last_fragment, tx::last_frame_fragment_id, tx::last_ts, tile::offset, video_frame::tile_count, video_frame::timestamp, TIMESTAMP_VALID, TRUE, ts, tx_send_base(), and vf_get_tile().

Referenced by ultragrid_rtp_video_rxtx::send_frame_async().

Here is the call graph for this function:

◆ tx_send_base()

static void tx_send_base ( struct tx * tx,
struct video_frame * frame,
struct rtp * rtp_session,
uint32_t ts,
int send_m,
unsigned int substream,
int fragment_offset )
static

Definition at line 659 of file transmit.cpp.

663{
664 assert(fragment_offset == 0); // no longer supported
665 if (!rtp_has_receiver(rtp_session)) {
666 return;
667 }
668
669 struct tile *tile = &frame->tiles[substream];
670
671 // see definition in rtp_callback.h
672 uint32_t rtp_hdr[100];
673 int rtp_hdr_len;
674 int pt = fec_pt_from_fec_type(TX_MEDIA_VIDEO, frame->fec_params.type, tx->encryption); /* A value specified in our packet format */
675#ifdef __linux__
676 struct timespec start, stop;
677#elif defined __APPLE__
678 struct timeval start, stop;
679#else // Windows
680 LARGE_INTEGER start, stop, freq;
681#endif
682 long delta, overslept = 0;
683 int hdrs_len = get_tx_hdr_len(rtp_is_ipv6(rtp_session));
684
685 assert(tx->magic == TRANSMIT_MAGIC);
686
687 tx_update(tx, frame, substream);
688
689 if (frame->fec_params.type == FEC_NONE) {
690 hdrs_len += (sizeof(video_payload_hdr_t));
691 rtp_hdr_len = sizeof(video_payload_hdr_t);
692 format_video_header(frame, substream, tx->buffer, rtp_hdr);
693 } else {
694 hdrs_len += (sizeof(fec_payload_hdr_t));
695 rtp_hdr_len = sizeof(fec_payload_hdr_t);
696 uint32_t tmp = substream << 22;
697 tmp |= 0x3fffff & tx->buffer;
698 // see definition in rtp_callback.h
699 rtp_hdr[0] = htonl(tmp);
700 rtp_hdr[2] = htonl(tile->data_len);
701 rtp_hdr[3] = htonl(
702 frame->fec_params.k << 19 |
703 frame->fec_params.m << 6 |
705 rtp_hdr[4] = htonl(frame->fec_params.seed);
706 }
707
708 if (tx->encryption) {
709 hdrs_len += sizeof(crypto_payload_hdr_t) + tx->enc_funcs->get_overhead(tx->encryption);
710 rtp_hdr[rtp_hdr_len / sizeof(uint32_t)] =
711 htonl(tx->enc_funcs->get_cipher(tx->encryption) << 24);
712 rtp_hdr_len += sizeof(crypto_payload_hdr_t);
713 }
714
715 vector<int> packet_sizes = get_packet_sizes(frame, substream, tx->mtu - hdrs_len);
716 long mult_pkt_cnt = (long) packet_sizes.size() * tx->mult_count;
717 const long packet_rate =
718 get_packet_rate(tx, frame, (int) substream, mult_pkt_cnt);
719
720 // initialize header array with values (except offset which is different among
721 // different packts)
722 void *rtp_headers = malloc((mult_pkt_cnt + 1) * rtp_hdr_len);
723 uint32_t *rtp_hdr_packet = (uint32_t *) rtp_headers;
724 for (int m = 0; m < tx->mult_count; ++m) {
725 unsigned pos = 0;
726 for (unsigned i = 0; i < packet_sizes.size(); ++i) {
727 memcpy(rtp_hdr_packet, rtp_hdr, rtp_hdr_len);
728 rtp_hdr_packet[1] = htonl(pos);
729 rtp_hdr_packet += rtp_hdr_len / sizeof(uint32_t);
730 pos += packet_sizes.at(i);
731 }
732 }
733 if (tx->fec_dup_1st_pkt) { // dup 1st pkt with RS/LDGM
734 mult_pkt_cnt += 1;
735 memcpy(rtp_hdr_packet, rtp_hdr, rtp_hdr_len);
736 rtp_hdr_packet[1] = htonl(0);
737 }
738
739 if (!tx->encryption) {
740 rtp_async_start(rtp_session, mult_pkt_cnt);
741 }
742
743 rtp_hdr_packet = (uint32_t *) rtp_headers;
744 for (long i = 0; i < mult_pkt_cnt; ++i) {
746 const int m = i == mult_pkt_cnt - 1 ? send_m : 0;
747 char *data = tile->data + ntohl(rtp_hdr_packet[1]);
748 int data_len = packet_sizes.at(i % packet_sizes.size());
749
750 char encrypted_data[RTP_MAX_PACKET_LEN + MAX_CRYPTO_EXCEED];
751 if (tx->encryption != nullptr) {
752 data_len = tx->enc_funcs->encrypt(
753 tx->encryption, data, data_len,
754 (char *) rtp_hdr_packet,
756 ? sizeof(fec_payload_hdr_t)
757 : sizeof(video_payload_hdr_t),
758 encrypted_data);
759 if (data_len <= 0) {
760 return;
761 }
762 data = encrypted_data;
763 }
764
765 rtp_send_data_hdr(rtp_session, ts, pt, m, 0, nullptr,
766 (char *) rtp_hdr_packet, rtp_hdr_len, data,
767 data_len, nullptr, 0, 0);
768 rtp_hdr_packet += rtp_hdr_len / sizeof(uint32_t);
769
770 // TRAFFIC SHAPER
771 if (m != 1) { // wait for all but last packet
772 do {
774 GET_DELTA;
775 } while (packet_rate - delta - overslept > 0);
776 overslept = -(packet_rate - delta - overslept);
777 //fprintf(stdout, "%ld ", overslept);
778 }
779 }
780
781 const long data_sent = tile->data_len + rtp_hdr_len * mult_pkt_cnt;
782 report_stats(tx, rtp_session, data_sent);
783
784 if (!tx->encryption) {
785 rtp_async_wait(rtp_session);
786 }
787 free(rtp_headers);
788}
void rtp_async_wait(struct rtp *session)
Definition rtp.c:4032
void rtp_async_start(struct rtp *session, int nr_packets)
Definition rtp.c:4027
uint32_t video_payload_hdr_t[6]
Definition rtp_types.h:107
static void start()
Definition sdp.c:202
Struct tile is an area of video_frame.
Definition types.h:279
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
#define GET_DELTA
Definition transmit.cpp:106
static void tx_update(struct tx *tx, struct video_frame *frame, int substream)
Definition transmit.cpp:166
#define GET_STOPTIME
Definition transmit.cpp:105
void format_video_header(struct video_frame *frame, int tile_idx, int buffer_idx, uint32_t *video_hdr)
Definition transmit.cpp:445
#define GET_STARTTIME
Definition transmit.cpp:104
static long get_packet_rate(struct tx *tx, struct video_frame *frame, int substream, long packet_count)
Definition transmit.cpp:614
static vector< int > get_packet_sizes(struct video_frame *frame, int substream, int mtu)
Definition transmit.cpp:552

References tx::buffer, fec_desc::c, tile::data, tile::data_len, tx::enc_funcs, openssl_encrypt_info::encrypt, tx::encryption, tx::fec_dup_1st_pkt, FEC_NONE, video_frame::fec_params, fec_pt_from_fec_type(), format_video_header(), frame, openssl_encrypt_info::get_cipher, GET_DELTA, openssl_encrypt_info::get_overhead, get_packet_rate(), get_packet_sizes(), GET_STARTTIME, GET_STOPTIME, get_tx_hdr_len(), fec_desc::k, fec_desc::m, tx::magic, MAX_CRYPTO_EXCEED, tx::mtu, tx::mult_count, packet_rate, report_stats(), rtp_async_start(), rtp_async_wait(), rtp_has_receiver(), rtp_is_ipv6(), RTP_MAX_PACKET_LEN, rtp_send_data_hdr(), fec_desc::seed, start(), video_frame::tiles, TRANSMIT_MAGIC, ts, TX_MEDIA_VIDEO, tx_update(), and fec_desc::type.

Referenced by tx_send().

Here is the call graph for this function:

◆ tx_send_h264()

void tx_send_h264 ( struct tx * tx,
struct video_frame * frame,
struct rtp * rtp_session )

H.264 standard transmission

Definition at line 1057 of file transmit.cpp.

1058 {
1059 assert(frame->tile_count == 1); // std transmit doesn't handle more than one tile
1060 assert(!frame->fragment || tx->fec_scheme == FEC_NONE); // currently no support for FEC with fragments
1061 assert(!frame->fragment || frame->tile_count); // multiple tiles are not currently supported for fragmented send
1062 uint32_t ts = get_std_video_local_mediatime();
1063 struct tile *tile = &frame->tiles[0];
1064
1065 char pt = PT_DynRTP_Type96;
1066 unsigned char hdr[2];
1067 int cc = 0;
1068 uint32_t csrc = 0;
1069 int m = 0;
1070 char *extn = 0;
1071 uint16_t extn_len = 0;
1072 uint16_t extn_type = 0;
1073 const uint8_t *start = (uint8_t *) tile->data;
1074 int data_len = tile->data_len;
1075 unsigned maxPacketSize = tx->mtu - 40;
1076
1077 const unsigned char *endptr = 0;
1078 const unsigned char *nal = start;
1079
1080 while ((nal = rtpenc_get_next_nal(nal, data_len - (nal - start), &endptr))) {
1081 unsigned int nalsize = endptr - nal;
1082 bool eof = endptr == start + data_len;
1083 bool lastNALUnitFragment = false; // by default
1084 unsigned curNALOffset = 0;
1085 char *nalc = const_cast<char *>(reinterpret_cast<const char *>(nal));
1086
1087 while(!lastNALUnitFragment){
1088 // We have NAL unit data in the buffer. There are three cases to consider:
1089 // 1. There is a new NAL unit in the buffer, and it's small enough to deliver
1090 // to the RTP sink (as is).
1091 // 2. There is a new NAL unit in the buffer, but it's too large to deliver to
1092 // the RTP sink in its entirety. Deliver the first fragment of this data,
1093 // as a FU packet, with one extra preceding header byte (for the "FU header").
1094 // 3. There is a NAL unit in the buffer, and we've already delivered some
1095 // fragment(s) of this. Deliver the next fragment of this data,
1096 // as a FU packet, with two (H.264) extra preceding header bytes
1097 // (for the "NAL header" and the "FU header").
1098 if (curNALOffset == 0) { // case 1 or 2
1099 if (nalsize <= maxPacketSize) { // case 1
1100
1101 if (eof) m = 1;
1102 if (rtp_send_data(rtp_session, ts, pt, m, cc, &csrc,
1103 nalc, nalsize,
1104 extn, extn_len, extn_type) < 0) {
1105 error_msg("There was a problem sending the RTP packet\n");
1106 }
1107 lastNALUnitFragment = true;
1108 } else { // case 2
1109 // We need to send the NAL unit data as FU packets. Deliver the first
1110 // packet now. Note that we add "NAL header" and "FU header" bytes to the front
1111 // of the packet (overwriting the existing "NAL header").
1112 hdr[0] = (nal[0] & 0xE0) | 28; //FU indicator
1113 hdr[1] = 0x80 | (nal[0] & 0x1F); // FU header (with S bit)
1114
1115 if (rtp_send_data_hdr(rtp_session, ts, pt, m, cc, &csrc,
1116 (char *) hdr, 2,
1117 nalc + 1, maxPacketSize - 2,
1118 extn, extn_len, extn_type) < 0) {
1119 error_msg("There was a problem sending the RTP packet\n");
1120 }
1121 curNALOffset += maxPacketSize - 1;
1122 lastNALUnitFragment = false;
1123 nalsize -= maxPacketSize - 1;
1124 }
1125 } else { // case 3
1126 // We are sending this NAL unit data as FU packets. We've already sent the
1127 // first packet (fragment). Now, send the next fragment. Note that we add
1128 // "NAL header" and "FU header" bytes to the front. (We reuse these bytes that
1129 // we already sent for the first fragment, but clear the S bit, and add the E
1130 // bit if this is the last fragment.)
1131 hdr[1] = hdr[1] & ~0x80;// FU header (no S bit)
1132
1133 if (nalsize + 1 > maxPacketSize) {
1134 // We can't send all of the remaining data this time:
1135 if (rtp_send_data_hdr(rtp_session, ts, pt, m, cc, &csrc,
1136 (char *) hdr, 2,
1137 nalc + curNALOffset,
1138 maxPacketSize - 2, extn, extn_len,
1139 extn_type) < 0) {
1140 error_msg("There was a problem sending the RTP packet\n");
1141 }
1142 curNALOffset += maxPacketSize - 2;
1143 lastNALUnitFragment = false;
1144 nalsize -= maxPacketSize - 2;
1145
1146 } else {
1147 // This is the last fragment:
1148 if (eof) m = 1;
1149
1150 hdr[1] |= 0x40;// set the E bit in the FU header
1151
1152 if (rtp_send_data_hdr(rtp_session, ts, pt, m, cc, &csrc,
1153 (char *) hdr, 2,
1154 nalc + curNALOffset,
1155 nalsize, extn, extn_len, extn_type) < 0) {
1156 error_msg("There was a problem sending the RTP packet\n");
1157 }
1158 lastNALUnitFragment = true;
1159 }
1160 }
1161 }
1162 }
1163 if (endptr != start + data_len) {
1164 error_msg("No NAL found!\n");
1165 }
1166}
#define error_msg(...)
Definition debug.h:89
#define PT_DynRTP_Type96
Definition rtp_types.h:78
const unsigned char * rtpenc_get_next_nal(const unsigned char *start, long len, const unsigned char **endptr)
uint32_t get_std_video_local_mediatime(void)
Definition tv.c:204

References tile::data, tile::data_len, error_msg, FEC_NONE, tx::fec_scheme, video_frame::fragment, frame, get_std_video_local_mediatime(), tx::mtu, PT_DynRTP_Type96, rtp_send_data(), rtp_send_data_hdr(), rtpenc_get_next_nal(), start(), video_frame::tile_count, video_frame::tiles, and ts.

Referenced by h264_rtp_video_rxtx::configure_rtsp_server_video(), and h264_sdp_video_rxtx::send_frame().

Here is the call graph for this function:

◆ tx_send_jpeg()

void tx_send_jpeg ( struct tx * tx,
struct video_frame * frame,
struct rtp * rtp_session )

Definition at line 1168 of file transmit.cpp.

1169 {
1170 uint32_t ts = 0;
1171
1172 assert(frame->tile_count == 1); // std transmit doesn't handle more than one tile
1173 assert(!frame->fragment || tx->fec_scheme == FEC_NONE); // currently no support for FEC with fragments
1174 assert(!frame->fragment || frame->tile_count); // multiple tiles are not currently supported for fragmented send
1175
1177
1178 struct tile *tile = &frame->tiles[0];
1179 char pt = PT_JPEG;
1180 struct jpeg_rtp_data d;
1181
1182 if (!jpeg_get_rtp_hdr_data((uint8_t *) frame->tiles[0].data, frame->tiles[0].data_len, &d)) {
1183 exit_uv(1);
1184 return;
1185 }
1186
1187 uint32_t jpeg_hdr[2 /* JPEG hdr */ + 1 /* RM hdr */ + 129 /* QT hdr */];
1188 int hdr_off = 0;
1189 unsigned int type_spec = 0u;
1190 jpeg_hdr[hdr_off++] = htonl(type_spec << 24u);
1191 jpeg_hdr[hdr_off++] = htonl(d.type << 24u | d.q << 16u | d.width / 8u << 8u | d.height / 8u);
1192 if (d.restart_interval != 0) {
1193 // we do not align restart interval on packet boundaries yet
1194 jpeg_hdr[hdr_off++] = htonl(d.restart_interval << 16u | 1u << 15u | 1u << 14u | 0x3fffu);
1195 }
1196 // quantization headers
1197 if (d.q == 255u) { // we must include the tables
1198 unsigned int mbz = 0u; // must be zero
1199 unsigned int precision = 0u;
1200 unsigned int qt_len = 2 * 64u;
1201 jpeg_hdr[hdr_off++] = htonl(mbz << 24u | precision << 16u | qt_len);
1202 memcpy(&jpeg_hdr[hdr_off], d.quantization_tables[0], 64);
1203 hdr_off += 64 / sizeof(uint32_t);
1204 memcpy(&jpeg_hdr[hdr_off], d.quantization_tables[1], 64);
1205 hdr_off += 64 / sizeof(uint32_t);
1206 }
1207
1208 char *data = (char *) d.data;
1209 int bytes_left = tile->data_len - ((char *) d.data - tile->data);
1210 int max_mtu = tx->mtu - ((rtp_is_ipv6(rtp_session) ? 40 : 20) + 8 + 12); // IP hdr size + UDP hdr size + RTP hdr size
1211
1212 int fragment_offset = 0;
1213 do {
1214 int hdr_len;
1215 if (fragment_offset == 0) { // include quantization header only in 1st pkt
1216 hdr_len = hdr_off * sizeof(uint32_t);
1217 } else {
1218 hdr_len = 8 + (d.restart_interval > 0 ? 4 : 0);
1219 }
1220 int data_len = max_mtu - hdr_len;
1221 int m = 0;
1222 if (bytes_left <= data_len) {
1223 data_len = bytes_left;
1224 m = 1;
1225 }
1226 jpeg_hdr[0] = htonl(type_spec << 24u | fragment_offset);
1227
1228 int ret = rtp_send_data_hdr(rtp_session, ts, pt, m, 0, 0,
1229 (char *) &jpeg_hdr, hdr_len,
1230 data, data_len, 0, 0, 0);
1231 if (ret < 0) {
1232 log_msg(LOG_LEVEL_ERROR, "Error sending RTP/JPEG packet!\n");
1233 }
1234 data += data_len;
1235 bytes_left -= data_len;
1236 fragment_offset += data_len;
1237 } while (bytes_left > 0);
1238}
void exit_uv(int status)
Definition host.cpp:625
bool jpeg_get_rtp_hdr_data(uint8_t *jpeg_data, int len, struct jpeg_rtp_data *hdr_data)
#define PT_JPEG
Definition rtp_types.h:71
uint8_t * data
Definition jpeg_reader.h:86

References jpeg_rtp_data::data, tile::data, tile::data_len, exit_uv(), FEC_NONE, tx::fec_scheme, video_frame::fragment, frame, get_std_video_local_mediatime(), jpeg_rtp_data::height, jpeg_get_rtp_hdr_data(), LOG_LEVEL_ERROR, log_msg(), tx::mtu, PT_JPEG, jpeg_rtp_data::q, jpeg_rtp_data::quantization_tables, jpeg_rtp_data::restart_interval, rtp_is_ipv6(), rtp_send_data_hdr(), video_frame::tile_count, video_frame::tiles, ts, jpeg_rtp_data::type, and jpeg_rtp_data::width.

Referenced by h264_rtp_video_rxtx::configure_rtsp_server_video(), and h264_sdp_video_rxtx::send_frame().

Here is the call graph for this function:

◆ tx_update()

static void tx_update ( struct tx * tx,
struct video_frame * frame,
int substream )
static

Definition at line 166 of file transmit.cpp.

167{
168 if(!frame) {
169 return;
170 }
171
172 uint64_t tmp_avg = tx->avg_len * tx->sent_frames + frame->tiles[substream].data_len *
174 (double) frame->fec_params.k / (frame->fec_params.k + frame->fec_params.m) :
175 1);
176 tx->sent_frames++;
177 tx->avg_len = tmp_avg / tx->sent_frames;
178 if(tx->sent_frames >= 100) {
179 if(tx->fec_scheme == FEC_LDGM && tx->max_loss > 0.0) {
180 if(abs(tx->avg_len_last - tx->avg_len) > tx->avg_len / 3) {
181 int data_len = tx->mtu - (40 + (sizeof(fec_payload_hdr_t)));
182 data_len = (data_len / 48) * 48;
183 //void *fec_state_old = tx->fec_state;
184
185 struct msg_sender *msg = (struct msg_sender *)
186 new_message(sizeof(struct msg_sender));
187 snprintf(msg->fec_cfg, sizeof(msg->fec_cfg), "LDGM percents %d %d %f",
188 data_len, tx->avg_len, tx->max_loss);
191 (struct message *) msg);
192 free_response(resp);
194 }
195 }
196 tx->avg_len = 0;
197 tx->sent_frames = 0;
198 }
199}
static __device__ vec2 abs(const vec2 &v)
Definition cuda_dxt.cu:118

References abs(), tx::avg_len, tx::avg_len_last, tile::data_len, FEC_LDGM, FEC_NONE, video_frame::fec_params, tx::fec_scheme, frame, free_response(), get_parent_module(), fec_desc::k, fec_desc::m, tx::max_loss, tx::mod, tx::mtu, new_message(), send_message_to_receiver(), SENDER_MSG_CHANGE_FEC, tx::sent_frames, video_frame::tiles, and fec_desc::type.

Referenced by tx_send_base().

Here is the call graph for this function:

◆ validate_std_audio()

static bool validate_std_audio ( const audio_frame2 * buffer,
int payload_size )
static

Definition at line 933 of file transmit.cpp.

934{
935 if ((buffer->get_codec() == AC_MP3 ||
936 buffer->get_codec() == AC_OPUS) &&
937 buffer->get_channel_count() > 1) { // we cannot interleave Opus here
938 const uint32_t msg_id = to_fourcc('t', 'x', 'v', 'a');
941 "%s can currently have only 1 channel in "
942 "RFC-compliant mode! Discarding channels but the "
943 "first one...\n",
945 }
946 if (buffer->get_codec() == AC_OPUS &&
947 payload_size < (int) buffer->get_data_len(0)) {
948 MSG(ERROR, "Opus frame larger than packet! Discarding...\n");
949 return false;
950 }
951 return true;
952}
const char * get_name_to_audio_codec(audio_codec_t codec)
Definition codec.cpp:450

References AC_MP3, AC_OPUS, audio_frame2::get_channel_count(), audio_frame2::get_codec(), audio_frame2::get_data_len(), get_name_to_audio_codec(), LOG_LEVEL_ERROR, log_msg_once(), MOD_NAME, MSG, and to_fourcc.

Referenced by audio_tx_send_standard().

Here is the call graph for this function: