1 /*
2  *      mp3rtp command line frontend program
3  *
4  *      initially contributed by Felix von Leitner
5  *
6  *      Copyright (c) 2000 Mark Taylor
7  *                    2010 Robert Hegemann
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24 
25 /* $Id: mp3rtp.c,v 1.37 2017/08/24 20:43:10 robert Exp $ */
26 
27 /* Still under work ..., need a client for test, where can I get one? */
28 
29 /* An audio player named Zinf (aka freeamp) can play rtp streams */
30 
31 /*
32  *  experimental translation:
33  *
34  *  gcc -I..\include -I..\libmp3lame -o mp3rtp mp3rtp.c ../libmp3lame/libmp3lame.a lametime.c get_audio.c ieeefloat.c timestatus.c parse.c rtp.c -lm
35  *
36  *  wavrec -t 14400 -s 44100 -S /proc/self/fd/1 | ./mp3rtp 10.1.1.42 -V2 -b128 -B256 - my_mp3file.mp3
37  */
38 
39 #ifdef HAVE_CONFIG_H
40 # include <config.h>
41 #endif
42 
43 #ifdef HAVE_STDINT_H
44 # include <stdint.h>
45 #endif
46 
47 #ifdef STDC_HEADERS
48 # include <stdlib.h>
49 # include <string.h>
50 #endif
51 
52 #include <time.h>
53 
54 #ifdef HAVE_UNISTD_H
55 # include <unistd.h>
56 #endif
57 
58 #include "lame.h"
59 #include "main.h"
60 #include "parse.h"
61 #include "lametime.h"
62 #include "timestatus.h"
63 #include "get_audio.h"
64 #include "rtp.h"
65 #include "console.h"
66 
67 #ifdef WITH_DMALLOC
68 #include <dmalloc.h>
69 #endif
70 
71 /*
72  * Encode (via LAME) to mp3 with RTP streaming of the output.
73  *
74  * Author: Felix von Leitner <leitner@vim.org>
75  *
76  *   mp3rtp ip[:port[:ttl]] [lame encoding options] infile outfile
77  *
78  * examples:
79  *   arecord -b 16 -s 22050 -w | ./mp3rtp 224.17.23.42:5004:2 -b 56 - /dev/null
80  *   arecord -b 16 -s 44100 -w | ./mp3rtp 10.1.1.42 -V2 -b128 -B256 - my_mp3file.mp3
81  *
82  */
83 
84 
85 static unsigned int
maxvalue(int Buffer[2][1152])86 maxvalue(int Buffer[2][1152])
87 {
88     int     max = 0;
89     int     i;
90 
91     for (i = 0; i < 1152; i++) {
92         if (abs(Buffer[0][i]) > max)
93             max = abs(Buffer[0][i]);
94         if (abs(Buffer[1][i]) > max)
95             max = abs(Buffer[1][i]);
96     }
97     return max >> 16;
98 }
99 
100 static void
levelmessage(unsigned int maxv,int * maxx,int * tmpx)101 levelmessage(unsigned int maxv, int* maxx, int* tmpx)
102 {
103     char    buff[] = "|  .  |  .  |  .  |  .  |  .  |  .  |  .  |  .  |  .  |  .  |  \r";
104     int     tmp = *tmpx, max = *maxx;
105 
106     buff[tmp] = '+';
107     tmp = (maxv * 61 + 16384) / (32767 + 16384 / 61);
108     if (tmp > sizeof(buff) - 2)
109         tmp = sizeof(buff) - 2;
110     if (max < tmp)
111         max = tmp;
112     buff[max] = 'x';
113     buff[tmp] = '#';
114     console_printf(buff);
115     console_flush();
116     *maxx = max;
117     *tmpx = tmp;
118 }
119 
120 
121 /************************************************************************
122 *
123 * main
124 *
125 * PURPOSE:  MPEG-1,2 Layer III encoder with GPSYCHO
126 * psychoacoustic model.
127 *
128 ************************************************************************/
129 
130 int
lame_main(lame_t gf,int argc,char ** argv)131 lame_main(lame_t gf, int argc, char **argv)
132 {
133     unsigned char mp3buffer[LAME_MAXMP3BUFFER];
134     char    inPath[PATH_MAX + 1];
135     char    outPath[PATH_MAX + 1];
136     int     Buffer[2][1152];
137 
138     int     maxx = 0, tmpx = 0;
139     int     ret;
140     int     wavsamples;
141     int     mp3bytes;
142     FILE   *outf;
143 
144     char    ip[16];
145     unsigned int port = 5004;
146     unsigned int ttl = 2;
147     char    dummy;
148 
149     if (argc <= 2) {
150         console_printf("Encode (via LAME) to mp3 with RTP streaming of the output\n"
151                        "\n"
152                        "    mp3rtp ip[:port[:ttl]] [lame encoding options] infile outfile\n"
153                        "\n"
154                        "    examples:\n"
155                        "      arecord -b 16 -s 22050 -w | ./mp3rtp 224.17.23.42:5004:2 -b 56 - /dev/null\n"
156                        "      arecord -b 16 -s 44100 -w | ./mp3rtp 10.1.1.42 -V2 -b128 -B256 - my_mp3file.mp3\n"
157                        "\n");
158         return 1;
159     }
160 
161     switch (sscanf(argv[1], "%11[.0-9]:%u:%u%c", ip, &port, &ttl, &dummy)) {
162     case 1:
163     case 2:
164     case 3:
165         break;
166     default:
167         error_printf("Illegal destination selector '%s', must be ip[:port[:ttl]]\n", argv[1]);
168         return -1;
169     }
170     rtp_initialization();
171     if (rtp_socket(ip, port, ttl)) {
172         rtp_deinitialization();
173         error_printf("fatal error during initialization\n");
174         return 1;
175     }
176 
177     lame_set_errorf(gf, &frontend_errorf);
178     lame_set_debugf(gf, &frontend_debugf);
179     lame_set_msgf(gf, &frontend_msgf);
180 
181     /* Remove the argumets that are rtp related, and then
182      * parse the command line arguments, setting various flags in the
183      * struct pointed to by 'gf'.  If you want to parse your own arguments,
184      * or call libmp3lame from a program which uses a GUI to set arguments,
185      * skip this call and set the values of interest in the gf struct.
186      * (see lame.h for documentation about these parameters)
187      */
188     {
189         int     i;
190         int     argc_mod = argc-1; /* leaving out exactly one argument */
191         char**  argv_mod = calloc(argc_mod, sizeof(char*));
192         argv_mod[0] = argv[0];
193         for (i = 2; i < argc; ++i) { /* leaving out argument number 1, parsed above */
194             argv_mod[i-1] = argv[i];
195         }
196         parse_args(gf, argc_mod, argv_mod, inPath, outPath, NULL, NULL);
197         free(argv_mod);
198     }
199 
200     /* open the output file.  Filename parsed into gf.inPath */
201     if (0 == strcmp(outPath, "-")) {
202         lame_set_stream_binary_mode(outf = stdout);
203     }
204     else {
205         if ((outf = lame_fopen(outPath, "wb+")) == NULL) {
206             rtp_deinitialization();
207             error_printf("Could not create \"%s\".\n", outPath);
208             return 1;
209         }
210     }
211 
212 
213     /* open the wav/aiff/raw pcm or mp3 input file.  This call will
214      * open the file with name gf.inFile, try to parse the headers and
215      * set gf.samplerate, gf.num_channels, gf.num_samples.
216      * if you want to do your own file input, skip this call and set
217      * these values yourself.
218      */
219     if (init_infile(gf, inPath) < 0) {
220         rtp_deinitialization();
221         fclose(outf);
222         error_printf("Can't init infile '%s'\n", inPath);
223         return 1;
224     }
225 
226 
227     /* Now that all the options are set, lame needs to analyze them and
228      * set some more options
229      */
230     ret = lame_init_params(gf);
231     if (ret < 0) {
232         if (ret == -1)
233             display_bitrates(stderr);
234         rtp_deinitialization();
235         fclose(outf);
236         close_infile();
237         error_printf("fatal error during initialization\n");
238         return -1;
239     }
240 
241     lame_print_config(gf); /* print useful information about options being used */
242 
243     if (global_ui_config.update_interval < 0.)
244         global_ui_config.update_interval = 2.;
245 
246     /* encode until we hit EOF */
247     while ((wavsamples = get_audio(gf, Buffer)) > 0) { /* read in 'wavsamples' samples */
248         levelmessage(maxvalue(Buffer), &maxx, &tmpx);
249         mp3bytes = lame_encode_buffer_int(gf, /* encode the frame */
250                                           Buffer[0], Buffer[1], wavsamples,
251                                           mp3buffer, sizeof(mp3buffer));
252         rtp_output(mp3buffer, mp3bytes); /* write MP3 output to RTP port */
253         fwrite(mp3buffer, 1, mp3bytes, outf); /* write the MP3 output to file */
254     }
255 
256     mp3bytes = lame_encode_flush(gf, /* may return one or more mp3 frame */
257                                  mp3buffer, sizeof(mp3buffer));
258     rtp_output(mp3buffer, mp3bytes); /* write MP3 output to RTP port */
259     fwrite(mp3buffer, 1, mp3bytes, outf); /* write the MP3 output to file */
260 
261     lame_mp3_tags_fid(gf, outf); /* add VBR tags to mp3 file */
262 
263     rtp_deinitialization();
264     fclose(outf);
265     close_infile();     /* close the sound input file */
266     return 0;
267 }
268 
269 /* end of mp3rtp.c */
270