1 // FLTK callback functions for butt
2 //
3 // Copyright 2007-2018 by Daniel Noethen.
4 //
5 // This program 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 2, or (at your option)
8 // any later version.
9 //
10 // This program 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 #include <sys/types.h>
16 #include <sys/stat.h>
17 
18 #include <errno.h>
19 #include <unistd.h>
20 #include <signal.h>
21 #include <time.h>
22 #include <pthread.h>
23 
24 #ifdef WIN32
25  #define usleep(us) Sleep(us/1000)
26 #else
27  #include <sys/wait.h>
28 #endif
29 
30 #include <FL/fl_ask.H>
31 #include <FL/Fl_Color_Chooser.H>
32 #include <samplerate.h>
33 
34 #include "gettext.h"
35 #include "config.h"
36 
37 #include "FL/Fl_My_Native_File_Chooser.H"
38 //#include <FL/Fl_Native_File_Chooser.H>
39 //#define Fl_My_Native_File_Chooser Fl_Native_File_Chooser
40 
41 #include "cfg.h"
42 #include "butt.h"
43 #include "port_audio.h"
44 #include "timer.h"
45 #include "shoutcast.h"
46 #include "icecast.h"
47 #include "lame_encode.h"
48 #include "opus_encode.h"
49 #include "fl_callbacks.h"
50 #include "strfuncs.h"
51 #include "flgui.h"
52 #include "util.h"
53 #include "fl_timer_funcs.h"
54 #include "fl_funcs.h"
55 #include "update.h"
56 
57 
58 flgui *fl_g;
59 int display_info = STREAM_TIME;
60 
61 pthread_t pt_connect;
62 
63 int ask_user = 0;
connect_thread(void * data)64 void *connect_thread(void *data)
65 {
66     int ret;
67     int (*xc_connect)() = NULL;
68 
69 
70     if (cfg.srv[cfg.selected_srv]->type == SHOUTCAST)
71         xc_connect = &sc_connect;
72     else //(cfg.srv[cfg.selected_srv]->type == ICECAST)
73         xc_connect = &ic_connect;
74 
75     //try to connect as long as xc_connect returns non-zero and try_to_connect == 1
76     while ( ((ret = xc_connect()) != IC_OK) && (try_to_connect == 1) ) //xc_connect returns 0 when connected
77     {
78         // Stop connecting in case of a fatal error
79         if (ret == IC_ABORT)
80         {
81             fl_g->lcd->clear();
82             fl_g->lcd->print((const uchar*)_("idle"), strlen(_("idle")));
83             break;
84         }
85         if (ret == IC_ASK)
86         {
87             ask_user = 1;
88             while (ask_user_get_has_clicked() != 1)
89                 usleep(100000); // 100ms
90 
91             if (ask_user_get_answer() == IC_ABORT)
92             {
93                 fl_g->lcd->clear();
94                 fl_g->lcd->print((const uchar*)_("idle"), strlen(_("idle")));
95                 ask_user_reset();
96                 break;
97             }
98             ask_user_reset();
99         }
100 
101         usleep(100000); // 100ms
102     }
103 
104     //Connection established, we are not trying to connect anymore
105     try_to_connect = 0;
106 
107     return NULL;
108 }
109 
110 // Print "Connecting..." on the LCD as long as we are trying to connect
print_connecting_timeout(void *)111 void print_connecting_timeout(void *)
112 {
113     static int dummy = 0;
114 
115     if (try_to_connect == 1)
116     {
117         if(dummy == 0)
118         {
119             print_lcd(_("connecting"), strlen(_("connecting")), 0, 1);
120             dummy++;
121         }
122         else if(dummy <= 3)
123         {
124             print_lcd(".", 1, 0, 0);
125             dummy++;
126         }
127         else if(dummy > 3)
128         {
129             dummy = 0;
130         }
131         else
132             dummy++;
133 
134         Fl::repeat_timeout(0.25, &print_connecting_timeout);
135     }
136     else
137     {
138         dummy = 0;
139     }
140 }
141 
button_connect_cb(void)142 void button_connect_cb(void)
143 {
144 
145     char text_buf[256];
146 
147     if(connected)
148         return;
149 
150     if(try_to_connect)
151         return;
152 
153     if(cfg.main.num_of_srv < 1)
154     {
155         print_info(_("Error: No server entry found.\nPlease add a server in the settings-window."), 1);
156         return;
157     }
158 
159     if(!strcmp(cfg.audio.codec, "ogg") && (cfg.audio.bitrate < 48))
160     {
161         print_info(_("Error: ogg vorbis encoder doesn't support bitrates\n"
162                     "lower than 48kbit"),1);
163         return;
164     }
165 
166     if(cfg.srv[cfg.selected_srv]->type == SHOUTCAST)
167     {
168         if( (!strcmp(cfg.audio.codec, "ogg")) || (!strcmp(cfg.audio.codec, "opus")) )
169         {
170             snprintf(text_buf, sizeof(text_buf), _("Warning: %s is not supported by every ShoutCast version"), cfg.audio.codec);
171             print_info(text_buf, 1);
172         }
173         if(!strcmp(cfg.audio.codec, "flac"))
174         {
175             print_info(_("Error: FLAC is not supported by ShoutCast"), 1);
176             return;
177         }
178     }
179 
180 
181     if(cfg.srv[cfg.selected_srv]->type == SHOUTCAST)
182         snprintf(text_buf, sizeof(text_buf), _("Connecting to %s:%u (%u) ..."),
183             cfg.srv[cfg.selected_srv]->addr,
184             cfg.srv[cfg.selected_srv]->port+1,
185             cfg.srv[cfg.selected_srv]->port);
186     else
187         snprintf(text_buf, sizeof(text_buf), _("Connecting to %s:%u ..."),
188             cfg.srv[cfg.selected_srv]->addr,
189             cfg.srv[cfg.selected_srv]->port);
190 
191     print_info(text_buf, 0);
192 
193 
194     //Clear libsamplerate state
195     snd_reset_samplerate_conv(SND_STREAM);
196 
197     try_to_connect = 1;
198     pthread_create(&pt_connect, NULL, connect_thread, NULL);
199     Fl::add_timeout(0, &print_connecting_timeout);
200     while(try_to_connect)
201     {
202         if (ask_user == 1)
203         {
204             ask_user_ask();
205             ask_user = 0;
206         }
207 
208         usleep(10000); //10 ms
209         Fl::wait(0); //update gui and parse user events
210     }
211 
212     Fl::add_timeout(0.25, &cmd_timer);
213 
214     if(!connected)
215         return;
216 
217 
218     //we have to make sure that the first audio data
219     //the server sees are the ogg headers
220     if(!strcmp(cfg.audio.codec, "ogg"))
221         vorbis_enc_write_header(&vorbis_stream);
222 
223     if(!strcmp(cfg.audio.codec, "opus"))
224         opus_enc_write_header(&opus_stream);
225 
226     // Reset the internal flac frame counter to zero to
227     // make sure that the header is sent to the server upon next connect
228     if(!strcmp(cfg.audio.codec, "flac"))
229         flac_enc_reinit(&flac_stream);
230 
231 
232 
233     char bitrate_str[32];
234     if (strcmp(cfg.audio.codec, "flac") == 0)
235         snprintf(bitrate_str, sizeof(bitrate_str), "-");
236     else
237         snprintf(bitrate_str, sizeof(bitrate_str), "%dkbps", cfg.audio.bitrate);
238 
239 
240     print_info(_("Connection established"), 0);
241     snprintf(text_buf, sizeof(text_buf),
242             "Settings:\n"
243             "Type:\t\t%s\n"
244             "Codec:\t\t%s\n"
245             "Bitrate:\t%s\n"
246             "Samplerate:\t%dHz\n",
247             cfg.srv[cfg.selected_srv]->type == SHOUTCAST ? "ShoutCast" : "IceCast",
248             cfg.audio.codec,
249             bitrate_str,
250             strcmp(cfg.audio.codec, "opus") == 0 ? 48000 : cfg.audio.samplerate
251             );
252 
253 
254     if(cfg.srv[cfg.selected_srv]->type == ICECAST)
255         snprintf(text_buf+strlen(text_buf), sizeof(text_buf)-strlen(text_buf),
256                 "Mountpoint:\t%s\n"
257                 "User:\t\t%s\n"
258                 "SSL/TLS:\t%s\n",
259                 cfg.srv[cfg.selected_srv]->mount,
260                 cfg.srv[cfg.selected_srv]->usr,
261                 cfg.srv[cfg.selected_srv]->tls == 0 ? _("no") : _("yes")
262                 );
263 
264     print_info(text_buf, 0);
265 
266     if (!cfg.main.song_update && !cfg.main.app_update)
267 	    update_song(1);
268 
269     //the user may not change the audio device while streaming
270     fl_g->choice_cfg_dev->deactivate();
271     //the sames applies to the codecs
272     fl_g->choice_cfg_codec->deactivate();
273     // and the mono to stereo conversion
274     fl_g->check_cfg_mono_to_stereo->deactivate();
275 
276 
277     //Changing any audio settings while streaming does not work with
278     //ogg/vorbis & ogg/opus :(
279     if((!strcmp(cfg.audio.codec, "ogg")) || (!strcmp(cfg.audio.codec, "opus")))
280     {
281         fl_g->choice_cfg_bitrate->deactivate();
282         fl_g->choice_cfg_samplerate->deactivate();
283         fl_g->choice_cfg_channel->deactivate();
284     }
285 
286     //Changing the sample rate while streaming does not work with aac
287     if(!strcmp(cfg.audio.codec, "aac"))
288     {
289         fl_g->choice_cfg_samplerate->deactivate();
290     }
291 
292     pa_new_frames = 0;
293 
294     //Just in case the record routine started a check_time timeout
295     //already
296     Fl::remove_timeout(&display_info_timer);
297 
298     Fl::add_timeout(0.1, &display_info_timer);
299     Fl::add_timeout(0.1, &is_connected_timer);
300 
301     if(cfg.main.song_update)
302     {
303         static int reset = 1;
304         Fl::remove_timeout(&songfile_timer);
305         Fl::add_timeout(0.5, &songfile_timer, &reset);
306     }
307 
308     if(cfg.main.app_update)
309     {
310         static int reset = 1;
311         current_track_app = getCurrentTrackFunctionFromId(cfg.main.app_update_service);
312         Fl::remove_timeout(&app_timer);
313         Fl::add_timeout(0.5, &app_timer, &reset);
314     }
315 
316     if(cfg.main.silence_threshold > 0)
317         Fl::add_timeout(1, &stream_silence_timer);
318 
319 
320     snd_start_stream();
321 
322     if(cfg.rec.start_rec && !recording)
323     {
324         button_record_cb();
325         timer_init(&rec_timer, 1);
326     }
327 
328     snprintf(text_buf, sizeof(text_buf), _("Connected to: %s"), cfg.srv[cfg.selected_srv]->name);
329     fl_g->window_main->label(text_buf);
330 
331     display_info = STREAM_TIME;
332 }
333 
button_cfg_cb(void)334 void button_cfg_cb(void)
335 {
336 
337     if(fl_g->window_cfg->shown())
338     {
339         fl_g->window_cfg->hide();
340         Fl::remove_timeout(&cfg_win_pos_timer);
341     }
342     else
343     {
344 
345 /*
346  * This is a bit stupid. Well, its Win32...
347  * We need to place the cfg window a bit more to the right, otherwise
348  * the main and the cfg window would overlap
349 */
350 
351 #ifdef WIN32
352     fl_g->window_cfg->position(fl_g->window_main->x() +
353                                 fl_g->window_main->w()+0,
354                                 fl_g->window_main->y());
355 #else
356     fl_g->window_cfg->position(fl_g->window_main->x() +
357                                 fl_g->window_main->w(),
358                                 fl_g->window_main->y());
359 #endif
360         fl_g->window_cfg->show();
361         fill_cfg_widgets();
362 
363         if(cfg.gui.attach)
364             Fl::add_timeout(0.1, &cfg_win_pos_timer);
365     }
366 }
367 
368 // add server
button_add_srv_add_cb(void)369 void button_add_srv_add_cb(void)
370 {
371     int i;
372 
373     //error checking
374     if((fl_g->radio_add_srv_icecast->value()) && (strlen(fl_g->input_add_srv_mount->value()) == 0))
375     {
376         fl_alert(_("No mountpoint specified\nSetting mountpoint to \"stream\""));
377         fl_g->input_add_srv_mount->value("stream");
378     }
379     if((fl_g->radio_add_srv_icecast->value()) && (strlen(fl_g->input_add_srv_usr->value()) == 0))
380     {
381         fl_alert(_("No user specified\nSetting user to \"source\""));
382         fl_g->input_add_srv_usr->value("source");
383     }
384     if(strlen(fl_g->input_add_srv_name->value()) == 0)
385     {
386         fl_alert(_("No name specified"));
387         return;
388     }
389     if(cfg.main.srv_ent != NULL)
390     {
391         if(strlen(fl_g->input_add_srv_name->value()) + strlen(cfg.main.srv_ent) > 1000)
392         {
393             fl_alert(_("The number of characters of all your server names exeeds 1000\n"
394                     "Please reduce the number of characters of each server name"));
395             return;
396         }
397     }
398     if(strpbrk(fl_g->input_add_srv_name->value(), ";\\/\n\r") != NULL)
399     {
400         fl_alert(_("No newline characters and ;/\\ are allowed in the name field"));
401         return;
402     }
403     if(strlen(fl_g->input_add_srv_addr->value()) == 0)
404     {
405         fl_alert(_("No address specified"));
406         return;
407     }
408     if(strlen(fl_g->input_add_srv_pwd->value()) == 0)
409     {
410         fl_alert(_("No password specified"));
411         return;
412     }
413     if(strlen(fl_g->input_add_srv_port->value()) == 0)
414     {
415         fl_alert(_("No port specified"));
416         return;
417     }
418     else if((atoi(fl_g->input_add_srv_port->value()) > 65535) ||
419             (atoi(fl_g->input_add_srv_port->value()) < 1) )
420     {
421         fl_alert(_("Invalid port number\nThe port number must be between 1 and 65535"));
422         return;
423 
424     }
425 
426     //check if the name already exists
427     for(i = 0; i < cfg.main.num_of_srv; i++)
428     {
429         if(!strcmp(fl_g->input_add_srv_name->value(), cfg.srv[i]->name))
430         {
431             fl_alert(_("Server name already exist!"));
432             return;
433         }
434     }
435 
436     i = cfg.main.num_of_srv;
437     cfg.main.num_of_srv++;
438 
439     cfg.srv = (server_t**)realloc(cfg.srv, cfg.main.num_of_srv * sizeof(server_t*));
440     cfg.srv[i] = (server_t*)malloc(sizeof(server_t));
441 
442     cfg.srv[i]->name = (char*)malloc(strlen(fl_g->input_add_srv_name->value())+1);
443     strcpy(cfg.srv[i]->name, fl_g->input_add_srv_name->value());
444 
445     cfg.srv[i]->addr = (char*)malloc(strlen(fl_g->input_add_srv_addr->value())+1);
446     strcpy(cfg.srv[i]->addr, fl_g->input_add_srv_addr->value());
447 
448     cfg.srv[i]->cert_hash = NULL;
449 
450     //strip leading http:// from addr
451     if(strstr(cfg.srv[i]->addr, "http://"))
452         cfg.srv[i]->addr += strlen("http://");
453     if(strstr(cfg.srv[i]->addr, "https://"))
454         cfg.srv[i]->addr += strlen("https://");
455 
456     cfg.srv[i]->pwd = (char*)malloc(strlen(fl_g->input_add_srv_pwd->value())+1);
457     strcpy(cfg.srv[i]->pwd, fl_g->input_add_srv_pwd->value());
458 
459     cfg.srv[i]->port = atoi(fl_g->input_add_srv_port->value());
460 
461     if(fl_g->radio_add_srv_icecast->value())
462     {
463         cfg.srv[i]->mount = (char*)malloc(strlen(fl_g->input_add_srv_mount->value())+1);
464         strcpy(cfg.srv[i]->mount, fl_g->input_add_srv_mount->value());
465 
466         cfg.srv[i]->usr = (char*)malloc(strlen(fl_g->input_add_srv_usr->value())+1);
467         strcpy(cfg.srv[i]->usr, fl_g->input_add_srv_usr->value());
468 
469         cfg.srv[i]->type = ICECAST;
470     }
471     else
472     {
473         cfg.srv[i]->mount = NULL;
474         cfg.srv[i]->usr = NULL;
475         cfg.srv[i]->type = SHOUTCAST;
476     }
477 
478     cfg.srv[i]->tls = fl_g->check_add_srv_tls->value();
479 
480     if(cfg.main.num_of_srv > 1)
481     {
482         cfg.main.srv_ent = (char*)realloc(cfg.main.srv_ent,
483                                          strlen(cfg.main.srv_ent) +
484                                          strlen(cfg.srv[i]->name) +2);
485         sprintf(cfg.main.srv_ent, "%s;%s", cfg.main.srv_ent, cfg.srv[i]->name);
486     }
487     else
488     {
489         cfg.main.srv_ent = (char*)malloc(strlen(cfg.srv[i]->name) +1);
490         sprintf(cfg.main.srv_ent, "%s", cfg.srv[i]->name);
491     }
492 
493     cfg.main.srv = (char*)realloc(cfg.main.srv, strlen(cfg.srv[i]->name)+1);
494 
495     strcpy(cfg.main.srv, cfg.srv[i]->name);
496 
497     //reset the input fields and hide the window
498     fl_g->input_add_srv_name->value("");
499     fl_g->input_add_srv_addr->value("");
500     fl_g->input_add_srv_port->value("");
501     fl_g->input_add_srv_pwd->value("");
502     fl_g->input_add_srv_mount->value("");
503     fl_g->input_add_srv_usr->value("");
504     fl_g->window_add_srv->hide();
505     fl_g->check_add_srv_tls->value(0);
506 
507     fl_g->choice_cfg_act_srv->add(cfg.srv[i]->name);
508     fl_g->choice_cfg_act_srv->redraw();
509 
510     //Activate del and edit buttons
511     fl_g->button_cfg_edit_srv->activate();
512     fl_g->button_cfg_del_srv->activate();
513 
514     fl_g->choice_cfg_act_srv->activate();
515 
516     // make added server the active server
517     fl_g->choice_cfg_act_srv->value(i);
518     choice_cfg_act_srv_cb();
519 
520 }
521 
button_cfg_del_srv_cb(void)522 void button_cfg_del_srv_cb(void)
523 {
524     int i;
525     int diff;
526 
527     if(cfg.main.num_of_srv == 0)
528         return;
529 
530     diff = cfg.main.num_of_srv-1 - cfg.selected_srv;
531 
532     for(i = 0; i < diff; i++)
533     {
534         memcpy(cfg.srv[cfg.selected_srv+i], cfg.srv[cfg.selected_srv+i+1],
535                 sizeof(server_t));
536     }
537 
538     free(cfg.srv[cfg.main.num_of_srv-1]);
539 
540     cfg.main.num_of_srv--;
541 
542     //rearrange the string that contains all server names
543     memset(cfg.main.srv_ent, 0, strlen(cfg.main.srv_ent));
544     for(i = 0; i < (int)cfg.main.num_of_srv; i++)
545     {
546         strcat(cfg.main.srv_ent, cfg.srv[i]->name);
547 
548         //the last entry doesn't have a trailing seperator ";"
549         if(i < (int)cfg.main.num_of_srv-1)
550             strcat(cfg.main.srv_ent, ";");
551 
552     }
553 
554     fl_g->choice_cfg_act_srv->remove(cfg.selected_srv);
555     fl_g->choice_cfg_act_srv->redraw();       //Yes we need this :-(
556 
557     if(cfg.main.num_of_srv == 0)
558     {
559         fl_g->button_cfg_edit_srv->deactivate();
560         fl_g->button_cfg_del_srv->deactivate();
561         fl_g->choice_cfg_act_srv->deactivate();
562     }
563 
564     if(cfg.selected_srv > 0)
565         cfg.selected_srv--;
566     else
567         cfg.selected_srv = 0;
568 
569     if(cfg.main.num_of_srv > 0)
570     {
571         fl_g->choice_cfg_act_srv->value(cfg.selected_srv);
572         choice_cfg_act_srv_cb();
573     }
574 }
575 
button_cfg_del_icy_cb(void)576 void button_cfg_del_icy_cb(void)
577 {
578     int i;
579     int diff;
580 
581     if(cfg.main.num_of_icy == 0)
582         return;
583 
584     diff = cfg.main.num_of_icy-1 - cfg.selected_icy;
585 
586     for(i = 0; i < diff; i++)
587     {
588         memcpy(cfg.icy[cfg.selected_icy+i], cfg.icy[cfg.selected_icy+i+1],
589                 sizeof(icy_t));
590     }
591 
592     free(cfg.icy[cfg.main.num_of_icy-1]);
593 
594     cfg.main.num_of_icy--;
595 
596      //rearrange the string that contains all ICY names
597     memset(cfg.main.icy_ent, 0, strlen(cfg.main.icy_ent));
598     for(i = 0; i < (int)cfg.main.num_of_icy; i++)
599     {
600         strcat(cfg.main.icy_ent, cfg.icy[i]->name);
601 
602         //the last entry doesn't have a trailing seperator ";"
603         if(i < (int)cfg.main.num_of_icy-1)
604             strcat(cfg.main.icy_ent, ";");
605     }
606 
607 
608     fl_g->choice_cfg_act_icy->remove(cfg.selected_icy);
609     fl_g->choice_cfg_act_icy->redraw();
610 
611     if(cfg.main.num_of_icy == 0)
612     {
613         fl_g->button_cfg_edit_icy->deactivate();
614         fl_g->button_cfg_del_icy->deactivate();
615         fl_g->choice_cfg_act_icy->deactivate();
616     }
617 
618     if(cfg.selected_icy > 0)
619         cfg.selected_icy--;
620     else
621         cfg.selected_icy = 0;
622 
623     if(cfg.main.num_of_icy > 0)
624     {
625         fl_g->choice_cfg_act_icy->value(cfg.selected_icy);
626         choice_cfg_act_icy_cb();
627     }
628 }
629 
button_disconnect_cb(void)630 void button_disconnect_cb(void)
631 {
632 
633     if(!connected && recording)
634         stop_recording(true); // true = ask user if recording shall be stopped
635 
636     if(connected && recording && cfg.rec.stop_rec)
637         stop_recording(false); // false = do not ask user
638 
639     if(!recording)
640     {
641         fl_g->lcd->clear();
642         fl_g->lcd->print((const uchar*)_("idle"), strlen(_("idle")));
643     }
644 
645     // We are not trying to connect anymore
646     try_to_connect = 0;
647 
648     if(cfg.main.signal_threshold > 0)
649         Fl::add_timeout(1, &stream_signal_timer);
650 
651     if(!connected)
652         return;
653 
654 
655     fl_g->choice_cfg_dev->activate();
656     fl_g->choice_cfg_codec->activate();
657     fl_g->choice_cfg_bitrate->activate();
658     fl_g->choice_cfg_samplerate->activate();
659     fl_g->choice_cfg_channel->activate();
660     fl_g->check_cfg_mono_to_stereo->activate();
661 
662 
663     if(!recording)
664         Fl::remove_timeout(&display_info_timer);
665     else
666         display_info = REC_TIME;
667 
668     Fl::remove_timeout(&songfile_timer);
669     Fl::remove_timeout(&app_timer);
670 
671     if(connected)
672     {
673         Fl::remove_timeout(&is_connected_timer);
674         Fl::remove_timeout(&stream_silence_timer);
675         snd_stop_stream();
676 
677         if(cfg.srv[cfg.selected_srv]->type == SHOUTCAST)
678             sc_disconnect();
679         else
680             ic_disconnect();
681 
682         fl_g->window_main->label(PACKAGE_STRING);
683     }
684     else
685         print_info("Connecting canceled\n", 0);
686 
687 }
688 
stop_recording(bool ask)689 bool stop_recording(bool ask)
690 {
691     if(!recording)
692 	return false;
693 
694     if(ask == true)
695     {
696         int rc = 0;
697         rc = fl_choice(_("stop recording?"), _("No"), _("Yes"), NULL);
698         if(rc == 0)//if NO pressed
699             return false;
700     }
701 
702     Fl::remove_timeout(&split_recording_timer);
703     Fl::remove_timeout(&record_silence_timer);
704     snd_stop_rec();
705 
706     // Let the user change record settings after stopping the recording
707     fl_g->choice_rec_codec->activate();
708     fl_g->choice_rec_bitrate->activate();
709 
710     if(!connected)
711     {
712         fl_g->choice_cfg_channel->activate();
713         fl_g->choice_cfg_dev->activate();
714         fl_g->choice_cfg_samplerate->activate();
715 
716         fl_g->lcd->clear();
717         fl_g->lcd->print((const uchar*)_("idle"), strlen(_("idle")));
718         Fl::remove_timeout(&display_info_timer);
719     }
720     else
721         display_info = STREAM_TIME;
722 
723     if (cfg.rec.signal_threshold > 0)
724         Fl::add_timeout(1, &record_signal_timer);
725 
726     return true;
727 }
728 
button_record_cb(void)729 void button_record_cb(void)
730 {
731     int i;
732     int rc = 0;
733     int cancel = 0;
734     static int with_repeat = 1;
735     char mode[3];
736     char i_str[12];
737     bool index = 0;
738     char *path_with_placeholder = NULL;
739     char *path_for_index_loop = NULL;
740     char *path_for_index_loop_fmt = NULL;
741     char *path_without_split_time = NULL;
742     FILE *fd;
743 
744     struct tm *local_time;
745 
746     const time_t t = time(NULL);
747 
748     if(recording)
749     {
750         stop_recording(true);
751         return;
752     }
753 
754     if(strlen(cfg.rec.filename) == 0)
755     {
756         fl_alert(_("No recording filename specified"));
757         return;
758     }
759 
760 
761     cfg.rec.path = (char*) malloc((strlen(cfg.rec.folder) +
762                 strlen(cfg.rec.filename)) * sizeof(char) + 10);
763 
764     strcpy(cfg.rec.path, cfg.rec.folder);
765     strcat(cfg.rec.path, cfg.rec.filename);
766 
767     cfg.rec.path_fmt = strdup(cfg.rec.path);
768 
769     //expand string like file_%d_%m_%y to file_05_11_2014
770     expand_string(&cfg.rec.path);
771 
772     //check if there is an index marker in the filename
773     if(strstr(cfg.rec.filename, "%i"))
774 	{
775 		index = 1;
776 
777         path_with_placeholder = strdup(cfg.rec.path);
778         path_for_index_loop = strdup(cfg.rec.path);
779         path_for_index_loop_fmt = strdup(cfg.rec.path_fmt);
780 
781 		strrpl(&cfg.rec.path, (char*)"%i", (char*)"1", MODE_ALL);
782 		strrpl(&cfg.rec.path_fmt, (char*)"%i", (char*)"1", MODE_ALL);
783 	}
784     path_without_split_time = strdup(cfg.rec.path);
785 
786 
787     //check if the file already exists
788     if((fd = fl_fopen(cfg.rec.path, "rb")) != NULL)
789     {
790         fclose(fd);
791 
792         if(index)
793         {
794             //increment the index until we find a filename that doesn't exist yet
795             for(i = 2; /*inf*/; i++) // index_loop
796             {
797                 free(cfg.rec.path);
798                 free(cfg.rec.path_fmt);
799                 cfg.rec.path = strdup(path_for_index_loop);
800                 cfg.rec.path_fmt = strdup(path_for_index_loop_fmt);
801                 snprintf(i_str, sizeof(i_str), "%d", i);
802                 strrpl(&cfg.rec.path, (char*)"%i", i_str, MODE_ALL);
803                 strrpl(&cfg.rec.path_fmt, (char*)"%i", i_str, MODE_ALL);
804 
805                 path_without_split_time = strdup(path_with_placeholder);
806                 strrpl(&path_without_split_time, (char*)"%i", i_str, MODE_ALL);
807 
808                 if((fd = fl_fopen(cfg.rec.path, "rb")) == NULL)
809                     break;
810 
811                 fclose(fd);
812 
813                 if (i == 0x7FFFFFFF) // 2^31-1
814                 {
815                     free(path_for_index_loop);
816                     free(path_for_index_loop_fmt);
817                     free(path_without_split_time);
818                     if (path_with_placeholder != NULL)
819                            free(path_with_placeholder);
820 
821                     print_info(_("Could not find a valid filename"), 0);
822                     return;
823                 }
824 
825             }
826             free(path_for_index_loop);
827             free(path_for_index_loop_fmt);
828             strcpy(mode, "wb");
829         }
830         else
831         {
832             rc = fl_choice(_("%s already exists!"),
833                     _("cancel"), _("overwrite"), _("append"), cfg.rec.path);
834             switch(rc)
835             {
836                 case 0:                   //cancel pressed
837                     cancel = 1;
838                     break;
839                 case 1:                   //overwrite pressed
840                     strcpy(mode, "wb");
841                     break;
842                 case 2:                   //append pressed
843                     strcpy(mode, "ab");
844             }
845         }
846     }
847     else //selected file doesn't exist yet
848 	{
849         strcpy(mode, "wb");
850         if (path_for_index_loop != NULL)
851             free(path_for_index_loop);
852         if (path_for_index_loop_fmt != NULL)
853             free(path_for_index_loop_fmt);
854 	}
855     if (path_with_placeholder != NULL)
856         free(path_with_placeholder);
857 
858 
859     if(cancel == 1)
860     {
861         if (path_without_split_time != NULL)
862             free(path_without_split_time);
863         return;
864     }
865 
866     if((cfg.rec.fd = fl_fopen(cfg.rec.path, mode)) == NULL)
867     {
868         fl_alert(_("Could not open:\n%s"), cfg.rec.path);
869         if (path_without_split_time != NULL)
870             free(path_without_split_time);
871         return;
872     }
873 
874     record = 1;
875     timer_init(&rec_timer, 1);
876 
877 
878     //Clear libsamplerate state
879     snd_reset_samplerate_conv(SND_REC);
880 
881     // Allow the flac codec to access the file pointed to by cfg.rec.fd
882     if (!strcmp(cfg.rec.codec, "flac"))
883     {
884         flac_enc_init(&flac_rec);
885         flac_enc_init_FILE(&flac_rec, cfg.rec.fd);
886     }
887 
888     // User may not change any record related audio settings while recording
889     fl_g->choice_rec_codec->deactivate();
890     fl_g->choice_rec_bitrate->deactivate();
891     fl_g->choice_cfg_channel->deactivate();
892     fl_g->choice_cfg_dev->deactivate();
893     fl_g->choice_cfg_samplerate->deactivate();
894 
895     //create the recording thread
896     snd_start_rec();
897 
898     if (cfg.rec.split_time > 0)
899     {
900         free(cfg.rec.path);
901         cfg.rec.path = strdup(path_without_split_time);
902 
903         local_time = localtime(&t);
904 
905         // Make sure that the 60 minutes boundary is not violated in case
906         // sync_to_hour == 1
907         if((cfg.rec.sync_to_hour == 1) && ((local_time->tm_min + cfg.rec.split_time) > 60))
908             Fl::add_timeout(60*(60 - local_time->tm_min), &split_recording_timer, &with_repeat);
909         else
910             Fl::add_timeout(60*cfg.rec.split_time, &split_recording_timer, &with_repeat);
911 
912     }
913 
914     if (cfg.rec.silence_threshold > 0)
915         Fl::add_timeout(1, &record_silence_timer);
916 
917     Fl::remove_timeout(&record_signal_timer);
918 
919 
920     if(!connected)
921     {
922         display_info = REC_TIME;
923         Fl::add_timeout(0.1, &display_info_timer);
924     }
925     if (path_without_split_time != NULL)
926         free(path_without_split_time);
927 }
928 
button_info_cb()929 void button_info_cb() //changed "Info" text to "More"
930 {
931     if (!fl_g->info_visible)
932     {
933         // Show info output...
934         fl_g->window_main->resize(fl_g->window_main->x(),
935                                   fl_g->window_main->y(),
936                                   fl_g->window_main->w(),
937                                   fl_g->info_output->y() + 185);
938         fl_g->info_output->show();
939         fl_g->button_info->label(_("Hide log"));
940         fl_g->info_visible = 1;
941     }
942     else
943     {
944         // Hide info output...
945         fl_g->window_main->resize(fl_g->window_main->x(),
946                                   fl_g->window_main->y(),
947                                   fl_g->window_main->w(),
948                                   fl_g->info_output->y() - 30);
949         fl_g->info_output->hide();
950         fl_g->button_info->label(_("Show log"));
951         fl_g->info_visible = 0;
952     }
953 }
954 
choice_cfg_act_srv_cb(void)955 void choice_cfg_act_srv_cb(void)
956 {
957     cfg.selected_srv = fl_g->choice_cfg_act_srv->value();
958 
959     cfg.main.srv = (char*)realloc(cfg.main.srv,
960                                   strlen(cfg.srv[cfg.selected_srv]->name)+1);
961 
962     strcpy(cfg.main.srv, cfg.srv[cfg.selected_srv]->name);
963 
964 }
965 
choice_cfg_act_icy_cb(void)966 void choice_cfg_act_icy_cb(void)
967 {
968     cfg.selected_icy = fl_g->choice_cfg_act_icy->value();
969 
970     cfg.main.icy = (char*)realloc(cfg.main.icy,
971                                   strlen(cfg.icy[cfg.selected_icy]->name)+1);
972 
973     strcpy(cfg.main.icy, cfg.icy[cfg.selected_icy]->name);
974 }
975 
button_cfg_add_srv_cb(void)976 void button_cfg_add_srv_cb(void)
977 {
978     fl_g->window_add_srv->label(_("Add Server"));
979     fl_g->radio_add_srv_shoutcast->setonly();
980     fl_g->input_add_srv_mount->deactivate();
981     fl_g->input_add_srv_usr->deactivate();
982 
983     fl_g->check_add_srv_tls->deactivate();
984     fl_g->frame_add_srv_tls->deactivate();
985     fl_g->button_add_srv_revoke_cert->deactivate();
986 
987     fl_g->input_add_srv_pwd->input_type(FL_SECRET_INPUT);
988     fl_g->input_add_srv_pwd->redraw();
989     fl_g->button_cfg_show_pw->label(_("Show"));
990 
991     fl_g->button_add_srv_save->hide();
992     fl_g->button_add_srv_add->show();
993 
994     fl_g->window_add_srv->position(fl_g->window_cfg->x(), fl_g->window_cfg->y());
995     fl_g->input_add_srv_name->take_focus();
996     fl_g->window_add_srv->show();
997 }
998 
button_cfg_edit_srv_cb(void)999 void button_cfg_edit_srv_cb(void)
1000 {
1001 
1002     char dummy[10];
1003     int srv;
1004 
1005     if(cfg.main.num_of_srv < 1)
1006         return;
1007 
1008     fl_g->window_add_srv->label(_("Edit Server"));
1009 
1010     srv = fl_g->choice_cfg_act_srv->value();
1011 
1012     fl_g->input_add_srv_name->value(cfg.srv[srv]->name);
1013     fl_g->input_add_srv_addr->value(cfg.srv[srv]->addr);
1014 
1015     snprintf(dummy, 6, "%u", cfg.srv[srv]->port);
1016     fl_g->input_add_srv_port->value(dummy);
1017     fl_g->input_add_srv_pwd->value(cfg.srv[srv]->pwd);
1018 
1019     fl_g->input_add_srv_pwd->input_type(FL_SECRET_INPUT);
1020     fl_g->input_add_srv_pwd->redraw();
1021     fl_g->button_cfg_show_pw->label(_("Show"));
1022 
1023 
1024     if(cfg.srv[srv]->type == SHOUTCAST)
1025     {
1026         fl_g->input_add_srv_mount->value("");
1027         fl_g->input_add_srv_mount->deactivate();
1028         fl_g->input_add_srv_usr->value("");
1029         fl_g->input_add_srv_usr->deactivate();
1030 	fl_g->check_add_srv_tls->deactivate();
1031 	fl_g->frame_add_srv_tls->deactivate();
1032 	fl_g->button_add_srv_revoke_cert->deactivate();
1033         fl_g->radio_add_srv_shoutcast->setonly();
1034     }
1035     else //if(cfg.srv[srv]->type == ICECAST)
1036     {
1037         fl_g->input_add_srv_mount->value(cfg.srv[srv]->mount);
1038         fl_g->input_add_srv_mount->activate();
1039         fl_g->input_add_srv_usr->value(cfg.srv[srv]->usr);
1040         fl_g->input_add_srv_usr->activate();
1041         fl_g->radio_add_srv_icecast->setonly();
1042 #ifdef HAVE_LIBSSL
1043 	fl_g->check_add_srv_tls->activate();
1044 	fl_g->frame_add_srv_tls->activate();
1045 #else
1046 	fl_g->check_add_srv_tls->deactivate();
1047 	fl_g->frame_add_srv_tls->deactivate();
1048 #endif
1049 
1050         if ( (cfg.srv[srv]->cert_hash != NULL) && (strlen(cfg.srv[srv]->cert_hash) == 64) )
1051             fl_g->button_add_srv_revoke_cert->activate();
1052         else
1053             fl_g->button_add_srv_revoke_cert->deactivate();
1054     }
1055 
1056     fl_g->check_add_srv_tls->value(cfg.srv[srv]->tls);
1057 
1058     fl_g->input_add_srv_name->take_focus();
1059 
1060     fl_g->button_add_srv_add->hide();
1061     fl_g->button_add_srv_save->show();
1062 
1063     fl_g->window_add_srv->position(fl_g->window_cfg->x(), fl_g->window_cfg->y());
1064     fl_g->window_add_srv->show();
1065 }
1066 
1067 
button_cfg_add_icy_cb(void)1068 void button_cfg_add_icy_cb(void)
1069 {
1070     fl_g->window_add_icy->label(_("Add Server Infos"));
1071 
1072     fl_g->button_add_icy_save->hide();
1073     fl_g->button_add_icy_add->show();
1074     fl_g->window_add_icy->position(fl_g->window_cfg->x(), fl_g->window_cfg->y());
1075 
1076     //give the "name" input field the input focus
1077     fl_g->input_add_icy_name->take_focus();
1078 
1079     fl_g->window_add_icy->show();
1080 }
1081 
1082 
update_song(int called_from_connect_cb)1083 void update_song(int called_from_connect_cb)
1084 {
1085     static int is_updating = 0;
1086 
1087     int prefix_len = 0;
1088     int suffix_len = 0;
1089     char text_buf[512];
1090     char song_buf[512];
1091     song_buf[0] = '\0';
1092 
1093     int (*xc_update_song)(char *song_name) = NULL;
1094 
1095 
1096     if(!connected || cfg.main.song == NULL)
1097         return;
1098 
1099 
1100     // Make sure this function is not executed from different places at the same time
1101     if (is_updating == 1)
1102         return;
1103 
1104     is_updating = 1;
1105 
1106 
1107     if (cfg.main.song_prefix != NULL)
1108     {
1109         prefix_len = strlen(cfg.main.song_prefix);
1110         strncat(song_buf, cfg.main.song_prefix, sizeof(song_buf)-1);
1111     }
1112 
1113     strncat(song_buf, cfg.main.song, sizeof(song_buf)-1 - prefix_len);
1114 
1115     if (cfg.main.song_suffix != NULL)
1116     {
1117         suffix_len = strlen(cfg.main.song_suffix);
1118         strncat(song_buf, cfg.main.song_suffix, sizeof(song_buf)-1 - prefix_len - suffix_len);
1119     }
1120 
1121 
1122     if (!strcmp(cfg.audio.codec, "flac"))
1123     {
1124         if (called_from_connect_cb == 0)
1125             flac_update_song_title(&flac_stream, song_buf);
1126         else
1127             flac_set_initial_song_title(&flac_stream, song_buf);
1128     }
1129 
1130     if (cfg.srv[cfg.selected_srv]->type == SHOUTCAST)
1131         xc_update_song = &sc_update_song;
1132     else //if(cfg.srv[cfg.selected_srv]->type == ICECAST)
1133         xc_update_song = &ic_update_song;
1134 
1135     if (xc_update_song(song_buf) == 0)
1136     {
1137         snprintf(text_buf, sizeof(text_buf),
1138                  _("Updated songname to:\n%s\n"),
1139                  song_buf);
1140 
1141         print_info(text_buf, 0);
1142     }
1143     else
1144         print_info(_("Updating songname failed"), 1);
1145 
1146     is_updating = 0;
1147 
1148 }
1149 
button_cfg_song_go_cb(void)1150 void button_cfg_song_go_cb(void)
1151 {
1152     cfg.main.song = (char*)realloc(cfg.main.song, strlen(fl_g->input_cfg_song->value())+1);
1153     strcpy(cfg.main.song, fl_g->input_cfg_song->value());
1154 
1155     update_song(0);
1156 
1157     // Set focus on the song input field and mark the whole text
1158     fl_g->input_cfg_song->take_focus();
1159     fl_g->input_cfg_song->position(0);
1160     fl_g->input_cfg_song->mark(fl_g->input_cfg_song->maximum_size());
1161 }
1162 
input_cfg_song_cb(void)1163 void input_cfg_song_cb(void)
1164 {
1165     if (strlen(fl_g->input_cfg_song->value()) == 0)
1166     {
1167         if (cfg.main.song != NULL)
1168             free(cfg.main.song);
1169 
1170         cfg.main.song = NULL;
1171     }
1172 }
1173 
input_cfg_song_prefix_cb(void)1174 void input_cfg_song_prefix_cb(void)
1175 {
1176     if (strlen(fl_g->input_cfg_song_prefix->value()) == 0)
1177     {
1178         if (cfg.main.song_prefix != NULL)
1179             free(cfg.main.song_prefix);
1180 
1181         cfg.main.song_prefix = NULL;
1182     }
1183     else
1184     {
1185         cfg.main.song_prefix = (char*)realloc(cfg.main.song_prefix, strlen(fl_g->input_cfg_song_prefix->value())+1);
1186         strcpy(cfg.main.song_prefix, fl_g->input_cfg_song_prefix->value());
1187     }
1188 }
input_cfg_song_suffix_cb(void)1189 void input_cfg_song_suffix_cb(void)
1190 {
1191     if (strlen(fl_g->input_cfg_song_suffix->value()) == 0)
1192     {
1193         if (cfg.main.song_suffix != NULL)
1194             free(cfg.main.song_suffix);
1195 
1196         cfg.main.song_suffix = NULL;
1197     }
1198     else
1199     {
1200         cfg.main.song_suffix = (char*)realloc(cfg.main.song_suffix, strlen(fl_g->input_cfg_song_suffix->value())+1);
1201         strcpy(cfg.main.song_suffix, fl_g->input_cfg_song_suffix->value());
1202     }
1203 }
1204 
input_cfg_buffer_cb(bool print_message)1205 void input_cfg_buffer_cb(bool print_message)
1206 {
1207     int ms;
1208     char text_buf[256];
1209 
1210     ms = fl_g->input_cfg_buffer->value();
1211 
1212     if(ms < 1)
1213         return;
1214 
1215     cfg.audio.buffer_ms = ms;
1216     snd_reinit();
1217 
1218     if(print_message)
1219     {
1220         snprintf(text_buf, sizeof(text_buf),
1221                 _("Audio buffer has been set to %d ms"), ms);
1222         print_info(text_buf, 0);
1223     }
1224 }
1225 
choice_cfg_resample_mode_cb(void)1226 void choice_cfg_resample_mode_cb(void)
1227 {
1228     cfg.audio.resample_mode = fl_g->choice_cfg_resample_mode->value();
1229     snd_reinit();
1230     switch(cfg.audio.resample_mode)
1231     {
1232         case SRC_SINC_BEST_QUALITY:
1233             print_info("Changed resample quality to SINC_BEST_QUALITY", 0);
1234             break;
1235         case SRC_SINC_MEDIUM_QUALITY:
1236             print_info("Changed resample quality to SINC_MEDIUM_QUALITY", 0);
1237             break;
1238         case SRC_SINC_FASTEST:
1239             print_info("Changed resample quality to SINC_FASTEST", 0);
1240             break;
1241         case SRC_ZERO_ORDER_HOLD:
1242             print_info("Changed resample quality to ZERO_ORDER_HOLD", 0);
1243             break;
1244         case SRC_LINEAR:
1245             print_info("Changed resample quality to LINEAR", 0);
1246             break;
1247         default:
1248             break;
1249     }
1250 
1251 }
1252 
radio_add_srv_shoutcast_cb(void)1253 void radio_add_srv_shoutcast_cb(void)
1254 {
1255     fl_g->input_add_srv_mount->deactivate();
1256     fl_g->input_add_srv_usr->deactivate();
1257     fl_g->check_add_srv_tls->deactivate();
1258     fl_g->frame_add_srv_tls->deactivate();
1259 }
1260 
radio_add_srv_icecast_cb(void)1261 void radio_add_srv_icecast_cb(void)
1262 {
1263     fl_g->input_add_srv_mount->activate();
1264     fl_g->input_add_srv_usr->activate();
1265 
1266     fl_g->input_add_srv_mount->value("stream");
1267     fl_g->input_add_srv_usr->value("source");
1268 
1269 #ifdef HAVE_LIBSSL
1270     fl_g->check_add_srv_tls->activate();
1271     fl_g->frame_add_srv_tls->activate();
1272 #else
1273     fl_g->check_add_srv_tls->deactivate();
1274     fl_g->frame_add_srv_tls->deactivate();
1275 #endif
1276 
1277 }
1278 
button_add_srv_show_pwd_cb(void)1279 void button_add_srv_show_pwd_cb(void)
1280 {
1281     if(fl_g->input_add_srv_pwd->input_type() == FL_SECRET_INPUT)
1282     {
1283         fl_g->input_add_srv_pwd->input_type(FL_NORMAL_INPUT);
1284         fl_g->input_add_srv_pwd->redraw();
1285         fl_g->button_cfg_show_pw->label(_("Hide"));
1286     }
1287     else
1288     {
1289         fl_g->input_add_srv_pwd->input_type(FL_SECRET_INPUT);
1290         fl_g->input_add_srv_pwd->redraw();
1291         fl_g->button_cfg_show_pw->label(_("Show"));
1292     }
1293 }
1294 
button_add_srv_revoke_cert_cb(void)1295 void button_add_srv_revoke_cert_cb(void)
1296 {
1297     int srv;
1298     srv = fl_g->choice_cfg_act_srv->value();
1299 
1300     if (cfg.srv[srv]->cert_hash != NULL)
1301     {
1302         free(cfg.srv[srv]->cert_hash);
1303         cfg.srv[srv]->cert_hash = NULL;
1304         fl_g->button_add_srv_revoke_cert->deactivate();
1305     }
1306     else
1307     {
1308         fl_alert(_("Could not revoke trust for certificate"));
1309     }
1310 }
1311 
1312 // edit server
button_add_srv_save_cb(void)1313 void button_add_srv_save_cb(void)
1314 {
1315     int i;
1316 
1317     if(cfg.main.num_of_srv < 1)
1318         return;
1319 
1320     int srv_num = fl_g->choice_cfg_act_srv->value();
1321     int len = 0;
1322 
1323     //error checking
1324     if((fl_g->radio_add_srv_icecast->value()) && (strlen(fl_g->input_add_srv_mount->value()) == 0))
1325     {
1326         fl_alert(_("No mountpoint specified\nSetting mountpoint to \"stream\""));
1327         fl_g->input_add_srv_mount->value("stream");
1328     }
1329     if((fl_g->radio_add_srv_icecast->value()) && (strlen(fl_g->input_add_srv_usr->value()) == 0))
1330     {
1331         fl_alert(_("No user specified\nSetting user to \"source\""));
1332         fl_g->input_add_srv_usr->value("source");
1333     }
1334     if(strlen(fl_g->input_add_srv_name->value()) == 0)
1335     {
1336         fl_alert(_("No name specified"));
1337         return;
1338     }
1339     if(cfg.main.srv_ent != NULL)
1340     {
1341         if(strlen(fl_g->input_add_srv_name->value()) + strlen(cfg.main.srv_ent) > 1000)
1342         {
1343             fl_alert(_("The number of characters of all your server names exeeds 1000\n"
1344                     "Please reduce the number of characters of each server name"));
1345             return;
1346         }
1347     }
1348     if(strpbrk(fl_g->input_add_srv_name->value(), ";\\/\n\r") != NULL)
1349     {
1350         fl_alert(_("No newline characters and ;/\\ are allowed in the name field"));
1351         return;
1352     }
1353     if(strlen(fl_g->input_add_srv_addr->value()) == 0)
1354     {
1355         fl_alert(_("No address specified"));
1356         return;
1357     }
1358     if(strlen(fl_g->input_add_srv_pwd->value()) == 0)
1359     {
1360         fl_alert(_("No password specified"));
1361         return;
1362     }
1363     if(strlen(fl_g->input_add_srv_port->value()) == 0)
1364     {
1365         fl_alert(_("No port specified"));
1366         return;
1367     }
1368     else if(( atoi(fl_g->input_add_srv_port->value()) > 65535) ||
1369             (atoi(fl_g->input_add_srv_port->value()) < 1) )
1370     {
1371         fl_alert(_("Invalid port number\nThe port number must be between 1 and 65535"));
1372         return;
1373     }
1374 
1375     //check if the name already exists
1376     for(i = 0; i < cfg.main.num_of_srv; i++)
1377     {
1378         if(i == srv_num) //don't check name against it self
1379             continue;
1380         if(!strcmp(fl_g->input_add_srv_name->value(), cfg.srv[i]->name))
1381         {
1382             fl_alert(_("Server name already exist!"));
1383             return;
1384         }
1385     }
1386 
1387 
1388     //update current server name
1389     cfg.srv[srv_num]->name =
1390         (char*) realloc(cfg.srv[srv_num]->name,
1391                 sizeof(char) * strlen(fl_g->input_add_srv_name->value())+1);
1392 
1393     strcpy(cfg.srv[srv_num]->name, fl_g->input_add_srv_name->value());
1394 
1395     //rewrite the string that contains all server names
1396     //first get the needed memory space
1397     for(int i = 0; i < cfg.main.num_of_srv; i++)
1398         len += strlen(cfg.srv[i]->name) + 1;
1399     //allocate enough memory
1400     cfg.main.srv_ent = (char*) realloc(cfg.main.srv_ent, sizeof(char)*len +1);
1401 
1402     memset(cfg.main.srv_ent, 0, len);
1403     //now append the server strings
1404     for(int i = 0; i < cfg.main.num_of_srv; i++)
1405     {
1406         strcat(cfg.main.srv_ent, cfg.srv[i]->name);
1407         if(i < cfg.main.num_of_srv-1)
1408             strcat(cfg.main.srv_ent, ";");
1409     }
1410 
1411     //update current server address
1412     cfg.srv[srv_num]->addr =
1413         (char*) realloc(cfg.srv[srv_num]->addr,
1414                 sizeof(char) * strlen(fl_g->input_add_srv_addr->value())+1);
1415 
1416     strcpy(cfg.srv[srv_num]->addr, fl_g->input_add_srv_addr->value());
1417 
1418     //strip leading http:// from addr
1419     if(strstr(cfg.srv[srv_num]->addr, "http://"))
1420         cfg.srv[srv_num]->addr += strlen("http://");
1421     if(strstr(cfg.srv[srv_num]->addr, "https://"))
1422         cfg.srv[srv_num]->addr += strlen("https://");
1423 
1424     //update current server port
1425     cfg.srv[srv_num]->port = (unsigned int)atoi(fl_g->input_add_srv_port->value());
1426 
1427     //update current server password
1428     cfg.srv[srv_num]->pwd =
1429         (char*) realloc(cfg.srv[srv_num]->pwd,
1430                     strlen(fl_g->input_add_srv_pwd->value())+1);
1431 
1432     strcpy(cfg.srv[srv_num]->pwd, fl_g->input_add_srv_pwd->value());
1433 
1434     //update current server type
1435     if(fl_g->radio_add_srv_shoutcast->value())
1436         cfg.srv[srv_num]->type = SHOUTCAST;
1437     if(fl_g->radio_add_srv_icecast->value())
1438         cfg.srv[srv_num]->type = ICECAST;
1439 
1440     //update current server mountpoint and user
1441     if(cfg.srv[srv_num]->type == ICECAST)
1442     {
1443         cfg.srv[srv_num]->mount =
1444             (char*) realloc(cfg.srv[srv_num]->mount,
1445                     sizeof(char) * strlen(fl_g->input_add_srv_mount->value())+1);
1446         strcpy(cfg.srv[srv_num]->mount, fl_g->input_add_srv_mount->value());
1447 
1448         cfg.srv[srv_num]->usr =
1449             (char*) realloc(cfg.srv[srv_num]->usr,
1450                     sizeof(char) * strlen(fl_g->input_add_srv_usr->value())+1);
1451         strcpy(cfg.srv[srv_num]->usr, fl_g->input_add_srv_usr->value());
1452 
1453     }
1454 
1455     cfg.srv[srv_num]->tls = fl_g->check_add_srv_tls->value();
1456 
1457     fl_g->choice_cfg_act_srv->replace(srv_num, cfg.srv[srv_num]->name);
1458     fl_g->choice_cfg_act_srv->redraw();
1459 
1460     //reset the input fields and hide the window
1461     fl_g->input_add_srv_name->value("");
1462     fl_g->input_add_srv_addr->value("");
1463     fl_g->input_add_srv_port->value("");
1464     fl_g->input_add_srv_pwd->value("");
1465     fl_g->input_add_srv_mount->value("");
1466     fl_g->input_add_srv_usr->value("");
1467     fl_g->check_add_srv_tls->value(0);
1468 
1469     fl_g->window_add_srv->hide();
1470 
1471     choice_cfg_act_srv_cb();
1472 }
1473 
button_add_icy_save_cb(void)1474 void button_add_icy_save_cb(void)
1475 {
1476     int i;
1477 
1478     if(cfg.main.num_of_icy < 1)
1479         return;
1480 
1481     int icy_num = fl_g->choice_cfg_act_icy->value();
1482     int len = 0;
1483 
1484     if(strlen(fl_g->input_add_icy_name->value()) == 0)
1485     {
1486         fl_alert(_("No name specified"));
1487         return;
1488     }
1489     if(cfg.main.icy_ent != NULL)
1490     {
1491         if(strlen(fl_g->input_add_icy_name->value()) + strlen(cfg.main.icy_ent) > 1000)
1492         {
1493             fl_alert(_("The number of characters of all your icy names exeeds 1000\n"
1494                     "Please reduce the count of characters of each icy name"));
1495             return;
1496         }
1497     }
1498     if(strpbrk(fl_g->input_add_icy_name->value(), ";\\/\n\r") != NULL)
1499     {
1500         fl_alert(_("No newline characters and ;/\\ are allowed in the name field"));
1501         return;
1502     }
1503 
1504     //check if the name already exists
1505     for(i = 0; i < cfg.main.num_of_icy; i++)
1506     {
1507         if(i == icy_num) //don't check name against it self
1508             continue;
1509         if(!strcmp(fl_g->input_add_icy_name->value(), cfg.icy[i]->name))
1510         {
1511             fl_alert(_("Icy name already exist!"));
1512             return;
1513         }
1514     }
1515 
1516     //update current icy name
1517     cfg.icy[icy_num]->name =
1518         (char*) realloc(cfg.icy[icy_num]->name,
1519                 sizeof(char) * strlen(fl_g->input_add_icy_name->value())+1);
1520 
1521     strcpy(cfg.icy[icy_num]->name, fl_g->input_add_icy_name->value());
1522 
1523     //rewrite the string that contains all server names
1524     //first get the needed memory space
1525     for(int i = 0; i < cfg.main.num_of_icy; i++)
1526         len += strlen(cfg.icy[i]->name) + 1;
1527     //reserve enough memory
1528     cfg.main.icy_ent = (char*) realloc(cfg.main.icy_ent, sizeof(char)*len +1);
1529 
1530     memset(cfg.main.icy_ent, 0, len);
1531     //now append the server strings
1532     for(int i = 0; i < cfg.main.num_of_icy; i++)
1533     {
1534         strcat(cfg.main.icy_ent, cfg.icy[i]->name);
1535         if(i < cfg.main.num_of_icy-1)
1536             strcat(cfg.main.icy_ent, ";");
1537     }
1538 
1539     cfg.icy[icy_num]->desc =
1540         (char*)realloc(cfg.icy[icy_num]->desc,
1541                   strlen(fl_g->input_add_icy_desc->value())+1 );
1542     strcpy(cfg.icy[icy_num]->desc, fl_g->input_add_icy_desc->value());
1543 
1544     cfg.icy[icy_num]->genre =
1545         (char*)realloc(cfg.icy[icy_num]->genre,
1546                   strlen(fl_g->input_add_icy_genre->value())+1 );
1547     strcpy(cfg.icy[icy_num]->genre, fl_g->input_add_icy_genre->value());
1548 
1549     cfg.icy[icy_num]->url =
1550         (char*)realloc(cfg.icy[icy_num]->url,
1551                   strlen(fl_g->input_add_icy_url->value())+1 );
1552     strcpy(cfg.icy[icy_num]->url, fl_g->input_add_icy_url->value());
1553 
1554     cfg.icy[icy_num]->icq =
1555         (char*)realloc(cfg.icy[icy_num]->icq,
1556                   strlen(fl_g->input_add_icy_icq->value())+1 );
1557     strcpy(cfg.icy[icy_num]->icq, fl_g->input_add_icy_icq->value());
1558 
1559     cfg.icy[icy_num]->irc =
1560         (char*)realloc(cfg.icy[icy_num]->irc,
1561                   strlen(fl_g->input_add_icy_irc->value())+1 );
1562     strcpy(cfg.icy[icy_num]->irc, fl_g->input_add_icy_irc->value());
1563 
1564     cfg.icy[icy_num]->aim =
1565         (char*)realloc(cfg.icy[icy_num]->aim,
1566                   strlen(fl_g->input_add_icy_aim->value())+1 );
1567     strcpy(cfg.icy[icy_num]->aim, fl_g->input_add_icy_aim->value());
1568 
1569     sprintf(cfg.icy[icy_num]->pub, "%d", fl_g->check_add_icy_pub->value());
1570 
1571     fl_g->input_add_icy_name->value("");
1572     fl_g->input_add_icy_desc->value("");
1573     fl_g->input_add_icy_url->value("");
1574     fl_g->input_add_icy_genre->value("");
1575     fl_g->input_add_icy_irc->value("");
1576     fl_g->input_add_icy_icq->value("");
1577     fl_g->input_add_icy_aim->value("");
1578     fl_g->check_add_icy_pub->value(0);
1579 
1580     fl_g->window_add_icy->hide();
1581 
1582 
1583     fl_g->choice_cfg_act_icy->replace(icy_num, cfg.icy[icy_num]->name);
1584     fl_g->choice_cfg_act_icy->redraw();
1585     choice_cfg_act_icy_cb();
1586 }
1587 
1588 /*
1589 void choice_cfg_edit_srv_cb(void)
1590 {
1591     char dummy[10];
1592     int server = fl_g->choice_cfg_edit_srv->value();
1593 
1594     fl_g->input_cfg_addr->value(cfg.srv[server]->addr);
1595 
1596     snprintf(dummy, 6, "%u", cfg.srv[server]->port);
1597     fl_g->input_cfg_port->value(dummy);
1598     fl_g->input_cfg_passwd->value(cfg.srv[server]->pwd);
1599 
1600     if(cfg.srv[server]->type == SHOUTCAST)
1601     {
1602         fl_g->input_cfg_mount->value("");
1603         fl_g->input_cfg_mount->deactivate();
1604         fl_g->radio_cfg_shoutcast->value(1);
1605         fl_g->radio_cfg_icecast->value(0);
1606     }
1607     else //if(cfg.srv[server]->type == ICECAST)
1608     {
1609         fl_g->input_cfg_mount->value(cfg.srv[server]->mount);
1610         fl_g->input_cfg_mount->activate();
1611         fl_g->radio_cfg_icecast->value(1);
1612         fl_g->radio_cfg_shoutcast->value(0);
1613     }
1614 }
1615 */
1616 
choice_cfg_bitrate_cb(void)1617 void choice_cfg_bitrate_cb(void)
1618 {
1619     int rc;
1620     int old_br;
1621     int sel_br;
1622     int br_list[] = { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,
1623                       112, 128, 160, 192, 224, 256, 320 };
1624     char text_buf[256];
1625 
1626     old_br = cfg.audio.bitrate;
1627     for(int i = 0; i < 14; i++)
1628         if(br_list[i] == cfg.audio.bitrate)
1629             old_br = i;
1630 
1631     sel_br = fl_g->choice_cfg_bitrate->value();
1632     cfg.audio.bitrate = br_list[sel_br];
1633     lame_stream.bitrate = br_list[sel_br];
1634     vorbis_stream.bitrate = br_list[sel_br];
1635 #ifdef HAVE_LIBFDK_AAC
1636     aac_stream.bitrate = br_list[sel_br];
1637 #endif
1638     opus_stream.bitrate = br_list[sel_br]*1000;
1639 
1640 
1641     if(fl_g->choice_cfg_codec->value() == CHOICE_MP3)
1642     {
1643         rc = lame_enc_reinit(&lame_stream);
1644         if(rc != 0)
1645         {
1646             print_info(_("Warning:\nThe stream Sample-/Bitrate combination is invalid"), 1);
1647             fl_g->choice_cfg_bitrate->value(old_br);
1648             fl_g->choice_cfg_bitrate->redraw();
1649             cfg.audio.bitrate = br_list[old_br];
1650             lame_stream.bitrate = br_list[old_br];
1651             lame_enc_reinit(&lame_stream);
1652             print_info(_("The previous values have been set\n"), 1);
1653             return;
1654         }
1655     }
1656     if(fl_g->choice_cfg_codec->value() == CHOICE_OGG)
1657     {
1658         rc = vorbis_enc_reinit(&vorbis_stream);
1659         if(rc != 0)
1660         {
1661             print_info(_("Warning:\nThe stream Sample-/Bitrate combination is invalid"), 1);
1662             cfg.audio.bitrate = br_list[old_br];
1663             vorbis_stream.bitrate = br_list[old_br];
1664             fl_g->choice_cfg_bitrate->value(old_br);
1665             fl_g->choice_cfg_bitrate->redraw();
1666             vorbis_enc_reinit(&vorbis_stream);
1667             print_info(_("The previous values have been set\n"), 1);
1668             return;
1669         }
1670     }
1671 
1672     if(fl_g->choice_cfg_codec->value() == CHOICE_OPUS)
1673     {
1674         rc = opus_enc_reinit(&opus_stream);
1675         if(rc != 0)
1676         {
1677             print_info(_("Warning:\nThe stream Sample-/Bitrate combination is invalid"), 1);
1678             cfg.audio.bitrate = br_list[old_br];
1679             opus_stream.bitrate = br_list[old_br]*1000;
1680             fl_g->choice_cfg_bitrate->value(old_br);
1681             fl_g->choice_cfg_bitrate->redraw();
1682             opus_enc_reinit(&opus_stream);
1683             print_info(_("The previous values have been set\n"), 1);
1684             return;
1685         }
1686     }
1687 
1688 #ifdef HAVE_LIBFDK_AAC
1689     if(fl_g->choice_cfg_codec->value() == CHOICE_AAC)
1690     {
1691         rc = aac_enc_reinit(&aac_stream);
1692         if(rc != 0)
1693         {
1694             print_info(_("Warning:\nThe stream Sample-/Bitrate combination is invalid"), 1);
1695             cfg.audio.bitrate = br_list[old_br];
1696             aac_stream.bitrate = br_list[old_br];
1697             fl_g->choice_cfg_bitrate->value(old_br);
1698             fl_g->choice_cfg_bitrate->redraw();
1699             aac_enc_reinit(&aac_stream);
1700             print_info(_("The previous values have been set\n"), 1);
1701             return;
1702         }
1703     }
1704 #endif
1705 
1706 
1707     snprintf(text_buf, sizeof(text_buf), _("Stream bitrate set to: %dk"), cfg.audio.bitrate);
1708     print_info(text_buf, 0);
1709 }
1710 
choice_rec_bitrate_cb(void)1711 void choice_rec_bitrate_cb(void)
1712 {
1713     int rc;
1714     int old_br;
1715     int sel_br;
1716     int br_list[] = { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,
1717                       112, 128, 160, 192, 224, 256, 320 };
1718     char text_buf[256];
1719 
1720     old_br = cfg.rec.bitrate;
1721     for(int i = 0; i < 14; i++)
1722         if(br_list[i] == cfg.rec.bitrate)
1723             old_br = i;
1724 
1725 
1726     sel_br = fl_g->choice_rec_bitrate->value();
1727     cfg.rec.bitrate = br_list[sel_br];
1728     lame_rec.bitrate = br_list[sel_br];
1729     vorbis_rec.bitrate = br_list[sel_br];
1730     opus_rec.bitrate = br_list[sel_br]*1000;
1731 #ifdef HAVE_LIBFDK_AAC
1732     aac_rec.bitrate = br_list[sel_br];
1733 #endif
1734 
1735 
1736     if(fl_g->choice_rec_codec->value() == CHOICE_MP3)
1737     {
1738         rc = lame_enc_reinit(&lame_rec);
1739         if(rc != 0)
1740         {
1741             print_info(_("Warning:\nThe record Sample-/Bitrate combination is invalid"), 1);
1742             cfg.rec.bitrate = br_list[old_br];
1743             fl_g->choice_rec_bitrate->value(old_br);
1744             fl_g->choice_rec_bitrate->redraw();
1745             lame_rec.bitrate = br_list[old_br];
1746             lame_enc_reinit(&lame_rec);
1747             print_info(_("The previous values have been set"), 1);
1748             return;
1749         }
1750     }
1751     if(fl_g->choice_rec_codec->value() == CHOICE_OGG)
1752     {
1753         rc = vorbis_enc_reinit(&vorbis_rec);
1754         if(rc != 0)
1755         {
1756             print_info(_("Warning:\nThe record Sample-/Bitrate combination is invalid"), 1);
1757             cfg.rec.bitrate = br_list[old_br];
1758             vorbis_rec.bitrate = br_list[old_br];
1759             fl_g->choice_rec_bitrate->value(old_br);
1760             fl_g->choice_rec_bitrate->redraw();
1761             vorbis_enc_reinit(&vorbis_rec);
1762             print_info(_("The previous values have been set"), 1);
1763             return;
1764         }
1765     }
1766 
1767     if(fl_g->choice_rec_codec->value() == CHOICE_OPUS)
1768     {
1769         rc = opus_enc_reinit(&opus_rec);
1770         if(rc != 0)
1771         {
1772             print_info(_("Warning:\nThe record Sample-/Bitrate combination is invalid"), 1);
1773             cfg.rec.bitrate = br_list[old_br];
1774             opus_rec.bitrate = br_list[old_br]*1000;
1775             fl_g->choice_rec_bitrate->value(old_br);
1776             fl_g->choice_rec_bitrate->redraw();
1777             opus_enc_reinit(&opus_rec);
1778             print_info(_("The previous values have been set"), 1);
1779             return;
1780         }
1781     }
1782 
1783 #ifdef HAVE_LIBFDK_AAC
1784     if(fl_g->choice_rec_codec->value() == CHOICE_AAC)
1785     {
1786         rc = aac_enc_reinit(&aac_rec);
1787         if(rc != 0)
1788         {
1789             print_info(_("Warning:\nThe record Sample-/Bitrate combination is invalid"), 1);
1790             cfg.rec.bitrate = br_list[old_br];
1791             aac_rec.bitrate = br_list[old_br];
1792             fl_g->choice_rec_bitrate->value(old_br);
1793             fl_g->choice_rec_bitrate->redraw();
1794             aac_enc_reinit(&aac_rec);
1795             print_info(_("The previous values have been set"), 1);
1796             return;
1797         }
1798     }
1799 #endif
1800 
1801     snprintf(text_buf, sizeof(text_buf), _("Record bitrate set to: %dk"), cfg.rec.bitrate);
1802     print_info(text_buf, 0);
1803 }
1804 
choice_cfg_samplerate_cb()1805 void choice_cfg_samplerate_cb()
1806 {
1807     int rc;
1808     int old_sr;
1809     int sel_sr;
1810     int *sr_list;
1811     char text_buf[256];
1812 
1813     sr_list = cfg.audio.pcm_list[cfg.audio.dev_num]->sr_list;
1814 
1815     old_sr = cfg.audio.samplerate;
1816 
1817     for(int i = 0; i < 9; i++)
1818         if(sr_list[i] == cfg.audio.samplerate)
1819             old_sr = i;
1820 
1821     sel_sr = fl_g->choice_cfg_samplerate->value();
1822 
1823 
1824     cfg.audio.samplerate = sr_list[sel_sr];
1825 
1826     // Reinit streaming codecs
1827     lame_stream.samplerate = sr_list[sel_sr];
1828     vorbis_stream.samplerate = sr_list[sel_sr];
1829     opus_stream.samplerate = sr_list[sel_sr];
1830 #ifdef HAVE_LIBFDK_AAC
1831     aac_stream.samplerate = sr_list[sel_sr];
1832 #endif
1833     flac_stream.samplerate = sr_list[sel_sr];
1834 
1835 
1836     if(fl_g->choice_cfg_codec->value() == CHOICE_MP3)
1837     {
1838         rc = lame_enc_reinit(&lame_stream);
1839         if(rc != 0)
1840         {
1841             print_info(_("Warning:\nThe stream Sample-/Bitrate combination is invalid"), 1);
1842             fl_g->choice_cfg_samplerate->value(old_sr);
1843             fl_g->choice_cfg_samplerate->redraw();
1844             cfg.audio.samplerate = sr_list[old_sr];
1845             lame_stream.samplerate = sr_list[old_sr];
1846             lame_enc_reinit(&lame_stream);
1847             print_info(_("The previous values have been set"), 1);
1848             return;
1849         }
1850     }
1851     if(fl_g->choice_cfg_codec->value() == CHOICE_OGG)
1852     {
1853         rc = vorbis_enc_reinit(&vorbis_stream);
1854         if(rc != 0)
1855         {
1856             print_info(_("Warning:\nThe stream Sample-/Bitrate combination is invalid"), 1);
1857             cfg.audio.samplerate = sr_list[old_sr];
1858             vorbis_stream.samplerate = sr_list[old_sr];
1859             fl_g->choice_cfg_samplerate->value(old_sr);
1860             fl_g->choice_cfg_samplerate->redraw();
1861             vorbis_enc_reinit(&vorbis_stream);
1862             print_info(_("The previous values have been set"), 1);
1863             return;
1864         }
1865     }
1866 
1867     if(fl_g->choice_cfg_codec->value() == CHOICE_OPUS)
1868     {
1869         rc = opus_enc_reinit(&opus_stream);
1870         if(rc != 0)
1871         {
1872             print_info(_("Warning:\nThe stream Sample-/Bitrate combination is invalid"), 1);
1873             cfg.audio.samplerate = sr_list[old_sr];
1874             opus_stream.samplerate = sr_list[old_sr];
1875             fl_g->choice_cfg_samplerate->value(old_sr);
1876             fl_g->choice_cfg_samplerate->redraw();
1877             opus_enc_reinit(&opus_stream);
1878             print_info(_("The previous values have been set"), 1);
1879             return;
1880         }
1881     }
1882 
1883 #ifdef HAVE_LIBFDK_AAC
1884     if(fl_g->choice_cfg_codec->value() == CHOICE_AAC)
1885     {
1886         rc = aac_enc_reinit(&aac_stream);
1887         if(rc != 0)
1888         {
1889             print_info(_("Warning:\nThe stream Sample-/Bitrate combination is invalid"), 1);
1890             cfg.audio.samplerate = sr_list[old_sr];
1891             aac_stream.samplerate = sr_list[old_sr];
1892             fl_g->choice_cfg_samplerate->value(old_sr);
1893             fl_g->choice_cfg_samplerate->redraw();
1894             aac_enc_reinit(&aac_stream);
1895             print_info(_("The previous values have been set"), 1);
1896             return;
1897         }
1898     }
1899 #endif
1900 
1901     if(fl_g->choice_cfg_codec->value() == CHOICE_FLAC)
1902     {
1903         rc = flac_enc_reinit(&flac_stream);
1904         if(rc != 0)
1905         {
1906             print_info(_("Warning:\nThe stream Sample-/Bitrate combination is invalid"), 1);
1907             cfg.audio.samplerate = sr_list[old_sr];
1908             flac_stream.samplerate = sr_list[old_sr];
1909             fl_g->choice_cfg_samplerate->value(old_sr);
1910             fl_g->choice_cfg_samplerate->redraw();
1911             flac_enc_reinit(&flac_stream);
1912             print_info(_("The previous values have been set"), 1);
1913             return;
1914         }
1915     }
1916 
1917     //Reinit record codecs
1918     lame_rec.samplerate = sr_list[sel_sr];
1919     vorbis_rec.samplerate = sr_list[sel_sr];
1920     opus_rec.samplerate = sr_list[sel_sr];
1921 #ifdef HAVE_LIBFDK_AAC
1922     aac_rec.samplerate = sr_list[sel_sr];
1923 #endif
1924     flac_rec.samplerate = sr_list[sel_sr];
1925 
1926     if(fl_g->choice_rec_codec->value() == CHOICE_MP3)
1927     {
1928         rc = lame_enc_reinit(&lame_rec);
1929         if(rc != 0)
1930         {
1931             print_info(_("Warning:\nThe record Sample-/Bitrate combination is invalid"), 1);
1932             cfg.audio.samplerate = sr_list[old_sr];
1933             lame_stream.samplerate = sr_list[old_sr];
1934             lame_rec.samplerate = sr_list[old_sr];
1935             fl_g->choice_cfg_samplerate->value(old_sr);
1936             fl_g->choice_cfg_samplerate->redraw();
1937             lame_enc_reinit(&lame_stream);
1938             lame_enc_reinit(&lame_rec);
1939             print_info(_("The previous values have been set"), 1);
1940             return;
1941         }
1942 
1943     }
1944     if(fl_g->choice_rec_codec->value() == CHOICE_OGG)
1945     {
1946         rc = vorbis_enc_reinit(&vorbis_rec);
1947         if(rc != 0)
1948         {
1949             print_info(_("Warning:\nThe record Sample-/Bitrate combination is invalid"), 1);
1950             cfg.audio.samplerate = sr_list[old_sr];
1951             vorbis_stream.samplerate = sr_list[old_sr];
1952             vorbis_rec.samplerate = sr_list[old_sr];
1953             fl_g->choice_cfg_samplerate->value(old_sr);
1954             fl_g->choice_cfg_samplerate->redraw();
1955             vorbis_enc_reinit(&vorbis_stream);
1956             vorbis_enc_reinit(&vorbis_rec);
1957             print_info(_("The previous values have been set"), 1);
1958             return;
1959         }
1960     }
1961 
1962     if(fl_g->choice_rec_codec->value() == CHOICE_OPUS)
1963     {
1964         rc = opus_enc_reinit(&opus_rec);
1965         if(rc != 0)
1966         {
1967             print_info(_("Warning:\nThe record Sample-/Bitrate combination is invalid"), 1);
1968             cfg.audio.samplerate = sr_list[old_sr];
1969             opus_stream.samplerate = sr_list[old_sr];
1970             opus_rec.samplerate = sr_list[old_sr];
1971             fl_g->choice_cfg_samplerate->value(old_sr);
1972             fl_g->choice_cfg_samplerate->redraw();
1973             opus_enc_reinit(&opus_stream);
1974             opus_enc_reinit(&opus_rec);
1975             print_info(_("The previous values have been set"), 1);
1976             return;
1977         }
1978     }
1979 
1980 #ifdef HAVE_LIBFDK_AAC
1981     if(fl_g->choice_rec_codec->value() == CHOICE_AAC)
1982     {
1983         rc = aac_enc_reinit(&aac_rec);
1984         if(rc != 0)
1985         {
1986             print_info(_("Warning:\nThe record Sample-/Bitrate combination is invalid"), 1);
1987             cfg.audio.samplerate = sr_list[old_sr];
1988             aac_stream.samplerate = sr_list[old_sr];
1989             aac_rec.samplerate = sr_list[old_sr];
1990             fl_g->choice_cfg_samplerate->value(old_sr);
1991             fl_g->choice_cfg_samplerate->redraw();
1992             aac_enc_reinit(&aac_stream);
1993             aac_enc_reinit(&aac_rec);
1994             print_info(_("The previous values have been set"), 1);
1995             return;
1996         }
1997     }
1998 #endif
1999     if(fl_g->choice_rec_codec->value() == CHOICE_FLAC)
2000     {
2001         rc = flac_enc_reinit(&flac_rec);
2002         if(rc != 0)
2003         {
2004             print_info(_("Warning:\nThe record Sample-/Bitrate combination is invalid"), 1);
2005             cfg.audio.samplerate = sr_list[old_sr];
2006             flac_rec.samplerate = sr_list[old_sr];
2007             fl_g->choice_cfg_samplerate->value(old_sr);
2008             fl_g->choice_cfg_samplerate->redraw();
2009             flac_enc_reinit(&flac_rec);
2010             print_info(_("The previous values have been set"), 1);
2011             return;
2012         }
2013     }
2014 
2015 
2016     //The buffer size is dependand on the samplerate
2017     input_cfg_buffer_cb(0);
2018 
2019 
2020     snprintf(text_buf, sizeof(text_buf), _("Samplerate set to: %dHz"), cfg.audio.samplerate);
2021     print_info(text_buf, 0);
2022 
2023 
2024     //reinit portaudio
2025     snd_reinit();
2026 }
2027 
choice_cfg_channel_stereo_cb(void)2028 void choice_cfg_channel_stereo_cb(void)
2029 {
2030     cfg.audio.channel = 2;
2031 
2032     // Reinit streaming codecs
2033     lame_stream.channel = 2;
2034     vorbis_stream.channel = 2;
2035     opus_stream.channel = 2;
2036 #ifdef HAVE_LIBFDK_AAC
2037     aac_stream.channel = 2;
2038 #endif
2039     flac_stream.channel = 2;
2040 
2041 
2042     if(fl_g->choice_cfg_codec->value() == CHOICE_MP3)
2043         lame_enc_reinit(&lame_stream);
2044     if(fl_g->choice_cfg_codec->value() == CHOICE_OGG)
2045         vorbis_enc_reinit(&vorbis_stream);
2046     if(fl_g->choice_cfg_codec->value() == CHOICE_OPUS)
2047         opus_enc_reinit(&opus_stream);
2048 #ifdef HAVE_LIBFDK_AAC
2049     if(fl_g->choice_cfg_codec->value() == CHOICE_AAC)
2050         aac_enc_reinit(&aac_stream);
2051 #endif
2052     if(fl_g->choice_cfg_codec->value() == CHOICE_FLAC)
2053         flac_enc_reinit(&flac_stream);
2054 
2055 
2056     // Reinit recording codecs
2057     lame_rec.channel = 2;
2058     vorbis_rec.channel = 2;
2059     opus_rec.channel = 2;
2060 #ifdef HAVE_LIBFDK_AAC
2061     aac_rec.channel = 2;
2062 #endif
2063     flac_rec.channel = 2;
2064 
2065     if(fl_g->choice_rec_codec->value() == CHOICE_MP3)
2066         lame_enc_reinit(&lame_rec);
2067     if(fl_g->choice_rec_codec->value() == CHOICE_OGG)
2068         vorbis_enc_reinit(&vorbis_rec);
2069     if(fl_g->choice_rec_codec->value() == CHOICE_OPUS)
2070         opus_enc_reinit(&opus_rec);
2071 #ifdef HAVE_LIBFDK_AAC
2072     if(fl_g->choice_rec_codec->value() == CHOICE_AAC)
2073         aac_enc_reinit(&aac_rec);
2074 #endif
2075     if(fl_g->choice_rec_codec->value() == CHOICE_FLAC)
2076         flac_enc_reinit(&flac_rec);
2077 
2078     snd_reinit();
2079 
2080     print_info(_("Channels set to: stereo"), 0);
2081 }
2082 
choice_cfg_channel_mono_cb(void)2083 void choice_cfg_channel_mono_cb(void)
2084 {
2085     cfg.audio.channel = 1;
2086 
2087     // Reinit streaming codecs
2088     lame_stream.channel = 1;
2089     vorbis_stream.channel = 1;
2090     opus_stream.channel = 1;
2091 #ifdef HAVE_LIBFDK_AAC
2092     aac_stream.channel = 1;
2093 #endif
2094     flac_stream.channel = 1;
2095 
2096     if(fl_g->choice_cfg_codec->value() == CHOICE_MP3)
2097         lame_enc_reinit(&lame_stream);
2098     if(fl_g->choice_cfg_codec->value() == CHOICE_OGG)
2099         vorbis_enc_reinit(&vorbis_stream);
2100     if(fl_g->choice_cfg_codec->value() == CHOICE_OPUS)
2101         opus_enc_reinit(&opus_stream);
2102 #ifdef HAVE_LIBFDK_AAC
2103     if(fl_g->choice_cfg_codec->value() == CHOICE_AAC)
2104         aac_enc_reinit(&aac_stream);
2105 #endif
2106     if(fl_g->choice_cfg_codec->value() == CHOICE_FLAC)
2107         flac_enc_reinit(&flac_stream);
2108 
2109     // Reinit recording codecs
2110     lame_rec.channel = 1;
2111     vorbis_rec.channel = 1;
2112     opus_rec.channel = 1;
2113 #ifdef HAVE_LIBFDK_AAC
2114     aac_rec.channel = 1;
2115 #endif
2116     flac_rec.channel = 1;
2117 
2118     if(fl_g->choice_rec_codec->value() == CHOICE_MP3)
2119         lame_enc_reinit(&lame_rec);
2120     if(fl_g->choice_rec_codec->value() == CHOICE_OGG)
2121         vorbis_enc_reinit(&vorbis_rec);
2122     if(fl_g->choice_rec_codec->value() == CHOICE_OPUS)
2123         opus_enc_reinit(&opus_rec);
2124 #ifdef HAVE_LIBFDK_AAC
2125     if(fl_g->choice_rec_codec->value() == CHOICE_AAC)
2126         aac_enc_reinit(&aac_rec);
2127 #endif
2128     if(fl_g->choice_rec_codec->value() == CHOICE_FLAC)
2129         flac_enc_reinit(&flac_rec);
2130 
2131     //Reinit PortAudio
2132     snd_reinit();
2133 
2134     print_info(_("Channels set to: mono"), 0);
2135 }
2136 
button_add_srv_cancel_cb(void)2137 void button_add_srv_cancel_cb(void)
2138 {
2139     fl_g->input_add_srv_name->value("");
2140     fl_g->input_add_srv_addr->value("");
2141     fl_g->input_add_srv_port->value("");
2142     fl_g->input_add_srv_pwd->value("");
2143     fl_g->input_add_srv_mount->value("");
2144     fl_g->input_add_srv_usr->value("");
2145     fl_g->check_add_srv_tls->value(0);
2146 
2147     fl_g->window_add_srv->hide();
2148 }
2149 
button_add_icy_add_cb(void)2150 void button_add_icy_add_cb(void)
2151 {
2152     int i;
2153     //error checking
2154     if(strlen(fl_g->input_add_icy_name->value()) == 0)
2155     {
2156         fl_alert(_("No name specified"));
2157         return;
2158     }
2159 
2160     if(cfg.main.icy_ent != NULL)
2161     {
2162         if(strlen(fl_g->input_add_icy_name->value()) + strlen(cfg.main.icy_ent) > 1000)
2163         {
2164             fl_alert(_("The number of characters of all your icy names exeeds 1000\n"
2165                     "Please reduce the number of characters of each icy name"));
2166             return;
2167         }
2168     }
2169     if(strpbrk(fl_g->input_add_icy_name->value(), ";\\/\n\r") != NULL)
2170     {
2171         fl_alert(_("No newline characters and ;/\\ are allowed in the name field"));
2172         return;
2173     }
2174 
2175 
2176     //check if the name already exists
2177     for(i = 0; i < cfg.main.num_of_icy; i++)
2178     {
2179         if(!strcmp(fl_g->input_add_icy_name->value(), cfg.icy[i]->name))
2180         {
2181             fl_alert(_("Server name already exist!"));
2182             return;
2183         }
2184     }
2185 
2186     i = cfg.main.num_of_icy;
2187     cfg.main.num_of_icy++;
2188 
2189     cfg.icy = (icy_t**)realloc(cfg.icy, cfg.main.num_of_icy * sizeof(icy_t*));
2190     cfg.icy[i] = (icy_t*)malloc(sizeof(icy_t));
2191 
2192     cfg.icy[i]->name = (char*)malloc(strlen(fl_g->input_add_icy_name->value())+1 );
2193     strcpy(cfg.icy[i]->name, fl_g->input_add_icy_name->value());
2194 
2195     cfg.icy[i]->desc = (char*)malloc(strlen(fl_g->input_add_icy_desc->value())+1 );
2196     strcpy(cfg.icy[i]->desc, fl_g->input_add_icy_desc->value());
2197 
2198     cfg.icy[i]->url = (char*)malloc(strlen(fl_g->input_add_icy_url->value())+1 );
2199     strcpy(cfg.icy[i]->url, fl_g->input_add_icy_url->value());
2200 
2201     cfg.icy[i]->genre = (char*)malloc(strlen(fl_g->input_add_icy_genre->value())+1 );
2202     strcpy(cfg.icy[i]->genre, fl_g->input_add_icy_genre->value());
2203 
2204     cfg.icy[i]->irc = (char*)malloc(strlen(fl_g->input_add_icy_irc->value())+1 );
2205     strcpy(cfg.icy[i]->irc, fl_g->input_add_icy_irc->value());
2206 
2207     cfg.icy[i]->icq = (char*)malloc(strlen(fl_g->input_add_icy_icq->value())+1 );
2208     strcpy(cfg.icy[i]->icq, fl_g->input_add_icy_icq->value());
2209 
2210     cfg.icy[i]->aim = (char*)malloc(strlen(fl_g->input_add_icy_aim->value())+1 );
2211     strcpy(cfg.icy[i]->aim, fl_g->input_add_icy_aim->value());
2212 
2213     cfg.icy[i]->pub = (char*)malloc(2 * sizeof(char));
2214     snprintf(cfg.icy[i]->pub, 2, "%d", fl_g->check_add_icy_pub->value());
2215 
2216     if(cfg.main.num_of_icy > 1)
2217     {
2218         cfg.main.icy_ent = (char*)realloc(cfg.main.icy_ent,
2219                                          strlen(cfg.main.icy_ent) +
2220                                          strlen(cfg.icy[i]->name) +2);
2221         sprintf(cfg.main.icy_ent, "%s;%s", cfg.main.icy_ent, cfg.icy[i]->name);
2222     }
2223     else
2224     {
2225         cfg.main.icy_ent = (char*)malloc(strlen(cfg.icy[i]->name) +1);
2226         sprintf(cfg.main.icy_ent, "%s", cfg.icy[i]->name);
2227     }
2228 
2229     cfg.main.icy = (char*)realloc(cfg.main.icy, strlen(cfg.icy[i]->name)+1);
2230 
2231     strcpy(cfg.main.icy, cfg.icy[i]->name);
2232 
2233     fl_g->input_add_icy_name->value("");
2234     fl_g->input_add_icy_desc->value("");
2235     fl_g->input_add_icy_url->value("");
2236     fl_g->input_add_icy_genre->value("");
2237     fl_g->input_add_icy_irc->value("");
2238     fl_g->input_add_icy_icq->value("");
2239     fl_g->input_add_icy_aim->value("");
2240     fl_g->check_add_icy_pub->value(0);
2241 
2242     fl_g->window_add_icy->hide();
2243 
2244     fl_g->choice_cfg_act_icy->add(cfg.icy[i]->name);
2245     fl_g->choice_cfg_act_icy->redraw();
2246 
2247     fl_g->button_cfg_edit_icy->activate();
2248     fl_g->button_cfg_del_icy->activate();
2249 
2250     fl_g->choice_cfg_act_icy->activate();
2251 
2252     // make added icy data the active icy entry
2253     fl_g->choice_cfg_act_icy->value(i);
2254     choice_cfg_act_icy_cb();
2255 }
2256 
button_add_icy_cancel_cb(void)2257 void button_add_icy_cancel_cb(void)
2258 {
2259     fl_g->input_add_icy_name->value("");
2260     fl_g->input_add_icy_desc->value("");
2261     fl_g->input_add_icy_url->value("");
2262     fl_g->input_add_icy_genre->value("");
2263     fl_g->input_add_icy_irc->value("");
2264     fl_g->input_add_icy_icq->value("");
2265     fl_g->input_add_icy_aim->value("");
2266     fl_g->check_add_icy_pub->value(0);
2267     fl_g->window_add_icy->hide();
2268 }
2269 
button_cfg_edit_icy_cb(void)2270 void button_cfg_edit_icy_cb(void)
2271 {
2272     if(cfg.main.num_of_icy < 1)
2273         return;
2274 
2275     int icy = fl_g->choice_cfg_act_icy->value();
2276 
2277     fl_g->window_add_icy->label(_("Edit Server Infos"));
2278 
2279     fl_g->button_add_icy_add->hide();
2280     fl_g->button_add_icy_save->show();
2281 
2282     fl_g->input_add_icy_name->value(cfg.icy[icy]->name);
2283     fl_g->input_add_icy_desc->value(cfg.icy[icy]->desc);
2284     fl_g->input_add_icy_genre->value(cfg.icy[icy]->genre);
2285     fl_g->input_add_icy_url->value(cfg.icy[icy]->url);
2286     fl_g->input_add_icy_irc->value(cfg.icy[icy]->irc);
2287     fl_g->input_add_icy_icq->value(cfg.icy[icy]->icq);
2288     fl_g->input_add_icy_aim->value(cfg.icy[icy]->aim);
2289 
2290     if(!strcmp(cfg.icy[icy]->pub, "1"))
2291         fl_g->check_add_icy_pub->value(1);
2292     else
2293         fl_g->check_add_icy_pub->value(0);
2294 
2295     fl_g->window_add_icy->position(fl_g->window_cfg->x(), fl_g->window_cfg->y());
2296 
2297     //give the "name" input field the input focus
2298     fl_g->input_add_icy_name->take_focus();
2299     fl_g->window_add_icy->show();
2300 }
2301 
choice_cfg_dev_cb(void)2302 void choice_cfg_dev_cb(void)
2303 {
2304     cfg.audio.dev_num = fl_g->choice_cfg_dev->value();
2305     update_samplerates();
2306     snd_reinit();
2307     update_channel_lists();
2308 }
2309 
choice_cfg_left_channel_cb(void)2310 void choice_cfg_left_channel_cb(void)
2311 {
2312     cfg.audio.left_ch = fl_g->choice_cfg_left_channel->value()+1;
2313 }
2314 
2315 
choice_cfg_right_channel_cb(void)2316 void choice_cfg_right_channel_cb(void)
2317 {
2318     cfg.audio.right_ch = fl_g->choice_cfg_right_channel->value()+1;
2319 }
2320 
choice_cfg_codec_mp3_cb(void)2321 void choice_cfg_codec_mp3_cb(void)
2322 {
2323     if(lame_enc_reinit(&lame_stream) != 0)
2324     {
2325         print_info(_("MP3 encoder doesn't support current\n"
2326                    "Sample-/Bitrate combination"), 1);
2327 
2328         if(!strcmp(cfg.audio.codec, "ogg"))
2329             fl_g->choice_cfg_codec->value(CHOICE_OGG);
2330         else if (!strcmp(cfg.audio.codec, "opus"))
2331             fl_g->choice_cfg_codec->value(CHOICE_OPUS);
2332         else if (!strcmp(cfg.audio.codec, "aac"))
2333             fl_g->choice_cfg_codec->value(CHOICE_AAC);
2334         else if (!strcmp(cfg.audio.codec, "flac"))
2335             fl_g->choice_cfg_codec->value(CHOICE_FLAC);
2336 
2337         return;
2338     }
2339     strcpy(cfg.audio.codec, "mp3");
2340     print_info(_("Stream codec set to mp3"), 0);
2341     fl_g->choice_cfg_bitrate->activate();
2342     fl_g->choice_cfg_bitrate->show();
2343 }
2344 
choice_cfg_codec_ogg_cb(void)2345 void choice_cfg_codec_ogg_cb(void)
2346 {
2347     if(vorbis_enc_reinit(&vorbis_stream) != 0)
2348     {
2349         print_info(_("OGG Vorbis encoder doesn't support current\n"
2350                    "Sample-/Bitrate combination"), 1);
2351 
2352         if(!strcmp(cfg.audio.codec, "mp3"))
2353             fl_g->choice_cfg_codec->value(CHOICE_MP3);
2354         else if (!strcmp(cfg.audio.codec, "opus"))
2355             fl_g->choice_cfg_codec->value(CHOICE_OPUS);
2356         else if (!strcmp(cfg.audio.codec, "aac"))
2357             fl_g->choice_cfg_codec->value(CHOICE_AAC);
2358         else if (!strcmp(cfg.audio.codec, "flac"))
2359             fl_g->choice_cfg_codec->value(CHOICE_FLAC);
2360 
2361         return;
2362     }
2363     strcpy(cfg.audio.codec, "ogg");
2364     print_info(_("Stream codec set to ogg/vorbis"), 0);
2365     fl_g->choice_cfg_bitrate->activate();
2366     fl_g->choice_cfg_bitrate->show();
2367 }
2368 
choice_cfg_codec_opus_cb(void)2369 void choice_cfg_codec_opus_cb(void)
2370 {
2371     if(opus_enc_reinit(&opus_stream) != 0)
2372     {
2373         print_info(_("Opus encoder doesn't support current\n"
2374                    "Sample-/Bitrate combination"), 1);
2375 
2376         if(!strcmp(cfg.audio.codec, "mp3"))
2377             fl_g->choice_cfg_codec->value(CHOICE_MP3);
2378         else if (!strcmp(cfg.audio.codec, "ogg"))
2379             fl_g->choice_cfg_codec->value(CHOICE_OGG);
2380         else if (!strcmp(cfg.audio.codec, "aac"))
2381             fl_g->choice_cfg_codec->value(CHOICE_AAC);
2382         else if (!strcmp(cfg.audio.codec, "flac"))
2383             fl_g->choice_cfg_codec->value(CHOICE_FLAC);
2384 
2385         return;
2386     }
2387 
2388     print_info(_("Stream codec set to opus"), 0);
2389     strcpy(cfg.audio.codec, "opus");
2390     fl_g->choice_cfg_bitrate->activate();
2391     fl_g->choice_cfg_bitrate->show();
2392 }
2393 
choice_cfg_codec_aac_cb(void)2394 void choice_cfg_codec_aac_cb(void)
2395 {
2396 #ifdef HAVE_LIBFDK_AAC
2397     if (g_aac_lib_available == 0)
2398     {
2399         fl_alert(_("Could not find aac library.\nPlease follow the instructions in the manual for adding aac support."));
2400         if(!strcmp(cfg.audio.codec, "ogg"))
2401             fl_g->choice_cfg_codec->value(CHOICE_OGG);
2402         else if (!strcmp(cfg.audio.codec, "opus"))
2403             fl_g->choice_cfg_codec->value(CHOICE_OPUS);
2404         else if (!strcmp(cfg.audio.codec, "mp3"))
2405             fl_g->choice_cfg_codec->value(CHOICE_MP3);
2406         else if (!strcmp(cfg.audio.codec, "flac"))
2407             fl_g->choice_cfg_codec->value(CHOICE_FLAC);
2408 
2409         return;
2410     }
2411     if(aac_enc_reinit(&aac_stream) != 0)
2412     {
2413         print_info(_("AAC encoder doesn't support current\n"
2414                    "Sample-/Bitrate combination"), 1);
2415 
2416         if(!strcmp(cfg.audio.codec, "ogg"))
2417             fl_g->choice_cfg_codec->value(CHOICE_OGG);
2418         else if (!strcmp(cfg.audio.codec, "opus"))
2419             fl_g->choice_cfg_codec->value(CHOICE_OPUS);
2420         else if (!strcmp(cfg.audio.codec, "mp3"))
2421             fl_g->choice_cfg_codec->value(CHOICE_MP3);
2422         else if (!strcmp(cfg.audio.codec, "flac"))
2423             fl_g->choice_cfg_codec->value(CHOICE_FLAC);
2424 
2425         return;
2426     }
2427     strcpy(cfg.audio.codec, "aac");
2428     print_info(_("Stream codec set to aac"), 0);
2429     fl_g->choice_cfg_bitrate->activate();
2430     fl_g->choice_cfg_bitrate->show();
2431 
2432 
2433 #endif
2434 }
2435 
choice_cfg_codec_flac_cb(void)2436 void choice_cfg_codec_flac_cb(void)
2437 {
2438     if(flac_enc_reinit(&flac_stream) != 0)
2439     {
2440         print_info(_("ERROR: While initializing flac settings"), 1);
2441 
2442         if(!strcmp(cfg.audio.codec, "mp3"))
2443             fl_g->choice_rec_codec->value(CHOICE_MP3);
2444         else if(!strcmp(cfg.audio.codec, "ogg"))
2445             fl_g->choice_rec_codec->value(CHOICE_OGG);
2446         else if(!strcmp(cfg.audio.codec, "opus"))
2447             fl_g->choice_rec_codec->value(CHOICE_OPUS);
2448         else if(!strcmp(cfg.audio.codec, "aac"))
2449             fl_g->choice_rec_codec->value(CHOICE_AAC);
2450 
2451         return;
2452     }
2453     strcpy(cfg.audio.codec, "flac");
2454     print_info(_("Stream codec set to flac"), 0);
2455 
2456     fl_g->choice_cfg_bitrate->hide();
2457     fl_g->window_cfg->redraw();
2458 }
2459 
choice_rec_codec_mp3_cb(void)2460 void choice_rec_codec_mp3_cb(void)
2461 {
2462     if(lame_enc_reinit(&lame_rec) != 0)
2463     {
2464         print_info(_("MP3 encoder doesn't support current\n"
2465                    "Sample-/Bitrate combination"), 1);
2466 
2467         //fall back to old rec codec
2468         if(!strcmp(cfg.rec.codec, "ogg"))
2469             fl_g->choice_rec_codec->value(CHOICE_OGG);
2470         else if(!strcmp(cfg.rec.codec, "wav"))
2471             fl_g->choice_rec_codec->value(CHOICE_WAV);
2472         else if(!strcmp(cfg.rec.codec, "opus"))
2473             fl_g->choice_rec_codec->value(CHOICE_OPUS);
2474         else if(!strcmp(cfg.rec.codec, "aac"))
2475             fl_g->choice_rec_codec->value(CHOICE_AAC);
2476         else if(!strcmp(cfg.rec.codec, "flac"))
2477             fl_g->choice_rec_codec->value(CHOICE_FLAC);
2478 
2479         return;
2480     }
2481     strcpy(cfg.rec.codec, "mp3");
2482 
2483     //check if the extension of the filename matches
2484     //the current selected codec
2485     test_file_extension();
2486 
2487     print_info(_("Record codec set to mp3"), 0);
2488     fl_g->choice_rec_bitrate->activate();
2489     fl_g->choice_rec_bitrate->show();
2490 }
2491 
choice_rec_codec_ogg_cb(void)2492 void choice_rec_codec_ogg_cb(void)
2493 {
2494     if(vorbis_enc_reinit(&vorbis_rec) != 0)
2495     {
2496         print_info(_("OGG Vorbis encoder doesn't support current\n"
2497                    "Sample-/Bitrate combination"), 1);
2498 
2499         if(!strcmp(cfg.rec.codec, "mp3"))
2500             fl_g->choice_rec_codec->value(CHOICE_MP3);
2501         else if(!strcmp(cfg.rec.codec, "wav"))
2502             fl_g->choice_rec_codec->value(CHOICE_WAV);
2503         else if(!strcmp(cfg.rec.codec, "opus"))
2504             fl_g->choice_rec_codec->value(CHOICE_OPUS);
2505         else if(!strcmp(cfg.rec.codec, "aac"))
2506             fl_g->choice_rec_codec->value(CHOICE_AAC);
2507         else if(!strcmp(cfg.rec.codec, "flac"))
2508             fl_g->choice_rec_codec->value(CHOICE_FLAC);
2509 
2510         return;
2511     }
2512     strcpy(cfg.rec.codec, "ogg");
2513 
2514     //check if the extension of the filename matches
2515     //the current selected codec
2516     test_file_extension();
2517 
2518     print_info(_("Record codec set to ogg/vorbis"), 0);
2519     fl_g->choice_rec_bitrate->activate();
2520     fl_g->choice_rec_bitrate->show();
2521 }
2522 
choice_rec_codec_opus_cb(void)2523 void choice_rec_codec_opus_cb(void)
2524 {
2525    if(opus_enc_reinit(&opus_rec) != 0)
2526     {
2527         print_info(_("Opus encoder doesn't support current\n"
2528                    "Sample-/Bitrate combination"), 1);
2529 
2530         if(!strcmp(cfg.rec.codec, "mp3"))
2531             fl_g->choice_rec_codec->value(CHOICE_MP3);
2532         else if(!strcmp(cfg.rec.codec, "wav"))
2533             fl_g->choice_rec_codec->value(CHOICE_WAV);
2534         else if(!strcmp(cfg.rec.codec, "ogg"))
2535             fl_g->choice_rec_codec->value(CHOICE_OGG);
2536         else if(!strcmp(cfg.rec.codec, "aac"))
2537             fl_g->choice_rec_codec->value(CHOICE_AAC);
2538         else if(!strcmp(cfg.rec.codec, "flac"))
2539             fl_g->choice_rec_codec->value(CHOICE_FLAC);
2540 
2541 
2542         return;
2543     }
2544     strcpy(cfg.rec.codec, "opus");
2545 
2546     //check if the extension of the filename matches
2547     //the current selected codec
2548     test_file_extension();
2549 
2550     print_info(_("Record codec set to opus"), 0);
2551     fl_g->choice_rec_bitrate->activate();
2552     fl_g->choice_rec_bitrate->show();
2553 }
2554 
choice_rec_codec_aac_cb(void)2555 void choice_rec_codec_aac_cb(void)
2556 {
2557 #ifdef HAVE_LIBFDK_AAC
2558     if (g_aac_lib_available == 0)
2559     {
2560         fl_alert(_("Could not find aac library.\nPlease follow the instructions in the manual for adding aac support."));
2561         if(!strcmp(cfg.audio.codec, "ogg"))
2562             fl_g->choice_cfg_codec->value(CHOICE_OGG);
2563         else if (!strcmp(cfg.audio.codec, "opus"))
2564             fl_g->choice_cfg_codec->value(CHOICE_OPUS);
2565         else if (!strcmp(cfg.audio.codec, "mp3"))
2566             fl_g->choice_cfg_codec->value(CHOICE_MP3);
2567         else if (!strcmp(cfg.audio.codec, "flac"))
2568             fl_g->choice_cfg_codec->value(CHOICE_FLAC);
2569 
2570         return;
2571     }
2572     if(aac_enc_reinit(&aac_rec) != 0)
2573     {
2574         print_info(_("AAC encoder doesn't support current\n"
2575                    "Sample-/Bitrate combination"), 1);
2576 
2577         //fall back to old rec codec
2578         if(!strcmp(cfg.rec.codec, "ogg"))
2579             fl_g->choice_rec_codec->value(CHOICE_OGG);
2580         else if(!strcmp(cfg.rec.codec, "wav"))
2581             fl_g->choice_rec_codec->value(CHOICE_WAV);
2582         else if(!strcmp(cfg.rec.codec, "opus"))
2583             fl_g->choice_rec_codec->value(CHOICE_OPUS);
2584         else if(!strcmp(cfg.rec.codec, "flac"))
2585             fl_g->choice_rec_codec->value(CHOICE_FLAC);
2586         else if(!strcmp(cfg.rec.codec, "mp3"))
2587             fl_g->choice_rec_codec->value(CHOICE_MP3);
2588 
2589         return;
2590     }
2591     strcpy(cfg.rec.codec, "aac");
2592 
2593     //check if the extension of the filename matches
2594     //the current selected codec
2595     test_file_extension();
2596 
2597     print_info(_("Record codec set to aac"), 0);
2598     fl_g->choice_rec_bitrate->activate();
2599     fl_g->choice_rec_bitrate->show();
2600 
2601 
2602 
2603 #endif
2604 }
2605 
choice_rec_codec_flac_cb(void)2606 void choice_rec_codec_flac_cb(void)
2607 {
2608     if(flac_enc_reinit(&flac_rec) != 0)
2609     {
2610         print_info(_("ERROR: While initializing flac settings"), 1);
2611 
2612         if(!strcmp(cfg.rec.codec, "mp3"))
2613             fl_g->choice_rec_codec->value(CHOICE_MP3);
2614         else if(!strcmp(cfg.rec.codec, "ogg"))
2615             fl_g->choice_rec_codec->value(CHOICE_OGG);
2616         else if(!strcmp(cfg.rec.codec, "opus"))
2617             fl_g->choice_rec_codec->value(CHOICE_OPUS);
2618         else if(!strcmp(cfg.rec.codec, "wav"))
2619             fl_g->choice_rec_codec->value(CHOICE_WAV);
2620         else if(!strcmp(cfg.rec.codec, "aac"))
2621             fl_g->choice_rec_codec->value(CHOICE_AAC);
2622 
2623         return;
2624     }
2625     strcpy(cfg.rec.codec, "flac");
2626 
2627     //check if the extension of the filename matches
2628     //the current selected codec
2629     test_file_extension();
2630 
2631     print_info(_("Record codec set to flac"), 0);
2632     fl_g->choice_rec_bitrate->hide();
2633     fl_g->window_cfg->redraw();
2634 }
2635 
choice_rec_codec_wav_cb(void)2636 void choice_rec_codec_wav_cb(void)
2637 {
2638     fl_g->choice_rec_bitrate->hide();
2639     fl_g->window_cfg->redraw();
2640 
2641     strcpy(cfg.rec.codec, "wav");
2642 
2643     //check if the extension of the filename matches
2644     //the current selected codec
2645     test_file_extension();
2646 
2647     print_info(_("Record codec set to wav"), 0);
2648 
2649 }
2650 
input_tls_cert_file_cb(void)2651 void input_tls_cert_file_cb(void)
2652 {
2653     cfg.tls.cert_file = (char*)realloc(cfg.tls.cert_file,
2654                         strlen(fl_g->input_tls_cert_file->value())+1);
2655 
2656       strcpy(cfg.tls.cert_file, fl_g->input_tls_cert_file->value());
2657       fl_g->input_tls_cert_file->tooltip(cfg.tls.cert_file);
2658 }
2659 
input_tls_cert_dir_cb(void)2660 void input_tls_cert_dir_cb(void)
2661 {
2662     int len = strlen(fl_g->input_tls_cert_dir->value());
2663 
2664     cfg.tls.cert_dir = (char*)realloc(cfg.tls.cert_dir, len +2);
2665 
2666     strcpy(cfg.tls.cert_dir, fl_g->input_tls_cert_dir->value());
2667 
2668 #ifdef WIN32    //Replace all "Windows slashes" with "unix slashes"
2669     strrpl(&cfg.tls.cert_dir, (char*)"\\", (char*)"/", MODE_ALL);
2670 #endif
2671 
2672     //Append an '/' if there isn't one
2673     if ( (len > 0) && (cfg.tls.cert_dir[len-1] != '/'))
2674         strcat(cfg.tls.cert_dir, "/");
2675 
2676     fl_g->input_tls_cert_dir->value(cfg.tls.cert_dir);
2677     fl_g->input_tls_cert_dir->tooltip(cfg.tls.cert_dir);
2678 }
2679 
button_tls_browse_file_cb(void)2680 void button_tls_browse_file_cb(void)
2681 {
2682     Fl_My_Native_File_Chooser nfc;
2683     nfc.title(_("Select certificate file..."));
2684     nfc.type(Fl_My_Native_File_Chooser::BROWSE_FILE);
2685 
2686     switch(nfc.show())
2687     {
2688         case -1: fl_alert(_("ERROR: %s"), nfc.errmsg());
2689             break;
2690         case  1:
2691             break; //cancel pressed
2692         default:
2693             fl_g->input_tls_cert_file->value(nfc.filename());
2694             input_tls_cert_file_cb();
2695     }
2696 }
2697 
button_tls_browse_dir_cb(void)2698 void button_tls_browse_dir_cb(void)
2699 {
2700     Fl_My_Native_File_Chooser nfc;
2701     nfc.title(_("Select certificate directory..."));
2702     nfc.type(Fl_My_Native_File_Chooser::BROWSE_DIRECTORY);
2703     nfc.options(Fl_My_Native_File_Chooser::NEW_FOLDER);
2704 
2705     nfc.directory(fl_g->input_tls_cert_dir->value());
2706 
2707     switch(nfc.show())
2708     {
2709         case -1:
2710             fl_alert(_("ERROR: %s"), nfc.errmsg()); //error
2711             break;
2712         case  1:
2713             break; //cancel pressed
2714         default:
2715             fl_g->input_tls_cert_dir->value(nfc.filename());
2716             input_tls_cert_dir_cb();
2717             break;
2718     }
2719 }
2720 
ILM216_cb(void)2721 void ILM216_cb(void)
2722 {
2723     if(Fl::event_button() == 1) //left mouse button
2724     {
2725         //change the display mode only when connected or recording
2726         //this will prevent confusing the user
2727         if(!connected && !recording)
2728             return;
2729 
2730         switch(display_info)
2731         {
2732             case STREAM_TIME:
2733                 if(recording)
2734                     display_info = REC_TIME;
2735                 else
2736                     display_info = SENT_DATA;
2737                 break;
2738 
2739             case REC_TIME:
2740                 if(connected)
2741                     display_info = SENT_DATA;
2742                 else
2743                     display_info = REC_DATA;
2744                 break;
2745 
2746             case SENT_DATA:
2747                 if(recording)
2748                     display_info = REC_DATA;
2749                 else
2750                     display_info = STREAM_TIME;
2751                 break;
2752 
2753             case REC_DATA:
2754                 if(connected)
2755                     display_info = STREAM_TIME;
2756                 else
2757                     display_info = REC_TIME;
2758         }
2759     }
2760    /* if(Fl::event_button() == 3) //right mouse button
2761     {
2762         uchar r, g, b;
2763 
2764         Fl_Color bg, txt;
2765         bg  = (Fl_Color)cfg.main.bg_color;
2766         txt = (Fl_Color)cfg.main.txt_color;
2767 
2768         //Set the r g b values the color_chooser should start with
2769         r = (bg & 0xFF000000) >> 24;
2770         g = (bg & 0x00FF0000) >> 16;
2771         b = (bg & 0x0000FF00) >>  8;
2772 
2773         fl_color_chooser((const char*)"select background color", r, g, b);
2774 
2775         //The color_chooser changes the r, g, b, values to selected color
2776         cfg.main.bg_color = fl_rgb_color(r, g, b);
2777 
2778         fl_g->lcd->redraw();
2779 
2780         r = (txt & 0xFF000000) >> 24;
2781         g = (txt & 0x00FF0000) >> 16;
2782         b = (txt & 0x0000FF00) >>  8;
2783 
2784         fl_color_chooser((const char*)"select text color", r, g, b);
2785         cfg.main.txt_color = fl_rgb_color(r, g, b);
2786 
2787         fl_g->lcd->redraw();
2788 
2789 
2790     }*/
2791 }
2792 
button_rec_browse_cb(void)2793 void button_rec_browse_cb(void)
2794 {
2795     Fl_My_Native_File_Chooser nfc;
2796     nfc.title(_("Record to..."));
2797     nfc.type(Fl_My_Native_File_Chooser::BROWSE_DIRECTORY);
2798     nfc.options(Fl_My_Native_File_Chooser::NEW_FOLDER);
2799 
2800 
2801     nfc.directory(fl_g->input_rec_folder->value());
2802 
2803     switch(nfc.show())
2804     {
2805         case -1: fl_alert(_("ERROR: %s"), nfc.errmsg()); //error
2806                  break;
2807         case  1: break; //cancel
2808         default:
2809                  fl_g->input_rec_folder->value(nfc.filename());
2810                  input_rec_folder_cb();
2811 
2812                  break;
2813     }
2814 }
button_rec_split_now_cb(void)2815 void button_rec_split_now_cb(void)
2816 {
2817     int mode = 0;
2818     split_recording_timer(&mode);
2819 }
2820 
input_rec_filename_cb(void)2821 void input_rec_filename_cb(void)
2822 {
2823     char *tooltip;
2824 
2825     cfg.rec.filename = (char*)realloc(cfg.rec.filename,
2826                        strlen(fl_g->input_rec_filename->value())+1);
2827 
2828     strcpy(cfg.rec.filename, fl_g->input_rec_filename->value());
2829 
2830     //check if the extension of the filename matches
2831     //the current selected codec
2832     test_file_extension();
2833 
2834     tooltip = strdup(cfg.rec.filename);
2835 
2836     expand_string(&tooltip);
2837 
2838     fl_g->input_rec_filename->copy_tooltip(tooltip);
2839 
2840 
2841     free(tooltip);
2842 }
2843 
input_rec_folder_cb(void)2844 void input_rec_folder_cb(void)
2845 {
2846     int len = strlen(fl_g->input_rec_folder->value());
2847 
2848     cfg.rec.folder = (char*)realloc(cfg.rec.folder, len +2);
2849 
2850     strcpy(cfg.rec.folder, fl_g->input_rec_folder->value());
2851 
2852 #ifdef WIN32    //Replace all "Windows slashes" with "unix slashes"
2853     char *p;
2854     p = cfg.rec.folder;
2855     while(*p != '\0')
2856     {
2857         if(*p == '\\')
2858             *p = '/';
2859         p++;
2860     }
2861 #endif
2862 
2863     //Append an '/' if there isn't one
2864     if(cfg.rec.folder[len-1] != '/')
2865         strcat(cfg.rec.folder, "/");
2866 
2867     fl_g->input_rec_folder->value(cfg.rec.folder);
2868     fl_g->input_rec_folder->tooltip(cfg.rec.folder);
2869 }
2870 
input_log_filename_cb(void)2871 void input_log_filename_cb(void)
2872 {
2873     cfg.main.log_file = (char*)realloc(cfg.main.log_file,
2874                        strlen(fl_g->input_log_filename->value())+1);
2875 
2876     strcpy(cfg.main.log_file, fl_g->input_log_filename->value());
2877     fl_g->input_log_filename->tooltip(cfg.main.log_file);
2878 }
2879 
button_cfg_browse_songfile_cb(void)2880 void button_cfg_browse_songfile_cb(void)
2881 {
2882     Fl_My_Native_File_Chooser nfc;
2883     nfc.title(_("Select Songfile"));
2884     nfc.type(Fl_My_Native_File_Chooser::BROWSE_FILE);
2885     switch(nfc.show())
2886     {
2887         case -1: fl_alert(_("ERROR: %s"), nfc.errmsg());
2888             break;
2889         case  1:
2890             break; //cancel
2891         default:
2892             fl_g->input_cfg_song_file->value(nfc.filename());
2893             input_cfg_song_file_cb();
2894     }
2895 }
2896 
input_cfg_song_file_cb(void)2897 void input_cfg_song_file_cb(void)
2898 {
2899     int len = strlen(fl_g->input_cfg_song_file->value());
2900 
2901     cfg.main.song_path = (char*)realloc(cfg.main.song_path, len +1);
2902 
2903     strcpy(cfg.main.song_path, fl_g->input_cfg_song_file->value());
2904 
2905 #ifdef WIN32    //Replace all "Windows slashes" with "unix slashes"
2906     char *p;
2907     p = cfg.main.song_path;
2908     while(*p != '\0')
2909     {
2910         if(*p == '\\')
2911             *p = '/';
2912         p++;
2913     }
2914 #endif
2915 
2916     fl_g->input_cfg_song_file->value(cfg.main.song_path);
2917     fl_g->input_cfg_song_file->tooltip(cfg.main.song_path);
2918 }
2919 
check_gui_attach_cb(void)2920 void check_gui_attach_cb(void)
2921 {
2922     if(fl_g->check_gui_attach->value())
2923     {
2924         cfg.gui.attach = 1;
2925         Fl::add_timeout(0.1, &cfg_win_pos_timer);
2926     }
2927     else
2928     {
2929         cfg.gui.attach = 0;
2930         Fl::remove_timeout(&cfg_win_pos_timer);
2931     }
2932 }
2933 
check_gui_ontop_cb(void)2934 void check_gui_ontop_cb(void)
2935 {
2936     if(fl_g->check_gui_ontop->value())
2937     {
2938         fl_g->window_main->stay_on_top(1);
2939         fl_g->window_cfg->stay_on_top(1);
2940         cfg.gui.ontop = 1;
2941     }
2942     else
2943     {
2944         fl_g->window_main->stay_on_top(0);
2945         fl_g->window_cfg->stay_on_top(0);
2946         cfg.gui.ontop = 0;
2947     }
2948 
2949 }
check_gui_hide_log_window_cb(void)2950 void check_gui_hide_log_window_cb(void)
2951 {
2952     if(fl_g->check_gui_hide_log_window->value())
2953         cfg.gui.hide_log_window = 1;
2954     else
2955         cfg.gui.hide_log_window = 0;
2956 }
2957 
check_gui_remember_pos_cb(void)2958 void check_gui_remember_pos_cb(void)
2959 {
2960     if(fl_g->check_gui_remember_pos->value())
2961         cfg.gui.remember_pos = 1;
2962     else
2963         cfg.gui.remember_pos = 0;
2964 }
2965 
check_gui_lcd_auto_cb(void)2966 void check_gui_lcd_auto_cb(void)
2967 {
2968     if(fl_g->check_gui_lcd_auto->value())
2969     {
2970         cfg.gui.lcd_auto = 1;
2971     }
2972     else
2973     {
2974         cfg.gui.lcd_auto = 0;
2975     }
2976 }
2977 
button_gui_bg_color_cb(void)2978 void button_gui_bg_color_cb(void)
2979 {
2980     uchar r, g, b;
2981 
2982     Fl_Color bg;
2983     bg  = (Fl_Color)cfg.main.bg_color;
2984 
2985     //Set the r g b values the color_chooser should start with
2986     r = (bg & 0xFF000000) >> 24;
2987     g = (bg & 0x00FF0000) >> 16;
2988     b = (bg & 0x0000FF00) >>  8;
2989 
2990     fl_color_chooser(_("select background color"), r, g, b);
2991 
2992     //The color_chooser changes the r, g, b, values to selected color
2993     cfg.main.bg_color = fl_rgb_color(r, g, b);
2994 
2995     fl_g->button_gui_bg_color->color(cfg.main.bg_color, fl_lighter((Fl_Color)cfg.main.bg_color));
2996     fl_g->button_gui_bg_color->redraw();
2997     fl_g->lcd->redraw();
2998 }
2999 
button_gui_text_color_cb(void)3000 void button_gui_text_color_cb(void)
3001 {
3002     uchar r, g, b;
3003 
3004     Fl_Color txt;
3005     txt = (Fl_Color)cfg.main.txt_color;
3006 
3007     //Set the r g b values the color_chooser should start with
3008     r = (txt & 0xFF000000) >> 24;
3009     g = (txt & 0x00FF0000) >> 16;
3010     b = (txt & 0x0000FF00) >>  8;
3011 
3012     fl_color_chooser(_("select text color"), r, g, b);
3013 
3014     //The color_chooser changes the r, g, b, values to selected color
3015     cfg.main.txt_color = fl_rgb_color(r, g, b);
3016 
3017     fl_g->button_gui_text_color->color(cfg.main.txt_color, fl_lighter((Fl_Color)cfg.main.txt_color));
3018     fl_g->button_gui_text_color->redraw();
3019     fl_g->lcd->redraw();
3020 }
3021 
choice_gui_language_cb(void)3022 void choice_gui_language_cb(void)
3023 {
3024     switch (fl_g->choice_gui_language->value()) {
3025         case LANG_DE:
3026             cfg.gui.lang = LANG_DE;
3027             break;
3028         case LANG_EN:
3029             cfg.gui.lang = LANG_EN;
3030             break;
3031         default:
3032             cfg.gui.lang = LANG_SYSTEM;
3033             break;
3034     }
3035 
3036     fl_alert(_("Please restart butt to apply new language."));
3037 
3038 }
3039 
3040 
check_cfg_auto_start_rec_cb(void)3041 void check_cfg_auto_start_rec_cb(void)
3042 {
3043     cfg.rec.start_rec = fl_g->check_cfg_auto_start_rec->value();
3044     fl_g->lcd->redraw();  //update the little record icon
3045 }
check_cfg_auto_stop_rec_cb(void)3046 void check_cfg_auto_stop_rec_cb(void)
3047 {
3048     cfg.rec.stop_rec = fl_g->check_cfg_auto_stop_rec->value();
3049 }
3050 
3051 
check_cfg_rec_after_launch_cb(void)3052 void check_cfg_rec_after_launch_cb(void)
3053 {
3054     cfg.rec.rec_after_launch = fl_g->check_cfg_rec_after_launch->value();
3055 }
3056 
check_cfg_rec_hourly_cb(void)3057 void check_cfg_rec_hourly_cb(void)
3058 {
3059     //cfg.rec.start_rec_hourly = fl_g->check_cfg_rec_hourly->value();
3060 }
3061 
check_cfg_connect_cb(void)3062 void check_cfg_connect_cb(void)
3063 {
3064     cfg.main.connect_at_startup = fl_g->check_cfg_connect->value();
3065 }
3066 
check_cfg_force_reconnecting_cb(void)3067 void check_cfg_force_reconnecting_cb(void)
3068 {
3069     cfg.main.force_reconnecting = fl_g->check_cfg_force_reconnecting->value();
3070 }
3071 
input_cfg_signal_cb(void)3072 void input_cfg_signal_cb(void)
3073 {
3074     // Values < 0 are not allowed
3075     if(fl_g->input_cfg_signal->value() <= 0)
3076     {
3077         fl_g->input_cfg_signal->value(0);
3078         Fl::remove_timeout(&stream_signal_timer);
3079     }
3080     else
3081         Fl::add_timeout(1, &stream_signal_timer);
3082 
3083     cfg.main.signal_threshold = fl_g->input_cfg_signal->value();
3084 }
3085 
3086 
input_cfg_present_level_cb(void)3087 void input_cfg_present_level_cb(void)
3088 {
3089     if(fl_g->input_cfg_present_level->value() < -90)
3090     {
3091         fl_alert(_("Value must be a number between -90.0 and 0"));
3092         fl_g->input_cfg_present_level->value(-cfg.audio.signal_level);
3093     }
3094 
3095     if(fl_g->input_cfg_present_level->value() > 0)
3096     {
3097         fl_alert(_("Value must be a number between -90.0 and 0"));
3098         fl_g->input_cfg_present_level->value(-cfg.audio.signal_level);
3099     }
3100 
3101     cfg.audio.signal_level = -fl_g->input_cfg_present_level->value();
3102 }
3103 
input_cfg_absent_level_cb(void)3104 void input_cfg_absent_level_cb(void)
3105 {
3106     if(fl_g->input_cfg_absent_level->value() < -90)
3107     {
3108         fl_alert(_("Value must be a number between -90.0 and 0"));
3109         fl_g->input_cfg_absent_level->value(-cfg.audio.silence_level);
3110     }
3111 
3112     if(fl_g->input_cfg_absent_level->value() > 0)
3113     {
3114         fl_alert(_("Value must be a number between -90.0 and 0"));
3115         fl_g->input_cfg_absent_level->value(-cfg.audio.silence_level);
3116     }
3117 
3118     cfg.audio.silence_level = -fl_g->input_cfg_absent_level->value();
3119 }
3120 
input_cfg_silence_cb(void)3121 void input_cfg_silence_cb(void)
3122 {
3123     // Values < 0 are not allowed
3124     if(fl_g->input_cfg_silence->value() < 0)
3125     {
3126         fl_g->input_cfg_silence->value(0);
3127         Fl::remove_timeout(&stream_silence_timer);
3128     }
3129     else
3130         Fl::add_timeout(1, &stream_silence_timer);
3131 
3132 
3133     cfg.main.silence_threshold = fl_g->input_cfg_silence->value();
3134 }
3135 
input_rec_signal_cb(void)3136 void input_rec_signal_cb(void)
3137 {
3138     // Values < 0 are not allowed
3139     if(fl_g->input_rec_signal->value() <= 0)
3140     {
3141         fl_g->input_rec_signal->value(0);
3142         Fl::remove_timeout(&record_signal_timer);
3143     }
3144     else
3145         Fl::add_timeout(1, &record_signal_timer);
3146 
3147     cfg.rec.signal_threshold = fl_g->input_rec_signal->value();
3148 }
3149 
input_rec_silence_cb(void)3150 void input_rec_silence_cb(void)
3151 {
3152     // Values < 0 are not allowed
3153     if(fl_g->input_rec_silence->value() < 0)
3154     {
3155         fl_g->input_rec_silence->value(0);
3156         Fl::remove_timeout(&record_silence_timer);
3157     }
3158     else
3159         Fl::add_timeout(1, &record_silence_timer);
3160 
3161     cfg.rec.silence_threshold = fl_g->input_rec_silence->value();
3162 }
3163 
check_song_update_active_cb(void)3164 void check_song_update_active_cb(void)
3165 {
3166    if(fl_g->check_song_update_active->value())
3167    {
3168        if(connected)
3169        {
3170            static int reset = 1;
3171            Fl::remove_timeout(&songfile_timer);
3172            Fl::add_timeout(0.1, &songfile_timer, &reset);
3173        }
3174        cfg.main.song_update = 1;
3175    }
3176    else
3177    {
3178        Fl::remove_timeout(&songfile_timer);
3179        if (cfg.main.song != NULL)
3180        {
3181            free(cfg.main.song);
3182            cfg.main.song = NULL;
3183        }
3184        cfg.main.song_update = 0;
3185    }
3186 }
3187 
check_read_last_line_cb(void)3188 void check_read_last_line_cb(void)
3189 {
3190     cfg.main.read_last_line = fl_g->check_read_last_line->value();
3191 }
3192 
check_sync_to_full_hour_cb(void)3193 void check_sync_to_full_hour_cb(void)
3194 {
3195    if(fl_g->check_sync_to_full_hour->value())
3196        cfg.rec.sync_to_hour = 1;
3197    else
3198        cfg.rec.sync_to_hour = 0;
3199 }
3200 
slider_gain_cb(void)3201 void slider_gain_cb(void)
3202 {
3203     float gain_db;
3204 
3205     //Without redrawing the main window the slider knob is not redrawn correctly
3206     fl_g->window_main->redraw();
3207 
3208     gain_db = (float)fl_g->slider_gain->value();
3209 
3210     if((int)gain_db == 0)
3211         cfg.main.gain = 1;
3212     else
3213         cfg.main.gain = util_db_to_factor(gain_db);
3214 
3215     fl_g->slider_gain->value_cb2("dB");
3216 }
3217 
input_rec_split_time_cb(void)3218 void input_rec_split_time_cb(void)
3219 {
3220     // Values < 0 are not allowed
3221     if (fl_g->input_rec_split_time->value() < 0)
3222     {
3223         fl_g->input_rec_split_time->value(0);
3224     }
3225 
3226     cfg.rec.split_time = fl_g->input_rec_split_time->value();
3227 }
3228 
button_cfg_export_cb(void)3229 void button_cfg_export_cb(void)
3230 {
3231     char *filename;
3232 
3233     Fl_My_Native_File_Chooser nfc;
3234 
3235     nfc.title(_("Export to..."));
3236     nfc.type(Fl_My_Native_File_Chooser::BROWSE_SAVE_FILE);
3237     nfc.options(Fl_My_Native_File_Chooser::NEW_FOLDER);
3238 
3239 
3240     switch(nfc.show())
3241     {
3242         case -1: fl_alert(_("ERROR: %s"), nfc.errmsg()); //error
3243             return;
3244             break;
3245         case  1: return; // cancel
3246             break;
3247         default:
3248             filename = (char*)nfc.filename();
3249     }
3250 
3251     cfg_write_file(filename);
3252 }
3253 
button_cfg_import_cb(void)3254 void button_cfg_import_cb(void)
3255 {
3256     char *filename;
3257     char info_buf[256];
3258 
3259     Fl_My_Native_File_Chooser nfc;
3260     nfc.title(_("Import..."));
3261     nfc.type(Fl_My_Native_File_Chooser::BROWSE_FILE);
3262 
3263     switch(nfc.show())
3264     {
3265         case -1: fl_alert(_("ERROR: %s"), nfc.errmsg()); //error
3266                  return;
3267                  break;
3268         case  1: return; // cancel
3269                  break;
3270         default: filename = (char*)nfc.filename();
3271                  break;
3272     }
3273 
3274     //read config and initialize config struct
3275     if(cfg_set_values(filename) != 0)
3276     {
3277         snprintf(info_buf, sizeof(info_buf), _("Could not import config %s"), filename);
3278         print_info(info_buf, 1);
3279         return;
3280     }
3281 
3282     //re-initialize some stuff after config has been successfully imported
3283     init_main_gui_and_audio();
3284     fill_cfg_widgets();
3285     snd_reinit();
3286 
3287     snprintf(info_buf, sizeof(info_buf), _("Config imported %s"), filename);
3288     print_info(info_buf, 1);
3289 }
3290 
check_update_at_startup_cb(void)3291 void check_update_at_startup_cb(void)
3292 {
3293     cfg.main.check_for_update = fl_g->check_update_at_startup->value();
3294 }
3295 
button_cfg_check_for_updates_cb(void)3296 void button_cfg_check_for_updates_cb(void)
3297 {
3298     int rc;
3299     char uri[100];
3300     char *new_version;
3301     int ret = update_check_for_new_version();
3302 
3303     switch(ret) {
3304         case UPDATE_NEW_VERSION:
3305             new_version = update_get_version();
3306             rc = fl_choice(_("New version available: %s\nYou have version %s"), _("Cancel"), _("Get new version"), NULL, new_version, VERSION);
3307             if(rc == 1)
3308             {
3309                 //snprintf(uri, sizeof(uri)-1, "https://sourceforge.net/projects/butt/files/butt/butt-%s/", new_version);
3310                 snprintf(uri, sizeof(uri)-1, "https://danielnoethen.de/butt/index.html#_download");
3311                 fl_open_uri(uri);
3312             }
3313 
3314             break;
3315         case UPDATE_SOCKET_ERROR:
3316             fl_alert(_("Could not get update information.\nReason: Network error"));
3317             break;
3318         case UPDATE_ILLEGAL_ANSWER:
3319             fl_alert(_("Could not get update information.\nReason: Unknown answer from server"));
3320             break;
3321         case UPDATE_UP_TO_DATE:
3322             fl_alert(_("You have the latest version!"));
3323             break;
3324         default:
3325             fl_alert(_("Could not get update information.\nReason: Unknown"));
3326             break;
3327     }
3328 }
3329 
check_cfg_mono_to_stereo_cb(void)3330 void check_cfg_mono_to_stereo_cb(void)
3331 {
3332     cfg.audio.mono_to_stereo = fl_g->check_cfg_mono_to_stereo->value();
3333 }
3334 
button_cfg_log_browse_cb(void)3335 void button_cfg_log_browse_cb(void)
3336 {
3337     Fl_My_Native_File_Chooser nfc;
3338     nfc.title(_("Select logfile..."));
3339     nfc.type(Fl_My_Native_File_Chooser::BROWSE_SAVE_FILE);
3340     nfc.options(Fl_My_Native_File_Chooser::NEW_FOLDER);
3341 
3342     switch(nfc.show())
3343     {
3344         case -1: fl_alert(_("ERROR: %s"), nfc.errmsg());
3345             break;
3346         case  1:
3347             break; //cancel
3348         default:
3349             fl_g->input_log_filename->value(nfc.filename());
3350             input_log_filename_cb();
3351     }
3352 }
3353 
window_main_close_cb(void)3354 void window_main_close_cb(void)
3355 {
3356 
3357 
3358     if(connected || recording)
3359     {
3360         int ret;
3361         if(connected)
3362             ret = fl_choice(_("butt is currently streaming.\n"
3363                             "Do you really want to close butt now?"),
3364                             _("no"), _("yes"), NULL);
3365         else
3366             ret = fl_choice(_("butt is currently recording.\n"
3367                             "Do you really want to close butt now?"),
3368                             _("no"), _("yes"), NULL);
3369 
3370         if(ret == 0)
3371             return;
3372     }
3373 
3374 
3375     if (cfg.gui.remember_pos)
3376     {
3377         cfg.gui.x_pos = fl_g->window_main->x_root();
3378         cfg.gui.y_pos = fl_g->window_main->y_root();
3379     }
3380 
3381     cfg_write_file(NULL);
3382     exit(0);
3383 }
3384 
check_cfg_use_app_cb()3385 void check_cfg_use_app_cb()
3386 {
3387     if(fl_g->check_cfg_use_app->value())
3388     {
3389         int app = fl_g->choice_cfg_app->value();
3390         current_track_app = getCurrentTrackFunctionFromId(app);
3391         cfg.main.app_update = 1;
3392         cfg.main.app_update_service = app;
3393 
3394         static int reset = 1;
3395         Fl::remove_timeout(&app_timer);
3396         Fl::add_timeout(0.1, &app_timer, &reset);
3397     }
3398     else
3399     {
3400         cfg.main.app_update = 0;
3401         Fl::remove_timeout(&app_timer);
3402 
3403        if (cfg.main.song != NULL)
3404        {
3405            free(cfg.main.song);
3406            cfg.main.song = NULL;
3407        }
3408     }
3409 }
3410 
choice_cfg_app_cb()3411 void choice_cfg_app_cb()
3412 {
3413     current_track_app = getCurrentTrackFunctionFromId(fl_g->choice_cfg_app->value());
3414     cfg.main.app_update_service = fl_g->choice_cfg_app->value();
3415 }
3416 
check_activate_eq_cb(void)3417 void check_activate_eq_cb(void)
3418 {
3419     cfg.dsp.equalizer = fl_g->check_activate_eq->value();
3420 }
3421 
slider_equalizer1_cb(double v)3422 void slider_equalizer1_cb(double v)
3423 {
3424     static char str[10];
3425     cfg.dsp.gain1 = v;
3426     snprintf(str, 10, "%+.1f", v);
3427     fl_g->equalizerGain1->label(str);
3428     fl_g->equalizerSlider1->value_cb2("dB"); // updates the tooltip
3429 
3430 }
3431 
slider_equalizer2_cb(double v)3432 void slider_equalizer2_cb(double v)
3433 {
3434     static char str[10];
3435     cfg.dsp.gain2 = v;
3436     snprintf(str, 10, "%+.1f", v);
3437     fl_g->equalizerGain2->label(str);
3438     fl_g->equalizerSlider2->value_cb2("dB");
3439 }
3440 
slider_equalizer3_cb(double v)3441 void slider_equalizer3_cb(double v)
3442 {
3443     static char str[10];
3444     cfg.dsp.gain3 = v;
3445     snprintf(str, 10, "%+.1f", v);
3446     fl_g->equalizerGain3->label(str);
3447     fl_g->equalizerSlider3->value_cb2("dB");
3448 }
3449 
slider_equalizer4_cb(double v)3450 void slider_equalizer4_cb(double v)
3451 {
3452     static char str[10];
3453     cfg.dsp.gain4 = v;
3454     snprintf(str, 10, "%+.1f", v);
3455     fl_g->equalizerGain4->label(str);
3456     fl_g->equalizerSlider4->value_cb2("dB");
3457 }
3458 
slider_equalizer5_cb(double v)3459 void slider_equalizer5_cb(double v)
3460 {
3461     static char str[10];
3462     cfg.dsp.gain5 = v;
3463     snprintf(str, 10, "%+.1f", v);
3464     fl_g->equalizerGain5->label(str);
3465     fl_g->equalizerSlider5->value_cb2("dB");
3466 }
3467 
3468 
check_activate_drc_cb(void)3469 void check_activate_drc_cb(void)
3470 {
3471     cfg.dsp.compressor = fl_g->check_activate_drc->value();
3472 }
3473 
slider_threshold_cb(double v)3474 void slider_threshold_cb(double v)
3475 {
3476     static char str[10];
3477     cfg.dsp.threshold = v;
3478     snprintf(str, 10, "%+.1f", v);
3479     fl_g->threshold->label(str);
3480     fl_g->thresholdSlider->value_cb2("dBFS"); // updates the tooltip
3481 
3482 }
3483 
slider_ratio_cb(double v)3484 void slider_ratio_cb(double v)
3485 {
3486     static char str[10];
3487     cfg.dsp.ratio = v;
3488     snprintf(str, 10, "%.1f", v);
3489     fl_g->ratio->label(str);
3490     fl_g->ratioSlider->value_cb2(":1");
3491 }
3492 
slider_attack_cb(double v)3493 void slider_attack_cb(double v)
3494 {
3495     static char str[10];
3496     cfg.dsp.attack = v;
3497     snprintf(str, 10, "%.1fs", v);
3498     fl_g->attack->label(str);
3499     fl_g->attackSlider->value_cb2("s");
3500 }
3501 
slider_release_cb(double v)3502 void slider_release_cb(double v)
3503 {
3504     static char str[10];
3505     cfg.dsp.release = v;
3506     snprintf(str, 10, "%.1fs", v);
3507     fl_g->release->label(str);
3508     fl_g->releaseSlider->value_cb2("s");
3509 }
3510 
slider_makeup_cb(double v)3511 void slider_makeup_cb(double v)
3512 {
3513     static char str[10];
3514     cfg.dsp.makeup_gain = v;
3515     snprintf(str, 10, "%+.1f", v);
3516     fl_g->makeup->label(str);
3517     fl_g->makeupSlider->value_cb2("dB");
3518 }
3519 
3520