2022-07-15 15:37:19 +00:00
# include "MediaPlayCtrl.h"
# include "Widgets/Button.hpp"
# include "Widgets/CheckBox.hpp"
# include "Widgets/Label.hpp"
# include "GUI_App.hpp"
# include "libslic3r/AppConfig.hpp"
# include "I18N.hpp"
2022-09-19 01:50:34 +00:00
# include "MsgDialog.hpp"
# include "DownloadProgressDialog.hpp"
2022-12-16 00:07:22 +00:00
# include <boost/filesystem/string_file.hpp>
2023-12-21 09:10:46 +00:00
# include <boost/lexical_cast.hpp>
# include <boost/log/trivial.hpp>
# include <boost/nowide/cstdio.hpp>
2023-11-01 08:08:09 +00:00
# include <boost/nowide/utf8_codecvt.hpp>
2022-09-19 01:50:34 +00:00
# undef pid_t
# include <boost/process.hpp>
# ifdef __WIN32__
# include <boost/process/windows.hpp>
2023-02-02 08:41:34 +00:00
# else
2022-09-19 01:50:34 +00:00
# include <sys/ipc.h>
# include <sys/shm.h>
# endif
2024-07-09 11:51:41 +00:00
# ifdef __APPLE__
# include <ApplicationServices/ApplicationServices.h>
# endif
2022-07-15 15:37:19 +00:00
2023-12-21 09:10:46 +00:00
# include <wx/clipbrd.h>
2024-01-17 12:01:13 +00:00
# include "wx/evtloop.h"
2023-12-21 09:10:46 +00:00
2024-01-10 01:03:34 +00:00
static std : : map < int , std : : string > error_messages = {
{ 1 , L ( " The device cannot handle more conversations. Please retry later. " ) } ,
{ 2 , L ( " Player is malfunctioning. Please reinstall the system player. " ) } ,
{ 100 , L ( " The player is not loaded, please click \" play \" button to retry. " ) } ,
{ 101 , L ( " The player is not loaded, please click \" play \" button to retry. " ) } ,
{ 102 , L ( " The player is not loaded, please click \" play \" button to retry. " ) } ,
{ 103 , L ( " The player is not loaded, please click \" play \" button to retry. " ) }
} ;
2022-07-15 15:37:19 +00:00
namespace Slic3r {
namespace GUI {
2024-07-09 11:51:41 +00:00
static int SecondsSinceLastInput ( ) ;
2024-10-15 07:44:29 +00:00
MediaPlayCtrl : : MediaPlayCtrl ( wxWindow * parent , wxMediaCtrl3 * media_ctrl , const wxPoint & pos , const wxSize & size )
2022-07-15 15:37:19 +00:00
: wxPanel ( parent , wxID_ANY , pos , size )
, m_media_ctrl ( media_ctrl )
{
2023-11-14 02:48:35 +00:00
SetLabel ( " MediaPlayCtrl " ) ;
2022-07-15 15:37:19 +00:00
SetBackgroundColour ( * wxWHITE ) ;
m_media_ctrl - > Bind ( wxEVT_MEDIA_STATECHANGED , & MediaPlayCtrl : : onStateChanged , this ) ;
2024-06-26 11:51:59 +00:00
m_media_ctrl - > SetIdleImage ( from_u8 ( resources_dir ( ) + " /images/live_stream_default.png " ) ) ;
2022-07-15 15:37:19 +00:00
m_button_play = new Button ( this , " " , " media_play " , wxBORDER_NONE ) ;
2022-08-26 01:39:45 +00:00
m_button_play - > SetCanFocus ( false ) ;
2022-07-15 15:37:19 +00:00
2022-12-15 10:18:01 +00:00
m_label_status = new Label ( this , " " ) ;
2023-05-30 12:59:07 +00:00
m_label_status - > SetForegroundColour ( wxColour ( " #323A3C " ) ) ;
2022-07-15 15:37:19 +00:00
2023-11-21 04:17:24 +00:00
m_label_stat = new Label ( this , " " ) ;
m_label_stat - > SetForegroundColour ( wxColour ( " #323A3C " ) ) ;
m_media_ctrl - > Bind ( EVT_MEDIA_CTRL_STAT , [ this ] ( auto & e ) {
2024-01-30 10:09:19 +00:00
# if !BBL_RELEASE_TO_PUBLIC
2023-12-01 01:58:53 +00:00
wxSize size = m_media_ctrl - > GetVideoSize ( ) ;
2024-10-15 07:44:29 +00:00
m_label_stat - > SetLabel ( e . GetString ( ) + wxString : : Format ( " VS:%ix%i LD:%i " , size . x , size . y , m_load_duration ) ) ;
2023-11-21 04:17:24 +00:00
# endif
2024-01-30 10:09:19 +00:00
wxString str = e . GetString ( ) ;
m_stat . clear ( ) ;
for ( auto k : { " FPS: " , " BPS: " , " T: " , " B: " } ) {
auto ik = str . Find ( k ) ;
double value = 0 ;
if ( ik ! = wxString : : npos ) {
ik + = strlen ( k ) ;
auto ip = str . find ( ' ' , ik ) ;
if ( ip = = wxString : : npos ) ip = str . Length ( ) ;
auto v = str . Mid ( ik , ip - ik ) ;
if ( k = = " T: " & & v . Length ( ) = = 8 ) {
long h = 0 , m = 0 , s = 0 ;
v . Left ( 2 ) . ToLong ( & h ) ;
v . Mid ( 3 , 2 ) . ToLong ( & m ) ;
v . Mid ( 6 , 2 ) . ToLong ( & s ) ;
value = h * 3600. + m * 60 + s ;
} else {
v . ToDouble ( & value ) ;
if ( v . Right ( 1 ) = = " K " ) value * = 1024 ;
else if ( v . Right ( 1 ) = = " % " ) value * = 0.01 ;
}
}
m_stat . push_back ( value ) ;
}
} ) ;
2023-11-21 04:17:24 +00:00
2022-09-19 01:50:34 +00:00
m_button_play - > Bind ( wxEVT_COMMAND_BUTTON_CLICKED , [ this ] ( auto & e ) { TogglePlay ( ) ; } ) ;
2022-07-15 15:37:19 +00:00
m_button_play - > Bind ( wxEVT_RIGHT_UP , [ this ] ( auto & e ) { m_media_ctrl - > Play ( ) ; } ) ;
2022-09-09 07:05:59 +00:00
m_label_status - > Bind ( wxEVT_LEFT_UP , [ this ] ( auto & e ) {
auto url = wxString : : Format ( L " https://wiki.bambulab.com/%s/software/bambu-studio/faq/live-view " , L " en " ) ;
wxLaunchDefaultBrowser ( url ) ;
} ) ;
2022-07-15 15:37:19 +00:00
2023-08-24 02:04:39 +00:00
Bind ( wxEVT_RIGHT_UP , [ this ] ( auto & e ) {
wxClipboard & c = * wxTheClipboard ;
if ( c . Open ( ) ) {
if ( wxGetKeyState ( WXK_SHIFT ) ) {
if ( c . IsSupported ( wxDF_TEXT ) ) {
wxTextDataObject data ;
c . GetData ( data ) ;
Stop ( ) ;
m_url = data . GetText ( ) ;
load ( ) ;
}
} else {
c . SetData ( new wxTextDataObject ( m_url ) ) ;
}
c . Close ( ) ;
}
} ) ;
2022-07-15 15:37:19 +00:00
wxBoxSizer * sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
2022-08-26 01:39:45 +00:00
sizer - > Add ( m_button_play , 0 , wxEXPAND | wxALL , 0 ) ;
2023-11-21 04:17:24 +00:00
sizer - > Add ( m_label_stat , 0 , wxALIGN_CENTER_VERTICAL | wxLEFT , FromDIP ( 25 ) ) ;
2022-07-15 15:37:19 +00:00
sizer - > AddStretchSpacer ( 1 ) ;
sizer - > Add ( m_label_status , 0 , wxALIGN_CENTER_VERTICAL | wxRIGHT , FromDIP ( 25 ) ) ;
SetSizer ( sizer ) ;
m_thread = boost : : thread ( [ this ] {
media_proc ( ) ;
} ) ;
2022-08-26 01:39:45 +00:00
2022-09-13 01:42:16 +00:00
//#if BBL_RELEASE_TO_PUBLIC
// m_next_retry = wxDateTime::Now();
//#endif
2022-08-31 09:15:34 +00:00
2022-11-21 09:34:18 +00:00
parent - > Bind ( wxEVT_SHOW , & MediaPlayCtrl : : on_show_hide , this ) ;
parent - > GetParent ( ) - > GetParent ( ) - > Bind ( wxEVT_SHOW , & MediaPlayCtrl : : on_show_hide , this ) ;
2022-09-26 03:11:05 +00:00
m_lan_user = " bblp " ;
m_lan_passwd = " bblp " ;
2022-07-15 15:37:19 +00:00
}
MediaPlayCtrl : : ~ MediaPlayCtrl ( )
{
{
boost : : unique_lock lock ( m_mutex ) ;
m_tasks . push_back ( " <exit> " ) ;
m_cond . notify_all ( ) ;
}
2024-01-17 12:01:13 +00:00
while ( ! m_thread . try_join_for ( boost : : chrono : : milliseconds ( 10 ) ) ) {
wxEventLoopBase : : GetActive ( ) - > Yield ( ) ;
}
2022-07-15 15:37:19 +00:00
}
void MediaPlayCtrl : : SetMachineObject ( MachineObject * obj )
{
std : : string machine = obj ? obj - > dev_id : " " ;
2023-08-14 06:44:17 +00:00
if ( obj ) {
2023-05-12 00:45:28 +00:00
m_camera_exists = obj - > has_ipcam ;
2023-08-14 06:44:17 +00:00
m_dev_ver = obj - > get_ota_version ( ) ;
2023-05-12 00:45:28 +00:00
m_lan_mode = obj - > is_lan_mode_printer ( ) ;
2023-08-14 06:44:17 +00:00
m_lan_proto = obj - > liveview_local ;
2024-04-08 01:48:36 +00:00
m_remote_proto = obj - > liveview_remote ;
2023-05-12 00:45:28 +00:00
m_lan_ip = obj - > dev_ip ;
m_lan_passwd = obj - > get_access_code ( ) ;
m_device_busy = obj - > is_camera_busy_off ( ) ;
2023-05-17 06:05:23 +00:00
m_tutk_state = obj - > tutk_state ;
2022-09-26 03:11:05 +00:00
} else {
2022-09-30 09:54:12 +00:00
m_camera_exists = false ;
2022-09-26 03:11:05 +00:00
m_lan_mode = false ;
2023-08-14 06:44:17 +00:00
m_lan_proto = MachineObject : : LVL_None ;
2022-09-26 03:11:05 +00:00
m_lan_ip . clear ( ) ;
m_lan_passwd . clear ( ) ;
2023-08-03 02:19:35 +00:00
m_dev_ver . clear ( ) ;
2023-05-17 06:05:23 +00:00
m_tutk_state . clear ( ) ;
2024-04-08 01:48:36 +00:00
m_remote_proto = 0 ;
2023-01-18 07:00:09 +00:00
m_device_busy = false ;
2022-09-26 03:11:05 +00:00
}
2023-12-06 05:26:38 +00:00
Enable ( obj & & obj - > is_connected ( ) & & obj - > m_push_count > 0 ) ;
2022-07-15 15:37:19 +00:00
if ( machine = = m_machine ) {
2023-06-27 05:53:05 +00:00
if ( m_last_state = = MEDIASTATE_IDLE & & IsEnabled ( ) )
2022-07-15 15:37:19 +00:00
Play ( ) ;
2024-09-02 07:14:42 +00:00
if ( m_last_state = = wxMediaState : : wxMEDIASTATE_PLAYING ) {
auto now = std : : chrono : : system_clock : : now ( ) ;
if ( m_play_timer < = now ) {
m_play_timer = now + 1 min ;
2024-10-23 02:21:26 +00:00
# if BBL_RELEASE_TO_PUBLIC
2024-09-06 01:13:21 +00:00
if ( SecondsSinceLastInput ( ) > = 900 ) { // 15 min
auto close = wxGetApp ( ) . app_config - > get ( " liveview " , " auto_stop_liveview " ) = = " true " ;
if ( close ) {
2024-09-14 08:48:30 +00:00
m_next_retry = wxDateTime ( ) ;
2024-09-06 01:13:21 +00:00
Stop ( _L ( " Temporarily closed because there is no operating for a long time. " ) ) ;
return ;
}
}
2024-09-02 07:14:42 +00:00
auto obj = wxGetApp ( ) . getDeviceManager ( ) - > get_selected_machine ( ) ;
if ( obj & & obj - > is_in_printing ( ) ) {
m_print_idle = 0 ;
} else if ( + + m_print_idle > = 5 ) {
2024-09-14 08:48:30 +00:00
m_next_retry = wxDateTime ( ) ;
2024-09-06 01:13:21 +00:00
Stop ( _L ( " Temporarily closed because there is no printing for a while. " ) ) ;
2024-09-02 07:14:42 +00:00
}
2024-10-23 02:21:26 +00:00
# endif
2024-09-02 07:14:42 +00:00
}
2024-07-09 11:51:41 +00:00
}
2022-07-15 15:37:19 +00:00
return ;
}
m_machine = machine ;
2024-01-26 06:24:58 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl switch machine: " < < m_machine ;
2023-05-06 05:54:14 +00:00
m_disable_lan = false ;
2022-07-15 15:37:19 +00:00
m_failed_retry = 0 ;
2023-05-05 02:32:00 +00:00
m_last_failed_codes . clear ( ) ;
2023-07-12 10:18:57 +00:00
m_last_user_play = wxDateTime : : Now ( ) ;
2022-09-19 01:50:34 +00:00
std : : string stream_url ;
if ( get_stream_url ( & stream_url ) ) {
m_streaming = boost : : algorithm : : contains ( stream_url , " device= " + m_machine ) ;
} else {
m_streaming = false ;
}
2022-07-15 15:37:19 +00:00
if ( m_last_state ! = MEDIASTATE_IDLE )
2023-06-27 05:53:05 +00:00
Stop ( " " ) ;
2022-12-16 07:22:56 +00:00
if ( m_next_retry . IsValid ( ) ) // Try open 2 seconds later, to avoid state conflict
2023-07-10 07:16:08 +00:00
m_next_retry = wxDateTime : : Now ( ) + wxTimeSpan : : Seconds ( 2 ) ;
2022-08-26 01:39:45 +00:00
else
2022-10-11 06:52:48 +00:00
SetStatus ( " " , false ) ;
2022-07-15 15:37:19 +00:00
}
2024-02-06 05:24:37 +00:00
wxString hide_id_middle_string ( wxString const & str , size_t offset = 0 , size_t length = - 1 )
2023-11-14 02:48:35 +00:00
{
2024-02-06 05:24:37 +00:00
# if BBL_RELEASE_TO_PUBLIC
if ( length = = size_t ( - 1 ) ) length = str . Length ( ) - offset ;
if ( length < = 8 ) return str ;
return str . Left ( offset + 4 ) + wxString ( length - 8 , ' * ' ) + str . Mid ( offset + length - 4 ) ;
# else
return str ;
# endif
2023-11-14 02:48:35 +00:00
}
2023-10-13 08:33:28 +00:00
wxString hide_passwd ( wxString url , std : : vector < wxString > const & passwords )
2023-08-24 02:04:39 +00:00
{
2024-01-23 03:46:26 +00:00
# if BBL_RELEASE_TO_PUBLIC
2023-08-24 02:04:39 +00:00
for ( auto & p : passwords ) {
auto i = url . find ( p ) ;
2023-10-13 08:33:28 +00:00
if ( i = = wxString : : npos )
continue ;
2023-08-24 02:04:39 +00:00
auto j = i + p . length ( ) ;
if ( p [ p . length ( ) - 1 ] = = ' = ' ) {
i = j ;
j = url . find ( ' & ' , i ) ;
2024-01-08 02:57:24 +00:00
if ( j = = wxString : : npos ) j = url . length ( ) ;
2023-08-24 02:04:39 +00:00
}
auto l = size_t ( j - i ) ;
2024-02-06 05:24:37 +00:00
if ( p [ 0 ] = = ' ? ' | | p [ 0 ] = = ' & ' )
url = hide_id_middle_string ( url , i , l ) ;
else if ( j = = url . length ( ) | | url [ j ] = = ' @ ' | | url [ j ] = = ' & ' )
2023-08-24 02:04:39 +00:00
url . replace ( i , l , l , wxUniChar ( ' * ' ) ) ;
}
2024-01-23 03:46:26 +00:00
# endif
2023-08-24 02:04:39 +00:00
return url ;
}
2024-06-04 01:13:47 +00:00
void refresh_agora_url ( char const * device , char const * dev_ver , char const * channel , void * context , void ( * callback ) ( void * context , char const * url ) )
{
std : : string device2 = device ;
device2 + = " | " ;
device2 + = dev_ver ;
device2 + = " | \" agora \" | " ;
device2 + = channel ;
wxGetApp ( ) . getAgent ( ) - > get_camera_url ( device2 , [ context , callback ] ( std : : string url ) {
callback ( context , url . c_str ( ) ) ;
} ) ;
}
2022-07-15 15:37:19 +00:00
void MediaPlayCtrl : : Play ( )
{
2023-01-18 07:00:09 +00:00
if ( ! m_next_retry . IsValid ( ) | | wxDateTime : : Now ( ) < m_next_retry )
2022-08-31 09:15:34 +00:00
return ;
if ( ! IsShownOnScreen ( ) )
return ;
2022-09-30 09:54:12 +00:00
if ( m_last_state ! = MEDIASTATE_IDLE ) {
return ;
}
2023-01-11 10:04:49 +00:00
m_failed_code = 0 ;
2022-07-15 15:37:19 +00:00
if ( m_machine . empty ( ) ) {
2024-01-10 01:03:34 +00:00
Stop ( _L ( " Please confirm if the printer is connected. " ) ) ;
2022-07-15 15:37:19 +00:00
return ;
}
2023-05-06 05:54:14 +00:00
if ( ! IsEnabled ( ) ) {
2024-01-10 01:03:34 +00:00
Stop ( _L ( " Please confirm if the printer is connected. " ) ) ;
2023-05-06 05:54:14 +00:00
return ;
}
if ( m_device_busy ) {
2024-01-10 01:03:34 +00:00
Stop ( _L ( " The printer is currently busy downloading. Please try again after it finishes. " ) ) ;
2023-05-06 05:54:14 +00:00
m_failed_retry = 0 ;
return ;
}
2024-02-21 08:00:52 +00:00
if ( ! m_camera_exists ) {
Stop ( _L ( " Printer camera is malfunctioning. " ) ) ;
return ;
}
2022-09-26 03:11:05 +00:00
2024-09-13 01:28:08 +00:00
m_play_timer = std : : chrono : : system_clock : : now ( ) ;
2022-12-14 01:12:08 +00:00
NetworkAgent * agent = wxGetApp ( ) . getAgent ( ) ;
std : : string agent_version = agent ? agent - > get_version ( ) : " " ;
2024-04-08 01:48:36 +00:00
if ( m_lan_proto > MachineObject : : LVL_Disable & & ( m_lan_mode | | ! m_remote_proto ) & & ! m_disable_lan & & ! m_lan_ip . empty ( ) ) {
m_disable_lan = m_remote_proto & & ! m_lan_mode ; // try remote next time
2024-03-01 11:20:23 +00:00
std : : string url ;
2023-08-14 06:44:17 +00:00
if ( m_lan_proto = = MachineObject : : LVL_Local )
2024-03-01 11:20:23 +00:00
url = " bambu:///local/ " + m_lan_ip + " .?port=6000&user= " + m_lan_user + " &passwd= " + m_lan_passwd ;
2023-08-14 06:44:17 +00:00
else if ( m_lan_proto = = MachineObject : : LVL_Rtsps )
2024-03-01 11:20:23 +00:00
url = " bambu:///rtsps___ " + m_lan_user + " : " + m_lan_passwd + " @ " + m_lan_ip + " /streaming/live/1?proto=rtsps " ;
2023-08-14 06:44:17 +00:00
else if ( m_lan_proto = = MachineObject : : LVL_Rtsp )
2024-03-01 11:20:23 +00:00
url = " bambu:///rtsp___ " + m_lan_user + " : " + m_lan_passwd + " @ " + m_lan_ip + " /streaming/live/1?proto=rtsp " ;
url + = " &device= " + m_machine ;
url + = " &net_ver= " + agent_version ;
url + = " &dev_ver= " + m_dev_ver ;
2024-03-05 05:37:28 +00:00
url + = " &cli_id= " + wxGetApp ( ) . app_config - > get ( " slicer_uuid " ) ;
2024-03-01 11:20:23 +00:00
url + = " &cli_ver= " + std : : string ( SLIC3R_VERSION ) ;
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl: " < < hide_passwd ( hide_id_middle_string ( url , url . find ( m_lan_ip ) , m_lan_ip . length ( ) ) , { m_lan_passwd } ) ;
m_url = url ;
2023-08-24 02:04:39 +00:00
load ( ) ;
2024-06-21 11:55:51 +00:00
m_button_play - > SetIcon ( " media_stop " ) ;
2022-09-26 03:11:05 +00:00
return ;
}
2022-11-08 05:36:28 +00:00
2024-02-18 06:59:59 +00:00
// m_lan_mode && m_lan_proto > LVL_Disable (use local tunnel)
// m_lan_mode && m_lan_proto == LVL_Disable (*)
2024-01-10 01:03:34 +00:00
// m_lan_mode && m_lan_proto == LVL_None (x)
2024-04-08 01:48:36 +00:00
// !m_lan_mode && m_remote_proto (go on)
// !m_lan_mode && !m_remote_proto && m_lan_proto > LVL_None (use local tunnel)
// !m_lan_mode && !m_remote_proto && m_lan_proto == LVL_Disable (*)
// !m_lan_mode && !m_remote_proto && m_lan_proto == LVL_None (x)
2023-05-06 05:54:14 +00:00
2024-04-08 01:48:36 +00:00
if ( m_lan_proto < = MachineObject : : LVL_Disable & & ( m_lan_mode | | ! m_remote_proto ) ) {
2024-06-26 11:51:59 +00:00
Stop ( m_lan_proto = = MachineObject : : LVL_None
2024-02-18 06:59:59 +00:00
? _L ( " Problem occured. Please update the printer firmware and try again. " )
: _L ( " LAN Only Liveview is off. Please turn on the liveview on printer screen. " ) ) ;
2022-09-30 09:54:12 +00:00
return ;
}
2024-01-10 01:03:34 +00:00
m_disable_lan = false ;
m_failed_code = 0 ;
m_last_state = MEDIASTATE_INITIALIZING ;
2024-07-09 11:51:41 +00:00
m_button_play - > SetIcon ( " media_stop " ) ;
2024-10-15 07:44:29 +00:00
if ( ! m_remote_proto ) { // not support tutk
2024-01-10 01:03:34 +00:00
m_failed_code = - 1 ;
m_url = " bambu:///local/ " ;
Stop ( _L ( " Please enter the IP of printer to connect. " ) ) ;
2022-09-26 03:11:05 +00:00
return ;
}
2023-05-12 00:45:28 +00:00
2024-01-23 03:46:26 +00:00
m_label_stat - > SetLabel ( { } ) ;
2023-06-28 09:14:37 +00:00
SetStatus ( _L ( " Initializing... " ) ) ;
2022-07-15 15:37:19 +00:00
if ( agent ) {
2024-04-08 01:48:36 +00:00
std : : string protocols [ ] = { " " , " \" tutk \" " , " \" agora \" " , " \" tutk \" , \" agora \" " } ;
agent - > get_camera_url ( m_machine + " | " + m_dev_ver + " | " + protocols [ m_remote_proto ] ,
2024-06-04 01:13:47 +00:00
[ this , m = m_machine , v = agent_version , dv = m_dev_ver ] ( std : : string url ) {
2022-12-14 01:12:08 +00:00
if ( boost : : algorithm : : starts_with ( url , " bambu:/// " ) ) {
2024-01-26 06:24:58 +00:00
url + = " &device= " + into_u8 ( m ) ;
2024-03-01 11:20:23 +00:00
url + = " &net_ver= " + v ;
2023-08-03 02:19:35 +00:00
url + = " &dev_ver= " + dv ;
2024-09-20 08:12:25 +00:00
url + = " &refresh_url= " + boost : : lexical_cast < std : : string > ( & refresh_agora_url ) ;
2024-03-05 05:37:28 +00:00
url + = " &cli_id= " + wxGetApp ( ) . app_config - > get ( " slicer_uuid " ) ;
2024-03-01 11:20:23 +00:00
url + = " &cli_ver= " + std : : string ( SLIC3R_VERSION ) ;
2022-12-14 01:12:08 +00:00
}
2024-06-26 11:51:59 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl: " < < hide_passwd ( url ,
2024-02-06 05:24:37 +00:00
{ " ?uid= " , " authkey= " , " passwd= " , " license= " , " token= " } ) ;
2022-09-30 09:54:12 +00:00
CallAfter ( [ this , m , url ] {
2023-05-30 04:16:37 +00:00
if ( m ! = m_machine ) {
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl drop late ttcode for machine: " < < m ;
return ;
}
2022-07-15 15:37:19 +00:00
if ( m_last_state = = MEDIASTATE_INITIALIZING ) {
2022-09-30 09:54:12 +00:00
if ( url . empty ( ) | | ! boost : : algorithm : : starts_with ( url , " bambu:/// " ) ) {
2023-04-10 08:25:53 +00:00
m_failed_code = 3 ;
2024-04-08 01:48:36 +00:00
Stop ( _L ( " Connection Failed. Please check the network and try again " ) , from_u8 ( url ) ) ;
2022-07-15 15:37:19 +00:00
} else {
2024-03-01 11:20:23 +00:00
m_url = url ;
2023-08-24 02:04:39 +00:00
load ( ) ;
2022-07-15 15:37:19 +00:00
}
2022-11-28 05:59:52 +00:00
} else {
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl drop late ttcode for state: " < < m_last_state ;
2022-07-15 15:37:19 +00:00
}
} ) ;
} ) ;
}
}
2024-02-28 03:55:23 +00:00
void start_ping_test ( ) ;
2024-04-08 01:48:36 +00:00
void MediaPlayCtrl : : Stop ( wxString const & msg , wxString const & msg2 )
2022-07-15 15:37:19 +00:00
{
2023-05-05 02:32:00 +00:00
int last_state = m_last_state ;
2023-04-13 07:58:27 +00:00
2022-07-15 15:37:19 +00:00
if ( m_last_state ! = MEDIASTATE_IDLE ) {
m_media_ctrl - > InvalidateBestSize ( ) ;
m_button_play - > SetIcon ( " media_play " ) ;
boost : : unique_lock lock ( m_mutex ) ;
2022-07-22 09:46:10 +00:00
m_tasks . push_back ( " <stop> " ) ;
2022-07-15 15:37:19 +00:00
m_cond . notify_all ( ) ;
2023-01-11 10:04:49 +00:00
if ( ! msg . IsEmpty ( ) )
2024-01-10 01:03:34 +00:00
SetStatus ( msg ) ;
else if ( m_failed_code ) {
auto iter = error_messages . find ( m_failed_code ) ;
auto msg2 = iter = = error_messages . end ( )
? _L ( " Please check the network and try again, You can restart or update the printer if the issue persists. " )
: _L ( iter - > second . c_str ( ) ) ;
if ( m_failed_code = = 1 ) {
if ( m_last_state = = wxMEDIASTATE_PLAYING )
msg2 = _L ( " The printer has been logged out and cannot connect. " ) ;
}
2024-02-28 03:55:23 +00:00
# if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__)
if ( m_failed_code < 0 )
boost : : thread ping_thread = Slic3r : : create_thread ( [ ] {
start_ping_test ( ) ;
} ) ;
# endif
2024-01-10 01:03:34 +00:00
SetStatus ( msg2 ) ;
} else
2024-08-13 06:25:00 +00:00
SetStatus ( _L ( " Video Stopped. " ) , false ) ;
2024-01-10 01:03:34 +00:00
m_last_state = MEDIASTATE_IDLE ;
2024-02-06 05:24:37 +00:00
bool auto_retry = wxGetApp ( ) . app_config - > get ( " liveview " , " auto_retry " ) ! = " false " ;
if ( ! auto_retry | | m_failed_code > = 100 | | m_failed_code = = 1 ) // not keep retry on local error or EOS
2022-09-07 06:03:53 +00:00
m_next_retry = wxDateTime ( ) ;
2023-01-11 10:04:49 +00:00
} else if ( ! msg . IsEmpty ( ) ) {
SetStatus ( msg , false ) ;
2024-03-01 05:56:57 +00:00
return ;
2023-04-13 07:58:27 +00:00
} else {
m_failed_code = 0 ;
2024-03-01 05:56:57 +00:00
return ;
2022-07-15 15:37:19 +00:00
}
2023-02-15 03:32:18 +00:00
2024-03-01 05:56:57 +00:00
auto tunnel = m_url . empty ( ) ? " " : into_u8 ( wxURI ( m_url ) . GetPath ( ) ) . substr ( 1 ) ;
2024-06-21 11:55:51 +00:00
if ( auto n = tunnel . find_first_of ( " /_ " ) ; n ! = std : : string : : npos )
2024-03-01 05:56:57 +00:00
tunnel = tunnel . substr ( 0 , n ) ;
2024-06-26 11:51:59 +00:00
if ( last_state ! = wxMEDIASTATE_PLAYING & & m_failed_code ! = 0
2023-05-05 02:32:00 +00:00
& & m_last_failed_codes . find ( m_failed_code ) = = m_last_failed_codes . end ( )
& & ( m_user_triggered | | m_failed_retry > 3 ) ) {
2023-02-15 03:32:18 +00:00
json j ;
2023-05-05 02:32:00 +00:00
j [ " stage " ] = last_state ;
2023-04-10 08:25:53 +00:00
j [ " dev_id " ] = m_machine ;
j [ " dev_ip " ] = m_lan_ip ;
j [ " result " ] = " failed " ;
2023-05-05 02:32:00 +00:00
j [ " user_triggered " ] = m_user_triggered ;
2023-07-12 10:18:57 +00:00
j [ " failed_retry " ] = m_failed_retry ;
2024-03-01 05:56:57 +00:00
j [ " tunnel " ] = tunnel ;
2023-04-10 08:25:53 +00:00
j [ " code " ] = m_failed_code ;
2024-03-01 05:56:57 +00:00
if ( tunnel = = " tutk " ) {
if ( m_url . size ( ) > 38 )
j [ " tutk_id " ] = m_url . substr ( 18 , 20 ) . c_str ( ) ;
2023-05-17 06:05:23 +00:00
j [ " tutk_state " ] = m_tutk_state ;
2024-03-01 05:56:57 +00:00
}
2023-04-10 08:25:53 +00:00
j [ " msg " ] = into_u8 ( msg ) ;
2024-04-08 01:48:36 +00:00
if ( ! msg2 . IsEmpty ( ) )
j [ " msg2 " ] = into_u8 ( msg2 ) ;
2023-04-10 08:25:53 +00:00
NetworkAgent * agent = wxGetApp ( ) . getAgent ( ) ;
2023-02-15 03:32:18 +00:00
if ( agent )
agent - > track_event ( " start_liveview " , j . dump ( ) ) ;
2023-05-05 02:32:00 +00:00
m_last_failed_codes . insert ( m_failed_code ) ;
2023-02-15 03:32:18 +00:00
}
2024-01-30 10:09:19 +00:00
if ( last_state = = wxMEDIASTATE_PLAYING & & m_stat . size ( ) = = 4 ) {
json j ;
j [ " dev_id " ] = m_machine ;
j [ " dev_ip " ] = m_lan_ip ;
j [ " result " ] = m_failed_code ? " failed " : " success " ;
2024-03-01 05:56:57 +00:00
j [ " tunnel " ] = tunnel ;
2024-01-30 10:09:19 +00:00
j [ " code " ] = m_failed_code ;
j [ " msg " ] = into_u8 ( msg ) ;
j [ " fps " ] = m_stat [ 0 ] ;
j [ " bps " ] = m_stat [ 1 ] ;
j [ " total_time " ] = m_stat [ 2 ] ;
j [ " block_rate " ] = m_stat [ 3 ] ;
NetworkAgent * agent = wxGetApp ( ) . getAgent ( ) ;
if ( agent ) agent - > track_event ( " stop_liveview " , j . dump ( ) ) ;
}
2023-05-17 06:05:23 +00:00
m_url . clear ( ) ;
2022-07-15 15:37:19 +00:00
+ + m_failed_retry ;
2024-03-01 05:56:57 +00:00
bool local = tunnel = = " local " | | tunnel = = " rtsp " | |
tunnel = = " rtsps " ;
if ( m_failed_code < 0 & & last_state ! = wxMEDIASTATE_PLAYING & & local & & ( m_failed_retry > 1 | | m_user_triggered ) ) {
2023-01-11 10:04:49 +00:00
m_next_retry = wxDateTime ( ) ; // stop retry
2023-01-18 03:45:35 +00:00
if ( wxGetApp ( ) . show_modal_ip_address_enter_dialog ( _L ( " LAN Connection Failed (Failed to start liveview) " ) ) ) {
2023-01-11 10:04:49 +00:00
m_failed_retry = 0 ;
2023-01-28 03:19:30 +00:00
m_user_triggered = true ;
2023-07-12 10:18:57 +00:00
if ( m_last_user_play + wxTimeSpan : : Minutes ( 5 ) < wxDateTime : : Now ( ) ) {
m_last_failed_codes . clear ( ) ;
m_last_user_play = wxDateTime : : Now ( ) ;
}
2023-01-11 10:04:49 +00:00
m_next_retry = wxDateTime : : Now ( ) ;
2023-01-18 10:47:56 +00:00
return ;
2023-01-11 10:04:49 +00:00
}
}
2023-01-28 03:19:30 +00:00
m_user_triggered = false ;
2022-08-26 01:39:45 +00:00
if ( m_next_retry . IsValid ( ) )
m_next_retry = wxDateTime : : Now ( ) + wxTimeSpan : : Seconds ( 5 * m_failed_retry ) ;
2022-07-15 15:37:19 +00:00
}
void MediaPlayCtrl : : TogglePlay ( )
{
2023-06-28 09:14:37 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl::TogglePlay " ;
2022-08-26 01:39:45 +00:00
if ( m_last_state ! = MEDIASTATE_IDLE ) {
m_next_retry = wxDateTime ( ) ;
2022-07-15 15:37:19 +00:00
Stop ( ) ;
2022-08-26 01:39:45 +00:00
} else {
m_failed_retry = 0 ;
2023-01-28 03:19:30 +00:00
m_user_triggered = true ;
2023-07-12 10:18:57 +00:00
if ( m_last_user_play + wxTimeSpan : : Minutes ( 5 ) < wxDateTime : : Now ( ) ) {
m_last_failed_codes . clear ( ) ;
m_last_user_play = wxDateTime : : Now ( ) ;
}
m_next_retry = wxDateTime : : Now ( ) ;
2022-07-15 15:37:19 +00:00
Play ( ) ;
2022-08-26 01:39:45 +00:00
}
2022-07-15 15:37:19 +00:00
}
2022-09-19 01:50:34 +00:00
void MediaPlayCtrl : : ToggleStream ( )
{
std : : string file_url = data_dir ( ) + " /cameratools/url.txt " ;
if ( m_streaming ) {
boost : : nowide : : ofstream file ( file_url ) ;
file . close ( ) ;
m_streaming = false ;
return ;
} else if ( ! boost : : filesystem : : exists ( file_url ) ) {
boost : : nowide : : ofstream file ( file_url ) ;
file . close ( ) ;
}
std : : string url ;
if ( ! get_stream_url ( & url ) ) {
// create stream pipeline
2022-12-12 02:12:12 +00:00
bool need_install = false ;
if ( ! start_stream_service ( & need_install ) ) {
if ( ! need_install ) return ;
2022-11-30 06:56:21 +00:00
auto res = MessageDialog ( this - > GetParent ( ) , _L ( " Virtual Camera Tools is required for this task! \n Do you want to install them? " ) , _L ( " Info " ) ,
2022-09-19 01:50:34 +00:00
wxOK | wxCANCEL ) . ShowModal ( ) ;
if ( res = = wxID_OK ) {
// download tools
struct DownloadProgressDialog2 : DownloadProgressDialog
{
MediaPlayCtrl * ctrl ;
DownloadProgressDialog2 ( MediaPlayCtrl * ctrl ) : DownloadProgressDialog ( _L ( " Downloading Virtual Camera Tools " ) ) , ctrl ( ctrl ) { }
struct UpgradeNetworkJob2 : UpgradeNetworkJob
{
UpgradeNetworkJob2 ( std : : shared_ptr < ProgressIndicator > pri ) : UpgradeNetworkJob ( pri ) {
name = " cameratools " ;
package_name = " camera_tools.zip " ;
}
} ;
std : : shared_ptr < UpgradeNetworkJob > make_job ( std : : shared_ptr < ProgressIndicator > pri ) override
{ return std : : make_shared < UpgradeNetworkJob2 > ( pri ) ; }
void on_finish ( ) override
{
2023-03-09 09:09:30 +00:00
ctrl - > CallAfter ( [ ctrl = this - > ctrl ] { ctrl - > ToggleStream ( ) ; } ) ;
2022-09-19 01:50:34 +00:00
EndModal ( wxID_CLOSE ) ;
}
} ;
DownloadProgressDialog2 dlg ( this ) ;
dlg . ShowModal ( ) ;
}
return ;
}
}
if ( ! url . empty ( ) & & wxGetApp ( ) . app_config - > get ( " not_show_vcamera_stop_prev " ) ! = " 1 " ) {
2022-11-30 06:56:21 +00:00
MessageDialog dlg ( this - > GetParent ( ) , _L ( " Another virtual camera is running. \n Bambu Studio supports only a single virtual camera. \n Do you want to stop this virtual camera? " ) , _L ( " Warning " ) ,
2022-09-19 01:50:34 +00:00
wxYES | wxCANCEL | wxICON_INFORMATION ) ;
dlg . show_dsa_button ( ) ;
auto res = dlg . ShowModal ( ) ;
if ( dlg . get_checkbox_state ( ) )
wxGetApp ( ) . app_config - > set ( " not_show_vcamera_stop_prev " , " 1 " ) ;
if ( res = = wxID_CANCEL ) return ;
}
2024-04-08 01:48:36 +00:00
if ( m_lan_proto > MachineObject : : LVL_Disable & & ( m_lan_mode | | ! m_remote_proto ) & & ! m_disable_lan & & ! m_lan_ip . empty ( ) ) {
2023-09-15 08:06:58 +00:00
std : : string url ;
if ( m_lan_proto = = MachineObject : : LVL_Local )
url = " bambu:///local/ " + m_lan_ip + " .?port=6000&user= " + m_lan_user + " &passwd= " + m_lan_passwd ;
else if ( m_lan_proto = = MachineObject : : LVL_Rtsps )
url = " bambu:///rtsps___ " + m_lan_user + " : " + m_lan_passwd + " @ " + m_lan_ip + " /streaming/live/1?proto=rtsps " ;
else if ( m_lan_proto = = MachineObject : : LVL_Rtsp )
url = " bambu:///rtsp___ " + m_lan_user + " : " + m_lan_passwd + " @ " + m_lan_ip + " /streaming/live/1?proto=rtsp " ;
2024-01-26 06:24:58 +00:00
url + = " &device= " + into_u8 ( m_machine ) ;
2023-09-15 08:06:58 +00:00
url + = " &dev_ver= " + m_dev_ver ;
2024-01-26 06:24:58 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl::ToggleStream: " < < hide_passwd ( hide_id_middle_string ( url , url . find ( m_lan_ip ) , m_lan_ip . length ( ) ) , { m_lan_passwd } ) ;
2023-09-15 08:06:58 +00:00
std : : string file_url = data_dir ( ) + " /cameratools/url.txt " ;
boost : : nowide : : ofstream file ( file_url ) ;
auto url2 = encode_path ( url . c_str ( ) ) ;
file . write ( url2 . c_str ( ) , url2 . size ( ) ) ;
file . close ( ) ;
m_streaming = true ;
2023-11-03 10:26:16 +00:00
return ;
2023-09-15 08:06:58 +00:00
}
2022-09-19 01:50:34 +00:00
NetworkAgent * agent = wxGetApp ( ) . getAgent ( ) ;
if ( ! agent ) return ;
2024-06-04 01:13:47 +00:00
agent - > get_camera_url ( m_machine , [ this , m = m_machine , v = agent - > get_version ( ) , dv = m_dev_ver ] ( std : : string url ) {
2022-12-14 01:12:08 +00:00
if ( boost : : algorithm : : starts_with ( url , " bambu:/// " ) ) {
url + = " &device= " + m ;
2024-03-01 11:20:23 +00:00
url + = " &net_ver= " + v ;
2023-08-03 02:19:35 +00:00
url + = " &dev_ver= " + dv ;
2024-09-20 08:12:25 +00:00
url + = " &refresh_url= " + boost : : lexical_cast < std : : string > ( & refresh_agora_url ) ;
2024-03-05 05:37:28 +00:00
url + = " &cli_id= " + wxGetApp ( ) . app_config - > get ( " slicer_uuid " ) ;
2024-03-01 11:20:23 +00:00
url + = " &cli_ver= " + std : : string ( SLIC3R_VERSION ) ;
2022-12-14 01:12:08 +00:00
}
2024-06-26 11:51:59 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl::ToggleStream: " < < hide_passwd ( url ,
2024-02-06 05:24:37 +00:00
{ " ?uid= " , " authkey= " , " passwd= " , " license= " , " token= " } ) ;
2022-09-19 01:50:34 +00:00
CallAfter ( [ this , m , url ] {
2022-11-08 05:36:28 +00:00
if ( m ! = m_machine ) return ;
if ( url . empty ( ) | | ! boost : : algorithm : : starts_with ( url , " bambu:/// " ) ) {
2022-11-30 06:56:21 +00:00
MessageDialog ( this - > GetParent ( ) , wxString : : Format ( _L ( " Virtual camera initialize failed (%s)! " ) , url . empty ( ) ? _L ( " Network unreachable " ) : from_u8 ( url ) ) , _L ( " Information " ) ,
2022-11-08 05:36:28 +00:00
wxICON_INFORMATION )
. ShowModal ( ) ;
return ;
}
2022-09-19 01:50:34 +00:00
std : : string file_url = data_dir ( ) + " /cameratools/url.txt " ;
boost : : nowide : : ofstream file ( file_url ) ;
2022-12-14 01:12:08 +00:00
auto url2 = encode_path ( url . c_str ( ) ) ;
2022-09-19 01:50:34 +00:00
file . write ( url2 . c_str ( ) , url2 . size ( ) ) ;
file . close ( ) ;
m_streaming = true ;
} ) ;
} ) ;
}
2024-06-26 11:51:59 +00:00
void MediaPlayCtrl : : msw_rescale ( ) {
m_button_play - > Rescale ( ) ;
2023-07-17 07:32:37 +00:00
}
2024-04-18 13:16:54 +00:00
void MediaPlayCtrl : : jump_to_play ( )
{
if ( m_last_state ! = MEDIASTATE_IDLE )
return ;
TogglePlay ( ) ;
}
2022-12-16 07:22:56 +00:00
void MediaPlayCtrl : : onStateChanged ( wxMediaEvent & event )
{
auto last_state = m_last_state ;
auto state = m_media_ctrl - > GetState ( ) ;
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl::onStateChanged: " < < state < < " , last_state: " < < last_state ;
if ( ( int ) state < 0 ) return ;
{
boost : : unique_lock lock ( m_mutex ) ;
if ( ! m_tasks . empty ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl::onStateChanged: skip when task not finished " ;
return ;
}
}
if ( ( last_state = = MEDIASTATE_IDLE | | last_state = = MEDIASTATE_INITIALIZING ) & & state = = wxMEDIASTATE_STOPPED ) { return ; }
if ( ( last_state = = wxMEDIASTATE_PAUSED | | last_state = = wxMEDIASTATE_PLAYING ) & & state = = wxMEDIASTATE_STOPPED ) {
m_failed_code = m_media_ctrl - > GetLastError ( ) ;
Stop ( ) ;
return ;
}
2023-03-06 08:02:57 +00:00
if ( last_state = = MEDIASTATE_LOADING & & ( state = = wxMEDIASTATE_STOPPED | | state = = wxMEDIASTATE_PAUSED ) ) {
2022-12-16 07:22:56 +00:00
wxSize size = m_media_ctrl - > GetVideoSize ( ) ;
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl::onStateChanged: size: " < < size . x < < " x " < < size . y ;
m_failed_code = m_media_ctrl - > GetLastError ( ) ;
2023-07-05 12:28:56 +00:00
if ( size . GetWidth ( ) > = 320 ) {
2022-12-16 07:22:56 +00:00
m_last_state = state ;
2024-01-17 10:33:41 +00:00
m_failed_code = 0 ;
2022-12-16 07:22:56 +00:00
SetStatus ( _L ( " Playing... " ) , false ) ;
2024-09-02 07:14:42 +00:00
m_print_idle = 0 ;
auto now = std : : chrono : : system_clock : : now ( ) ;
m_load_duration = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( now - m_play_timer ) . count ( ) ;
m_play_timer = now + 1 min ;
2023-02-15 03:32:18 +00:00
// track event
json j ;
j [ " stage " ] = std : : to_string ( m_last_state ) ;
j [ " dev_id " ] = m_machine ;
j [ " dev_ip " ] = m_lan_ip ;
j [ " result " ] = " success " ;
j [ " code " ] = 0 ;
2024-03-01 05:56:57 +00:00
auto tunnel = into_u8 ( wxURI ( m_url ) . GetPath ( ) ) . substr ( 1 ) ;
2024-06-21 11:55:51 +00:00
if ( auto n = tunnel . find_first_of ( " /_ " ) ; n ! = std : : string : : npos )
2024-03-01 05:56:57 +00:00
tunnel = tunnel . substr ( 0 , n ) ;
j [ " tunnel " ] = tunnel ;
if ( tunnel = = " tutk " ) {
if ( m_url . size ( ) > 38 )
j [ " tutk_id " ] = m_url . substr ( 18 , 20 ) . c_str ( ) ;
j [ " tutk_state " ] = m_tutk_state ;
}
NetworkAgent * agent = wxGetApp ( ) . getAgent ( ) ;
2023-02-15 03:32:18 +00:00
if ( agent )
agent - > track_event ( " start_liveview " , j . dump ( ) ) ;
2022-12-16 07:22:56 +00:00
m_failed_retry = 0 ;
2023-05-17 06:05:23 +00:00
m_disable_lan = false ;
2022-12-16 07:22:56 +00:00
boost : : unique_lock lock ( m_mutex ) ;
m_tasks . push_back ( " <play> " ) ;
m_cond . notify_all ( ) ;
} else if ( event . GetId ( ) ) {
if ( m_failed_code = = 0 )
m_failed_code = 2 ;
2024-01-10 01:03:34 +00:00
Stop ( ) ;
2022-12-16 07:22:56 +00:00
}
} else {
m_last_state = state ;
}
}
2022-10-11 06:52:48 +00:00
void MediaPlayCtrl : : SetStatus ( wxString const & msg2 , bool hyperlink )
2022-07-15 15:37:19 +00:00
{
2024-01-10 01:03:34 +00:00
auto msg = msg2 ;
if ( m_failed_code ! = 0 ) {
int state2 = m_last_state > = MEDIASTATE_IDLE ? m_last_state - MEDIASTATE_IDLE :
m_last_state + MEDIASTATE_BUFFERING - MEDIASTATE_IDLE ;
msg + = wxString : : Format ( " [%d:%d] " , state2 , m_failed_code ) ;
2024-08-30 03:18:01 +00:00
msg + = wxDateTime : : Now ( ) . Format ( _T ( " <%m-%d %H:%M> " ) ) ;
2024-01-10 01:03:34 +00:00
}
2024-02-06 05:24:37 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl::SetStatus: " < < msg . ToUTF8 ( ) . data ( ) < < " tutk_state: " < < m_tutk_state ;
2022-07-22 09:46:10 +00:00
# ifdef __WXMSW__
OutputDebugStringA ( " MediaPlayCtrl::SetStatus: " ) ;
OutputDebugStringA ( msg . ToUTF8 ( ) . data ( ) ) ;
OutputDebugStringA ( " \n " ) ;
# endif // __WXMSW__
2022-07-15 15:37:19 +00:00
m_label_status - > SetLabel ( msg ) ;
2024-02-06 05:24:37 +00:00
m_label_status - > Wrap ( GetSize ( ) . GetWidth ( ) - 120 - m_label_stat - > GetSize ( ) . GetWidth ( ) ) ;
2022-09-09 07:05:59 +00:00
long style = m_label_status - > GetWindowStyle ( ) & ~ LB_HYPERLINK ;
2022-10-11 06:52:48 +00:00
if ( hyperlink ) {
2022-09-09 07:05:59 +00:00
style | = LB_HYPERLINK ;
}
2022-12-14 09:21:15 +00:00
m_label_status - > SetWindowStyle ( style ) ;
2022-10-11 06:52:48 +00:00
m_label_status - > InvalidateBestSize ( ) ;
2022-07-15 15:37:19 +00:00
Layout ( ) ;
}
2022-09-19 01:50:34 +00:00
bool MediaPlayCtrl : : IsStreaming ( ) const { return m_streaming ; }
2023-08-24 02:04:39 +00:00
void MediaPlayCtrl : : load ( )
{
m_last_state = MEDIASTATE_LOADING ;
SetStatus ( _L ( " Loading... " ) ) ;
if ( wxGetApp ( ) . app_config - > get ( " internal_developer_mode " ) = = " true " ) {
std : : string file_h264 = data_dir ( ) + " /video.h264 " ;
std : : string file_info = data_dir ( ) + " /video.info " ;
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl dump video to " < < file_h264 ;
// closed by BambuSource
FILE * dump_h264_file = boost : : nowide : : fopen ( file_h264 . c_str ( ) , " wb " ) ;
FILE * dump_info_file = boost : : nowide : : fopen ( file_info . c_str ( ) , " wb " ) ;
m_url = m_url + " &dump_h264= " + boost : : lexical_cast < std : : string > ( dump_h264_file ) ;
m_url = m_url + " &dump_info= " + boost : : lexical_cast < std : : string > ( dump_info_file ) ;
}
boost : : unique_lock lock ( m_mutex ) ;
m_tasks . push_back ( m_url ) ;
m_cond . notify_all ( ) ;
}
2022-11-21 09:34:18 +00:00
void MediaPlayCtrl : : on_show_hide ( wxShowEvent & evt )
{
evt . Skip ( ) ;
if ( m_isBeingDeleted ) return ;
2023-01-18 07:00:09 +00:00
m_failed_retry = 0 ;
2023-07-10 07:16:08 +00:00
if ( m_next_retry . IsValid ( ) ) // Try open 2 seconds later, to avoid quick play/stop
m_next_retry = wxDateTime : : Now ( ) + wxTimeSpan : : Seconds ( 2 ) ;
2022-11-21 09:34:18 +00:00
IsShownOnScreen ( ) ? Play ( ) : Stop ( ) ;
}
2022-07-15 15:37:19 +00:00
void MediaPlayCtrl : : media_proc ( )
{
boost : : unique_lock lock ( m_mutex ) ;
while ( true ) {
while ( m_tasks . empty ( ) ) {
m_cond . wait ( lock ) ;
}
wxString url = m_tasks . front ( ) ;
2023-06-29 05:43:52 +00:00
if ( m_tasks . size ( ) > = 2 & & ! url . IsEmpty ( ) & & url [ 0 ] ! = ' < ' & & m_tasks [ 1 ] = = " <stop> " ) {
2024-01-26 06:24:58 +00:00
BOOST_LOG_TRIVIAL ( trace ) < < " MediaPlayCtrl: busy skip url: " < < url ;
2023-06-29 05:43:52 +00:00
m_tasks . pop_front ( ) ;
m_tasks . pop_front ( ) ;
continue ;
}
2022-07-15 15:37:19 +00:00
lock . unlock ( ) ;
if ( url . IsEmpty ( ) ) {
2022-07-22 09:46:10 +00:00
break ;
}
else if ( url = = " <stop> " ) {
2022-12-16 07:22:56 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl: start stop " ;
2022-07-15 15:37:19 +00:00
m_media_ctrl - > Stop ( ) ;
2022-12-16 07:22:56 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl: end stop " ;
2022-07-15 15:37:19 +00:00
}
else if ( url = = " <exit> " ) {
break ;
}
2022-07-22 09:46:10 +00:00
else if ( url = = " <play> " ) {
2024-09-26 09:14:20 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl: start play " ;
2022-07-22 09:46:10 +00:00
m_media_ctrl - > Play ( ) ;
2024-09-26 09:14:20 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl: end play " ;
2022-07-22 09:46:10 +00:00
}
2022-07-15 15:37:19 +00:00
else {
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl: start load " ;
m_media_ctrl - > Load ( wxURI ( url ) ) ;
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl: end load " ;
}
lock . lock ( ) ;
m_tasks . pop_front ( ) ;
wxMediaEvent theEvent ( wxEVT_MEDIA_STATECHANGED , m_media_ctrl - > GetId ( ) ) ;
theEvent . SetId ( 0 ) ;
m_media_ctrl - > GetEventHandler ( ) - > AddPendingEvent ( theEvent ) ;
}
}
2022-12-12 02:12:12 +00:00
bool MediaPlayCtrl : : start_stream_service ( bool * need_install )
{
# ifdef __WIN32__
2024-02-28 08:16:42 +00:00
auto tools_dir = boost : : nowide : : widen ( data_dir ( ) ) + L " \\ cameratools \\ " ;
auto file_source = tools_dir + L " bambu_source.exe " ;
auto file_ffmpeg = tools_dir + L " ffmpeg.exe " ;
auto file_ff_cfg = tools_dir + L " ffmpeg.cfg " ;
2022-12-12 02:12:12 +00:00
# else
2024-02-28 08:16:42 +00:00
auto tools_dir = data_dir ( ) + " /cameratools/ " ;
auto file_source = tools_dir + " bambu_source " ;
auto file_ffmpeg = tools_dir + " ffmpeg " ;
auto file_ff_cfg = tools_dir + " ffmpeg.cfg " ;
2022-12-12 02:12:12 +00:00
# endif
if ( ! boost : : filesystem : : exists ( file_source ) | | ! boost : : filesystem : : exists ( file_ffmpeg ) | | ! boost : : filesystem : : exists ( file_ff_cfg ) ) {
if ( need_install ) * need_install = true ;
return false ;
}
std : : string file_url = data_dir ( ) + " /cameratools/url.txt " ;
if ( ! boost : : filesystem : : exists ( file_url ) ) {
boost : : nowide : : ofstream file ( file_url ) ;
file . close ( ) ;
}
wxString file_url2 = L " bambu:///camera/ " + from_u8 ( file_url ) ;
file_url2 . Replace ( " \\ " , " / " ) ;
file_url2 = wxURI ( file_url2 ) . BuildURI ( ) ;
try {
std : : string configs ;
boost : : filesystem : : load_string_file ( file_ff_cfg , configs ) ;
std : : vector < std : : string > configss ;
boost : : algorithm : : split ( configss , configs , boost : : algorithm : : is_any_of ( " \r \n " ) ) ;
configss . erase ( std : : remove ( configss . begin ( ) , configss . end ( ) , std : : string ( ) ) , configss . end ( ) ) ;
boost : : process : : pipe intermediate ;
boost : : filesystem : : path start_dir ( boost : : filesystem : : path ( data_dir ( ) ) / " plugins " ) ;
# ifdef __WXMSW__
2024-02-28 08:16:42 +00:00
auto plugins_dir = boost : : nowide : : widen ( data_dir ( ) ) + L " \\ plugins \\ " ;
for ( auto dll : { L " BambuSource.dll " , L " live555.dll " } ) {
auto file_dll = tools_dir + dll ;
auto file_dll2 = plugins_dir + dll ;
if ( ! boost : : filesystem : : exists ( file_dll ) | | boost : : filesystem : : last_write_time ( file_dll ) ! = boost : : filesystem : : last_write_time ( file_dll2 ) )
boost : : filesystem : : copy_file ( file_dll2 , file_dll , boost : : filesystem : : copy_option : : overwrite_if_exists ) ;
}
2024-06-26 11:51:59 +00:00
boost : : process : : child process_source ( file_source , file_url2 . ToStdWstring ( ) , boost : : process : : start_dir ( tools_dir ) ,
boost : : process : : windows : : create_no_window ,
2022-12-14 01:12:08 +00:00
boost : : process : : std_out > intermediate , boost : : process : : limit_handles ) ;
2024-06-26 11:51:59 +00:00
boost : : process : : child process_ffmpeg ( file_ffmpeg , configss , boost : : process : : windows : : create_no_window ,
2022-12-14 01:12:08 +00:00
boost : : process : : std_in < intermediate , boost : : process : : limit_handles ) ;
2022-12-12 02:12:12 +00:00
# else
boost : : filesystem : : permissions ( file_source , boost : : filesystem : : owner_exe | boost : : filesystem : : add_perms ) ;
boost : : filesystem : : permissions ( file_ffmpeg , boost : : filesystem : : owner_exe | boost : : filesystem : : add_perms ) ;
2024-06-26 11:51:59 +00:00
boost : : process : : child process_source ( file_source , file_url2 . data ( ) . AsInternal ( ) , boost : : process : : start_dir ( start_dir ) ,
2022-12-14 01:12:08 +00:00
boost : : process : : std_out > intermediate , boost : : process : : limit_handles ) ;
boost : : process : : child process_ffmpeg ( file_ffmpeg , configss , boost : : process : : std_in < intermediate , boost : : process : : limit_handles ) ;
2022-12-12 02:12:12 +00:00
# endif
process_source . detach ( ) ;
process_ffmpeg . detach ( ) ;
} catch ( std : : exception & e ) {
2024-02-28 08:16:42 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl failed to start camera stream: " < < decode_path ( e . what ( ) ) ;
2022-12-12 02:12:12 +00:00
return false ;
}
return true ;
}
2022-09-19 01:50:34 +00:00
bool MediaPlayCtrl : : get_stream_url ( std : : string * url )
{
# ifdef __WIN32__
HANDLE shm = : : OpenFileMapping ( FILE_MAP_READ , FALSE , L " bambu_stream_url " ) ;
if ( shm = = NULL ) return false ;
if ( url ) {
char * addr = ( char * ) MapViewOfFile ( shm , FILE_MAP_READ , 0 , 0 , 0 ) ;
if ( addr ) {
* url = addr ;
UnmapViewOfFile ( addr ) ;
url = nullptr ;
}
}
CloseHandle ( shm ) ;
2023-02-02 08:41:34 +00:00
# else
2022-12-07 03:35:06 +00:00
std : : string file_url = data_dir ( ) + " /cameratools/url.txt " ;
2022-09-19 01:50:34 +00:00
key_t key = : : ftok ( file_url . c_str ( ) , 1000 ) ;
int shm = : : shmget ( key , 1024 , 0 ) ;
if ( shm = = - 1 ) return false ;
struct shmid_ds ds ;
: : shmctl ( shm , IPC_STAT , & ds ) ;
if ( ds . shm_nattch = = 0 ) {
return false ;
}
if ( url ) {
char * addr = ( char * ) : : shmat ( shm , nullptr , 0 ) ;
if ( addr ! = ( void * ) - 1 ) {
* url = addr ;
: : shmdt ( addr ) ;
url = nullptr ;
}
}
# endif
return url = = nullptr ;
}
2024-07-09 11:51:41 +00:00
static int SecondsSinceLastInput ( )
{
# ifdef _WIN32
LASTINPUTINFO lii ;
lii . cbSize = sizeof ( lii ) ;
: : GetLastInputInfo ( & lii ) ;
return ( : : GetTickCount ( ) - lii . dwTime ) / 1000 ;
# elif defined(__APPLE__)
return ( int ) CGEventSourceSecondsSinceLastEventType ( kCGEventSourceStateHIDSystemState , kCGAnyInputEventType ) ;
# else
return 0 ;
# endif
}
2022-07-15 15:37:19 +00:00
} }
2024-06-26 11:51:59 +00:00
void wxMediaCtrl_OnSize ( wxWindow * ctrl , wxSize const & videoSize , int width , int height )
2022-07-15 15:37:19 +00:00
{
2024-06-26 11:51:59 +00:00
wxSize size = videoSize ;
if ( ! size . IsFullySpecified ( ) ) size = { 16 , 9 } ;
2024-01-18 10:11:41 +00:00
int maxHeight = ( width * size . GetHeight ( ) + size . GetHeight ( ) - 1 ) / size . GetWidth ( ) ;
2024-06-26 11:51:59 +00:00
if ( maxHeight ! = ctrl - > GetMaxHeight ( ) ) {
// BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl_OnSize: width: " << width << ", height: " << height << ", maxHeight: " << maxHeight;
ctrl - > SetMaxSize ( { - 1 , maxHeight } ) ;
ctrl - > CallAfter ( [ ctrl ] {
if ( auto p = ctrl - > GetParent ( ) ) {
2024-01-18 10:11:41 +00:00
p - > Layout ( ) ;
p - > Refresh ( ) ;
}
} ) ;
}
2022-07-15 15:37:19 +00:00
}