mirror of
https://github.com/radio95-rnt/fm95.git
synced 2026-02-26 19:23:51 +01:00
improve vban a lot
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -25,7 +25,8 @@
|
|||||||
"optimization.h": "c",
|
"optimization.h": "c",
|
||||||
"string.h": "c",
|
"string.h": "c",
|
||||||
"getopt.h": "c",
|
"getopt.h": "c",
|
||||||
"audio.h": "c"
|
"audio.h": "c",
|
||||||
|
"signal.h": "c"
|
||||||
},
|
},
|
||||||
"C_Cpp.errorSquiggles": "disabled"
|
"C_Cpp.errorSquiggles": "disabled"
|
||||||
}
|
}
|
||||||
298
src/vban95.c
298
src/vban95.c
@@ -6,6 +6,14 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#define buffer_maxlength 12288
|
#define buffer_maxlength 12288
|
||||||
#define buffer_tlength_fragsize 12288
|
#define buffer_tlength_fragsize 12288
|
||||||
@@ -43,25 +51,83 @@ static char VBAN_TextBITList[VBAN_BIT_MAXNUMBER][4] = {
|
|||||||
#define VBAN_PROTOCOL_TXT 0x40
|
#define VBAN_PROTOCOL_TXT 0x40
|
||||||
#define VBAN_PROTOCOL_SERVICE 0x60
|
#define VBAN_PROTOCOL_SERVICE 0x60
|
||||||
|
|
||||||
|
#define VBAN_SERVICE_IDENTIFICATION 0
|
||||||
|
#define VBAN_SERVICE_CHATUTF8 1
|
||||||
|
#define VBAN_SERVICE_RTPACKETREGISTER 32
|
||||||
|
#define VBAN_SERVICE_RTPACKET 33
|
||||||
|
|
||||||
|
#define VBANPING_TYPE_RECEPTOR 0x00000001 // Simple receptor
|
||||||
|
#define VBANPING_TYPE_TRANSMITTER 0x00000002 // Simple Transmitter
|
||||||
|
#define VBANPING_TYPE_RECEPTORSPOT 0x00000004 // SPOT receptor (able to receive several streams)
|
||||||
|
#define VBANPING_TYPE_TRANSMITTERSPOT 0x00000008 // SPOT transmitter (able to send several streams)
|
||||||
|
#define VBANPING_TYPE_VIRTUALDEVICE 0x00000010 // Virtual Device
|
||||||
|
#define VBANPING_TYPE_VIRTUALMIXER 0x00000020 // Virtual Mixer
|
||||||
|
#define VBANPING_TYPE_MATRIX 0x00000040 // MATRIX
|
||||||
|
#define VBANPING_TYPE_DAW 0x00000080 // Workstation
|
||||||
|
#define VBANPING_TYPE_SERVER 0x01000000 // VBAN SERVER
|
||||||
|
|
||||||
|
#define VBANPING_FEATURE_AUDIO 0x00000001
|
||||||
|
#define VBANPING_FEATURE_AOIP 0x00000002
|
||||||
|
#define VBANPING_FEATURE_VOIP 0x00000004
|
||||||
|
#define VBANPING_FEATURE_SERIAL 0x00000100
|
||||||
|
#define VBANPING_FEATURE_MIDI 0x00000300
|
||||||
|
#define VBANPING_FEATURE_FRAME 0x00001000
|
||||||
|
#define VBANPING_FEATURE_TXT 0x00010000
|
||||||
|
|
||||||
#define BUF_SIZE 2048
|
#define BUF_SIZE 2048
|
||||||
#define MAX_AUDIO_DATA_SIZE (BUF_SIZE - sizeof(VBANHeader))
|
#define MAX_AUDIO_DATA_SIZE (BUF_SIZE - sizeof(VBANHeader))
|
||||||
#define MAX_BUFFER_PACKETS 128
|
#define MAX_BUFFER_PACKETS 128
|
||||||
|
|
||||||
|
#define POLL_TIMEOUT_MS 100
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char vban[4];
|
char vban[4];
|
||||||
uint8_t sample_rate_idx;
|
uint8_t protocol_sample_rate_idx; // format_SR
|
||||||
uint8_t samples_per_frame;
|
uint8_t samples_per_frame; // format_nbs
|
||||||
uint8_t sample_channels;
|
uint8_t sample_channels; // format_nbc
|
||||||
uint8_t format_type;
|
uint8_t format_type; // format_bit
|
||||||
char streamname[16];
|
char streamname[16];
|
||||||
uint32_t frame_num;
|
uint32_t frame_num; // nuFrame
|
||||||
} VBANHeader;
|
} VBANHeader;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
VBANHeader packet_data;
|
VBANHeader packet_data;
|
||||||
char raw_data[sizeof(VBANHeader)];
|
char raw_data[sizeof(VBANHeader)];
|
||||||
} VBANHeaderUnion;
|
} VBANHeaderUnion;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t bitType; // device type
|
||||||
|
uint32_t bitfeature;
|
||||||
|
uint32_t bitfeatureEx;
|
||||||
|
uint32_t PreferredRate;
|
||||||
|
uint32_t MinRate;
|
||||||
|
uint32_t MaxRate;
|
||||||
|
uint32_t colorRGB;
|
||||||
|
uint8_t nVersion[4];
|
||||||
|
|
||||||
|
char GPS_Position[8];
|
||||||
|
char USER_Position[8];
|
||||||
|
char LangCode_ascii[8];
|
||||||
|
char reserved_ascii[8];
|
||||||
|
|
||||||
|
char reservedEx[64];
|
||||||
|
char DistantIP_ascii[32];
|
||||||
|
uint16_t DistantPort;
|
||||||
|
uint16_t DistantReserved;
|
||||||
|
|
||||||
|
char DeviceName_ascii[64];
|
||||||
|
char ManufacturerName_ascii[64];
|
||||||
|
char ApplicationName_ascii[64];
|
||||||
|
char HostName_ascii[64];
|
||||||
|
char UserName_utf8[128];
|
||||||
|
char UserComment_utf8[128];
|
||||||
|
} VBANPing0Data;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
VBANPing0Data data;
|
||||||
|
char raw_data[sizeof(VBANPing0Data)];
|
||||||
|
} VBANPing0DataUnion;
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -129,7 +195,6 @@ int add_to_buffer(AudioBuffer* buffer, const char* data, size_t size, const VBAN
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
volatile uint8_t to_run = 1;
|
volatile uint8_t to_run = 1;
|
||||||
|
|
||||||
static void stop(int signum) {
|
static void stop(int signum) {
|
||||||
@@ -156,18 +221,72 @@ void reset_audio_buffer(AudioBuffer* buffer) {
|
|||||||
buffer->count = 0;
|
buffer->count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
void show_version() {
|
||||||
if (argc < 6) {
|
printf("vban95 (a VBAN AOIP receiver by radio95) version 1.1\n");
|
||||||
fprintf(stderr, "Usage: %s <remote_ip> <port> <streamname> <buffer_size> <pulse_device> <optional: quiet>\n", argv[0]);
|
}
|
||||||
return 1;
|
void show_help(char *name) {
|
||||||
}
|
printf(
|
||||||
|
"Usage: \t%s\n"
|
||||||
|
"\t-i,--ip\t\tOverride remote IP address\n"
|
||||||
|
"\t-p,--port\tOverride listen port\n"
|
||||||
|
"\t-s,--stream\tOverride stream name\n"
|
||||||
|
"\t-b,--buffer\tOverride buffer size (1 to %d)\n"
|
||||||
|
"\t-d,--device\tOverride PulseAudio device\n"
|
||||||
|
"\t-q,--quiet\tSuppress output messages\n",
|
||||||
|
name, MAX_BUFFER_PACKETS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
char *remote_ip = argv[1];
|
int main(int argc, char *argv[]) {
|
||||||
int listen_port = atoi(argv[2]);
|
show_version();
|
||||||
char *stream_name = argv[3];
|
|
||||||
int buffer_size = atoi(argv[4]);
|
char *remote_ip = "0.0.0.0";
|
||||||
char *pulse_device = argv[5];
|
int listen_port = 6980;
|
||||||
int quiet = (argc == 7);
|
char *stream_name = "VBAN";
|
||||||
|
int buffer_size = 1;
|
||||||
|
char *pulse_device = "";
|
||||||
|
int quiet = 0;
|
||||||
|
|
||||||
|
int opt;
|
||||||
|
const char *short_opt = "i:p:s:b:d:qh";
|
||||||
|
const struct option long_opt[] = {
|
||||||
|
{"ip", required_argument, NULL, 'i'},
|
||||||
|
{"port", required_argument, NULL, 'p'},
|
||||||
|
{"stream", required_argument, NULL, 's'},
|
||||||
|
{"buffer", required_argument, NULL, 'b'},
|
||||||
|
{"device", required_argument, NULL, 'd'},
|
||||||
|
{"quiet", no_argument, NULL, 'q'},
|
||||||
|
{"help", no_argument, NULL, 'h'},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
while ((opt = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'i':
|
||||||
|
remote_ip = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
listen_port = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
stream_name = optarg;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
buffer_size = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
pulse_device = optarg;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
quiet = 1;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
show_help(argv[0]);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
show_help(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_size <= 0 || buffer_size > MAX_BUFFER_PACKETS) {
|
if (buffer_size <= 0 || buffer_size > MAX_BUFFER_PACKETS) {
|
||||||
fprintf(stderr, "Buffer size must be between 1 and %d\n", MAX_BUFFER_PACKETS);
|
fprintf(stderr, "Buffer size must be between 1 and %d\n", MAX_BUFFER_PACKETS);
|
||||||
@@ -182,6 +301,17 @@ int main(int argc, char *argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int flags = fcntl(sockfd, F_GETFL, 0);
|
||||||
|
if (flags == -1) {
|
||||||
|
perror("fcntl(F_GETFL)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||||
|
perror("fcntl(F_SETFL)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
struct sockaddr_in local_addr;
|
struct sockaddr_in local_addr;
|
||||||
memset(&local_addr, 0, sizeof(local_addr));
|
memset(&local_addr, 0, sizeof(local_addr));
|
||||||
local_addr.sin_family = AF_INET;
|
local_addr.sin_family = AF_INET;
|
||||||
@@ -217,40 +347,116 @@ int main(int argc, char *argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pa_buffer_attr buffer_attr = {
|
||||||
|
.maxlength = buffer_maxlength,
|
||||||
|
.tlength = buffer_tlength_fragsize,
|
||||||
|
.prebuf = buffer_prebuf
|
||||||
|
};
|
||||||
|
|
||||||
signal(SIGINT, stop);
|
signal(SIGINT, stop);
|
||||||
signal(SIGTERM, stop);
|
signal(SIGTERM, stop);
|
||||||
|
|
||||||
while (to_run) {
|
while (to_run) {
|
||||||
ssize_t recv_len = recvfrom(sockfd, buffer, BUF_SIZE, 0,
|
ssize_t recv_len = recvfrom(sockfd, buffer, BUF_SIZE, 0,
|
||||||
(struct sockaddr *)&sender_addr, &sender_len);
|
(struct sockaddr *)&sender_addr, &sender_len);
|
||||||
|
|
||||||
if (recv_len < 0) {
|
if (recv_len < 0) {
|
||||||
perror("recvfrom");
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
break;
|
// No data available, just continue with the loop
|
||||||
|
// Add a small sleep to avoid consuming too much CPU
|
||||||
|
usleep(POLL_TIMEOUT_MS * 1000); // Convert ms to microseconds
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
perror("recvfrom error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((size_t)recv_len < sizeof(VBANHeader)) continue;
|
||||||
|
|
||||||
if (sender_addr.sin_addr.s_addr == remote_addr_bin.s_addr || remote_addr_bin.s_addr == 0) {
|
if (sender_addr.sin_addr.s_addr == remote_addr_bin.s_addr || remote_addr_bin.s_addr == 0) {
|
||||||
VBANHeaderUnion data;
|
VBANHeaderUnion data;
|
||||||
memcpy(&data.raw_data, buffer, sizeof(VBANHeader));
|
memcpy(&data.raw_data, buffer, sizeof(VBANHeader));
|
||||||
|
|
||||||
if (memcmp(data.packet_data.vban, "VBAN", 4) != 0) continue; // Not VBAN
|
if (memcmp(data.packet_data.vban, "VBAN", 4) != 0) continue;
|
||||||
if (memcmp(data.packet_data.streamname, stream_name, strlen(stream_name)) != 0) continue; // Not this
|
|
||||||
|
|
||||||
if (vban_frame == 0 && data.packet_data.frame_num != 0) {
|
uint8_t protocol = data.packet_data.protocol_sample_rate_idx & 0xe0;
|
||||||
// This means either this is our first packet, sync to the sender then
|
if(protocol != VBAN_PROTOCOL_AUDIO) {
|
||||||
vban_frame = data.packet_data.frame_num;
|
if(protocol == VBAN_PROTOCOL_SERVICE) {
|
||||||
}
|
// Handle Service protocol
|
||||||
|
uint8_t service_type = data.packet_data.sample_channels;
|
||||||
|
uint8_t service_function = data.packet_data.samples_per_frame; // 0 if ping, 80 if reply
|
||||||
|
|
||||||
if(data.packet_data.frame_num != vban_frame) {
|
if(service_type == VBAN_SERVICE_IDENTIFICATION) {
|
||||||
if (data.packet_data.frame_num > vban_frame) {
|
if(service_function == 0) {
|
||||||
if (quiet == 0) printf("Dropped %u packets\n", data.packet_data.frame_num - vban_frame);
|
// Handle ping
|
||||||
} else {
|
VBANPing0DataUnion ping_data;
|
||||||
if (quiet == 0) printf("Packets received out of order (got:%u, expected:%u)\n", data.packet_data.frame_num, vban_frame);
|
memset(&ping_data, 0, sizeof(VBANPing0Data));
|
||||||
|
|
||||||
|
ping_data.data.bitType = VBANPING_TYPE_RECEPTOR;
|
||||||
|
ping_data.data.bitfeature = VBANPING_FEATURE_AUDIO | VBANPING_FEATURE_AOIP;
|
||||||
|
ping_data.data.nVersion[0] = 1;
|
||||||
|
ping_data.data.nVersion[1] = 1;
|
||||||
|
|
||||||
|
snprintf(ping_data.data.DistantIP_ascii, sizeof(ping_data.data.DistantIP_ascii), "%s", inet_ntoa(sender_addr.sin_addr));
|
||||||
|
ping_data.data.DistantPort = htons(listen_port);
|
||||||
|
strncpy(ping_data.data.ApplicationName_ascii, "vban95", sizeof(ping_data.data.ApplicationName_ascii));
|
||||||
|
|
||||||
|
uid_t uid = getuid();
|
||||||
|
struct passwd *pw = getpwuid(uid);
|
||||||
|
if (pw != NULL) snprintf(ping_data.data.UserName_utf8, sizeof(ping_data.data.UserName_utf8), "%s", pw->pw_name);
|
||||||
|
|
||||||
|
gethostname(ping_data.data.HostName_ascii, sizeof(ping_data.data.HostName_ascii));
|
||||||
|
|
||||||
|
VBANHeaderUnion reply_header;
|
||||||
|
memset(&reply_header, 0, sizeof(VBANHeader));
|
||||||
|
|
||||||
|
memcpy(reply_header.packet_data.vban, "VBAN", 4);
|
||||||
|
reply_header.packet_data.protocol_sample_rate_idx = VBAN_PROTOCOL_SERVICE;
|
||||||
|
reply_header.packet_data.sample_channels = VBAN_SERVICE_IDENTIFICATION;
|
||||||
|
reply_header.packet_data.samples_per_frame = 0x80; // reply
|
||||||
|
reply_header.packet_data.frame_num = data.packet_data.frame_num;
|
||||||
|
|
||||||
|
char reply_buffer[sizeof(VBANHeader) + sizeof(VBANPing0Data)];
|
||||||
|
memcpy(reply_buffer, &reply_header.raw_data, sizeof(VBANHeader));
|
||||||
|
memcpy(reply_buffer + sizeof(VBANHeader), &ping_data.raw_data, sizeof(VBANPing0Data));
|
||||||
|
ssize_t sent_len = sendto(sockfd, reply_buffer, sizeof(reply_buffer), 0,
|
||||||
|
(struct sockaddr *)&sender_addr, sender_len);
|
||||||
|
if (sent_len < 0) {
|
||||||
|
perror("sendto");
|
||||||
|
} else {
|
||||||
|
if (quiet == 0) printf("Sent VBAN ping reply to %s:%d\n", inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vban_frame == 0) {
|
||||||
|
// First packet we receive, just accept whatever frame number it has
|
||||||
|
vban_frame = data.packet_data.frame_num;
|
||||||
|
} else {
|
||||||
|
// Normal packet processing
|
||||||
|
uint32_t expected_frame = vban_frame + 1;
|
||||||
|
|
||||||
|
if(data.packet_data.frame_num != expected_frame) {
|
||||||
|
if (data.packet_data.frame_num > expected_frame) {
|
||||||
|
if (quiet == 0) printf("Dropped %u packets\n", data.packet_data.frame_num - expected_frame);
|
||||||
|
} else {
|
||||||
|
if (quiet == 0) printf("Packets received out of order (got:%u, expected:%u)\n",
|
||||||
|
data.packet_data.frame_num, expected_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vban_frame = data.packet_data.frame_num;
|
vban_frame = data.packet_data.frame_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(vban_last_sr != data.packet_data.sample_rate_idx) {
|
if (strncmp(data.packet_data.streamname, stream_name, sizeof(data.packet_data.streamname)) != 0) continue;
|
||||||
vban_last_sr = data.packet_data.sample_rate_idx;
|
|
||||||
|
uint8_t actual_sr_idx = data.packet_data.protocol_sample_rate_idx & 0x1f;
|
||||||
|
if(vban_last_sr != actual_sr_idx) {
|
||||||
|
vban_last_sr = actual_sr_idx;
|
||||||
if(quiet == 0) printf("New sample rate of %ld\n", VBAN_SRList[vban_last_sr % VBAN_SR_MAXNUMBER]);
|
if(quiet == 0) printf("New sample rate of %ld\n", VBAN_SRList[vban_last_sr % VBAN_SR_MAXNUMBER]);
|
||||||
vban_audio_reset = 1;
|
vban_audio_reset = 1;
|
||||||
reset_audio_buffer(audio_buffer);
|
reset_audio_buffer(audio_buffer);
|
||||||
@@ -270,24 +476,15 @@ int main(int argc, char *argv[]) {
|
|||||||
reset_audio_buffer(audio_buffer);
|
reset_audio_buffer(audio_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle audio reset if needed
|
|
||||||
if(vban_audio_reset) {
|
if(vban_audio_reset) {
|
||||||
if (vban_last_sr >= VBAN_SR_MAXNUMBER || vban_last_format >= VBAN_BIT_MAXNUMBER) {
|
if (vban_last_sr >= VBAN_SR_MAXNUMBER || vban_last_format >= VBAN_BIT_MAXNUMBER) {
|
||||||
fprintf(stderr, "Unsupported sample rate or format\n");
|
fprintf(stderr, "Unsupported sample rate or format\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.initialized) {
|
if (output.initialized) free_PulseOutputDevice(&output);
|
||||||
free_PulseOutputDevice(&output);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_buffer_attr buffer_attr = {
|
int result = init_PulseOutputDevicef( // the f suffix is to specify the format, because without f it defaults to float
|
||||||
.maxlength = buffer_maxlength,
|
|
||||||
.tlength = buffer_tlength_fragsize,
|
|
||||||
.prebuf = buffer_prebuf
|
|
||||||
};
|
|
||||||
|
|
||||||
int result = init_PulseOutputDevicef(
|
|
||||||
&output,
|
&output,
|
||||||
VBAN_SRList[vban_last_sr],
|
VBAN_SRList[vban_last_sr],
|
||||||
vban_last_channels + 1, // Add 1 because VBAN channels are 0-based
|
vban_last_channels + 1, // Add 1 because VBAN channels are 0-based
|
||||||
@@ -298,9 +495,7 @@ int main(int argc, char *argv[]) {
|
|||||||
VBAN_BITList[vban_last_format]
|
VBAN_BITList[vban_last_format]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) fprintf(stderr, "Failed to initialize PulseAudio output device: %s\n", pa_strerror(result));
|
||||||
fprintf(stderr, "Failed to initialize PulseAudio output device: %s\n", pa_strerror(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
vban_audio_reset = 0;
|
vban_audio_reset = 0;
|
||||||
continue;
|
continue;
|
||||||
@@ -310,19 +505,14 @@ int main(int argc, char *argv[]) {
|
|||||||
size_t audio_data_size = recv_len - sizeof(VBANHeader);
|
size_t audio_data_size = recv_len - sizeof(VBANHeader);
|
||||||
|
|
||||||
if (add_to_buffer(audio_buffer, audio_data, audio_data_size, &data.packet_data) > 0) {
|
if (add_to_buffer(audio_buffer, audio_data, audio_data_size, &data.packet_data) > 0) {
|
||||||
if (audio_buffer->count >= audio_buffer->capacity) {
|
if (audio_buffer->count >= audio_buffer->capacity) process_audio_buffer(audio_buffer, &output);
|
||||||
process_audio_buffer(audio_buffer, &output);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
vban_frame++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
printf("Cleaning up...\n");
|
printf("Cleaning up...\n");
|
||||||
if (output.initialized) {
|
if (output.initialized) free_PulseOutputDevice(&output);
|
||||||
free_PulseOutputDevice(&output);
|
|
||||||
}
|
|
||||||
destroy_audio_buffer(audio_buffer);
|
destroy_audio_buffer(audio_buffer);
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user