MythTV  master
mythmediamonitor.cpp
Go to the documentation of this file.
1 
2 // Standard C headers
3 #include <cstdio>
4 
5 // C++ headers
6 #include <iostream>
7 #include <typeinfo>
8 using namespace std;
9 
10 // Qt headers
11 #include <QCoreApplication>
12 #include <QFile>
13 #include <QList>
14 #include <QDir>
15 
16 // MythTV headers
17 #include "mythmediamonitor.h"
18 #include "mythcdrom.h"
19 #include "mythcorecontext.h"
20 #include "mythdialogs.h"
21 #include "mythconfig.h"
22 #include "mythdialogbox.h"
23 #include "mythdate.h"
24 #include "mythlogging.h"
25 #include "mythmainwindow.h"
26 #include "mythsystemlegacy.h"
27 #include "mythmiscutil.h"
28 
29 #ifdef USING_DARWIN_DA
30 #include "mediamonitor-darwin.h"
31 #elif CONFIG_CYGWIN || defined(_WIN32)
32 #include "mediamonitor-windows.h"
33 #else
34 #include "mediamonitor-unix.h"
35 #endif
36 
37 static const QString _Location = QObject::tr("Media Monitor");
38 
40 
41 // MonitorThread
42 MonitorThread::MonitorThread(MediaMonitor* pMon, unsigned long interval) :
43  MThread("Monitor")
44 {
45  m_Monitor = pMon;
46  m_Interval = interval;
47  m_lastCheckTime = QDateTime::currentDateTimeUtc();
48 }
49 
50 // Nice and simple, as long as our monitor is valid and active,
51 // loop and check it's devices.
53 {
54  RunProlog();
55  QMutex mtx;
56  mtx.lock();
57  while (m_Monitor && m_Monitor->IsActive())
58  {
59  m_Monitor->CheckDevices();
60  m_Monitor->m_wait.wait(&mtx, m_Interval);
61  QDateTime now(QDateTime::currentDateTimeUtc());
62  // if 10 seconds have elapsed instead of 5 seconds
63  // assume the system was suspended and reconnect
64  // sockets
65  if (m_lastCheckTime.secsTo(now) > 120)
66  {
68  if (HasMythMainWindow())
69  {
70  LOG(VB_GENERAL, LOG_INFO, "Restarting LIRC handler");
72  }
73  }
74  m_lastCheckTime = now;
75  }
76  mtx.unlock();
77  RunEpilog();
78 }
79 
81 // MediaMonitor
82 
83 #define MONITOR_INTERVAL 5000
84 
86 {
87  if (c_monitor)
88  return c_monitor;
89 
90 #ifdef USING_DARWIN_DA
91  c_monitor = new MediaMonitorDarwin(nullptr, MONITOR_INTERVAL, true);
92 #else
93  #if CONFIG_CYGWIN || defined(_WIN32)
94  c_monitor = new MediaMonitorWindows(nullptr, MONITOR_INTERVAL, true);
95  #else
96  c_monitor = new MediaMonitorUnix(nullptr, MONITOR_INTERVAL, true);
97  #endif
98 #endif
99 
100  return c_monitor;
101 }
102 
103 void MediaMonitor::SetCDSpeed(const char *device, int speed)
104 {
105  MediaMonitor *mon = GetMediaMonitor();
106  if (mon)
107  {
108  MythMediaDevice *pMedia = mon->GetMedia(device);
109  if (pMedia && mon->ValidateAndLock(pMedia))
110  {
111  pMedia->setSpeed(speed);
112  mon->Unlock(pMedia);
113  return;
114  }
115  }
116 
117  MythCDROM *cd = MythCDROM::get(nullptr, device, false, false);
118  if (cd)
119  {
120  cd->setDeviceSpeed(device, speed);
121  delete cd;
122  return;
123  }
124 
125  LOG(VB_MEDIA, LOG_INFO,
126  QString("MediaMonitor::setSpeed(%1) - Cannot find/create CDROM?")
127  .arg(device));
128 }
129 
130 // When ejecting one of multiple devices, present a nice name to the user
131 static const QString DevName(MythMediaDevice *d)
132 {
133  QString str = d->getVolumeID(); // First choice, the name of the media
134 
135  if (str.isEmpty())
136  {
137  str = d->getDeviceModel(); // otherwise, the drive manufacturer/model
138 
139  if (!str.isEmpty()) // and/or the device node
140  str += " (" + d->getDevicePath() + ')';
141  else
142  str = d->getDevicePath();
143  }
144  // We could add even more information here, but volume names
145  // are usually descriptively unique (i.e. usually good enough)
146  //else
147  // str += " (" + d->getDeviceModel() + ", " + d->getDevicePath() + ')';
148 
149  return str;
150 }
151 
157 QList<MythMediaDevice*> MediaMonitor::GetRemovable(bool showMounted,
158  bool showUsable)
159 {
160  QList <MythMediaDevice *> drives;
161  QList <MythMediaDevice *>::iterator it;
162  QMutexLocker locker(&m_DevicesLock);
163 
164  for (it = m_Devices.begin(); it != m_Devices.end(); ++it)
165  {
166  // By default, we only list CD/DVD devices.
167  // Caller can also request mounted drives to be listed (e.g. USB flash)
168 
169  if (showUsable && !(*it)->isUsable())
170  continue;
171 
172  if (QString(typeid(**it).name()).contains("MythCDROM") ||
173  (showMounted && (*it)->isMounted(false)))
174  drives.append(*it);
175  }
176 
177  return drives;
178 }
179 
186  bool showMounted,
187  bool showUsable)
188 {
189  QList <MythMediaDevice *> drives = GetRemovable(showMounted,
190  showUsable);
191 
192  if (drives.count() == 0)
193  {
194  QString msg = "MediaMonitor::selectDrivePopup() - no removable devices";
195 
196  LOG(VB_MEDIA, LOG_INFO, msg);
197  return nullptr;
198  }
199 
200  if (drives.count() == 1)
201  {
202  LOG(VB_MEDIA, LOG_INFO,
203  "MediaMonitor::selectDrivePopup(" + label +
204  ") - One suitable device");
205  return drives.front();
206  }
207 
208  QList <MythMediaDevice *>::iterator it;
209  QStringList buttonmsgs;
210  for (it = drives.begin(); it != drives.end(); ++it)
211  buttonmsgs += DevName(*it);
212  buttonmsgs += tr("Cancel");
213  const DialogCode cancelbtn = (DialogCode)
214  (((int)kDialogCodeButton0) + buttonmsgs.size() - 1);
215 
217  GetMythMainWindow(), "select drive", label,
218  buttonmsgs, cancelbtn);
219 
220  // If the user cancelled, return a special value
221  if ((kDialogCodeRejected == ret) || (cancelbtn == ret))
222  return (MythMediaDevice *)-1;
223 
224  int idx = MythDialog::CalcItemIndex(ret);
225  if (idx < drives.count())
226  return drives[idx];
227 
228  return nullptr;
229 }
230 
231 
241 {
242  MythMediaDevice *selected;
243 
244 
245  selected = selectDrivePopup(tr("Select removable media"
246  " to eject or insert"), true);
247 
248  // If the user cancelled, no need to display or do anything more
249  if (selected == (MythMediaDevice *) -1)
250  return;
251 
252  if (!selected)
253  {
254  ShowNotification(tr("No devices to eject"), _Location);
255  return;
256  }
257 
258  AttemptEject(selected);
259 }
260 
261 
262 void MediaMonitor::EjectMedia(const QString &path)
263 {
264  MythMediaDevice *device = GetMedia(path);
265  if (device)
266  AttemptEject(device);
267 }
268 
269 
271 {
272  QString dev = DevName(device);
273 
274  if (device->getStatus() == MEDIASTAT_OPEN)
275  {
276  LOG(VB_MEDIA, LOG_INFO,
277  QString("Disk %1's tray is OPEN. Closing tray").arg(dev));
278 
279  if (device->eject(false) != MEDIAERR_OK)
280  {
281  QString msg =
282  QObject::tr("Unable to open or close the empty drive %1");
283  QString extra =
284  QObject::tr("You may have to use the eject button under its tray");
285  ShowNotificationError(msg.arg(dev), _Location, extra);
286  }
287  return;
288  }
289 
290  if (device->isMounted())
291  {
292  LOG(VB_MEDIA, LOG_INFO,
293  QString("Disk %1 is mounted? Unmounting").arg(dev));
294  device->unmount();
295 
296 #if !CONFIG_DARWIN
297  if (device->isMounted())
298  {
299  ShowNotificationError(tr("Failed to unmount %1").arg(dev),
300  _Location);
301  return;
302  }
303 #endif
304  }
305 
306  LOG(VB_MEDIA, LOG_INFO,
307  QString("Unlocking disk %1, then ejecting").arg(dev));
308  device->unlock();
309 
310  MythMediaError err = device->eject();
311 
312  if (err == MEDIAERR_UNSUPPORTED)
313  {
314  // Physical ejection isn't possible (there is no tray or slot),
315  // but logically the device is now ejected (ignored by the OS).
316  ShowNotification(tr("You may safely remove %1").arg(dev), _Location);
317  }
318  else if (err == MEDIAERR_FAILED)
319  {
320  ShowNotificationError(tr("Failed to eject %1").arg(dev), _Location);
321  }
322 }
323 
330 MediaMonitor::MediaMonitor(QObject* par, unsigned long interval,
331  bool allowEject)
332  : QObject(par), m_DevicesLock(QMutex::Recursive),
333  m_Active(false), m_Thread(nullptr),
334  m_MonitorPollingInterval(interval), m_AllowEject(allowEject)
335 {
336  // User can specify that some devices are not monitored
337  QString ignore = gCoreContext->GetSetting("IgnoreDevices", "");
338 
339  if (ignore.length())
340  m_IgnoreList = ignore.split(',', QString::SkipEmptyParts);
341  else
342  m_IgnoreList = QStringList(); // Force empty list
343 
344  LOG(VB_MEDIA, LOG_NOTICE, "Creating MediaMonitor");
345  LOG(VB_MEDIA, LOG_INFO, "IgnoreDevices=" + ignore);
346 
347  // If any of IgnoreDevices are symlinks, also add the real device
348  QStringList::Iterator dev;
349  for (dev = m_IgnoreList.begin(); dev != m_IgnoreList.end(); ++dev)
350  {
351  QFileInfo *fi = new QFileInfo(*dev);
352 
353  if (fi && fi->isSymLink())
354  {
355  QString target = getSymlinkTarget(*dev);
356 
357  if (m_IgnoreList.filter(target).isEmpty())
358  {
359  LOG(VB_MEDIA, LOG_INFO,
360  "Also ignoring " + target + " (symlinked from " +
361  *dev + ").");
362  m_IgnoreList += target;
363  }
364  }
365  delete fi;
366  }
367 }
368 
370 {
371  if (m_Thread)
372  {
373  StopMonitoring();
374  delete m_Thread;
375  m_Thread = nullptr;
376  }
377  QObject::deleteLater();
378 }
379 
388 bool MediaMonitor::RemoveDevice(const QString &dev)
389 {
390  QMutexLocker locker(&m_DevicesLock);
391 
392  QList<MythMediaDevice*>::iterator it;
393  for (it = m_Devices.begin(); it != m_Devices.end(); ++it)
394  {
395  if ((*it)->getDevicePath() == dev)
396  {
397  // Ensure device gets an unmount
398  (*it)->checkMedia();
399 
400  if (m_UseCount[*it] == 0)
401  {
402  m_UseCount.remove(*it);
403  (*it)->deleteLater();
404  m_Devices.erase(it);
405  }
406  else
407  {
408  // Other threads are still using this device
409  // postpone actual delete until they finish.
410  disconnect(*it);
411  m_RemovedDevices.append(*it);
412  m_Devices.erase(it);
413  }
414 
415  return true;
416  }
417  }
418  return false;
419 }
420 
425 {
426  /* check if new devices have been plugged in */
428 
429  QMutexLocker locker(&m_DevicesLock);
430 
431  QList<MythMediaDevice*>::iterator itr = m_Devices.begin();
432  MythMediaDevice* pDev;
433  while (itr != m_Devices.end())
434  {
435  pDev = *itr;
436  if (pDev)
437  pDev->checkMedia();
438  ++itr;
439  }
440 }
441 
446 {
447  // Sanity check
448  if (m_Active)
449  return;
450  if (!gCoreContext->GetBoolSetting("MonitorDrives", false)) {
451  LOG(VB_MEDIA, LOG_NOTICE, "MediaMonitor diasabled by user setting.");
452  return;
453  }
454 
455  if (!m_Thread)
457 
458  qRegisterMetaType<MythMediaStatus>("MythMediaStatus");
459 
460  LOG(VB_MEDIA, LOG_NOTICE, "Starting MediaMonitor");
461  m_Active = true;
462  m_Thread->start();
463 }
464 
469 {
470  // Sanity check
471  if (!m_Active)
472  return;
473 
474  LOG(VB_MEDIA, LOG_NOTICE, "Stopping MediaMonitor");
475  m_Active = false;
476  m_wait.wakeAll();
477  m_Thread->wait();
478  LOG(VB_MEDIA, LOG_NOTICE, "Stopped MediaMonitor");
479 }
480 
492 {
493  QMutexLocker locker(&m_DevicesLock);
494 
495  if (!m_Devices.contains(pMedia))
496  return false;
497 
498  m_UseCount[pMedia]++;
499 
500  return true;
501 }
502 
509 {
510  QMutexLocker locker(&m_DevicesLock);
511 
512  if (!m_UseCount.contains(pMedia))
513  return;
514 
515  m_UseCount[pMedia]--;
516 
517  if (m_UseCount[pMedia] == 0 && m_RemovedDevices.contains(pMedia))
518  {
519  m_RemovedDevices.removeAll(pMedia);
520  m_UseCount.remove(pMedia);
521  pMedia->deleteLater();
522  }
523 }
524 
532 {
533  QMutexLocker locker(&m_DevicesLock);
534 
535  QList<MythMediaDevice*>::iterator it = m_Devices.begin();
536  for (;it != m_Devices.end(); ++it)
537  {
538  if ((*it)->isSameDevice(path) &&
539  (((*it)->getStatus() == MEDIASTAT_USEABLE) ||
540  ((*it)->getStatus() == MEDIASTAT_MOUNTED) ||
541  ((*it)->getStatus() == MEDIASTAT_NOTMOUNTED)))
542  {
543  return(*it);
544  }
545  }
546 
547  return nullptr;
548 }
549 
556 QString MediaMonitor::GetMountPath(const QString& devPath)
557 {
558  QString mountPath;
559 
560  if (c_monitor)
561  {
562  MythMediaDevice *pMedia = c_monitor->GetMedia(devPath);
563  if (pMedia && c_monitor->ValidateAndLock(pMedia))
564  {
565  mountPath = pMedia->getMountPath();
566  c_monitor->Unlock(pMedia);
567  }
568  // The media monitor could be inactive.
569  // Create a fake media device just to lookup mount map:
570  else
571  {
572  pMedia = MythCDROM::get(nullptr, devPath.toLatin1(), true, false);
573  if (pMedia && pMedia->findMountPath())
574  mountPath = pMedia->getMountPath();
575  else
576  LOG(VB_MEDIA, LOG_INFO,
577  "MediaMonitor::GetMountPath() - failed");
578  // need some way to delete the media device.
579  }
580  }
581 
582  return mountPath;
583 }
584 
603 QList<MythMediaDevice*> MediaMonitor::GetMedias(unsigned mediatypes)
604 {
605  QMutexLocker locker(&m_DevicesLock);
606 
607  QList<MythMediaDevice*> medias;
608 
609  QList<MythMediaDevice*>::iterator it = m_Devices.begin();
610  for (;it != m_Devices.end(); ++it)
611  {
612  if (((*it)->getMediaType() & mediatypes) &&
613  (((*it)->getStatus() == MEDIASTAT_USEABLE) ||
614  ((*it)->getStatus() == MEDIASTAT_MOUNTED) ||
615  ((*it)->getStatus() == MEDIASTAT_NOTMOUNTED)))
616  {
617  medias.push_back(*it);
618  }
619  }
620 
621  return medias;
622 }
623 
643 void MediaMonitor::RegisterMediaHandler(const QString &destination,
644  const QString &description,
645  void (*callback)
646  (MythMediaDevice*),
647  int mediaType,
648  const QString &extensions)
649 {
650  if (m_handlerMap.count(destination) == 0)
651  {
652  MHData mhd = { callback, mediaType, destination, description };
653  QString msg = MythMediaDevice::MediaTypeString((MythMediaType)mediaType);
654 
655  if (extensions.length())
656  msg += QString(", ext(%1)").arg(extensions, 0, 16);
657 
658  LOG(VB_MEDIA, LOG_INFO,
659  "Registering '" + destination + "' as a media handler for " +
660  msg);
661 
662  m_handlerMap[destination] = mhd;
663 
664  if (extensions.length())
665  MythMediaDevice::RegisterMediaExtensions(mediaType, extensions);
666  }
667  else
668  {
669  LOG(VB_GENERAL, LOG_INFO,
670  destination + " is already registered as a media handler.");
671  }
672 }
673 
682 {
683  QList<MHData> handlers;
684  QMap<QString, MHData>::Iterator itr = m_handlerMap.begin();
685 
686  while (itr != m_handlerMap.end())
687  {
688  if (((*itr).MythMediaType & (int)pMedia->getMediaType()))
689  {
690  LOG(VB_GENERAL, LOG_NOTICE,
691  QString("Found a handler for %1 - '%2'")
692  .arg(pMedia->MediaTypeString()) .arg(itr.key()));
693  handlers.append(*itr);
694  }
695  itr++;
696  }
697 
698  if (handlers.empty())
699  {
700  LOG(VB_MEDIA, LOG_INFO, "No media handler found for event type");
701  return;
702  }
703 
704 
705  // TODO - Generate a dialog, add buttons for each description,
706  // if user didn't cancel, selected = handlers.at(choice);
707  int selected = 0;
708 
709  handlers.at(selected).callback(pMedia);
710 }
711 
717  MythMediaDevice* pMedia)
718 {
719  // If we're not active then ignore signal.
720  if (!m_Active)
721  return;
722 
723  MythMediaStatus stat = pMedia->getStatus();
724  QString msg = QString(" (%1, %2 -> %3)")
725  .arg(pMedia->MediaTypeString())
726  .arg(MythMediaDevice::MediaStatusStrings[oldStatus])
728 
729  // This gets called from outside the main thread so we need
730  // to post an event back to the main thread.
731  // We now send events for all non-error statuses, so plugins get ejects
732  if (stat != MEDIASTAT_ERROR && stat != MEDIASTAT_UNKNOWN &&
733  // Don't send an event for a new device that's not mounted
734  !(oldStatus == MEDIASTAT_UNPLUGGED && stat == MEDIASTAT_NOTMOUNTED))
735  {
736  // Should we ValidateAndLock() first?
737  QEvent *e = new MythMediaEvent(stat, pMedia);
738 
739  LOG(VB_MEDIA, LOG_INFO, "Posting MediaEvent" + msg);
740 
741  // sendEvent() is needed here - it waits for the event to be used.
742  // postEvent() would result in pDevice's media type changing
743  // ... before the plugin's event chain would process it.
744  // Another way would be to send an exact copy of pDevice instead.
745  QCoreApplication::sendEvent((QObject*)GetMythMainWindow(), e);
746  delete e;
747  }
748  else
749  LOG(VB_MEDIA, LOG_INFO,
750  "Media status changed, but not sending event" + msg);
751 
752 
753  if (stat == MEDIASTAT_OPEN || stat == MEDIASTAT_NODISK
754  || stat == MEDIASTAT_UNPLUGGED)
755  {
756  pMedia->clearData();
757  }
758 }
759 
764 {
765  if (m_IgnoreList.contains(device->getMountPath()) ||
766  m_IgnoreList.contains(device->getRealDevice())||
767  m_IgnoreList.contains(device->getDevicePath()) )
768  {
769  LOG(VB_MEDIA, LOG_INFO,
770  "Ignoring device: " + device->getDevicePath());
771  return true;
772  }
773 #if 0
774  else
775  {
776  LOG(VB_MEDIA, LOG_DEBUG,
777  "Not ignoring: " + device->getDevicePath() + " / " +
778  device->getMountPath());
779  LOG(VB_MEDIA, LOG_DEBUG,
780  "Paths not in: " + m_IgnoreList.join(", "));
781  }
782 #endif
783 
784  return false;
785 }
786 
791 bool MediaMonitor::eventFilter(QObject *obj, QEvent *event)
792 {
793  if (event->type() == MythMediaEvent::kEventType)
794  {
795  MythMediaDevice *pDev = ((MythMediaEvent*)event)->getDevice();
796 
797  if (!pDev)
798  {
799  LOG(VB_GENERAL, LOG_ALERT,
800  "MediaMonitor::eventFilter() got a bad media event?");
801  return true;
802  }
803 
804  if (pDev->isUsable())
805  JumpToMediaHandler(pDev);
806  else
807  {
808  // We don't want to jump around in the menus, but should
809  // call each plugin's callback so it can track this change.
810 
811  QMap<QString, MHData>::Iterator itr = m_handlerMap.begin();
812  while (itr != m_handlerMap.end())
813  {
814  if ((*itr).MythMediaType & (int)pDev->getMediaType() ||
815  pDev->getStatus() == MEDIASTAT_OPEN)
816  (*itr).callback(pDev);
817  itr++;
818  }
819  }
820 
821  return false; // Don't eat the event
822  }
823 
824  // standard event processing
825  return QObject::eventFilter(obj, event);
826 }
827 
828 /*
829  * These methods return the user's preferred devices for playing and burning
830  * CDs and DVDs. Traditionally we had a database setting to remember this,
831  * but that is a bit wasteful when most users only have one drive.
832  *
833  * To make it a bit more beginner friendly, if no database default exists,
834  * or if it contains "default", the code tries to find a monitored drive.
835  * If, still, nothing is suitable, a caller hard-coded default is used.
836  *
837  * Ideally, these would return a MythMediaDevice * instead of a QString
838  */
839 
840 QString MediaMonitor::defaultDevice(const QString &dbSetting,
841  const QString &label,
842  const char *hardCodedDefault)
843 {
844  QString device = gCoreContext->GetSetting(dbSetting);
845 
846  LOG(VB_MEDIA, LOG_DEBUG,
847  QString("MediaMonitor::defaultDevice(%1,..,%2) dbSetting='%3'")
848  .arg(dbSetting).arg(hardCodedDefault).arg(device));
849 
850  // No settings database defaults? Try to choose one:
851  if (device.isEmpty() || device == "default")
852  {
853  device = hardCodedDefault;
854 
855  if (!c_monitor)
857 
858  if (c_monitor)
859  {
860  MythMediaDevice *d = c_monitor->selectDrivePopup(label, false, true);
861 
862  if (d == (MythMediaDevice *) -1) // User cancelled
863  {
864  device.clear(); // If user has explicitly cancelled return empty string
865  d = nullptr;
866  }
867 
868  if (d && c_monitor->ValidateAndLock(d))
869  {
870  device = d->getDevicePath();
871  c_monitor->Unlock(d);
872  }
873  }
874  }
875 
876  LOG(VB_MEDIA, LOG_DEBUG,
877  "MediaMonitor::defaultDevice() returning " + device);
878  return device;
879 }
880 
885 {
886  return defaultDevice("CDDevice", tr("Select a CD drive"), DEFAULT_CD);
887 }
888 
893 {
894  return defaultDevice("VCDDeviceLocation",
895  tr("Select a VCD drive"), DEFAULT_CD);
896 }
897 
902 {
903  return defaultDevice("DVDDeviceLocation",
904  tr("Select a DVD drive"), DEFAULT_DVD);
905 }
906 
911 {
912  return defaultDevice("CDWriterDeviceLocation",
913  tr("Select a CD writer"), DEFAULT_CD);
914 }
915 
923 {
924  QString device = defaultDevice("MythArchiveDVDLocation",
925  tr("Select a DVD writer"), DEFAULT_DVD);
926 
927  return device;
928 }
929 
930 
934 const QString MediaMonitor::listDevices(void)
935 {
936  QList<MythMediaDevice*>::const_iterator dev;
937  QStringList list;
938 
939  for (dev = m_Devices.begin(); dev != m_Devices.end(); ++dev)
940  {
941  QString devStr;
942  QString model = (*dev)->getDeviceModel();
943  QString path = (*dev)->getDevicePath();
944  QString real = (*dev)->getRealDevice();
945 
946  if (path != real)
947  devStr += path + "->";
948  devStr += real;
949 
950  if (!model.length())
951  model = "unknown";
952  devStr += " (" + model + ")";
953 
954  list += devStr;
955  }
956 
957  return list.join(", ");
958 }
959 
967 {
969  if (mon)
970  mon->ChooseAndEjectMedia();
971  else
972  {
973  LOG(VB_MEDIA, LOG_INFO, "CD/DVD Monitor isn't enabled.");
974 #ifdef __linux__
975  LOG(VB_MEDIA, LOG_INFO, "Trying Linux 'eject -T' command");
976  myth_system("eject -T");
977 #elif CONFIG_DARWIN
978  QString def = DEFAULT_CD;
979  LOG(VB_MEDIA, LOG_INFO, "Trying 'diskutil eject " + def);
980  myth_system("diskutil eject " + def);
981 #endif
982  }
983 }
984 
985 /*
986  * vim:ts=4:sw=4:ai:et:si:sts=4
987  */
MythMediaType getMediaType() const
Definition: mythmedia.h:91
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:216
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:295
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
const QString & getDevicePath() const
Definition: mythmedia.h:61
CD/DVD tray open (meaningless for non-CDs?)
Definition: mythmedia.h:16
QMap< MythMediaDevice *, int > m_UseCount
QMap< QString, MHData > m_handlerMap
Registered Media Handlers.
MythMediaType
Definition: mythmedia.h:24
QPointer< MediaMonitor > m_Monitor
MonitorThread * m_Thread
static QString GetMountPath(const QString &devPath)
If the device is being monitored, return its mountpoint.
unsigned long m_MonitorPollingInterval
void EjectMedia(const QString &path)
static int CalcItemIndex(DialogCode code)
bool shouldIgnore(const MythMediaDevice *device)
Check user preferences to see if this device should be monitored.
I am assuming, for now, that everything on Windows uses drive letters (e.g.
Unable to mount, but could be usable.
Definition: mythmedia.h:13
QList< MythMediaDevice * > m_RemovedDevices
static void ejectOpticalDisc(void)
Eject a disk, unmount a drive, open a tray.
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:312
static QString defaultCDWriter()
CDWriterDeviceLocation, user-selected drive, or /dev/cdrom.
MythMediaDevice * GetMedia(const QString &path)
Get media device by pathname.
virtual void StartMonitoring(void)
Start the monitoring thread if needed.
static void RegisterMediaExtensions(uint mediatype, const QString &extensions)
Used to register media types with extensions.
Definition: mythmedia.cpp:304
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static QString defaultDevice(const QString &setting, const QString &label, const char *hardCodedDefault)
Stores details of media handlers.
static QString defaultDVDdevice()
DVDDeviceLocation, user-selected drive, or /dev/dvd.
unsigned long m_Interval
friend class MonitorThread
virtual void deleteLater(void)
static const char * MediaStatusStrings[]
Definition: mythmedia.h:117
void StopMonitoring(void)
Stop the monitoring thread if needed.
#define MONITOR_INTERVAL
static void SetCDSpeed(const char *device, int speed)
QList< MythMediaDevice * > m_Devices
QWaitCondition m_wait
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
DialogCode
Definition: mythdialogs.h:21
virtual MythMediaError unlock()
Definition: mythmedia.cpp:355
void ShowNotification(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
void mediaStatusChanged(MythMediaStatus oldStatus, MythMediaDevice *pMedia)
Slot which is called when the device status changes and posts a media event to the mainwindow.
static const uint16_t * d
QString GetSetting(const QString &key, const QString &defaultval="")
void CheckDevices(void)
Poll the devices in our list.
MythMediaError
Definition: mythmedia.h:39
static MediaMonitor * GetMediaMonitor(void)
static QString defaultVCDdevice()
VCDDeviceLocation, user-selected drive, or /dev/cdrom.
void ShowNotificationError(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
convenience utility to display error message as notification
MonitorThread(MediaMonitor *pMon, unsigned long interval)
static QString defaultCDdevice()
CDDevice, user-selected drive, or /dev/cdrom.
QList< MythMediaDevice * > GetMedias(unsigned mediatypes)
Ask for available media.
void AttemptEject(MythMediaDevice *device)
static QList< GameHandler * > * handlers
Definition: gamehandler.cpp:23
void Unlock(MythMediaDevice *pMedia)
decrements the MythMediaDevices reference count
uint myth_system(const QString &command, uint flags, uint timeout)
const QString & getRealDevice() const
Definition: mythmedia.h:63
bool eventFilter(QObject *obj, QEvent *event) override
Installed into the main window's event chain, so that the main thread can safely jump to plugin code.
void setDeviceSpeed(const char *devicePath, int speed) override
Definition: mythcdrom.cpp:132
virtual void setSpeed(int speed)
Definition: mythmedia.cpp:337
bool HasMythMainWindow(void)
QList< MythMediaDevice * > GetRemovable(bool showMounted=false, bool showUsable=false)
Generate a list of removable drives.
virtual MythMediaError eject(bool open_close=true)
Definition: mythmedia.cpp:312
MythMainWindow * GetMythMainWindow(void)
static MythCDROM * get(QObject *par, const char *devicePath, bool SuperMount, bool AllowEject)
Definition: mythcdrom.cpp:35
static Type kEventType
Definition: mythmedia.h:190
bool RemoveDevice(const QString &dev)
Remove a device from the media monitor.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static const QString DevName(MythMediaDevice *d)
bool ValidateAndLock(MythMediaDevice *pMedia)
Validates the MythMediaDevice and increments its reference count.
bool findMountPath()
Try to find a mount of m_DevicePath in the mounts file.
Definition: mythmedia.cpp:372
bool GetBoolSetting(const QString &key, bool defaultval=false)
static DialogCode ShowButtonPopup(MythMainWindow *parent, const QString &title, const QString &message, const QStringList &buttonmsgs, DialogCode default_button)
MediaMonitor(QObject *par, unsigned long interval, bool allowEject)
Lookup some settings, and do OS-specific stuff in sub-classes.
This currently depends on Apple's DiskArbitration framework.
const QString & getMountPath() const
Definition: mythmedia.h:58
void RegisterMediaHandler(const QString &destination, const QString &description, void(*callback)(MythMediaDevice *), int mediaType, const QString &extensions)
Register a handler for media related events.
static QString defaultDVDWriter()
MythArchiveDVDLocation, user-selected drive, or /dev/dvd.
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:203
QDateTime m_lastCheckTime
#define DEFAULT_CD
bool isUsable() const
Is this device "ready", for a plugin to access?
Definition: mythmedia.h:84
virtual MythMediaStatus checkMedia()=0
QString MediaTypeString()
Definition: mythmedia.cpp:522
static MediaMonitor * c_monitor
void JumpToMediaHandler(MythMediaDevice *pMedia)
Find a relevant jump point for this type of media.
bool isMounted(bool bVerify=true)
Tells us if m_DevicePath is a mounted device.
Definition: mythmedia.cpp:363
CD/DVD tray closed but empty, device unusable.
Definition: mythmedia.h:17
MythMediaStatus
Definition: mythmedia.h:12
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
bool volatile m_Active
Was MonitorThread started?
static const QString _Location
void StartLIRC(void)
virtual void CheckDeviceNotifications(void)
MythMediaDevice * selectDrivePopup(const QString &label, bool showMounted=false, bool showUsable=false)
List removable drives, let the user select one.
bool unmount()
Definition: mythmedia.h:108
MythMediaStatus getStatus() const
Definition: mythmedia.h:70
QStringList m_IgnoreList
const QString listDevices(void)
A string summarising the current devices, for debugging.
void ChooseAndEjectMedia(void)
Unmounts and ejects removable media devices.
#define DEFAULT_DVD