cue function prototype added
[omnplay] / 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 #include "timecode.h"
35
36 #include "omplrclnt.h"
37
38 static gboolean on_main_window_delete_event( GtkWidget *widget, GdkEvent *event, gpointer user_data )
39 {
40 gtk_exit(0);
41 return TRUE;
42 }
43
44 omnplay_instance_t* omnplay_create(int argc, char** argv)
45 {
46 int i, c;
47 omnplay_instance_t* app;
48
49 /* prepare application instance */
50 app = (omnplay_instance_t*)malloc(sizeof(omnplay_instance_t));
51 memset(app, 0, sizeof(omnplay_instance_t));
52
53 /* load parameters from command line */
54 if(!omnplay_opt(argc, argv, app) && app->players.count)
55 app->window = ui_omnplay(app);
56 else
57 omnplay_usage();
58
59 return app;
60 };
61
62 void omnplay_destroy(omnplay_instance_t* app)
63 {
64 free(app);
65 };
66
67 static void omnplay_update_status(omnplay_player_t* player, OmPlrStatus *prev , OmPlrStatus *curr)
68 {
69 char tc_cur[32], tc_rem[32], state[32], status[32];
70 const char *clip;
71
72 if(curr)
73 {
74 frames2tc(curr->pos - curr->minPos, 25.0, tc_cur);
75 frames2tc(curr->maxPos - curr->pos, 25.0, tc_rem);
76 strcpy(status, "ONLINE");
77 clip = curr->currClipName;
78
79 switch(curr->state)
80 {
81 case omPlrStateStopped: strcpy(state, "STOPPED"); break;
82 case omPlrStateCuePlay: strcpy(state, "CUE_PLAY"); break;
83 case omPlrStatePlay: strcpy(state, "PLAY"); break;
84 case omPlrStateCueRecord: strcpy(state, "CUE_RECORD"); break;
85 case omPlrStateRecord: strcpy(state, "RECORD"); break;
86 };
87 }
88 else
89 {
90 tc_cur[0] = 0;
91 tc_rem[0] = 0;
92 clip = "";
93 state[0] = 0;
94 strcpy(status, "OFFLINE");
95 };
96
97 gdk_threads_enter();
98 gtk_label_set_text(GTK_LABEL (player->label_tc_cur), tc_cur);
99 gtk_label_set_text(GTK_LABEL (player->label_tc_rem), tc_rem);
100 gtk_label_set_text(GTK_LABEL (player->label_state), state);
101 gtk_label_set_text(GTK_LABEL (player->label_status), status);
102 gtk_label_set_text(GTK_LABEL (player->label_clip), clip);
103 gdk_flush();
104 gdk_threads_leave();
105
106 memcpy(prev, curr, sizeof(OmPlrStatus));
107 };
108
109 static void* omnplay_thread_proc(void* data)
110 {
111 int r;
112 OmPlrStatus st_curr, st_prev;
113 omnplay_player_t* player = (omnplay_player_t*)data;
114
115 /* connect */
116 pthread_mutex_lock(&player->app->players.lock);
117 r = OmPlrOpen(player->host, player->name, (OmPlrHandle*)&player->handle);
118 pthread_mutex_unlock(&player->app->players.lock);
119 if(r)
120 {
121 fprintf(stderr, "ERROR: OmPlrOpen(%s, %s) failed with 0x%.8X\n",
122 player->host, player->name, r);
123
124 return (void*)r;
125 };
126
127 /* setup to do not reconnect */
128 pthread_mutex_lock(&player->app->players.lock);
129 OmPlrSetRetryOpen((OmPlrHandle)player->handle, 0);
130 pthread_mutex_unlock(&player->app->players.lock);
131
132 /* setup directory */
133 if(player->app->players.path[0])
134 {
135 pthread_mutex_lock(&player->app->players.lock);
136 // r = OmPlrClipSetDirectory((OmPlrHandle)player->handle, player->app->players.path);
137 pthread_mutex_unlock(&player->app->players.lock);
138
139 if(r)
140 {
141 fprintf(stderr, "ERROR: OmPlrClipSetDirectory(%s) failed with 0x%.8X\n",
142 player->app->players.path, r);
143
144 pthread_mutex_lock(&player->app->players.lock);
145 OmPlrClose((OmPlrHandle)player->handle);
146 pthread_mutex_unlock(&player->app->players.lock);
147
148 return (void*)r;
149 };
150 };
151
152 /* endless loop */
153 for(r = 0 ; !player->app->f_exit && !r;)
154 {
155 /* sleep */
156 usleep(100000);
157
158 /* get status */
159 pthread_mutex_lock(&player->app->players.lock);
160 st_curr.size = sizeof(OmPlrStatus);
161 r = OmPlrGetPlayerStatus((OmPlrHandle)player->handle, &st_curr);
162 pthread_mutex_unlock(&player->app->players.lock);
163
164 if(r)
165 fprintf(stderr, "ERROR: OmPlrGetPlayerStatus failed with 0x%.8X\n", r);
166 else
167 if(memcmp(&st_curr, &st_prev, sizeof(OmPlrStatus)))
168 omnplay_update_status(player, &st_prev , &st_curr);
169 };
170
171 pthread_mutex_lock(&player->app->players.lock);
172 OmPlrClose((OmPlrHandle)player->handle);
173 pthread_mutex_unlock(&player->app->players.lock);
174
175 return NULL;
176 };
177
178 static void omnplay_cue(omnplay_instance_t* app)
179 {
180 int idx, start, stop;
181 GtkTreeIter iter;
182 GtkTreeModel *model;
183 GtkTreeSelection *selection;
184 omnplay_player_t *player;
185
186 pthread_mutex_lock(&app->playlist.lock);
187
188 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(app->playlist_grid));
189 if(selection && gtk_tree_selection_get_selected(selection, &model, &iter))
190 {
191 gtk_tree_model_get(model, &iter, 7, &idx, -1);
192
193 fprintf(stderr, "cue: selected item is %d\n", idx);
194
195 for(start = idx; start >= 0; start--)
196 if(app->playlist.item[start].type & OMNPLAY_PLAYLIST_BLOCK_BEGIN)
197 break;
198
199 for(stop = idx; stop < app->playlist.count; stop++)
200 if(app->playlist.item[stop].type & OMNPLAY_PLAYLIST_BLOCK_END)
201 break;
202
203 /* check block range */
204 if(start >= 0 && stop < app->playlist.count)
205 {
206 fprintf(stderr, "cue: range %d -> %d\n", start, stop);
207
208 /* check player range */
209 if(app->playlist.item[start].player > -1 && app->playlist.item[start].player < player->app->players.count)
210 {
211 player = &app->players.item[app->playlist.item[start].player];
212
213 /* 1. stop */
214 pthread_mutex_lock(&app->players.lock);
215 OmPlrStop((OmPlrHandle)player->handle);
216 pthread_mutex_unlock(&app->players.lock);
217
218 /* 2. detach previous clips */
219 pthread_mutex_lock(&app->players.lock);
220 OmPlrDetachAllClips((OmPlrHandle)player->handle);
221 pthread_mutex_unlock(&app->players.lock);
222
223 // http://research.m1stereo.tv/viewvc-int/viewvc.cgi/Ingest2Srv/trunk/SrvPlayCtl.cpp?view=markup
224 };
225 };
226 };
227
228 pthread_mutex_unlock(&app->playlist.lock);
229
230 };
231
232 static gboolean omnplay_button_click(omnplay_instance_t* app, control_buttons_t button)
233 {
234 switch(button)
235 {
236 case BUTTON_PLAYLIST_ITEM_ADD:
237 case BUTTON_PLAYLIST_ITEM_DEL:
238 case BUTTON_PLAYLIST_ITEM_EDIT:
239 case BUTTON_PLAYLIST_LOAD:
240 omnplay_playlist_load(app);
241 break;
242 case BUTTON_PLAYLIST_SAVE:
243 omnplay_playlist_save(app);
244 break;
245 case BUTTON_PLAYLIST_BLOCK_SINGLE:
246 case BUTTON_PLAYLIST_BLOCK_LOOP:
247 case BUTTON_PLAYLIST_ITEM_UP:
248 case BUTTON_PLAYLIST_ITEM_DOWN:
249 case BUTTON_PLAYER_CUE:
250 omnplay_cue(app);
251 case BUTTON_PLAYER_PLAY:
252 case BUTTON_PLAYER_PAUSE:
253 case BUTTON_PLAYER_STOP:
254 case BUTTON_LIBRARY_ADD:
255 case BUTTON_LIBRARY_REFRESH:
256 break;
257 };
258
259 return TRUE;
260 };
261
262 static gboolean on_button_click(GtkWidget *button, gpointer user_data)
263 {
264 int i;
265 omnplay_instance_t* app = (omnplay_instance_t*)user_data;
266
267 for(i = 1; i < BUTTON_LAST; i++)
268 if(app->buttons[i] == button)
269 return omnplay_button_click(app, (control_buttons_t)i);
270
271 return FALSE;
272 };
273
274 void omnplay_init(omnplay_instance_t* app)
275 {
276 int i;
277
278 gtk_signal_connect( GTK_OBJECT( app->window ), "destroy",
279 GTK_SIGNAL_FUNC(on_main_window_delete_event), app);
280
281 /* create lock */
282 pthread_mutex_init(&app->players.lock, NULL);
283
284 /* create a omneon status thread */
285 for(i = 0; i < app->players.count; i++)
286 pthread_create(&app->players.item[i].thread, NULL,
287 omnplay_thread_proc, &app->players.item[i]);
288
289 /* create lock */
290 pthread_mutex_init(&app->playlist.lock, NULL);
291
292 /* attach buttons click */
293 for(i = 1; i < BUTTON_LAST; i++)
294 gtk_signal_connect(GTK_OBJECT(app->buttons[i]), "clicked",
295 GTK_SIGNAL_FUNC( on_button_click), app );
296
297 };
298
299 void omnplay_release(omnplay_instance_t* app)
300 {
301 int i;
302 void* r;
303
304 app->f_exit = 1;
305
306 for(i = 0; i < app->players.count; i++)
307 /* create a omneon status thread */
308 pthread_join(app->players.item[i].thread, &r);
309
310 /* destroy lock */
311 pthread_mutex_destroy(&app->players.lock);
312
313 /* destroy lock */
314 pthread_mutex_destroy(&app->playlist.lock);
315 };