2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "DetectDVDType.h"
11 #include "GUIUserMessages.h"
12 #include "ServiceBroker.h"
13 #include "application/ApplicationComponents.h"
14 #include "application/ApplicationPlayer.h"
15 #include "cdioSupport.h"
16 #include "guilib/GUIComponent.h"
17 #include "guilib/GUIWindowManager.h"
18 #include "guilib/LocalizeStrings.h"
19 #include "settings/AdvancedSettings.h"
20 #include "settings/SettingsComponent.h"
21 #include "storage/MediaManager.h"
22 #include "utils/StringUtils.h"
23 #include "utils/log.h"
27 using namespace MEDIA_DETECT
;
28 using namespace std::chrono_literals
;
30 CCriticalSection
CDetectDVDMedia::m_muReadingMedia
;
31 CEvent
CDetectDVDMedia::m_evAutorun
;
32 DriveState
CDetectDVDMedia::m_DriveState
{DriveState::CLOSED_NO_MEDIA
};
33 CCdInfo
* CDetectDVDMedia::m_pCdInfo
= NULL
;
34 time_t CDetectDVDMedia::m_LastPoll
= 0;
35 CDetectDVDMedia
* CDetectDVDMedia::m_pInstance
= NULL
;
36 std::string
CDetectDVDMedia::m_diskLabel
= "";
37 std::string
CDetectDVDMedia::m_diskPath
= "";
38 UTILS::DISCS::DiscInfo
CDetectDVDMedia::m_discInfo
;
40 CDetectDVDMedia::CDetectDVDMedia() : CThread("DetectDVDMedia"),
41 m_cdio(CLibcdio::GetInstance())
47 CDetectDVDMedia::~CDetectDVDMedia() = default;
49 void CDetectDVDMedia::OnStartup()
51 // SetPriority( ThreadPriority::LOWEST );
52 CLog::Log(LOGDEBUG
, "Compiled with libcdio Version 0.{}", LIBCDIO_VERSION_NUM
);
55 void CDetectDVDMedia::Process()
57 // for apple - currently disable this check since cdio will return null if no media is loaded
58 #if !defined(TARGET_DARWIN)
59 //Before entering loop make sure we actually have a CDrom drive
60 CdIo_t
*p_cdio
= m_cdio
->cdio_open(NULL
, DRIVER_DEVICE
);
64 m_cdio
->cdio_destroy(p_cdio
);
67 const auto& components
= CServiceBroker::GetAppComponents();
68 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
72 if (appPlayer
->IsPlayingVideo())
74 CThread::Sleep(10000ms
);
80 CThread::Sleep(2000ms
);
83 // Media in drive, wait 1.5s more to be sure the device is ready for playback
84 CThread::Sleep(1500ms
);
92 void CDetectDVDMedia::OnExit()
96 // Gets state of the DVD drive
97 void CDetectDVDMedia::UpdateDvdrom()
99 // Signal for WaitMediaReady()
100 // that we are busy detecting the
101 // newly inserted media.
103 std::unique_lock
<CCriticalSection
> waitLock(m_muReadingMedia
);
104 switch (PollDriveState())
106 case DriveState::NONE
:
107 //! @todo reduce / stop polling for drive updates
110 case DriveState::OPEN
:
112 // Send Message to GUI that disc been ejected
113 SetNewDVDShareUrl(CServiceBroker::GetMediaManager().TranslateDevicePath(m_diskPath
), false,
114 g_localizeStrings
.Get(502));
115 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_REMOVED_MEDIA
);
116 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
117 // Clear all stored info
119 // Update drive state
121 m_DriveState
= DriveState::OPEN
;
125 case DriveState::NOT_READY
:
127 // Drive is not ready (closing, opening)
128 SetNewDVDShareUrl(CServiceBroker::GetMediaManager().TranslateDevicePath(m_diskPath
), false,
129 g_localizeStrings
.Get(503));
130 m_DriveState
= DriveState::NOT_READY
;
131 // DVD-ROM in undefined state
132 // Better delete old CD Information
133 if (m_pCdInfo
!= nullptr)
139 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_SOURCES
);
140 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
141 // Do we really need sleep here? This will fix: [ 1530771 ] "Open tray" problem
142 // CThread::Sleep(6000ms);
147 case DriveState::CLOSED_NO_MEDIA
:
149 // Nothing in there...
150 SetNewDVDShareUrl(CServiceBroker::GetMediaManager().TranslateDevicePath(m_diskPath
), false,
151 g_localizeStrings
.Get(504));
152 m_DriveState
= DriveState::CLOSED_NO_MEDIA
;
153 // Send Message to GUI that disc has changed
154 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_SOURCES
);
156 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
160 case DriveState::READY
:
161 #if !defined(TARGET_DARWIN)
165 case DriveState::CLOSED_MEDIA_PRESENT
:
167 if (m_DriveState
!= DriveState::CLOSED_MEDIA_PRESENT
)
169 m_DriveState
= DriveState::CLOSED_MEDIA_PRESENT
;
170 // Detect ISO9660(mode1/mode2) or CDDA filesystem
172 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_SOURCES
);
174 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
175 // Tell the application object that a new Cd is inserted
176 // So autorun can be started.
186 // We have finished media detection
187 // Signal for WaitMediaReady()
193 // Generates the drive url, (like iso9660://)
194 // from the CCdInfo class
195 void CDetectDVDMedia::DetectMediaType()
198 CLog::Log(LOGINFO
, "Detecting DVD-ROM media filesystem...");
200 // Probe and store DiscInfo result
201 // even if no valid tracks are detected we might still be able to play the disc via libdvdnav or libbluray
202 // as long as they can correctly detect the disc
203 UTILS::DISCS::DiscInfo discInfo
;
204 if (UTILS::DISCS::GetDiscInfo(discInfo
,
205 CServiceBroker::GetMediaManager().TranslateDevicePath(m_diskPath
)))
207 m_discInfo
= discInfo
;
210 std::string strNewUrl
;
213 // Delete old CD-Information
214 if ( m_pCdInfo
!= NULL
)
220 // Detect new CD-Information
221 m_pCdInfo
= cdio
.GetCdInfo();
222 if (m_pCdInfo
== NULL
)
224 CLog::Log(LOGERROR
, "Detection of DVD-ROM media failed.");
227 CLog::Log(LOGINFO
, "Tracks overall:{}; Audio tracks:{}; Data tracks:{}",
228 m_pCdInfo
->GetTrackCount(), m_pCdInfo
->GetAudioTrackCount(),
229 m_pCdInfo
->GetDataTrackCount());
231 // Detect ISO9660(mode1/mode2), CDDA filesystem or UDF
232 if (m_pCdInfo
->IsISOHFS(1) || m_pCdInfo
->IsIso9660(1) || m_pCdInfo
->IsIso9660Interactive(1))
234 strNewUrl
= "iso9660://";
238 if (m_pCdInfo
->IsUDF(1))
239 strNewUrl
= CServiceBroker::GetMediaManager().TranslateDevicePath(m_diskPath
);
240 else if (m_pCdInfo
->IsAudio(1))
242 strNewUrl
= "cdda://local/";
246 strNewUrl
= CServiceBroker::GetMediaManager().TranslateDevicePath(m_diskPath
);
249 if (m_pCdInfo
->IsISOUDF(1))
251 if (!CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_detectAsUdf
)
253 strNewUrl
= "iso9660://";
257 strNewUrl
= CServiceBroker::GetMediaManager().TranslateDevicePath(m_diskPath
);
261 CLog::Log(LOGINFO
, "Using protocol {}", strNewUrl
);
263 if (m_pCdInfo
->IsValidFs())
265 if (!m_pCdInfo
->IsAudio(1))
266 CLog::Log(LOGINFO
, "Disc label: {}", m_pCdInfo
->GetDiscLabel());
270 CLog::Log(LOGWARNING
, "Filesystem is not supported");
273 std::string strLabel
;
276 strLabel
= "Audio-CD";
280 strLabel
= m_pCdInfo
->GetDiscLabel();
281 StringUtils::TrimRight(strLabel
);
284 SetNewDVDShareUrl( strNewUrl
, bCDDA
, strLabel
);
287 void CDetectDVDMedia::SetNewDVDShareUrl( const std::string
& strNewUrl
, bool bCDDA
, const std::string
& strDiscLabel
)
289 std::string strDescription
= "DVD";
290 if (bCDDA
) strDescription
= "CD";
292 if (strDiscLabel
!= "") strDescription
= strDiscLabel
;
294 // Store it in case others want it
295 m_diskLabel
= strDescription
;
296 m_diskPath
= strNewUrl
;
299 DriveState
CDetectDVDMedia::PollDriveState()
301 const std::shared_ptr
<IDiscDriveHandler
> platformDiscDriveHandler
=
302 CServiceBroker::GetMediaManager().GetDiscDriveHandler();
303 if (!platformDiscDriveHandler
)
305 return DriveState::NONE
;
308 const std::string discPath
= CServiceBroker::GetMediaManager().TranslateDevicePath("");
309 const DriveState driveState
= platformDiscDriveHandler
->GetDriveState(discPath
);
312 case DriveState::CLOSED_MEDIA_UNDEFINED
:
313 // We only poll for new traystatus when driveState has changed or if the last recorded
314 // tray state is undefined
315 if (driveState
== DriveState::CLOSED_MEDIA_UNDEFINED
&&
316 (m_LastTrayState
== TrayState::UNDEFINED
|| driveState
!= m_LastDriveState
))
318 m_TrayState
= platformDiscDriveHandler
->GetTrayState(discPath
);
321 case DriveState::OPEN
:
322 m_TrayState
= TrayState::OPEN
;
325 m_TrayState
= TrayState::UNDEFINED
;
328 m_LastDriveState
= driveState
;
330 if (m_TrayState
== TrayState::CLOSED_MEDIA_PRESENT
)
332 if (m_LastTrayState
!= TrayState::CLOSED_MEDIA_PRESENT
)
334 m_LastTrayState
= m_TrayState
;
335 return DriveState::CLOSED_MEDIA_PRESENT
;
339 return DriveState::READY
;
342 else if (m_TrayState
== TrayState::CLOSED_NO_MEDIA
)
344 if ((m_LastTrayState
!= TrayState::CLOSED_NO_MEDIA
) &&
345 (m_LastTrayState
!= TrayState::CLOSED_MEDIA_PRESENT
))
347 m_LastTrayState
= m_TrayState
;
348 return DriveState::CLOSED_NO_MEDIA
;
352 return DriveState::READY
;
355 else if (m_TrayState
== TrayState::OPEN
)
357 if (m_LastTrayState
!= TrayState::OPEN
)
359 m_LastTrayState
= m_TrayState
;
360 return DriveState::OPEN
;
364 return DriveState::READY
;
369 m_LastTrayState
= m_TrayState
;
373 return DriveState::NOT_READY
;
375 return DriveState::READY
;
379 void CDetectDVDMedia::UpdateState()
381 std::unique_lock
<CCriticalSection
> waitLock(m_muReadingMedia
);
382 m_pInstance
->DetectMediaType();
386 // Wait for drive, to finish media detection.
387 void CDetectDVDMedia::WaitMediaReady()
389 std::unique_lock
<CCriticalSection
> waitLock(m_muReadingMedia
);
393 // Returns status of the DVD Drive
394 bool CDetectDVDMedia::DriveReady()
396 return m_DriveState
== DriveState::READY
;
399 DriveState
CDetectDVDMedia::GetDriveState()
405 // Whether a disc is in drive
406 bool CDetectDVDMedia::IsDiscInDrive()
408 return m_DriveState
== DriveState::CLOSED_MEDIA_PRESENT
;
412 // Returns a CCdInfo class, which contains
413 // Media information of the current inserted CD.
415 CCdInfo
* CDetectDVDMedia::GetCdInfo()
417 std::unique_lock
<CCriticalSection
> waitLock(m_muReadingMedia
);
418 CCdInfo
* pCdInfo
= m_pCdInfo
;
422 const std::string
&CDetectDVDMedia::GetDVDLabel()
424 if (!m_discInfo
.empty())
426 return m_discInfo
.name
;
432 const std::string
&CDetectDVDMedia::GetDVDPath()
438 void CDetectDVDMedia::Clear()
440 if (!m_discInfo
.empty())