static void *DemuxThread( void *p_data ) { demux_t *p_demux = (demux_t *) p_data; demux_sys_t *p_sys = p_demux->p_sys; vlc_tick_t i_next_frame_date = vlc_tick_now() + p_sys->i_frame_interval; int i_status; for(;;) { p_sys->i_cancel_state = vlc_savecancel(); i_status = WaitForMessage( p_sys->p_client, p_sys->i_frame_interval ); vlc_restorecancel( p_sys->i_cancel_state ); /* Ensure we're not building frames too fast */ /* as WaitForMessage takes only a maximum wait */ vlc_tick_wait( i_next_frame_date ); i_next_frame_date += p_sys->i_frame_interval; if ( i_status > 0 ) { p_sys->p_client->frameBuffer = p_sys->p_block->p_buffer; p_sys->i_cancel_state = vlc_savecancel(); i_status = HandleRFBServerMessage( p_sys->p_client ); vlc_restorecancel( p_sys->i_cancel_state ); if ( ! i_status ) { msg_Warn( p_demux, "Cannot get announced data. Server closed ?" ); es_out_Del( p_demux->out, p_sys->es ); p_sys->es = NULL; return NULL; } else { block_t *p_block = block_Duplicate( p_sys->p_block ); if ( p_block ) /* drop frame/content if no next block */ { p_sys->p_block->i_dts = p_sys->p_block->i_pts = vlc_tick_now(); es_out_SetPCR( p_demux->out, p_sys->p_block->i_pts ); es_out_Send( p_demux->out, p_sys->es, p_sys->p_block ); p_sys->p_block = p_block; } } } } return NULL; }
/***************************************************************************** * Demux: *****************************************************************************/ static void *DemuxThread( void *p_data ) { demux_t *p_demux = (demux_t *) p_data; demux_sys_t *p_sys = p_demux->p_sys; p_sys->i_starttime = vlc_tick_now(); vlc_tick_t i_next_frame_date = vlc_tick_now() + p_sys->i_frame_interval; int i_ret; for(;;) { i_ret = 0; p_sys->i_cancel_state = vlc_savecancel(); if ( freerdp_shall_disconnect( p_sys->p_instance ) ) { vlc_restorecancel( p_sys->i_cancel_state ); msg_Warn( p_demux, "RDP server closed session" ); es_out_Del( p_demux->out, p_sys->es ); p_sys->es = NULL; return NULL; } struct { void* pp_rfds[RDP_MAX_FD]; /* Declared by rdp */ void* pp_wfds[RDP_MAX_FD]; int i_nbr; int i_nbw; struct pollfd ufds[RDP_MAX_FD]; } fds; fds.i_nbr = fds.i_nbw = 0; if ( freerdp_get_fds( p_sys->p_instance, fds.pp_rfds, &fds.i_nbr, fds.pp_wfds, &fds.i_nbw ) != true ) { vlc_restorecancel( p_sys->i_cancel_state ); msg_Err( p_demux, "cannot get FDS" ); } else if ( (fds.i_nbr + fds.i_nbw) > 0 && p_sys->es ) { vlc_restorecancel( p_sys->i_cancel_state ); int i_count = 0; for( int i = 0; i < fds.i_nbr; i++ ) { fds.ufds[ i_count ].fd = (long) fds.pp_rfds[ i ]; fds.ufds[ i_count ].events = POLLIN ; fds.ufds[ i_count++ ].revents = 0; } for( int i = 0; i < fds.i_nbw && i_count < RDP_MAX_FD; i++ ) { /* may be useless */ fds.ufds[ i_count ].fd = (long) fds.pp_wfds[ i ]; fds.ufds[ i_count ].events = POLLOUT; fds.ufds[ i_count++ ].revents = 0; } i_ret = poll( fds.ufds, i_count, p_sys->i_frame_interval * 1000/2 ); } else { vlc_restorecancel( p_sys->i_cancel_state ); } vlc_tick_wait( i_next_frame_date ); i_next_frame_date += p_sys->i_frame_interval; if ( i_ret >= 0 ) { /* Do the rendering */ p_sys->i_cancel_state = vlc_savecancel(); freerdp_check_fds( p_sys->p_instance ); vlc_restorecancel( p_sys->i_cancel_state ); block_t *p_block = block_Duplicate( p_sys->p_block ); if (likely( p_block && p_sys->p_block )) { p_sys->p_block->i_dts = p_sys->p_block->i_pts = vlc_tick_now() - p_sys->i_starttime; es_out_SetPCR( p_demux->out, p_sys->p_block->i_pts ); es_out_Send( p_demux->out, p_sys->es, p_sys->p_block ); p_sys->p_block = p_block; } } } return NULL; }
/***************************************************************************** * Run : call Handshake() then submit songs *****************************************************************************/ static void *Run(void *data) { intf_thread_t *p_intf = data; uint8_t p_buffer[1024]; int canc = vlc_savecancel(); bool b_handshaked = false; bool b_nowp_submission_ongoing = false; /* data about audioscrobbler session */ vlc_tick_t next_exchange = VLC_TICK_INVALID; /**< when can we send data */ unsigned int i_interval = 0; /**< waiting interval (secs)*/ intf_sys_t *p_sys = p_intf->p_sys; /* main loop */ for (;;) { vlc_restorecancel(canc); if (next_exchange != VLC_TICK_INVALID) vlc_tick_wait(next_exchange); vlc_mutex_lock(&p_sys->lock); mutex_cleanup_push(&p_sys->lock); while (p_sys->i_songs == 0 && p_sys->b_submit_nowp == false) vlc_cond_wait(&p_sys->wait, &p_sys->lock); vlc_cleanup_pop(); vlc_mutex_unlock(&p_sys->lock); canc = vlc_savecancel(); /* handshake if needed */ if (!b_handshaked) { msg_Dbg(p_intf, "Handshaking with last.fm ..."); switch(Handshake(p_intf)) { case VLC_ENOMEM: goto out; case VLC_ENOVAR: /* username not set */ vlc_dialog_display_error(p_intf, _("Last.fm username not set"), "%s", _("Please set a username or disable the " "audioscrobbler plugin, and restart VLC.\n" "Visit http://www.last.fm/join/ to get an account.")); goto out; case VLC_SUCCESS: msg_Dbg(p_intf, "Handshake successful :)"); b_handshaked = true; i_interval = 0; next_exchange = VLC_TICK_INVALID; break; case VLC_AUDIOSCROBBLER_EFATAL: msg_Warn(p_intf, "Exiting..."); goto out; case VLC_EGENERIC: default: /* protocol error : we'll try later */ HandleInterval(&next_exchange, &i_interval); break; } /* if handshake failed let's restart the loop */ if (!b_handshaked) continue; } msg_Dbg(p_intf, "Going to submit some data..."); vlc_url_t *url; struct vlc_memstream req, payload; vlc_memstream_open(&payload); vlc_memstream_printf(&payload, "s=%s", p_sys->psz_auth_token); /* forge the HTTP POST request */ vlc_mutex_lock(&p_sys->lock); if (p_sys->b_submit_nowp) { audioscrobbler_song_t *p_song = &p_sys->p_current_song; b_nowp_submission_ongoing = true; url = &p_sys->p_nowp_url; vlc_memstream_printf(&payload, "&a=%s", p_song->psz_a); vlc_memstream_printf(&payload, "&t=%s", p_song->psz_t); vlc_memstream_puts(&payload, "&b="); if (p_song->psz_b != NULL) vlc_memstream_puts(&payload, p_song->psz_b); vlc_memstream_printf(&payload, "&l=%d", p_song->i_l); vlc_memstream_puts(&payload, "&n="); if (p_song->psz_n != NULL) vlc_memstream_puts(&payload, p_song->psz_n); vlc_memstream_puts(&payload, "&m="); if (p_song->psz_m != NULL) vlc_memstream_puts(&payload, p_song->psz_m); } else { url = &p_sys->p_submit_url; for (int i_song = 0 ; i_song < p_sys->i_songs ; i_song++) { audioscrobbler_song_t *p_song = &p_sys->p_queue[i_song]; vlc_memstream_printf(&payload, "&a%%5B%d%%5D=%s", i_song, p_song->psz_a); vlc_memstream_printf(&payload, "&t%%5B%d%%5D=%s", i_song, p_song->psz_t); vlc_memstream_printf(&payload, "&i%%5B%d%%5D=%"PRIu64, i_song, (uint64_t)p_song->date); vlc_memstream_printf(&payload, "&o%%5B%d%%5D=P", i_song); vlc_memstream_printf(&payload, "&r%%5B%d%%5D=", i_song); vlc_memstream_printf(&payload, "&l%%5B%d%%5D=%d", i_song, p_song->i_l); vlc_memstream_printf(&payload, "&b=%%5B%d%%5D=", i_song); if (p_song->psz_b != NULL) vlc_memstream_puts(&payload, p_song->psz_b); vlc_memstream_printf(&payload, "&n=%%5B%d%%5D=", i_song); if (p_song->psz_n != NULL) vlc_memstream_puts(&payload, p_song->psz_n); vlc_memstream_printf(&payload, "&m=%%5B%d%%5D=", i_song); if (p_song->psz_m != NULL) vlc_memstream_puts(&payload, p_song->psz_m); } } vlc_mutex_unlock(&p_sys->lock); if (vlc_memstream_close(&payload)) goto out; vlc_memstream_open(&req); vlc_memstream_printf(&req, "POST %s HTTP/1.1\r\n", url->psz_path); vlc_memstream_printf(&req, "Host: %s\r\n", url->psz_host); vlc_memstream_puts(&req, "User-Agent:" " "PACKAGE_NAME"/"PACKAGE_VERSION"\r\n"); vlc_memstream_puts(&req, "Connection: close\r\n"); vlc_memstream_puts(&req, "Accept-Encoding: identity\r\n"); vlc_memstream_puts(&req, "Content-Type:" " application/x-www-form-urlencoded\r\n"); vlc_memstream_printf(&req, "Content-Length: %zu\r\n", payload.length); vlc_memstream_puts(&req, "\r\n"); /* Could avoid copying payload with iovec... but efforts */ vlc_memstream_write(&req, payload.ptr, payload.length); vlc_memstream_puts(&req, "\r\n\r\n"); free(payload.ptr); if (vlc_memstream_close(&req)) /* Out of memory */ goto out; vlc_tls_t *sock = vlc_tls_SocketOpenTCP(VLC_OBJECT(p_intf), url->psz_host, url->i_port); if (sock == NULL) { /* If connection fails, we assume we must handshake again */ HandleInterval(&next_exchange, &i_interval); b_handshaked = false; free(req.ptr); continue; } /* we transmit the data */ int i_net_ret = vlc_tls_Write(sock, req.ptr, req.length); free(req.ptr); if (i_net_ret == -1) { /* If connection fails, we assume we must handshake again */ HandleInterval(&next_exchange, &i_interval); b_handshaked = false; vlc_tls_Close(sock); continue; } /* FIXME: this might wait forever */ /* FIXME: With TCP, you should never assume that a single read will * return the entire response... */ i_net_ret = vlc_tls_Read(sock, p_buffer, sizeof(p_buffer) - 1, false); vlc_tls_Close(sock); if (i_net_ret <= 0) { /* if we get no answer, something went wrong : try again */ continue; } p_buffer[i_net_ret] = '\0'; char *failed = strstr((char *) p_buffer, "FAILED"); if (failed) { msg_Warn(p_intf, "%s", failed); HandleInterval(&next_exchange, &i_interval); continue; } if (strstr((char *) p_buffer, "BADSESSION")) { msg_Err(p_intf, "Authentication failed (BADSESSION), are you connected to last.fm with another program ?"); b_handshaked = false; HandleInterval(&next_exchange, &i_interval); continue; } if (strstr((char *) p_buffer, "OK")) { if (b_nowp_submission_ongoing) { b_nowp_submission_ongoing = false; p_sys->b_submit_nowp = false; } else { for (int i = 0; i < p_sys->i_songs; i++) DeleteSong(&p_sys->p_queue[i]); p_sys->i_songs = 0; } i_interval = 0; next_exchange = VLC_TICK_INVALID; msg_Dbg(p_intf, "Submission successful!"); } else { msg_Err(p_intf, "Authentication failed, handshaking again (%s)", p_buffer); b_handshaked = false; HandleInterval(&next_exchange, &i_interval); } } out: vlc_restorecancel(canc); return NULL; }