2 * Copyright (C) 2005-2013 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 "threads/SingleLock.h"
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
36 #if !defined(TARGET_DARWIN) && !defined(TARGET_FREEBSD)
37 #include <linux/cdrom.h>
40 #include "settings/AdvancedSettings.h"
41 #include "GUIUserMessages.h"
42 #include "utils/URIUtils.h"
43 #if defined (LIBCDIO_VERSION_NUM) && (LIBCDIO_VERSION_NUM > 77) || defined (TARGET_DARWIN)
46 #include "guilib/GUIWindowManager.h"
48 #include "Application.h"
49 #include "IoSupport.h"
50 #include "cdioSupport.h"
51 #include "storage/MediaManager.h"
54 using namespace XFILE;
55 using namespace MEDIA_DETECT;
57 CCriticalSection CDetectDVDMedia::m_muReadingMedia;
58 CEvent CDetectDVDMedia::m_evAutorun;
59 int CDetectDVDMedia::m_DriveState = DRIVE_CLOSED_NO_MEDIA;
60 CCdInfo* CDetectDVDMedia::m_pCdInfo = NULL;
61 time_t CDetectDVDMedia::m_LastPoll = 0;
62 CDetectDVDMedia* CDetectDVDMedia::m_pInstance = NULL;
63 CStdString CDetectDVDMedia::m_diskLabel = "";
64 CStdString CDetectDVDMedia::m_diskPath = "";
66 CDetectDVDMedia::CDetectDVDMedia() : CThread("DetectDVDMedia")
70 m_dwLastTrayState = 0;
71 m_bStartup = true; // Do not autorun on startup
73 m_cdio = CLibcdio::GetInstance();
76 CDetectDVDMedia::~CDetectDVDMedia()
80 void CDetectDVDMedia::OnStartup()
82 // SetPriority( THREAD_PRIORITY_LOWEST );
83 CLog::Log(LOGDEBUG, "Compiled with libcdio Version 0.%d", LIBCDIO_VERSION_NUM);
86 void CDetectDVDMedia::Process()
88 // for apple - currently disable this check since cdio will return null if no media is loaded
89 #if !defined(TARGET_DARWIN)
90 //Before entering loop make sure we actually have a CDrom drive
91 CdIo_t *p_cdio = m_cdio->cdio_open(NULL, DRIVER_DEVICE);
95 m_cdio->cdio_destroy(p_cdio);
100 if (g_application.m_pPlayer->IsPlayingVideo())
111 Sleep(1500); // Media in drive, wait 1.5s more to be sure the device is ready for playback
119 void CDetectDVDMedia::OnExit()
123 // Gets state of the DVD drive
124 VOID CDetectDVDMedia::UpdateDvdrom()
126 // Signal for WaitMediaReady()
127 // that we are busy detecting the
128 // newly inserted media.
130 CSingleLock waitLock(m_muReadingMedia);
131 switch (GetTrayState())
134 // TODO: reduce / stop polling for drive updates
139 // Send Message to GUI that disc been ejected
140 SetNewDVDShareUrl("D:\\", false, g_localizeStrings.Get(502));
142 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REMOVED_MEDIA);
143 g_windowManager.SendThreadMessage( msg );
145 m_DriveState = DRIVE_OPEN;
150 case DRIVE_NOT_READY:
152 // drive is not ready (closing, opening)
154 SetNewDVDShareUrl("D:\\", false, g_localizeStrings.Get(503));
155 m_DriveState = DRIVE_NOT_READY;
156 // DVD-ROM in undefined state
157 // better delete old CD Information
158 if ( m_pCdInfo != NULL )
164 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_SOURCES);
165 g_windowManager.SendThreadMessage( msg );
166 // Do we really need sleep here? This will fix: [ 1530771 ] "Open tray" problem
172 case DRIVE_CLOSED_NO_MEDIA:
174 // nothing in there...
176 SetNewDVDShareUrl("D:\\", false, g_localizeStrings.Get(504));
177 m_DriveState = DRIVE_CLOSED_NO_MEDIA;
178 // Send Message to GUI that disc has changed
179 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_SOURCES);
181 g_windowManager.SendThreadMessage( msg );
186 #if !defined(TARGET_DARWIN)
189 case DRIVE_CLOSED_MEDIA_PRESENT:
191 if ( m_DriveState != DRIVE_CLOSED_MEDIA_PRESENT)
193 m_DriveState = DRIVE_CLOSED_MEDIA_PRESENT;
194 // Detect ISO9660(mode1/mode2) or CDDA filesystem
196 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_SOURCES);
198 g_windowManager.SendThreadMessage( msg );
199 // Tell the application object that a new Cd is inserted
200 // So autorun can be started.
209 // We have finished media detection
210 // Signal for WaitMediaReady()
216 // Generates the drive url, (like iso9660://)
217 // from the CCdInfo class
218 void CDetectDVDMedia::DetectMediaType()
221 CLog::Log(LOGINFO, "Detecting DVD-ROM media filesystem...");
223 CStdString strNewUrl;
226 // Delete old CD-Information
227 if ( m_pCdInfo != NULL )
233 // Detect new CD-Information
234 m_pCdInfo = cdio.GetCdInfo();
235 if (m_pCdInfo == NULL)
237 CLog::Log(LOGERROR, "Detection of DVD-ROM media failed.");
240 CLog::Log(LOGINFO, "Tracks overall:%i; Audio tracks:%i; Data tracks:%i",
241 m_pCdInfo->GetTrackCount(),
242 m_pCdInfo->GetAudioTrackCount(),
243 m_pCdInfo->GetDataTrackCount() );
245 // Detect ISO9660(mode1/mode2), CDDA filesystem or UDF
246 if (m_pCdInfo->IsISOHFS(1) || m_pCdInfo->IsIso9660(1) || m_pCdInfo->IsIso9660Interactive(1))
248 strNewUrl = "iso9660://";
253 if (m_pCdInfo->IsUDF(1) || m_pCdInfo->IsUDFX(1))
255 else if (m_pCdInfo->IsAudio(1))
257 strNewUrl = "cdda://local/";
264 if (m_pCdInfo->IsISOUDF(1))
266 if (!g_advancedSettings.m_detectAsUdf)
268 strNewUrl = "iso9660://";
277 CLog::Log(LOGINFO, "Using protocol %s", strNewUrl.c_str());
279 if (m_pCdInfo->IsValidFs())
281 if (!m_pCdInfo->IsAudio(1))
282 CLog::Log(LOGINFO, "Disc label: %s", m_pCdInfo->GetDiscLabel().c_str());
286 CLog::Log(LOGWARNING, "Filesystem is not supported");
289 CStdString strLabel = "";
292 strLabel = "Audio-CD";
296 strLabel = m_pCdInfo->GetDiscLabel();
297 StringUtils::TrimRight(strLabel);
300 SetNewDVDShareUrl( strNewUrl , bCDDA, strLabel);
303 void CDetectDVDMedia::SetNewDVDShareUrl( const CStdString& strNewUrl, bool bCDDA, const CStdString& strDiscLabel )
305 CStdString strDescription = "DVD";
306 if (bCDDA) strDescription = "CD";
308 if (strDiscLabel != "") strDescription = strDiscLabel;
310 // store it in case others want it
311 m_diskLabel = strDescription;
312 m_diskPath = strNewUrl;
315 DWORD CDetectDVDMedia::GetTrayState()
319 char* dvdDevice = m_cdio->GetDeviceFileName();
320 if (strlen(dvdDevice) == 0)
327 fd = open(dvdDevice, O_RDONLY | O_NONBLOCK);
330 CLog::Log(LOGERROR, "Unable to open CD-ROM device %s for polling.", dvdDevice);
331 return DRIVE_NOT_READY;
334 int drivestatus = ioctl(fd, CDROM_DRIVE_STATUS, 0);
339 m_dwTrayState = TRAY_CLOSED_NO_MEDIA;
343 m_dwTrayState = TRAY_CLOSED_NO_MEDIA;
347 m_dwTrayState = TRAY_OPEN;
351 m_dwTrayState = TRAY_CLOSED_MEDIA_PRESENT;
354 case CDS_DRIVE_NOT_READY:
356 return DRIVE_NOT_READY;
359 m_dwTrayState = TRAY_CLOSED_NO_MEDIA;
366 // The following code works with libcdio >= 0.78
367 // To enable it, download and install the latest version from
368 // http://www.gnu.org/software/libcdio/
372 m_dwTrayState = TRAY_CLOSED_MEDIA_PRESENT;
373 CdIo_t* cdio = m_cdio->cdio_open(dvdDevice, DRIVER_UNKNOWN);
376 static discmode_t discmode = CDIO_DISC_MODE_NO_INFO;
377 int status = m_cdio->mmc_get_tray_status(cdio);
378 static int laststatus = -1;
379 // 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)
380 if (status == 0 && (laststatus != status || discmode == CDIO_DISC_MODE_ERROR))
381 discmode = m_cdio->cdio_get_discmode(cdio);
386 if (discmode==CDIO_DISC_MODE_NO_INFO || discmode==CDIO_DISC_MODE_ERROR)
387 m_dwTrayState = TRAY_CLOSED_NO_MEDIA;
389 m_dwTrayState = TRAY_CLOSED_MEDIA_PRESENT;
393 m_dwTrayState = TRAY_OPEN;
397 m_cdio->cdio_destroy(cdio);
400 return DRIVE_NOT_READY;
402 #endif // USING_CDIO78
403 #endif // TARGET_POSIX
405 if (m_dwTrayState == TRAY_CLOSED_MEDIA_PRESENT)
407 if (m_dwLastTrayState != TRAY_CLOSED_MEDIA_PRESENT)
409 m_dwLastTrayState = m_dwTrayState;
410 return DRIVE_CLOSED_MEDIA_PRESENT;
417 else if (m_dwTrayState == TRAY_CLOSED_NO_MEDIA)
419 if ( (m_dwLastTrayState != TRAY_CLOSED_NO_MEDIA) && (m_dwLastTrayState != TRAY_CLOSED_MEDIA_PRESENT) )
421 m_dwLastTrayState = m_dwTrayState;
422 return DRIVE_CLOSED_NO_MEDIA;
429 else if (m_dwTrayState == TRAY_OPEN)
431 if (m_dwLastTrayState != TRAY_OPEN)
433 m_dwLastTrayState = m_dwTrayState;
443 m_dwLastTrayState = m_dwTrayState;
447 return DRIVE_NOT_READY;
453 void CDetectDVDMedia::UpdateState()
455 CSingleLock waitLock(m_muReadingMedia);
456 m_pInstance->DetectMediaType();
460 // Wait for drive, to finish media detection.
461 void CDetectDVDMedia::WaitMediaReady()
463 CSingleLock waitLock(m_muReadingMedia);
467 // Returns status of the DVD Drive
468 int CDetectDVDMedia::DriveReady()
474 // Whether a disc is in drive
475 bool CDetectDVDMedia::IsDiscInDrive()
477 return m_DriveState == DRIVE_CLOSED_MEDIA_PRESENT;
481 // Returns a CCdInfo class, which contains
482 // Media information of the current
485 CCdInfo* CDetectDVDMedia::GetCdInfo()
487 CSingleLock waitLock(m_muReadingMedia);
488 CCdInfo* pCdInfo = m_pCdInfo;
492 const CStdString &CDetectDVDMedia::GetDVDLabel()
497 const CStdString &CDetectDVDMedia::GetDVDPath()