2 * Copyright (C) 2005-2015 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
25 #include "DetectDVDType.h"
26 #include "guilib/LocalizeStrings.h"
27 #include "utils/StringUtils.h"
28 #include "utils/log.h"
29 #include "cdioSupport.h"
30 #include "filesystem/iso9660.h"
31 #include "filesystem/File.h"
32 #include "threads/SingleLock.h"
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
37 #if !defined(TARGET_DARWIN) && !defined(TARGET_FREEBSD)
38 #include <linux/cdrom.h>
41 #include "settings/AdvancedSettings.h"
42 #include "GUIUserMessages.h"
43 #include "utils/URIUtils.h"
44 #if defined (LIBCDIO_VERSION_NUM) && (LIBCDIO_VERSION_NUM > 77) || defined (TARGET_DARWIN)
47 #include "guilib/GUIWindowManager.h"
49 #include "Application.h"
50 #include "IoSupport.h"
51 #include "cdioSupport.h"
52 #include "storage/MediaManager.h"
55 using namespace XFILE
;
56 using namespace MEDIA_DETECT
;
58 CCriticalSection
CDetectDVDMedia::m_muReadingMedia
;
59 CEvent
CDetectDVDMedia::m_evAutorun
;
60 int CDetectDVDMedia::m_DriveState
= DRIVE_CLOSED_NO_MEDIA
;
61 CCdInfo
* CDetectDVDMedia::m_pCdInfo
= NULL
;
62 time_t CDetectDVDMedia::m_LastPoll
= 0;
63 CDetectDVDMedia
* CDetectDVDMedia::m_pInstance
= NULL
;
64 std::string
CDetectDVDMedia::m_diskLabel
= "";
65 std::string
CDetectDVDMedia::m_diskPath
= "";
67 CDetectDVDMedia::CDetectDVDMedia() : CThread("DetectDVDMedia"),
68 m_bStartup(true), // Do not autorun on startup
71 m_cdio(CLibcdio::GetInstance())
77 CDetectDVDMedia::~CDetectDVDMedia()
81 void CDetectDVDMedia::OnStartup()
83 // SetPriority( THREAD_PRIORITY_LOWEST );
84 CLog::Log(LOGDEBUG
, "Compiled with libcdio Version 0.%d", LIBCDIO_VERSION_NUM
);
87 void CDetectDVDMedia::Process()
89 // for apple - currently disable this check since cdio will return null if no media is loaded
90 #if !defined(TARGET_DARWIN)
91 //Before entering loop make sure we actually have a CDrom drive
92 CdIo_t
*p_cdio
= m_cdio
->cdio_open(NULL
, DRIVER_DEVICE
);
96 m_cdio
->cdio_destroy(p_cdio
);
101 if (g_application
.m_pPlayer
->IsPlayingVideo())
112 Sleep(1500); // Media in drive, wait 1.5s more to be sure the device is ready for playback
120 void CDetectDVDMedia::OnExit()
124 // Gets state of the DVD drive
125 VOID
CDetectDVDMedia::UpdateDvdrom()
127 // Signal for WaitMediaReady()
128 // that we are busy detecting the
129 // newly inserted media.
131 CSingleLock
waitLock(m_muReadingMedia
);
132 switch (GetTrayState())
135 //! @todo reduce / stop polling for drive updates
140 // Send Message to GUI that disc been ejected
141 SetNewDVDShareUrl("D:\\", false, g_localizeStrings
.Get(502));
143 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_REMOVED_MEDIA
);
144 g_windowManager
.SendThreadMessage( msg
);
146 m_DriveState
= DRIVE_OPEN
;
151 case DRIVE_NOT_READY
:
153 // Drive is not ready (closing, opening)
155 SetNewDVDShareUrl("D:\\", false, g_localizeStrings
.Get(503));
156 m_DriveState
= DRIVE_NOT_READY
;
157 // DVD-ROM in undefined state
158 // Better delete old CD Information
159 if ( m_pCdInfo
!= NULL
)
165 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_SOURCES
);
166 g_windowManager
.SendThreadMessage( msg
);
167 // Do we really need sleep here? This will fix: [ 1530771 ] "Open tray" problem
173 case DRIVE_CLOSED_NO_MEDIA
:
175 // Nothing in there...
177 SetNewDVDShareUrl("D:\\", false, g_localizeStrings
.Get(504));
178 m_DriveState
= DRIVE_CLOSED_NO_MEDIA
;
179 // Send Message to GUI that disc has changed
180 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_SOURCES
);
182 g_windowManager
.SendThreadMessage( msg
);
187 #if !defined(TARGET_DARWIN)
190 case DRIVE_CLOSED_MEDIA_PRESENT
:
192 if ( m_DriveState
!= DRIVE_CLOSED_MEDIA_PRESENT
)
194 m_DriveState
= DRIVE_CLOSED_MEDIA_PRESENT
;
195 // Detect ISO9660(mode1/mode2) or CDDA filesystem
197 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_SOURCES
);
199 g_windowManager
.SendThreadMessage( msg
);
200 // Tell the application object that a new Cd is inserted
201 // So autorun can be started.
210 // We have finished media detection
211 // Signal for WaitMediaReady()
217 // Generates the drive url, (like iso9660://)
218 // from the CCdInfo class
219 void CDetectDVDMedia::DetectMediaType()
222 CLog::Log(LOGINFO
, "Detecting DVD-ROM media filesystem...");
224 std::string strNewUrl
;
227 // Delete old CD-Information
228 if ( m_pCdInfo
!= NULL
)
234 // Detect new CD-Information
235 m_pCdInfo
= cdio
.GetCdInfo();
236 if (m_pCdInfo
== NULL
)
238 CLog::Log(LOGERROR
, "Detection of DVD-ROM media failed.");
241 CLog::Log(LOGINFO
, "Tracks overall:%i; Audio tracks:%i; Data tracks:%i",
242 m_pCdInfo
->GetTrackCount(),
243 m_pCdInfo
->GetAudioTrackCount(),
244 m_pCdInfo
->GetDataTrackCount() );
246 // Detect ISO9660(mode1/mode2), CDDA filesystem or UDF
247 if (m_pCdInfo
->IsISOHFS(1) || m_pCdInfo
->IsIso9660(1) || m_pCdInfo
->IsIso9660Interactive(1))
249 strNewUrl
= "iso9660://";
254 if (m_pCdInfo
->IsUDF(1))
256 else if (m_pCdInfo
->IsAudio(1))
258 strNewUrl
= "cdda://local/";
265 if (m_pCdInfo
->IsISOUDF(1))
267 if (!g_advancedSettings
.m_detectAsUdf
)
269 strNewUrl
= "iso9660://";
278 CLog::Log(LOGINFO
, "Using protocol %s", strNewUrl
.c_str());
280 if (m_pCdInfo
->IsValidFs())
282 if (!m_pCdInfo
->IsAudio(1))
283 CLog::Log(LOGINFO
, "Disc label: %s", m_pCdInfo
->GetDiscLabel().c_str());
287 CLog::Log(LOGWARNING
, "Filesystem is not supported");
290 std::string strLabel
;
293 strLabel
= "Audio-CD";
297 strLabel
= m_pCdInfo
->GetDiscLabel();
298 StringUtils::TrimRight(strLabel
);
301 SetNewDVDShareUrl( strNewUrl
, bCDDA
, strLabel
);
304 void CDetectDVDMedia::SetNewDVDShareUrl( const std::string
& strNewUrl
, bool bCDDA
, const std::string
& strDiscLabel
)
306 std::string strDescription
= "DVD";
307 if (bCDDA
) strDescription
= "CD";
309 if (strDiscLabel
!= "") strDescription
= strDiscLabel
;
311 // Store it in case others want it
312 m_diskLabel
= strDescription
;
313 m_diskPath
= strNewUrl
;
316 DWORD
CDetectDVDMedia::GetTrayState()
320 char* dvdDevice
= m_cdio
->GetDeviceFileName();
321 if (strlen(dvdDevice
) == 0)
328 fd
= open(dvdDevice
, O_RDONLY
| O_NONBLOCK
);
331 CLog::Log(LOGERROR
, "Unable to open CD-ROM device %s for polling.", dvdDevice
);
332 return DRIVE_NOT_READY
;
335 int drivestatus
= ioctl(fd
, CDROM_DRIVE_STATUS
, 0);
340 m_dwTrayState
= TRAY_CLOSED_NO_MEDIA
;
344 m_dwTrayState
= TRAY_CLOSED_NO_MEDIA
;
348 m_dwTrayState
= TRAY_OPEN
;
352 m_dwTrayState
= TRAY_CLOSED_MEDIA_PRESENT
;
355 case CDS_DRIVE_NOT_READY
:
357 return DRIVE_NOT_READY
;
360 m_dwTrayState
= TRAY_CLOSED_NO_MEDIA
;
367 // The following code works with libcdio >= 0.78
368 // To enable it, download and install the latest version from
369 // http://www.gnu.org/software/libcdio/
373 m_dwTrayState
= TRAY_CLOSED_MEDIA_PRESENT
;
374 CdIo_t
* cdio
= m_cdio
->cdio_open(dvdDevice
, DRIVER_UNKNOWN
);
377 static discmode_t discmode
= CDIO_DISC_MODE_NO_INFO
;
378 int status
= m_cdio
->mmc_get_tray_status(cdio
);
379 static int laststatus
= -1;
380 // We only poll for new discmode when status has changed or there have been read errors (The last usually happens when new media is inserted)
381 if (status
== 0 && (laststatus
!= status
|| discmode
== CDIO_DISC_MODE_ERROR
))
382 discmode
= m_cdio
->cdio_get_discmode(cdio
);
387 if (discmode
==CDIO_DISC_MODE_NO_INFO
|| discmode
==CDIO_DISC_MODE_ERROR
)
388 m_dwTrayState
= TRAY_CLOSED_NO_MEDIA
;
390 m_dwTrayState
= TRAY_CLOSED_MEDIA_PRESENT
;
394 m_dwTrayState
= TRAY_OPEN
;
398 m_cdio
->cdio_destroy(cdio
);
401 return DRIVE_NOT_READY
;
403 #endif // USING_CDIO78
404 #endif // TARGET_POSIX
406 if (m_dwTrayState
== TRAY_CLOSED_MEDIA_PRESENT
)
408 if (m_dwLastTrayState
!= TRAY_CLOSED_MEDIA_PRESENT
)
410 m_dwLastTrayState
= m_dwTrayState
;
411 return DRIVE_CLOSED_MEDIA_PRESENT
;
418 else if (m_dwTrayState
== TRAY_CLOSED_NO_MEDIA
)
420 if ( (m_dwLastTrayState
!= TRAY_CLOSED_NO_MEDIA
) && (m_dwLastTrayState
!= TRAY_CLOSED_MEDIA_PRESENT
) )
422 m_dwLastTrayState
= m_dwTrayState
;
423 return DRIVE_CLOSED_NO_MEDIA
;
430 else if (m_dwTrayState
== TRAY_OPEN
)
432 if (m_dwLastTrayState
!= TRAY_OPEN
)
434 m_dwLastTrayState
= m_dwTrayState
;
444 m_dwLastTrayState
= m_dwTrayState
;
448 return DRIVE_NOT_READY
;
454 void CDetectDVDMedia::UpdateState()
456 CSingleLock
waitLock(m_muReadingMedia
);
457 m_pInstance
->DetectMediaType();
461 // Wait for drive, to finish media detection.
462 void CDetectDVDMedia::WaitMediaReady()
464 CSingleLock
waitLock(m_muReadingMedia
);
468 // Returns status of the DVD Drive
469 int CDetectDVDMedia::DriveReady()
475 // Whether a disc is in drive
476 bool CDetectDVDMedia::IsDiscInDrive()
478 return m_DriveState
== DRIVE_CLOSED_MEDIA_PRESENT
;
482 // Returns a CCdInfo class, which contains
483 // Media information of the current inserted CD.
485 CCdInfo
* CDetectDVDMedia::GetCdInfo()
487 CSingleLock
waitLock(m_muReadingMedia
);
488 CCdInfo
* pCdInfo
= m_pCdInfo
;
492 const std::string
&CDetectDVDMedia::GetDVDLabel()
497 const std::string
&CDetectDVDMedia::GetDVDPath()