playlist preparation
[melted_gui] / src / omnplay.cpp
1 /*
2 * omnplay.c -- GTK+ 2 omnplay
3 * Copyright (C) 2011 Maksym Veremeyenko <verem@m1stereo.tv>
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 of the License, or
8 * (at your option) 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 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <gtk/gtk.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <pthread.h>
30
31 #include "omnplay.h"
32 #include "ui.h"
33 #include "opts.h"
34
35 #include "omplrclnt.h"
36
37 static char* frames2tc( int f, float fps, char* buf )
38 {
39 int tc[4] = { 0, 0, 0, 0 };
40 float d;
41 int t;
42
43 if ( fps && f >= 0)
44 {
45 d = f / fps;
46 t = d;
47
48 tc[0] = (d - t) * fps;
49 tc[1] = t % 60; t /= 60;
50 tc[2] = t % 60; t /= 60;
51 tc[3] = t % 24;
52 }
53
54 sprintf(buf, "%.2d:%.2d:%.2d:%.2d", tc[3], tc[2], tc[1], tc[0]);
55
56 return buf;
57 }
58
59
60 static gboolean on_main_window_delete_event( GtkWidget *widget, GdkEvent *event, gpointer user_data )
61 {
62 gtk_exit(0);
63 return TRUE;
64 }
65
66 omnplay_instance_t* omnplay_create(int argc, char** argv)
67 {
68 int i, c;
69 omnplay_instance_t* app;
70
71 /* prepare application instance */
72 app = (omnplay_instance_t*)malloc(sizeof(omnplay_instance_t));
73 memset(app, 0, sizeof(omnplay_instance_t));
74
75 /* load parameters from command line */
76 if(!omnplay_opt(argc, argv, app) && app->players.count)
77 app->window = ui_omnplay(app);
78 else
79 omnplay_usage();
80
81 return app;
82 };
83
84 void omnplay_destroy(omnplay_instance_t* app)
85 {
86 free(app);
87 };
88
89 static void omnplay_update_status(omnplay_player_t* player, OmPlrStatus *prev , OmPlrStatus *curr)
90 {
91 char tc_cur[32], tc_rem[32], state[32], status[32];
92 const char *clip;
93
94 if(curr)
95 {
96 frames2tc(curr->pos - curr->minPos, 25.0, tc_cur);
97 frames2tc(curr->maxPos - curr->pos, 25.0, tc_rem);
98 strcpy(status, "ONLINE");
99 clip = curr->currClipName;
100
101 switch(curr->state)
102 {
103 case omPlrStateStopped: strcpy(state, "STOPPED"); break;
104 case omPlrStateCuePlay: strcpy(state, "CUE_PLAY"); break;
105 case omPlrStatePlay: strcpy(state, "PLAY"); break;
106 case omPlrStateCueRecord: strcpy(state, "CUE_RECORD"); break;
107 case omPlrStateRecord: strcpy(state, "RECORD"); break;
108 };
109 }
110 else
111 {
112 tc_cur[0] = 0;
113 tc_rem[0] = 0;
114 clip = "";
115 state[0] = 0;
116 strcpy(status, "OFFLINE");
117 };
118
119 gdk_threads_enter();
120 gtk_label_set_text(GTK_LABEL (player->label_tc_cur), tc_cur);
121 gtk_label_set_text(GTK_LABEL (player->label_tc_rem), tc_rem);
122 gtk_label_set_text(GTK_LABEL (player->label_state), state);
123 gtk_label_set_text(GTK_LABEL (player->label_status), status);
124 gtk_label_set_text(GTK_LABEL (player->label_clip), clip);
125 gdk_flush();
126 gdk_threads_leave();
127
128 memcpy(prev, curr, sizeof(OmPlrStatus));
129 };
130
131 static void* omnplay_thread_proc(void* data)
132 {
133 int r;
134 OmPlrStatus st_curr, st_prev;
135 omnplay_player_t* player = (omnplay_player_t*)data;
136
137 /* connect */
138 pthread_mutex_lock(&player->lock);
139 r = OmPlrOpen(player->host, player->name, (OmPlrHandle*)&player->handle);
140 pthread_mutex_unlock(&player->lock);
141 if(r)
142 {
143 fprintf(stderr, "ERROR: OmPlrOpen(%s, %s) failed with 0x%.8X\n",
144 player->host, player->name, r);
145
146 return (void*)r;
147 };
148
149 /* setup to do not reconnect */
150 pthread_mutex_lock(&player->lock);
151 OmPlrSetRetryOpen((OmPlrHandle)player->handle, 0);
152 pthread_mutex_unlock(&player->lock);
153
154 /* setup directory */
155 if(player->app->players.path[0])
156 {
157 pthread_mutex_lock(&player->lock);
158 // r = OmPlrClipSetDirectory((OmPlrHandle)player->handle, player->app->players.path);
159 pthread_mutex_unlock(&player->lock);
160
161 if(r)
162 {
163 fprintf(stderr, "ERROR: OmPlrClipSetDirectory(%s) failed with 0x%.8X\n",
164 player->app->players.path, r);
165
166 pthread_mutex_lock(&player->lock);
167 OmPlrClose((OmPlrHandle)player->handle);
168 pthread_mutex_unlock(&player->lock);
169
170 return (void*)r;
171 };
172 };
173
174 /* endless loop */
175 for(r = 0 ; !player->app->f_exit && !r;)
176 {
177 /* sleep */
178 usleep(100000);
179
180 /* get status */
181 pthread_mutex_lock(&player->lock);
182 st_curr.size = sizeof(OmPlrStatus);
183 r = OmPlrGetPlayerStatus((OmPlrHandle)player->handle, &st_curr);
184 pthread_mutex_unlock(&player->lock);
185
186 if(r)
187 fprintf(stderr, "ERROR: OmPlrGetPlayerStatus failed with 0x%.8X\n", r);
188 else
189 if(memcmp(&st_curr, &st_prev, sizeof(OmPlrStatus)))
190 omnplay_update_status(player, &st_prev , &st_curr);
191 };
192
193 pthread_mutex_lock(&player->lock);
194 OmPlrClose((OmPlrHandle)player->handle);
195 pthread_mutex_unlock(&player->lock);
196
197 return NULL;
198 };
199
200 static gboolean omnplay_button_click(omnplay_instance_t* app, control_buttons_t button)
201 {
202 switch(button)
203 {
204 case BUTTON_PLAYLIST_ITEM_ADD:
205 case BUTTON_PLAYLIST_ITEM_DEL:
206 case BUTTON_PLAYLIST_ITEM_EDIT:
207 case BUTTON_PLAYLIST_LOAD:
208 omnplay_playlist_load(app);
209 break;
210 case BUTTON_PLAYLIST_SAVE:
211 omnplay_playlist_save(app);
212 break;
213 case BUTTON_PLAYLIST_BLOCK_SINGLE:
214 case BUTTON_PLAYLIST_BLOCK_LOOP:
215 case BUTTON_PLAYLIST_ITEM_UP:
216 case BUTTON_PLAYLIST_ITEM_DOWN:
217 case BUTTON_PLAYER_CUE:
218 case BUTTON_PLAYER_PLAY:
219 case BUTTON_PLAYER_PAUSE:
220 case BUTTON_PLAYER_STOP:
221 case BUTTON_LIBRARY_ADD:
222 case BUTTON_LIBRARY_REFRESH:
223 break;
224 };
225
226 return TRUE;
227 };
228
229 static gboolean on_button_click(GtkWidget *button, gpointer user_data)
230 {
231 int i;
232 omnplay_instance_t* app = (omnplay_instance_t*)user_data;
233
234 for(i = 1; i < BUTTON_LAST; i++)
235 if(app->buttons[i] == button)
236 return omnplay_button_click(app, (control_buttons_t)i);
237
238 return FALSE;
239 };
240
241 void omnplay_init(omnplay_instance_t* app)
242 {
243 int i;
244
245 gtk_signal_connect( GTK_OBJECT( app->window ), "destroy",
246 GTK_SIGNAL_FUNC(on_main_window_delete_event), app);
247
248 for(i = 0; i < app->players.count; i++)
249 {
250 /* create lock */
251 pthread_mutex_init(&app->players.item[i].lock, NULL);
252
253 /* create a omneon status thread */
254 pthread_create(&app->players.item[i].thread, NULL,
255 omnplay_thread_proc, &app->players.item[i]);
256 };
257
258 /* create lock */
259 pthread_mutex_init(&app->playlist.lock, NULL);
260
261 /* attach buttons click */
262 for(i = 1; i < BUTTON_LAST; i++)
263 gtk_signal_connect(GTK_OBJECT(app->buttons[i]), "clicked",
264 GTK_SIGNAL_FUNC( on_button_click), app );
265
266 };
267
268 void omnplay_release(omnplay_instance_t* app)
269 {
270 int i;
271 void* r;
272
273 app->f_exit = 1;
274
275 for(i = 0; i < app->players.count; i++)
276 {
277 /* create a omneon status thread */
278 pthread_join(app->players.item[i].thread, &r);
279
280 /* create lock */
281 pthread_mutex_destroy(&app->players.item[i].lock);
282
283 };
284
285 /* create lock */
286 pthread_mutex_destroy(&app->playlist.lock);
287 };