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
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 {
MediaPlayCtrl : : MediaPlayCtrl ( wxWindow * parent , wxMediaCtrl2 * media_ctrl , const wxPoint & pos , const wxSize & size )
: 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 ) ;
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 ( ) ;
m_label_stat - > SetLabel ( e . GetString ( ) + wxString : : Format ( " VS:%ix%i " , size . x , size . y ) ) ;
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
}
2024-01-08 02:57:24 +00:00
wxString hide_id_middle_string ( wxString const & str , size_t offset = 0 , size_t length = - 1 )
{
2024-01-23 03:46:26 +00:00
# if BBL_RELEASE_TO_PUBLIC
2024-01-08 02:57:24 +00:00
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 ) ;
2024-01-23 03:46:26 +00:00
# else
return str ;
# endif
2024-01-08 02:57:24 +00:00
}
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 ;
m_remote_support = 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-01-10 01:03:34 +00:00
m_remote_support = false ;
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-03-01 05:56:57 +00:00
else if ( m_last_state = = MEDIASTATE_LOADING & & m_tutk_state = = " disable "
& & m_last_user_play + wxTimeSpan : : Seconds ( 3 ) < wxDateTime : : Now ( ) ) {
// resend ttcode to printer
if ( auto agent = wxGetApp ( ) . getAgent ( ) )
agent - > get_camera_url ( machine , [ ] ( auto ) { } ) ;
m_last_user_play = wxDateTime : : Now ( ) ;
}
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
}
2023-11-14 02:48:35 +00:00
void MediaPlayCtrl : : SetAutoRetry ( bool b )
{
m_auto_retry = b ;
}
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 ) ;
if ( j = = url . length ( ) | | url [ j ] = = ' @ ' | | url [ j ] = = ' & ' )
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 ;
}
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
2022-07-15 15:37:19 +00:00
m_button_play - > SetIcon ( " media_stop " ) ;
2022-12-14 01:12:08 +00:00
NetworkAgent * agent = wxGetApp ( ) . getAgent ( ) ;
std : : string agent_version = agent ? agent - > get_version ( ) : " " ;
2024-02-18 06:59:59 +00:00
if ( m_lan_proto > MachineObject : : LVL_Disable & & ( m_lan_mode | | ! m_remote_support ) & & ! m_disable_lan & & ! m_lan_ip . empty ( ) ) {
2023-05-06 05:54:14 +00:00
m_disable_lan = m_remote_support & & ! 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 ( ) ;
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-02-18 06:59:59 +00:00
// !m_lan_mode && m_remote_support (go on)
2024-01-10 01:03:34 +00:00
// !m_lan_mode && !m_remote_support && m_lan_proto > LVL_None (use local tunnel)
2024-02-18 06:59:59 +00:00
// !m_lan_mode && !m_remote_support && m_lan_proto == LVL_Disable (*)
2024-01-10 01:03:34 +00:00
// !m_lan_mode && !m_remote_support && m_lan_proto == LVL_None (x)
2023-05-06 05:54:14 +00:00
2024-02-18 06:59:59 +00:00
if ( m_lan_proto < = MachineObject : : LVL_Disable & & ( m_lan_mode | | ! m_remote_support ) ) {
Stop ( m_lan_proto = = MachineObject : : LVL_None
? _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 ;
2022-09-30 09:54:12 +00:00
2023-05-06 05:54:14 +00:00
if ( ! m_remote_support ) { // 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 ) {
2023-08-03 02:19:35 +00:00
agent - > get_camera_url ( m_machine , [ 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-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-01-23 03:46:26 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl: " < < hide_id_middle_string ( hide_passwd ( url , { " authkey= " , " passwd= " } ) , 9 , 20 ) < < " tutk_state: " < < m_tutk_state ;
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-01-10 01:03:34 +00:00
Stop ( _L ( " Connection Failed. Please check the network and try again " ) ) ;
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 ( ) ;
2023-01-11 10:04:49 +00:00
void MediaPlayCtrl : : Stop ( wxString const & msg )
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
2022-10-17 01:55:18 +00:00
SetStatus ( _L ( " Stopped. " ) , false ) ;
2024-01-10 01:03:34 +00:00
m_last_state = MEDIASTATE_IDLE ;
2023-12-29 02:13:52 +00:00
if ( ! m_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 ) ;
if ( auto n = tunnel . find_first_of ( ' / _ ' ) ; n ! = std : : string : : npos )
tunnel = tunnel . substr ( 0 , n ) ;
2023-05-05 02:32:00 +00:00
if ( last_state ! = wxMEDIASTATE_PLAYING & & m_failed_code ! = 0
& & 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 ) ;
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-02-18 06:59:59 +00:00
if ( m_lan_proto > MachineObject : : LVL_Disable & & ( m_lan_mode | | ! m_remote_support ) & & ! 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 ;
2023-08-03 02:19:35 +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-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-01-08 02:57:24 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl::ToggleStream: " < < hide_id_middle_string ( hide_passwd ( url , { " authkey= " , " passwd= " } ) , 9 , 20 ) ;
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 ;
} ) ;
} ) ;
}
2023-07-17 07:32:37 +00:00
void MediaPlayCtrl : : msw_rescale ( ) {
m_button_play - > Rescale ( ) ;
}
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 ;
SetStatus ( _L ( " Playing... " ) , false ) ;
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 ) ;
if ( auto n = tunnel . find_first_of ( ' / _ ' ) ; n ! = std : : string : : npos )
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 ;
m_failed_code = 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-01-23 03:46:26 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " MediaPlayCtrl::SetStatus: " < < msg . ToUTF8 ( ) . data ( ) < < 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-01-23 03:46:26 +00:00
m_label_status - > Wrap ( GetSize ( ) . GetWidth ( ) - 120 ) ;
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> " ) {
m_media_ctrl - > Play ( ) ;
}
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 ) ;
}
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 ) ;
boost : : process : : child process_ffmpeg ( file_ffmpeg , configss , boost : : process : : windows : : create_no_window ,
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 ) ;
2022-12-14 01:12:08 +00:00
boost : : process : : child process_source ( file_source , file_url2 . data ( ) . AsInternal ( ) , boost : : process : : start_dir ( start_dir ) ,
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 ;
}
2022-07-15 15:37:19 +00:00
} }
void wxMediaCtrl2 : : DoSetSize ( int x , int y , int width , int height , int sizeFlags )
{
Add support for Bambu Lab X1 series live video stream on Linux.
wxWidgets on Linux uses GStreamer as its back-end for wxMediaCtrl, which
doesn't have a bambu: URI handler. On Windows, this is handled by a Windows
Media subsystem plugin, and on Mac, this is handled with a BambuPlayer
class. Luckily, the libBambuSource.so binary that is distributed with the
network plugin package already contains support for receiving h.264 data
from the network, and the API is the same as is used by the tiny
bambusource.exe binary on Windows; we glue this into a GStreamer source
plugin that registers a URI handler for bambu:.
To make this work, we make a few additional changes elsewhere. GStreamer
seems to have trouble rendering an Xv overlay onto a 32bpp X visual, but
Bambu Slicer seems to request a 32bpp visual for some background
transparency in the Notebook; it doesn't seem to use it in an interesting
way on Linux, though, so we remove that request for transparency to allow
Bambu Studio to render to a 24bpp visual. The media controller
infrastructure also makes a few assumptions about when sizing information
can be queried from a wxMediaCtrl backend that do not hold true on Linux; we
either fix those assumptions, or fake them out, as needed. We also make a
few changes needed to successfully compile C.
This has only been tested with the GStreamer backend for wxWidgets --
notably, not the GStreamer-play backend (these are, astonishingly, two
different things!). If you find that this seems not to work, consider
*un*installing the libgstreamer-plugins-bad1.0-dev package and then
rebuilding wxWidgets.
2023-01-10 09:40:39 +00:00
# ifdef __WXMAC__
2022-07-15 15:37:19 +00:00
wxWindow : : DoSetSize ( x , y , width , height , sizeFlags ) ;
Add support for Bambu Lab X1 series live video stream on Linux.
wxWidgets on Linux uses GStreamer as its back-end for wxMediaCtrl, which
doesn't have a bambu: URI handler. On Windows, this is handled by a Windows
Media subsystem plugin, and on Mac, this is handled with a BambuPlayer
class. Luckily, the libBambuSource.so binary that is distributed with the
network plugin package already contains support for receiving h.264 data
from the network, and the API is the same as is used by the tiny
bambusource.exe binary on Windows; we glue this into a GStreamer source
plugin that registers a URI handler for bambu:.
To make this work, we make a few additional changes elsewhere. GStreamer
seems to have trouble rendering an Xv overlay onto a 32bpp X visual, but
Bambu Slicer seems to request a 32bpp visual for some background
transparency in the Notebook; it doesn't seem to use it in an interesting
way on Linux, though, so we remove that request for transparency to allow
Bambu Studio to render to a 24bpp visual. The media controller
infrastructure also makes a few assumptions about when sizing information
can be queried from a wxMediaCtrl backend that do not hold true on Linux; we
either fix those assumptions, or fake them out, as needed. We also make a
few changes needed to successfully compile C.
This has only been tested with the GStreamer backend for wxWidgets --
notably, not the GStreamer-play backend (these are, astonishingly, two
different things!). If you find that this seems not to work, consider
*un*installing the libgstreamer-plugins-bad1.0-dev package and then
rebuilding wxWidgets.
2023-01-10 09:40:39 +00:00
# else
wxMediaCtrl : : DoSetSize ( x , y , width , height , sizeFlags ) ;
# endif
2024-01-18 10:11:41 +00:00
if ( sizeFlags & wxSIZE_USE_EXISTING ) return ;
2024-02-02 00:52:04 +00:00
wxSize size = m_video_size ;
2024-01-18 10:11:41 +00:00
int maxHeight = ( width * size . GetHeight ( ) + size . GetHeight ( ) - 1 ) / size . GetWidth ( ) ;
if ( maxHeight ! = GetMaxHeight ( ) ) {
// BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl2::DoSetSize: width: " << width << ", height: " << height << ", maxHeight: " << maxHeight;
SetMaxSize ( { - 1 , maxHeight } ) ;
CallAfter ( [ this ] {
if ( auto p = GetParent ( ) ) {
p - > Layout ( ) ;
p - > Refresh ( ) ;
}
} ) ;
}
2022-07-15 15:37:19 +00:00
}