-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.c
327 lines (271 loc) · 9.17 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/*
* HTTP Live Streaming Audio Record Application
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <alsa/asoundlib.h>
#include <lame.h>
/**
* Number of samples read by one iteration
*/
#define HLSREC_SAMPLES_PER_ITERATION (128)
#define HLSREC_SAMPLE_ITERATIONS (1722)
#define HLSREC_PCM_BUFFER_SIZE (HLSREC_SAMPLES_PER_ITERATION * HLSREC_SAMPLE_ITERATIONS)
#define HLSREC_SAMPLES_TO_ENCODE (HLSREC_PCM_BUFFER_SIZE)
/**
* Global flags
*/
typedef struct {
int byte_per_sample;
int sample_rate;
int num_channels;
} hlsrec_global_flags;
/*
* foreward declaration
*/
void hlsrec_loop(snd_pcm_t *capture_handle, short buf[HLSREC_PCM_BUFFER_SIZE], hlsrec_global_flags* gfp);
int hlsrec_configure_hw(snd_pcm_t * capture_handle, hlsrec_global_flags * gfp);
int hlsrec_prepare_input_device(snd_pcm_t **capture_handle, const char * device, hlsrec_global_flags * gfp);
int hlsrec_write_m3u8(int i);
/**
*
*/
int main (int argc, char *argv[])
{
int i, res, nencoded, nwrite;
int err;
short int pcm_buf[HLSREC_PCM_BUFFER_SIZE];
snd_pcm_t *capture_handle;
FILE *fpOut;
hlsrec_global_flags hlsrec_gf;
lame_global_flags * lame_gfp;
const int mp3buffer_size = 1.25 * HLSREC_PCM_BUFFER_SIZE + 7200;
char mp3_buffer[mp3buffer_size];
/* Setup the global flags */
hlsrec_gf.sample_rate = 44100;
hlsrec_gf.num_channels = 1;
fprintf(stderr, "start...\n");
if( (res = hlsrec_prepare_input_device(&capture_handle, argv[1], &hlsrec_gf) ) < 0) {
exit(res);
}
/*
* start here to configure the LAME library and prepare something
*
* Initialize the encoder. sets default for all encoder parameters.
* #include "lame.h"
*/
lame_gfp = lame_init();
/*
* The default (if you set nothing) is a J-Stereo, 44.1khz
* 128kbps CBR mp3 file at quality 5. Override various default settings
* as necessary, for example:
*
* See lame.h for the complete list of options. Note that there are
* some lame_set_*() calls not documented in lame.h. These functions
* are experimental and for testing only. They may be removed in
* the future.
*/
lame_set_num_samples(lame_gfp, HLSREC_PCM_BUFFER_SIZE);
lame_set_num_channels(lame_gfp, hlsrec_gf.num_channels);
lame_set_in_samplerate(lame_gfp, hlsrec_gf.sample_rate);
lame_set_brate(lame_gfp, 128);
/* mode = 0,1,2,3 = stereo, jstereo, dual channel (not supported), mono */
lame_set_mode(lame_gfp, 3);
lame_set_quality(lame_gfp, 2); /* 2=high 5 = medium 7=low */
/*
* Set more internal configuration based on data provided above,
* as well as checking for problems. Check that ret_code >= 0.
*/
res = lame_init_params(lame_gfp);
if(res < 0) {
fprintf(stderr, "invalid lame params (%d)\n", res);
}
fprintf(stderr, "prepared\n");
char filename[100];
for (i = 0; i < 20; i++) {
memset(filename, 0, 100);
sprintf(filename, "/var/www/test%d.mp3", i);
/* open the output file */
fpOut = fopen(filename, "wb"); /* open the output file*/
/* record data from input device and write to pcm_buf */
hlsrec_loop(capture_handle, pcm_buf, &hlsrec_gf);
fprintf(stderr, "recorded\n");
/* encode data from pcm_buf and write to mp3_buffer */
nencoded = lame_encode_buffer(
lame_gfp,
pcm_buf, pcm_buf,
HLSREC_SAMPLES_TO_ENCODE,
(char*)&mp3_buffer[0],
mp3buffer_size);
if(nencoded < 0) {
fprintf(stderr, "error encoding (%d)\n", nencoded);
}
/* write the encoded data to the output file */
nwrite = fwrite((void *)&mp3_buffer[0], sizeof(char), nencoded, fpOut);
if(nencoded != nwrite){
fprintf(stderr, "error write (%d) should be %d\n", nwrite, nencoded);
}
fclose(fpOut);
hlsrec_write_m3u8(i);
}
/*
* free the internal data structures from lame
* close the output file and close the alsa input device.
*/
lame_close(lame_gfp);
snd_pcm_close (capture_handle);
fprintf(stderr, "successfuly closed\n");
exit (0);
}
int hlsrec_write_m3u8(int i)
{
int nwrite, towrite, b;
FILE * fp;
char * buf = malloc(400);
char str[100];
static const char * head = "#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-TARGETDURATION:5\n";
static const char * head2 = "#EXT-X-PLAYLIST-TYPE:EVENT\n";
static const char* tail = "#EXT-X-ENDLIST\n";
memset(buf, 0, 400);
memset(str, 0, 100);
strcat(buf, head);
if(i > 1) {
b = i - 2;
sprintf((char*)&str[0], "#EXT-X-MEDIA-SEQUENCE:%d\n", b);
strcat(buf, str);
}else if (i > 0) {
b = i - 1;
sprintf((char*)&str[0], "#EXT-X-MEDIA-SEQUENCE:%d\n", b);
strcat(buf, str);
}else {
b = 0;
sprintf((char*)&str[0], "#EXT-X-MEDIA-SEQUENCE:%d\n", b);
strcat(buf, str);
}
// strcat(buf, head2);
if (i > 1) {
b = i - 2;
sprintf((char*)&str[0], "#EXTINF:4.9,\nhttp://192.168.1.146/test%d.mp3\n", b);
strcat(buf, str);
}
if (i > 0) {
b = i - 1;
sprintf((char*)&str[0], "#EXTINF:4.9,\nhttp://192.168.1.146/test%d.mp3\n", b);
strcat(buf, str);
}
sprintf((char*)&str[0], "#EXTINF:4.9,\nhttp://192.168.1.146/test%d.mp3\n", i);
strcat(buf, str);
// strcat(buf, tail);
if( (fp = fopen("/var/www/index.m3u8", "wb")) == NULL){
fprintf(stderr, "error open index.m3u8\n");
return -1;
}
towrite = strlen(buf);
nwrite = fwrite((void *)&buf[0], 1, towrite, fp);
if(towrite != nwrite){
fprintf(stderr, "error write (%d) should be %d\n", nwrite, towrite);
}
fclose(fp);
free(buf);
}
/**
* \brief prepare the input device
*
* \param capture_handle
* \param device
* \param gfp Pointer to the global flags of the hlsrec
*/
int hlsrec_prepare_input_device(snd_pcm_t **capture_handle, const char * device, hlsrec_global_flags * gfp)
{
int err;
if ((err = snd_pcm_open (capture_handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
fprintf (stderr, "cannot open audio device %s (%s)\n",
device,
snd_strerror (err));
return (-1);
}
fprintf(stderr, "opened\n");
if( (err = hlsrec_configure_hw(*capture_handle, gfp) ) < 0) {
return (-2);
}
fprintf(stderr, "configured\n");
if ((err = snd_pcm_prepare (*capture_handle)) < 0) {
fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
snd_strerror (err));
return (-3);
}
}
/**
* \brief Loop the capture process
*
* \param capture_handle ALSA device handle to capture the data
* \param buf Buffer to write the captured data
*/
void hlsrec_loop(snd_pcm_t *capture_handle, short buf[HLSREC_PCM_BUFFER_SIZE], hlsrec_global_flags * gfp)
{
int i, err;
/* load the reading process and write the data to the output file */
/* for (i = 0; i < HLSREC_SAMPLE_ITERATIONS; ++i) {
if ((err = snd_pcm_readi (capture_handle, buf, HLSREC_PCM_BUFFER_SIZE)) != HLSREC_PCM_BUFFER_SIZE) {
fprintf (stderr, "read from audio interface failed (%s)\n",
snd_strerror (err));
exit (1);
}
}
*/
if ((err = snd_pcm_readi (capture_handle, buf, HLSREC_PCM_BUFFER_SIZE)) != HLSREC_PCM_BUFFER_SIZE) {
fprintf (stderr, "read from audio interface failed (%s)\n",
snd_strerror (err));
exit (1);
}
}
/**
* \brief Configure the alsa audio hardware
*
* \return
*/
int hlsrec_configure_hw(snd_pcm_t * capture_handle, hlsrec_global_flags * gfp)
{
int err;
snd_pcm_hw_params_t *hw_params;
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
snd_strerror (err));
return (-1);
}
if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0) {
fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
snd_strerror (err));
return (-2);
}
if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
fprintf (stderr, "cannot set access type (%s)\n",
snd_strerror (err));
return (-3);
}
if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
fprintf (stderr, "cannot set sample format (%s)\n",
snd_strerror (err));
return (-4);
}
if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &gfp->sample_rate, 0)) < 0) {
fprintf (stderr, "cannot set sample rate (%s)\n",
snd_strerror (err));
return (-5);
}
if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, gfp->num_channels)) < 0) {
fprintf (stderr, "cannot set channel count (%s)\n",
snd_strerror (err));
return (-6);
}
if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0) {
fprintf (stderr, "cannot set parameters (%s)\n",
snd_strerror (err));
return (-7);
}
snd_pcm_hw_params_free (hw_params);
}