/* * player.h -- GTK+ 2 melted gui * Copyright (C) 2012 Maksym Veremeyenko * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #if defined(__MINGW32__) #include #endif #include "player.h" #include "ui.h" #include "timecode.h" #include "playlist.h" static char* status_to_text(mvcp_status status) { switch(status->status) { case unit_offline: return "offline"; break; case unit_undefined: return "undefined"; break; case unit_not_loaded: return "unloaded"; break; case unit_stopped: return "stopped"; break; case unit_playing: return "playing"; break; case unit_paused: return "paused"; break; case unit_disconnected: return "disconnect"; break; case unit_unknown: return "unknown"; break; } return "unknown"; } typedef struct player_handle_desc { mvcp_parser parser; mvcp command; mvcp status; } player_handle_t; static void player_update_status(player_t* player, mvcp_status_t *status_prev , mvcp_status_t *status_curr, int *playlist_start_prev) { int idx; char tc_cur[32], tc_rem[32], *state, status[32], *clip; if(status_curr->status == unit_disconnected) { tc_cur[0] = 0; tc_rem[0] = 0; clip = ""; state = ""; strcpy(status, "OFFLINE"); } else { int p = status_curr->start + (status_curr->position - status_curr->in); frames2tc(p, 25.0, tc_cur); frames2tc(status_curr->dur - p, 25.0, tc_rem); clip = strrchr(status_curr->clip, '/'); if(clip) clip++; else clip = status_curr->clip; state = status_to_text(status_curr); strcpy(status, "ONLINE"); }; ui_update_player(player, tc_cur, tc_rem, state, status, clip); /* update remaining time of playlist's item */ pthread_mutex_lock(&player->app->playlist.lock); pthread_mutex_lock(&player->app->players.lock); if(player->playlist_length) { /* clear remain on "previous" item */ if((status_curr->clip_index != status_prev->clip_index && 1 != player->playlist_length) || (*playlist_start_prev != player->playlist_start)) { tc_rem[0] = 0; idx = playlist_item_index /* find_index_of_playlist_item */(player->app, *playlist_start_prev, status_prev->clip_index); if(idx >= 0) ui_playlist_draw_item_rem(player->app, idx, tc_rem); }; /* update current item */ idx = playlist_item_index /* find_index_of_playlist_item */(player->app, player->playlist_start, status_curr->clip_index); if(idx >= 0) { /* reset value */ tc_rem[0] = 0; /* for play and cue calc new value */ if(/*status_curr->status == unit_stopped || */ status_curr->status == unit_playing || status_curr->status == unit_paused) frames2tc(status_curr->out - status_curr->position, 25.0, tc_rem); /* setup that value */ ui_playlist_draw_item_rem(player->app, idx, tc_rem); }; }; pthread_mutex_unlock(&player->app->players.lock); pthread_mutex_unlock(&player->app->playlist.lock); }; static void* player_thread_proc(void* data) { int r, f; int playlist_start_prev = 0; mvcp_status_t status_curr, status_prev; player_t* player = (player_t*)data; player_handle_t* handle = player->handle; mvcp_notifier notifier = mvcp_get_notifier(handle->status); g_warning("player_thread_proc: started (player=%d, unit=%d)\n", player->idx, player->unit); // memset(&st_curr, 0, sizeof(OmPlrStatus)); // memset(&st_prev, 0, sizeof(OmPlrStatus)); /* endless reconnect loop */ for(; !player->app->f_exit;) { r = mvcp_connect(handle->command); /* connect */ if(mvcp_ok != r) { g_warning("player_thread_proc: failed to connect to server %s:%d (player=%d, unit=%d), r=%d\n", player->app->players.host, player->app->players.port, player->idx, player->unit, r); #if defined(__MINGW32__) Sleep(1000); #else sleep(1); #endif continue; }; g_warning("player_thread_proc: connected to server %s (player=%d, unit=%d)\n", player->app->players.host, player->idx, player->unit); /* status request loop */ for(r = 0, f = 0; !player->app->f_exit && !r;) { int c; /* wait for any event from notifier */ mvcp_notifier_wait(notifier, &status_curr); /* get status for our unit */ if(player->unit != status_curr.unit) mvcp_notifier_get(notifier, &status_curr, player->unit); /* notify about exit from loop and reconnect */ if(status_curr.status == unit_disconnected) { r = 1; continue; }; /* do we need to update status */ c = memcmp(&status_curr, &status_prev, sizeof(mvcp_status_t)); if(!c && f) continue; /* call update func */ player_update_status(player, &status_prev , &status_curr, &playlist_start_prev); playlist_start_prev = player->playlist_start; status_prev = status_curr; f = 1; }; }; pthread_mutex_lock(&player->app->players.lock); // OmPlrClose((OmPlrHandle)player->handle); pthread_mutex_unlock(&player->app->players.lock); return NULL; }; void player_run(instance_t* app, int idx) { player_handle_t* handle = malloc(sizeof(player_handle_t)); handle->parser = mvcp_parser_init_remote(app->players.host, app->players.port); handle->status = mvcp_init(handle->parser); handle->command = mvcp_init(handle->parser); app->players.item[idx].handle = handle; app->players.item[idx].thread = g_thread_create( player_thread_proc, &app->players.item[idx], TRUE, NULL); }; void player_stop(instance_t* app, int idx) { player_handle_t* handle = app->players.item[idx].handle; g_thread_join(app->players.item[idx].thread); mvcp_close(handle->status); mvcp_close(handle->command); mvcp_parser_close(handle->parser); free(handle); };