1 /**********************************************************
2 *
3 * mp3splt-gtk -- utility based on mp3splt,
4 * for mp3/ogg splitting without decoding
5 *
6 * Copyright: (C) 2005-2014 Alexandru Munteanu
7 * Contact: m@ioalex.net
8 *
9 * http://mp3splt.sourceforge.net/
10 *
11 *********************************************************/
12
13 /**********************************************************
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
28 * USA.
29 *
30 *********************************************************/
31
32 /*!********************************************************
33 * \file
34 * Snackamp control
35 *
36 * this file contains functions to control the snackamp
37 * player
38 **********************************************************/
39
40 #define _WIN32_WINNT 0x0501
41
42 #include "snackamp_control.h"
43
44 /*!connecting to the player to the port port
45
46 Might possibley return an error
47 */
connect_snackamp(gint port,ui_state * ui)48 gint connect_snackamp(gint port, ui_state *ui)
49 {
50 gint return_err = 0;
51
52 #ifdef __WIN32__
53 long winsockinit;
54 WSADATA winsock;
55 winsockinit = WSAStartup(0x0101,&winsock);
56 #endif
57
58 struct addrinfo hints;
59 memset(&hints, 0, sizeof(struct addrinfo));
60 hints.ai_family = AF_UNSPEC;
61 hints.ai_socktype = SOCK_STREAM;
62
63 struct addrinfo *result;
64
65 char *port_as_string = alloca(16);
66 snprintf(port_as_string, 16, "%d", port);
67
68 int return_code = getaddrinfo("localhost", port_as_string, &hints, &result);
69 if (return_code != 0) {
70 return_err = 1;
71 }
72
73 if (return_err == 0)
74 {
75 struct addrinfo *result_p;
76 for (result_p = result; result_p != NULL; result_p = result_p->ai_next)
77 {
78 return_err = 0;
79
80 ui->pi->socket_id = socket(result_p->ai_family, result_p->ai_socktype, result_p->ai_protocol);
81 if (ui->pi->socket_id == -1)
82 {
83 return_err = 2;
84 continue;
85 }
86
87 if (connect(ui->pi->socket_id, result_p->ai_addr, result_p->ai_addrlen) != -1)
88 {
89 break;
90 }
91
92 return_err = 3;
93 close(ui->pi->socket_id);
94 }
95
96 freeaddrinfo(result);
97 }
98
99 if (return_err == 0)
100 {
101 #ifdef __WIN32__
102 #else
103 if (NULL == (ui->pi->in = fdopen(ui->pi->socket_id, "r")) ||
104 NULL == (ui->pi->out = fdopen(ui->pi->socket_id, "w")))
105 {
106 return_err = 4;
107 }
108 #endif
109 }
110
111 if (return_err == 0)
112 {
113 setvbuf(ui->pi->out, NULL, _IOLBF, 0);
114 ui->pi->connected = TRUE;
115 }
116
117 if (return_err >= 2)
118 {
119 disconnect_snackamp(ui);
120 }
121
122 return return_err;
123 }
124
125 /*gint connect_snackamp(gint port, ui_state *ui)
126 {
127 struct sockaddr_in host;
128 struct hostent *h;
129 gint return_err = 0;
130 #ifdef __WIN32__
131 long winsockinit;
132 WSADATA winsock;
133 winsockinit = WSAStartup(0x0101,&winsock);
134 #endif
135 if((h = gethostbyname("localhost"))==NULL)
136 {
137 return_err = 1;
138 }
139 host.sin_family = AF_INET;
140 host.sin_addr.s_addr = ((struct in_addr *) (h->h_addr)) ->s_addr;
141 host.sin_port=htons(port);
142 if (return_err == 0)
143 {
144 if ((ui->pi->socket_id = socket(AF_INET, SOCK_STREAM, 0))==-1)
145 {
146 return_err = 2;
147 }
148 }
149 if (return_err == 0)
150 {
151 if ((connect(ui->pi->socket_id, (void *)&host, sizeof(host)))==-1)
152 {
153 return_err = 3;
154 }
155 }
156 if (return_err == 0)
157 {
158 #ifdef __WIN32__
159 #else
160 if (NULL == (ui->pi->in = fdopen(ui->pi->socket_id, "r")) ||
161 NULL == (ui->pi->out = fdopen(ui->pi->socket_id, "w")))
162 {
163 return_err = 4;
164 }
165 #endif
166 }
167 if (return_err == 0)
168 {
169 setvbuf(ui->pi->out, NULL, _IOLBF, 0);
170 ui->pi->connected = TRUE;
171 }
172 if (return_err >= 2)
173 {
174 disconnect_snackamp(ui);
175 }
176 return return_err;
177 }*/
178
cut_begin_end(gchar * result)179 static gchar *cut_begin_end(gchar *result)
180 {
181 if (strchr(result,' ') != NULL)
182 {
183 gchar *test = strchr(result, ' ');
184 g_snprintf(result, strlen(result), "%s",test+1);
185 }
186
187 //cut the \n at the end
188 gint result_str = strlen(result);
189 if (result_str >= 2)
190 {
191 result[result_str - 2] = '\0';
192 }
193
194 return result;
195 }
196
197 /*! disconnecting with the player
198 possibly returns an error
199 */
disconnect_snackamp(ui_state * ui)200 gint disconnect_snackamp(ui_state *ui)
201 {
202 ui->pi->connected = FALSE;
203 #ifdef __WIN32__
204 gint result = closesocket(ui->pi->socket_id);
205 WSACleanup();
206 return result;
207 #else
208 return close(ui->pi->socket_id);
209 #endif
210 }
211
212 /*! send a message to snackamp through the socket interface
213
214 \return the result; must be g_freed after use
215 \todo rewrite this function
216 */
snackamp_socket_send_message(gchar * message,ui_state * ui)217 static gchar *snackamp_socket_send_message(gchar *message, ui_state *ui)
218 {
219 gchar *result = malloc(1024 * sizeof(gchar *));
220 strcpy(result,"disconnected");
221
222 #ifdef __WIN32__
223 gboolean r = TRUE;
224
225 gint err1 = send(ui->pi->socket_id, message, strlen(message), 0);
226 if (err1 <= 0)
227 {
228 disconnect_snackamp(ui);
229 }
230 else
231 {
232 gint err = recv(ui->pi->socket_id, result, 1024, 0);
233 if (err <= 0)
234 {
235 disconnect_snackamp(ui);
236 r = FALSE;
237 }
238 }
239 #else
240 fputs(message, ui->pi->out);
241 fgets(result, 1024, ui->pi->in);
242 #endif
243
244 //if on win32 we put the \0 when we find \n because no line buffering
245 #ifdef __WIN32__
246 if (r)
247 {
248 if (strchr(result,'\n') != NULL)
249 {
250 gchar *line_end;
251 line_end = strchr(result,'\n') + 1;
252 *line_end = '\0';
253 }
254 }
255 #endif
256
257 return result;
258 }
259
260 //!gets an integer from the string
get_integer_from_string(gchar * result)261 static gint get_integer_from_string(gchar *result)
262 {
263 gint our_integer = 0;
264 gint i = 0;
265 gchar *number = NULL;
266 while ((isdigit(result[i])==0) && (result[i]!='\0') && (result[i]!='-'))
267 {
268 i++;
269 number = result + i;
270 }
271 if (! (number == (result + strlen(result))))
272 {
273 our_integer = atoi (number);
274 }
275
276 return our_integer;
277 }
278
279 //!Test if we are connected to snackamp
snackamp_is_connected(ui_state * ui)280 static gboolean snackamp_is_connected(ui_state *ui)
281 {
282 return ui->pi->connected;
283 }
284
285 //!gets informations about the song
snackamp_get_song_infos(gchar * total_infos,ui_state * ui)286 void snackamp_get_song_infos(gchar *total_infos, ui_state *ui)
287 {
288 gchar *result = snackamp_socket_send_message("xmms_remote_get_info\n", ui);
289 result = cut_begin_end(result);
290
291 //stereo/mono
292 char *a = strstr(result, " ");
293 if (a == NULL)
294 {
295 g_snprintf(total_infos, 512, "disconnected");
296 g_free(result);
297 return;
298 }
299
300 gchar rate_str[32] = { '\0' };
301 gchar freq_str[32] = { '\0' };
302 gchar nch_str[32] = { '\0' };
303 gchar *ptr = NULL;
304
305 if (strstr(a+1, " ") != NULL)
306 {
307 ptr = strstr(a+1, " ") + 1;
308 }
309
310 //rate
311 gint i = 0;
312 while (result[i] != ' ' && isdigit(result[i]) && i < 16)
313 {
314 g_sprintf(rate_str, "%s%c",rate_str,result[i]);
315 i++;
316 }
317
318 //cut the beginning
319 if (strchr(result, ' ') != NULL)
320 {
321 gchar *test = strchr(result,' ');
322 g_snprintf(result, strlen(result), "%s",test+1);
323 }
324
325 //freq
326 i = 0;
327 while (result[i] != ' ' && isdigit(result[i]) && i < 16)
328 {
329 g_sprintf(freq_str, "%s%c",freq_str,result[i]);
330 i++;
331 }
332
333 //channels int
334 gint nch = atoi(ptr);
335 if (nch == 2)
336 {
337 snprintf(nch_str, 32, "%s", _("stereo"));
338 }
339 else
340 {
341 snprintf(nch_str, 32, "%s", _("mono"));
342 }
343
344 gchar *_Kbps = _("Kbps");
345 gchar *_Khz = _("Khz");
346 g_snprintf(total_infos, 512, "%s %s %s %s %s", rate_str, _Kbps, freq_str, _Khz, nch_str);
347
348 g_free(result);
349 }
350
351 //!returns current song position in the playlist
snackamp_get_playlist_pos(ui_state * ui)352 static gint snackamp_get_playlist_pos(ui_state *ui)
353 {
354 gchar *result = snackamp_socket_send_message("xmms_remote_get_playlist_pos\n", ui);
355 gint number = get_integer_from_string(result);
356 g_free(result);
357 return number;
358 }
359
360 /*!returns the filename
361
362 The result of this query must be freed after use.
363 */
snackamp_get_filename(ui_state * ui)364 gchar *snackamp_get_filename(ui_state *ui)
365 {
366 gint playlist_pos = snackamp_get_playlist_pos(ui);
367
368 //we get the current file
369 gchar temp[100];
370 g_snprintf(temp, 100, "%s %d\n", "xmms_remote_get_playlist_file", playlist_pos);
371
372 gchar *result = snackamp_socket_send_message(temp, ui);
373 result = cut_begin_end(result);
374
375 return result;
376 }
377
378 //!stops playing a song
snackamp_stop(ui_state * ui)379 void snackamp_stop(ui_state *ui)
380 {
381 gchar *result = snackamp_socket_send_message("xmms_remote_stop\n", ui);
382 g_free(result);
383 }
384
385 //!returns the number of songs of the playlist
snackamp_get_playlist_number(ui_state * ui)386 gint snackamp_get_playlist_number(ui_state *ui)
387 {
388 gchar *result = snackamp_socket_send_message("xmms_remote_get_playlist_length\n", ui);
389 gint number = get_integer_from_string(result);
390 g_free(result);
391
392 if (number == -1)
393 {
394 snackamp_stop(ui);
395 }
396
397 return number;
398 }
399
400 /*!returns the title of the song
401
402 The return value must be g_free'd after use.
403 */
snackamp_get_title_song(ui_state * ui)404 gchar *snackamp_get_title_song(ui_state *ui)
405 {
406 gint playlist_pos = snackamp_get_playlist_pos(ui);
407
408 gchar temp[100];
409 g_snprintf(temp, 100,"%s %d\n", "xmms_remote_get_playlist_title",playlist_pos);
410
411 gchar *result = snackamp_socket_send_message(temp, ui);
412 result = cut_begin_end(result);
413
414 return result;
415 }
416
417 //!returns elapsed time
snackamp_get_time_elapsed(ui_state * ui)418 gint snackamp_get_time_elapsed(ui_state *ui)
419 {
420 gchar *result = snackamp_socket_send_message("xmms_remote_get_output_time\n", ui);
421 gint pos = get_integer_from_string(result);
422 g_free(result);
423
424 return pos;
425 }
426
427 //!starts snackamp
snackamp_start(ui_state * ui)428 void snackamp_start(ui_state *ui)
429 {
430 static gchar *exec_command = "snackAmp";
431 gchar *exec_this = g_strdup_printf("%s &", exec_command);
432 system(exec_this);
433
434 time_t lt;
435 gint timer = time(<);
436 while ((!snackamp_is_running(ui)) && ((time(<) - timer) < 8))
437 {
438 usleep(0);
439 }
440
441 g_free(exec_this);
442 }
443
444 //!jumps to the position pos in the playlist
snackamp_set_playlist_pos(gint pos,ui_state * ui)445 static void snackamp_set_playlist_pos(gint pos, ui_state *ui)
446 {
447 gchar temp[100];
448 g_snprintf(temp, 100, "%s %d\n", "xmms_remote_set_playlist_pos",pos);
449 gchar *result = snackamp_socket_send_message(temp, ui);
450 g_free(result);
451 }
452
453 //!selects the last file in the playlist
snackamp_select_last_file(ui_state * ui)454 void snackamp_select_last_file(ui_state *ui)
455 {
456 gint last_song = snackamp_get_playlist_number(ui);
457 snackamp_set_playlist_pos(last_song - 1, ui);
458 }
459
460 //!plays a song
snackamp_play(ui_state * ui)461 void snackamp_play(ui_state *ui)
462 {
463 gchar *result = snackamp_socket_send_message("xmms_remote_play\n", ui);
464 g_free(result);
465 }
466
467 //!plays the last file of the playlist
snackamp_play_last_file(ui_state * ui)468 void snackamp_play_last_file(ui_state *ui)
469 {
470 snackamp_select_last_file(ui);
471 snackamp_play(ui);
472 }
473
474 //!add files to the snackamp playlist
snackamp_add_files(GList * list,ui_state * ui)475 void snackamp_add_files(GList *list, ui_state *ui)
476 {
477 gint i = 0;
478 gchar *song = NULL;
479 while ((song = g_list_nth_data(list, i)) != NULL)
480 {
481 gint malloc_int = strlen(song) + 30;
482 gchar *local = malloc(malloc_int * sizeof(gchar *));
483 g_snprintf(local, malloc_int, "%s {%s}\n", "xmms_remote_playlist_add ", song);
484
485 gchar *result = snackamp_socket_send_message(local, ui);
486 g_free(result);
487
488 g_free(local);
489 i++;
490 }
491 }
492
493 //!sets volume
snackamp_set_volume(gint volume,ui_state * ui)494 void snackamp_set_volume(gint volume, ui_state *ui)
495 {
496 gchar temp[100];
497 g_snprintf(temp, 100, "%s %d\n", "xmms_remote_set_main_volume", volume);
498 gchar *result = snackamp_socket_send_message(temp, ui);
499 g_free(result);
500 }
501
502 //!returns volume
snackamp_get_volume(ui_state * ui)503 gint snackamp_get_volume(ui_state *ui)
504 {
505 gchar *result = snackamp_socket_send_message("xmms_remote_get_main_volume\n", ui);
506 gint vol = get_integer_from_string(result);
507 g_free(result);
508
509 return vol;
510 }
511
512 //!starts snackamp with songs
snackamp_start_with_songs(GList * list,ui_state * ui)513 void snackamp_start_with_songs(GList *list, ui_state *ui)
514 {
515 snackamp_start(ui);
516 snackamp_add_files(list, ui);
517 }
518
519 //!returns TRUE if snackamp is running; if not, FALSE
snackamp_is_running(ui_state * ui)520 gint snackamp_is_running(ui_state *ui)
521 {
522 if (ui->pi->connected)
523 {
524 return TRUE;
525 }
526
527 if (connect_snackamp(8775, ui) == 0)
528 {
529 return TRUE;
530 }
531
532 return FALSE;
533 }
534
535 //!pause a song
snackamp_pause(ui_state * ui)536 void snackamp_pause(ui_state *ui)
537 {
538 gchar *result = snackamp_socket_send_message("xmms_remote_pause\n", ui);
539 g_free(result);
540 }
541
542 //!changes to next song
snackamp_next(ui_state * ui)543 void snackamp_next(ui_state *ui)
544 {
545 gchar *result = snackamp_socket_send_message("xmms_remote_playlist_next\n", ui);
546 g_free(result);
547 }
548
549 //!changes to previous song
snackamp_prev(ui_state * ui)550 void snackamp_prev(ui_state *ui)
551 {
552 gint playlist_pos = snackamp_get_playlist_pos(ui);
553
554 if (playlist_pos > 0)
555 {
556 gchar *result = snackamp_socket_send_message("xmms_remote_playlist_prev\n", ui);
557 g_free(result);
558 return;
559 }
560
561 snackamp_play_last_file(ui);
562 }
563
564 //!jump to time
snackamp_jump(gint position,ui_state * ui)565 void snackamp_jump(gint position, ui_state *ui)
566 {
567 gint hundr_secs_pos = position / 10;
568 gint hundr_secs = hundr_secs_pos % 100;
569 if (hundr_secs == 1)
570 {
571 hundr_secs = 0;
572 }
573
574 gint secs = hundr_secs_pos / 100;
575 gfloat total_pos = hundr_secs + secs * 100;
576 total_pos /= 100;
577
578 gchar temp[100];
579 g_snprintf(temp, 100, "%s %f\n", "xmms_remote_jump_to_time", total_pos);
580
581 gchar *result = snackamp_socket_send_message(temp, ui);
582 g_free(result);
583 }
584
585 //!returns total time of the current song
snackamp_get_total_time(ui_state * ui)586 gint snackamp_get_total_time(ui_state *ui)
587 {
588 gchar *result = snackamp_socket_send_message("xmms_remote_get_playlist_time\n", ui);
589 gint hundr_secs = get_integer_from_string(result) * 1000;
590 g_free(result);
591
592 return hundr_secs;
593 }
594
595 //!returns TRUE if snackamp is playing, else FALSE
snackamp_is_playing(ui_state * ui)596 gint snackamp_is_playing(ui_state *ui)
597 {
598 if (!snackamp_is_connected(ui))
599 {
600 return FALSE;
601 }
602
603 gchar *result = snackamp_socket_send_message("xmms_remote_is_playing\n", ui);
604 gint i = atoi(result);
605 g_free(result);
606
607 if (i == 0)
608 {
609 return FALSE;
610 }
611
612 return TRUE;
613 }
614
615 /*! returns TRUE if snackamp is paused, else FALSE
616
617 not yet implemented in snackamp
618 */
snackamp_is_paused(ui_state * ui)619 gint snackamp_is_paused(ui_state *ui)
620 {
621 if (!snackamp_is_connected(ui))
622 {
623 return FALSE;
624 }
625
626 gchar *result = snackamp_socket_send_message("xmms_remote_is_paused\n", ui);
627 result = cut_begin_end(result);
628
629 gint i = atoi(result);
630 g_free(result);
631
632 if (i == 1)
633 {
634 return TRUE;
635 }
636
637 return FALSE;
638 }
639
640