VTB: release CVBuffer after it actually has been rendered
[xbmc.git] / xbmc / storage / DetectDVDType.cpp
blob14b03049e9725d565c3b1f1bedf7bd2ed972f3dc
1 /*
2 * Copyright (C) 2005-2015 Team XBMC
3 * http://kodi.tv/
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)
8 * any later version.
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/>.
21 #include "system.h"
23 #ifdef HAS_DVD_DRIVE
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"
33 #ifdef TARGET_POSIX
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <fcntl.h>
37 #if !defined(TARGET_DARWIN) && !defined(TARGET_FREEBSD)
38 #include <linux/cdrom.h>
39 #endif
40 #endif
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)
45 #define USING_CDIO78
46 #endif
47 #include "guilib/GUIWindowManager.h"
48 #include "FileItem.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
69 m_bAutorun(false),
70 m_dwLastTrayState(0),
71 m_cdio(CLibcdio::GetInstance())
73 m_bStop = false;
74 m_pInstance = this;
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);
93 if (p_cdio == NULL)
94 return;
95 else
96 m_cdio->cdio_destroy(p_cdio);
97 #endif
99 while (( !m_bStop ))
101 if (g_application.m_pPlayer->IsPlayingVideo())
103 Sleep(10000);
105 else
107 UpdateDvdrom();
108 m_bStartup = false;
109 Sleep(2000);
110 if ( m_bAutorun )
112 Sleep(1500); // Media in drive, wait 1.5s more to be sure the device is ready for playback
113 m_evAutorun.Set();
114 m_bAutorun = false;
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())
134 case DRIVE_NONE:
135 //! @todo reduce / stop polling for drive updates
136 break;
138 case DRIVE_OPEN:
140 // Send Message to GUI that disc been ejected
141 SetNewDVDShareUrl("D:\\", false, g_localizeStrings.Get(502));
142 m_isoReader.Reset();
143 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REMOVED_MEDIA);
144 g_windowManager.SendThreadMessage( msg );
145 waitLock.Leave();
146 m_DriveState = DRIVE_OPEN;
147 return;
149 break;
151 case DRIVE_NOT_READY:
153 // Drive is not ready (closing, opening)
154 m_isoReader.Reset();
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 )
161 delete m_pCdInfo;
162 m_pCdInfo = NULL;
164 waitLock.Leave();
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
168 // Sleep(6000);
169 return ;
171 break;
173 case DRIVE_CLOSED_NO_MEDIA:
175 // Nothing in there...
176 m_isoReader.Reset();
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);
181 waitLock.Leave();
182 g_windowManager.SendThreadMessage( msg );
183 return ;
185 break;
186 case DRIVE_READY:
187 #if !defined(TARGET_DARWIN)
188 return ;
189 #endif
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
196 DetectMediaType();
197 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_SOURCES);
198 waitLock.Leave();
199 g_windowManager.SendThreadMessage( msg );
200 // Tell the application object that a new Cd is inserted
201 // So autorun can be started.
202 if ( !m_bStartup )
203 m_bAutorun = true;
205 return ;
207 break;
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()
221 bool bCDDA(false);
222 CLog::Log(LOGINFO, "Detecting DVD-ROM media filesystem...");
224 std::string strNewUrl;
225 CCdIoSupport cdio;
227 // Delete old CD-Information
228 if ( m_pCdInfo != NULL )
230 delete m_pCdInfo;
231 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.");
239 return ;
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://";
250 m_isoReader.Scan();
252 else
254 if (m_pCdInfo->IsUDF(1))
255 strNewUrl = "D:\\";
256 else if (m_pCdInfo->IsAudio(1))
258 strNewUrl = "cdda://local/";
259 bCDDA = true;
261 else
262 strNewUrl = "D:\\";
265 if (m_pCdInfo->IsISOUDF(1))
267 if (!g_advancedSettings.m_detectAsUdf)
269 strNewUrl = "iso9660://";
270 m_isoReader.Scan();
272 else
274 strNewUrl = "D:\\";
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());
285 else
287 CLog::Log(LOGWARNING, "Filesystem is not supported");
290 std::string strLabel;
291 if (bCDDA)
293 strLabel = "Audio-CD";
295 else
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()
318 #ifdef TARGET_POSIX
320 char* dvdDevice = m_cdio->GetDeviceFileName();
321 if (strlen(dvdDevice) == 0)
322 return DRIVE_NONE;
324 #ifndef USING_CDIO78
326 int fd = 0;
328 fd = open(dvdDevice, O_RDONLY | O_NONBLOCK);
329 if (fd<0)
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);
337 switch(drivestatus)
339 case CDS_NO_INFO:
340 m_dwTrayState = TRAY_CLOSED_NO_MEDIA;
341 break;
343 case CDS_NO_DISC:
344 m_dwTrayState = TRAY_CLOSED_NO_MEDIA;
345 break;
347 case CDS_TRAY_OPEN:
348 m_dwTrayState = TRAY_OPEN;
349 break;
351 case CDS_DISC_OK:
352 m_dwTrayState = TRAY_CLOSED_MEDIA_PRESENT;
353 break;
355 case CDS_DRIVE_NOT_READY:
356 close(fd);
357 return DRIVE_NOT_READY;
359 default:
360 m_dwTrayState = TRAY_CLOSED_NO_MEDIA;
363 close(fd);
365 #else
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/
370 // -d4rk 06/27/07
373 m_dwTrayState = TRAY_CLOSED_MEDIA_PRESENT;
374 CdIo_t* cdio = m_cdio->cdio_open(dvdDevice, DRIVER_UNKNOWN);
375 if (cdio)
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);
384 switch(status)
386 case 0: //closed
387 if (discmode==CDIO_DISC_MODE_NO_INFO || discmode==CDIO_DISC_MODE_ERROR)
388 m_dwTrayState = TRAY_CLOSED_NO_MEDIA;
389 else
390 m_dwTrayState = TRAY_CLOSED_MEDIA_PRESENT;
391 break;
393 case 1: //open
394 m_dwTrayState = TRAY_OPEN;
395 break;
397 laststatus = status;
398 m_cdio->cdio_destroy(cdio);
400 else
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;
413 else
415 return DRIVE_READY;
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;
425 else
427 return DRIVE_READY;
430 else if (m_dwTrayState == TRAY_OPEN)
432 if (m_dwLastTrayState != TRAY_OPEN)
434 m_dwLastTrayState = m_dwTrayState;
435 return DRIVE_OPEN;
437 else
439 return DRIVE_READY;
442 else
444 m_dwLastTrayState = m_dwTrayState;
447 #ifdef HAS_DVD_DRIVE
448 return DRIVE_NOT_READY;
449 #else
450 return DRIVE_READY;
451 #endif
454 void CDetectDVDMedia::UpdateState()
456 CSingleLock waitLock(m_muReadingMedia);
457 m_pInstance->DetectMediaType();
460 // Static function
461 // Wait for drive, to finish media detection.
462 void CDetectDVDMedia::WaitMediaReady()
464 CSingleLock waitLock(m_muReadingMedia);
467 // Static function
468 // Returns status of the DVD Drive
469 int CDetectDVDMedia::DriveReady()
471 return m_DriveState;
474 // Static function
475 // Whether a disc is in drive
476 bool CDetectDVDMedia::IsDiscInDrive()
478 return m_DriveState == DRIVE_CLOSED_MEDIA_PRESENT;
481 // Static function
482 // Returns a CCdInfo class, which contains
483 // Media information of the current inserted CD.
484 // Can be NULL
485 CCdInfo* CDetectDVDMedia::GetCdInfo()
487 CSingleLock waitLock(m_muReadingMedia);
488 CCdInfo* pCdInfo = m_pCdInfo;
489 return pCdInfo;
492 const std::string &CDetectDVDMedia::GetDVDLabel()
494 return m_diskLabel;
497 const std::string &CDetectDVDMedia::GetDVDPath()
499 return m_diskPath;
501 #endif