1 /*
2 * This file is part of vban_emitter.
3 * Copyright (c) 2015 by Benoît Quiniou <quiniouben@yahoo.fr>
4 *
5 * vban_emitter is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * vban_emitter is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with vban_emitter. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <signal.h>
23 #include <getopt.h>
24 #include "common/version.h"
25 #include "common/socket.h"
26 #include "common/audio.h"
27 #include "common/logger.h"
28 #include "common/packet.h"
29 #include "common/backend/audio_backend.h"
30
31 struct config_t
32 {
33 struct socket_config_t socket;
34 struct audio_config_t audio;
35 struct stream_config_t stream;
36 struct audio_map_config_t map;
37 char stream_name[VBAN_STREAM_NAME_SIZE];
38 };
39
40 struct main_t
41 {
42 socket_handle_t socket;
43 audio_handle_t audio;
44 char buffer[VBAN_PROTOCOL_MAX_SIZE];
45 };
46
47 static int MainRun = 1;
signalHandler(int signum)48 void signalHandler(int signum)
49 {
50 MainRun = 0;
51 }
52
usage()53 void usage()
54 {
55 printf("\nUsage: vban_emitter [OPTIONS]...\n\n");
56 printf("-i, --ipaddress=IP : MANDATORY. ipaddress to send stream to\n");
57 printf("-p, --port=PORT : MANDATORY. port to use\n");
58 printf("-s, --streamname=NAME : MANDATORY. streamname to use\n");
59 printf("-b, --backend=TYPE : audio backend to use. %s\n", audio_backend_get_help());
60 printf("-d, --device=NAME : Audio device name. This is file name for file backend, server name for jack backend, device for alsa, stream_name for pulseaudio.\n");
61 printf("-r, --rate=VALUE : Audio device sample rate. default 44100\n");
62 printf("-n, --nbchannels=VALUE : Audio device number of channels. default 2\n");
63 printf("-f, --format=VALUE : Audio device sample format (see below). default is 16I (16bits integer)\n");
64 printf("-c, --channels=LIST : channels from the audio device to use. LIST is of form x,y,z,... default is to forward the stream as it is\n");
65
66 printf("-l, --loglevel=LEVEL : Log level, from 0 (FATAL) to 4 (DEBUG). default is 1 (ERROR)\n");
67 printf("-h, --help : display this message\n\n");
68 printf("%s\n\n", stream_bit_fmt_help());
69 }
70
get_options(struct config_t * config,int argc,char * const * argv)71 int get_options(struct config_t* config, int argc, char* const* argv)
72 {
73 int c = 0;
74 int ret = 0;
75
76 static const struct option options[] =
77 {
78 {"ipaddress", required_argument, 0, 'i'},
79 {"port", required_argument, 0, 'p'},
80 {"streamname", required_argument, 0, 's'},
81 {"backend", required_argument, 0, 'b'},
82 {"device", required_argument, 0, 'd'},
83 {"rate", required_argument, 0, 'r'},
84 {"nbchannels", required_argument, 0, 'n'},
85 {"format", required_argument, 0, 'f'},
86 {"channels", required_argument, 0, 'c'},
87 {"loglevel", required_argument, 0, 'l'},
88 {"help", no_argument, 0, 'h'},
89 {0, 0, 0, 0 }
90 };
91
92 // default values
93 config->stream.nb_channels = 2;
94 config->stream.sample_rate = 44100;
95 config->stream.bit_fmt = VBAN_BITFMT_16_INT;
96 config->audio.buffer_size = 1024; /*XXX Why ?*/
97
98 config->socket.direction = SOCKET_OUT;
99
100 /* yes, I assume config is not 0 */
101 while (1)
102 {
103 c = getopt_long(argc, argv, "i:p:s:b:d:r:n:f:c:l:h", options, 0);
104 if (c == -1)
105 break;
106
107 switch (c)
108 {
109 case 'i':
110 strncpy(config->socket.ip_address, optarg, SOCKET_IP_ADDRESS_SIZE-1);
111 break;
112
113 case 'p':
114 config->socket.port = atoi(optarg);
115 break;
116
117 case 's':
118 strncpy(config->stream_name, optarg, VBAN_STREAM_NAME_SIZE-1);
119 break;
120
121 case 'b':
122 strncpy(config->audio.backend_name, optarg, AUDIO_BACKEND_NAME_SIZE-1);
123 break;
124
125 case 'd':
126 strncpy(config->audio.device_name, optarg, AUDIO_DEVICE_NAME_SIZE-1);
127 break;
128
129 case 'r':
130 config->stream.sample_rate = atoi(optarg);
131 break;
132
133 case 'n':
134 config->stream.nb_channels = atoi(optarg);
135 break;
136
137 case 'f':
138 config->stream.bit_fmt = stream_parse_bit_fmt(optarg);
139 break;
140
141 case 'c':
142 ret = audio_parse_map_config(&config->map, optarg);
143 break;
144
145 case 'l':
146 logger_set_output_level(atoi(optarg));
147 break;
148
149 case 'h':
150 default:
151 usage();
152 return 1;
153 }
154
155 if (ret)
156 {
157 return ret;
158 }
159 }
160
161 /** check if we got all arguments */
162 if ((config->socket.ip_address[0] == 0)
163 || (config->socket.port == 0)
164 || (config->stream_name[0] == 0))
165 {
166 logger_log(LOG_FATAL, "Missing ip address, port or stream name");
167 usage();
168 return 1;
169 }
170
171 if (!strncmp(config->audio.backend_name, "jack", AUDIO_BACKEND_NAME_SIZE))
172 {
173 logger_log(LOG_FATAL, "Sorry jack backend is not ready for emitter yet");
174 return 1;
175 }
176
177 return 0;
178 }
179
180
main(int argc,char * const * argv)181 int main(int argc, char* const* argv)
182 {
183 int ret = 0;
184 int size = 0;
185 struct config_t config;
186 struct stream_config_t stream_config;
187 struct main_t main_s;
188 int max_size = 0;
189
190 printf("%s version %s\n\n", argv[0], VBAN_VERSION);
191
192 memset(&config, 0, sizeof(struct config_t));
193 memset(&main_s, 0, sizeof(struct main_t));
194
195 ret = get_options(&config, argc, argv);
196 if (ret != 0)
197 {
198 return ret;
199 }
200
201 ret = socket_init(&main_s.socket, &config.socket);
202 if (ret != 0)
203 {
204 return ret;
205 }
206
207 ret = audio_init(&main_s.audio, &config.audio);
208 if (ret != 0)
209 {
210 return ret;
211 }
212
213 ret = audio_set_map_config(main_s.audio, &config.map);
214 if (ret != 0)
215 {
216 return ret;
217 }
218
219 ret = audio_set_stream_config(main_s.audio, &config.stream);
220 if (ret != 0)
221 {
222 return ret;
223 }
224
225 audio_get_stream_config(main_s.audio, &stream_config);
226 packet_init_header(main_s.buffer, &stream_config, config.stream_name);
227 max_size = packet_get_max_payload_size(main_s.buffer);
228
229 while (MainRun)
230 {
231 size = audio_read(main_s.audio, PACKET_PAYLOAD_PTR(main_s.buffer), max_size);
232 if (size < 0)
233 {
234 MainRun = 0;
235 break;
236 }
237
238 packet_set_new_content(main_s.buffer, size);
239 ret = packet_check(config.stream_name, main_s.buffer, size + sizeof(struct VBanHeader));
240 if (ret != 0)
241 {
242 logger_log(LOG_ERROR, "%s: packet prepared is invalid", __func__);
243 break;
244 }
245
246 ret = socket_write(main_s.socket, main_s.buffer, size + sizeof(struct VBanHeader));
247 if (ret < 0)
248 {
249 MainRun = 0;
250 break;
251 }
252 }
253
254 audio_release(&main_s.audio);
255 socket_release(&main_s.socket);
256
257 return ret;
258 }
259
260