add winsock support
[melted_gui] / src / player.c
1 /*
2 * player.h -- GTK+ 2 melted gui
3 * Copyright (C) 2012 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 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <gtk/gtk.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <pthread.h>
34
35 #include <mvcp/mvcp.h>
36 #include <mvcp/mvcp_remote.h>
37
38 #if defined(__MINGW32__)
39 #include <windows.h>
40 #endif
41
42 #include "player.h"
43 #include "ui.h"
44 #include "timecode.h"
45 #include "playlist.h"
46
47 static char* status_to_text(mvcp_status status)
48 {
49 switch(status->status)
50 {
51 case unit_offline: return "offline"; break;
52 case unit_undefined: return "undefined"; break;
53 case unit_not_loaded: return "unloaded"; break;
54 case unit_stopped: return "stopped"; break;
55 case unit_playing: return "playing"; break;
56 case unit_paused: return "paused"; break;
57 case unit_disconnected: return "disconnect"; break;
58 case unit_unknown: return "unknown"; break;
59 }
60 return "unknown";
61 }
62
63 typedef struct player_handle_desc
64 {
65 mvcp_parser parser;
66 mvcp command;
67 mvcp status;
68 } player_handle_t;
69
70 static void player_update_status(player_t* player, mvcp_status_t *status_prev , mvcp_status_t *status_curr,
71 int *playlist_start_prev)
72 {
73 int idx;
74 char tc_cur[32], tc_rem[32], *state, status[32], *clip;
75
76 if(status_curr->status == unit_disconnected)
77 {
78 tc_cur[0] = 0;
79 tc_rem[0] = 0;
80 clip = "";
81 state = "";
82 strcpy(status, "OFFLINE");
83 }
84 else
85 {
86 int p = status_curr->start + (status_curr->position - status_curr->in);
87
88 frames2tc(p, 25.0, tc_cur);
89 frames2tc(status_curr->dur - p, 25.0, tc_rem);
90 clip = strrchr(status_curr->clip, '/');
91 if(clip)
92 clip++;
93 else
94 clip = status_curr->clip;
95 state = status_to_text(status_curr);
96 strcpy(status, "ONLINE");
97 };
98
99 ui_update_player(player, tc_cur, tc_rem, state, status, clip);
100
101 /* update remaining time of playlist's item */
102 pthread_mutex_lock(&player->app->playlist.lock);
103 pthread_mutex_lock(&player->app->players.lock);
104 if(player->playlist_length)
105 {
106 /* clear remain on "previous" item */
107 if((status_curr->clip_index != status_prev->clip_index && 1 != player->playlist_length) ||
108 (*playlist_start_prev != player->playlist_start))
109 {
110 tc_rem[0] = 0;
111 idx = playlist_item_index /* find_index_of_playlist_item */(player->app, *playlist_start_prev, status_prev->clip_index);
112 if(idx >= 0)
113 ui_playlist_draw_item_rem(player->app, idx, tc_rem);
114 };
115
116 /* update current item */
117 idx = playlist_item_index /* find_index_of_playlist_item */(player->app, player->playlist_start, status_curr->clip_index);
118 if(idx >= 0)
119 {
120 /* reset value */
121 tc_rem[0] = 0;
122
123 /* for play and cue calc new value */
124 if(/*status_curr->status == unit_stopped || */ status_curr->status == unit_playing || status_curr->status == unit_paused)
125 frames2tc(status_curr->out - status_curr->position, 25.0, tc_rem);
126
127 /* setup that value */
128 ui_playlist_draw_item_rem(player->app, idx, tc_rem);
129 };
130 };
131 pthread_mutex_unlock(&player->app->players.lock);
132 pthread_mutex_unlock(&player->app->playlist.lock);
133 };
134
135 static void* player_thread_proc(void* data)
136 {
137 int r, f;
138 int playlist_start_prev = 0;
139 mvcp_status_t status_curr, status_prev;
140 player_t* player = (player_t*)data;
141 player_handle_t* handle = player->handle;
142 mvcp_notifier notifier = mvcp_get_notifier(handle->status);
143
144 g_warning("player_thread_proc: started (player=%d, unit=%d)\n", player->idx, player->unit);
145
146 // memset(&st_curr, 0, sizeof(OmPlrStatus));
147 // memset(&st_prev, 0, sizeof(OmPlrStatus));
148
149 /* endless reconnect loop */
150 for(; !player->app->f_exit;)
151 {
152 r = mvcp_connect(handle->command);
153 /* connect */
154 if(mvcp_ok != r)
155 {
156 g_warning("player_thread_proc: failed to connect to server %s:%d (player=%d, unit=%d), r=%d\n",
157 player->app->players.host, player->app->players.port, player->idx, player->unit, r);
158 #if defined(__MINGW32__)
159 Sleep(1000);
160 #else
161 sleep(1);
162 #endif
163 continue;
164 };
165
166 g_warning("player_thread_proc: connected to server %s (player=%d, unit=%d)\n",
167 player->app->players.host, player->idx, player->unit);
168
169 /* status request loop */
170 for(r = 0, f = 0; !player->app->f_exit && !r;)
171 {
172 int c;
173
174 /* wait for any event from notifier */
175 mvcp_notifier_wait(notifier, &status_curr);
176
177 /* get status for our unit */
178 if(player->unit != status_curr.unit)
179 mvcp_notifier_get(notifier, &status_curr, player->unit);
180
181 /* notify about exit from loop and reconnect */
182 if(status_curr.status == unit_disconnected)
183 {
184 r = 1;
185 continue;
186 };
187
188 /* do we need to update status */
189 c = memcmp(&status_curr, &status_prev, sizeof(mvcp_status_t));
190 if(!c && f)
191 continue;
192
193 /* call update func */
194 player_update_status(player, &status_prev , &status_curr, &playlist_start_prev);
195 playlist_start_prev = player->playlist_start;
196 status_prev = status_curr;
197 f = 1;
198 };
199 };
200
201 pthread_mutex_lock(&player->app->players.lock);
202 // OmPlrClose((OmPlrHandle)player->handle);
203 pthread_mutex_unlock(&player->app->players.lock);
204
205 return NULL;
206 };
207
208
209 void player_run(instance_t* app, int idx)
210 {
211 player_handle_t* handle = malloc(sizeof(player_handle_t));
212 handle->parser = mvcp_parser_init_remote(app->players.host, app->players.port);
213 handle->status = mvcp_init(handle->parser);
214 handle->command = mvcp_init(handle->parser);
215 app->players.item[idx].handle = handle;
216 app->players.item[idx].thread = g_thread_create(
217 player_thread_proc, &app->players.item[idx], TRUE, NULL);
218 };
219
220 void player_stop(instance_t* app, int idx)
221 {
222 player_handle_t* handle = app->players.item[idx].handle;
223 g_thread_join(app->players.item[idx].thread);
224 mvcp_close(handle->status);
225 mvcp_close(handle->command);
226 mvcp_parser_close(handle->parser);
227 free(handle);
228 };