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 
9 // Qt headers
10 #include <QCoreApplication>
11 #include <QFile>
12 #include <QList>
13 #include <QDir>
14 
15 // MythTV headers
16 #include "mythmediamonitor.h"
17 #include "mythcdrom.h"
18 #include "mythcorecontext.h"
19 #include "mythconfig.h"
20 #include "mythdialogbox.h"
21 #include "mythdate.h"
22 #include "mythlogging.h"
23 #include "mythmainwindow.h"
24 #include "mythsystemlegacy.h"
25 #include "mythmiscutil.h"
26 
27 #ifdef USING_DARWIN_DA
28 #include "mediamonitor-darwin.h"
29 #elif CONFIG_CYGWIN || defined(_WIN32)
30 #include "mediamonitor-windows.h"
31 #else
32 #include "mediamonitor-unix.h"
33 #endif
34 
35 static const QString sLocation = QObject::tr("Media Monitor");
36 
38 
39 // MonitorThread
40 MonitorThread::MonitorThread(MediaMonitor* pMon, unsigned long interval) :
41  MThread("Monitor")
42 {
43  m_monitor = pMon;
44  m_interval = interval;
45  m_lastCheckTime = QDateTime::currentDateTimeUtc();
46 }
47 
48 // Nice and simple, as long as our monitor is valid and active,
49 // loop and check it's devices.
51 {
52  RunProlog();
53  QMutex mtx;
54  mtx.lock();
55  while (m_monitor && m_monitor->IsActive())
56  {
57  m_monitor->CheckDevices();
58  m_monitor->m_wait.wait(&mtx, m_interval);
59  QDateTime now(QDateTime::currentDateTimeUtc());
60  // if 10 seconds have elapsed instead of 5 seconds
61  // assume the system was suspended and reconnect
62  // sockets
63  if (m_lastCheckTime.secsTo(now) > 120)
64  {
66  if (HasMythMainWindow())
67  {
68  LOG(VB_GENERAL, LOG_INFO, "Restarting LIRC handler");
70  }
71  }
72  m_lastCheckTime = now;
73  }
74  mtx.unlock();
75  RunEpilog();
76 }
77 
79 // MediaMonitor
80 
81 #define MONITOR_INTERVAL 5000
82 
84 {
85  if (s_monitor)
86  return s_monitor;
87 
88 #ifdef USING_DARWIN_DA
89  s_monitor = new MediaMonitorDarwin(nullptr, MONITOR_INTERVAL, true);
90 #else
91  #if CONFIG_CYGWIN || defined(_WIN32)
92  s_monitor = new MediaMonitorWindows(nullptr, MONITOR_INTERVAL, true);
93  #else
94  s_monitor = new MediaMonitorUnix(nullptr, MONITOR_INTERVAL, true);
95  #endif
96 #endif
97 
98  return s_monitor;
99 }
100 
101 void MediaMonitor::SetCDSpeed(const char *device, int speed)
102 {
103  MediaMonitor *mon = GetMediaMonitor();
104  if (mon)
105  {
106  MythMediaDevice *pMedia = mon->GetMedia(device);
107  if (pMedia && mon->ValidateAndLock(pMedia))
108  {
109  pMedia->setSpeed(speed);
110  mon->Unlock(pMedia);
111  return;
112  }
113  }
114 
115  MythCDROM *cd = MythCDROM::get(nullptr, device, false, false);
116  if (cd)
117  {
118  cd->setDeviceSpeed(device, speed);
119  delete cd;
120  return;
121  }
122 
123  LOG(VB_MEDIA, LOG_INFO,
124  QString("MediaMonitor::setSpeed(%1) - Cannot find/create CDROM?")
125  .arg(device));
126 }
127 
128 // When ejecting one of multiple devices, present a nice name to the user
129 static QString DevName(MythMediaDevice *d)
130 {
131  QString str = d->getVolumeID(); // First choice, the name of the media
132 
133  if (str.isEmpty())
134  {
135  str = d->getDeviceModel(); // otherwise, the drive manufacturer/model
136 
137  if (!str.isEmpty()) // and/or the device node
138  str += " (" + d->getDevicePath() + ')';
139  else
140  str = d->getDevicePath();
141  }
142  // We could add even more information here, but volume names
143  // are usually descriptively unique (i.e. usually good enough)
144  //else
145  // str += " (" + d->getDeviceModel() + ", " + d->getDevicePath() + ')';
146 
147  return str;
148 }
149 
155 QList<MythMediaDevice*> MediaMonitor::GetRemovable(bool showMounted,
156  bool showUsable)
157 {
158  QList <MythMediaDevice *> drives;
159  QList <MythMediaDevice *>::iterator it;
160  QMutexLocker locker(&m_devicesLock);
161 
162  for (it = m_devices.begin(); it != m_devices.end(); ++it)
163  {
164  // By default, we only list CD/DVD devices.
165  // Caller can also request mounted drives to be listed (e.g. USB flash)
166 
167  if (showUsable && !(*it)->isUsable())
168  continue;
169 
170  if (QString(typeid(**it).name()).contains("MythCDROM") ||
171  (showMounted && (*it)->isMounted(false)))
172  drives.append(*it);
173  }
174 
175  return drives;
176 }
177 
184  bool showMounted,
185  bool showUsable)
186 {
187  QList <MythMediaDevice *> drives = GetRemovable(showMounted,
188  showUsable);
189 
190  if (drives.count() == 0)
191  {
192  QString msg = "MediaMonitor::selectDrivePopup() - no removable devices";
193 
194  LOG(VB_MEDIA, LOG_INFO, msg);
195  return nullptr;
196  }
197 
198  if (drives.count() == 1)
199  {
200  LOG(VB_MEDIA, LOG_INFO,
201  "MediaMonitor::selectDrivePopup(" + label +
202  ") - One suitable device");
203  return drives.front();
204  }
205 
207  if (!win)
208  return nullptr;
209 
210  MythScreenStack *stack = win->GetMainStack();
211  if (!stack)
212  return nullptr;
213 
214  // Ignore MENU dialog actions
215  int btnIndex = -2;
216  while (btnIndex < -1)
217  {
218  auto *dlg = new MythDialogBox(label, stack, "select drive");
219  if (!dlg->Create())
220  {
221  delete dlg;
222  return nullptr;
223  }
224 
225  // Add button for each drive
226  for (auto *drive : drives)
227  dlg->AddButton(DevName(drive));
228 
229  dlg->AddButton(tr("Cancel"));
230 
231  stack->AddScreen(dlg);
232 
233  // Wait in local event loop so events are processed
234  QEventLoop block;
235  connect(dlg, &MythDialogBox::Closed,
236  &block, [&](const QString& /*resultId*/, int result) { block.exit(result); });
237 
238  // Block until dialog closes
239  btnIndex = block.exec();
240  }
241 
242  // If the user cancelled, return a special value
243  return btnIndex < 0 || btnIndex >= drives.size() ? (MythMediaDevice *)-1
244  : drives.at(btnIndex);
245 }
246 
247 
257 {
258  MythMediaDevice *selected =
259  selectDrivePopup(tr("Select removable media to eject or insert"), true);
260 
261  // If the user cancelled, no need to display or do anything more
262  if (selected == (MythMediaDevice *) -1)
263  return;
264 
265  if (!selected)
266  {
267  ShowNotification(tr("No devices to eject"), sLocation);
268  return;
269  }
270 
271  AttemptEject(selected);
272 }
273 
274 
275 void MediaMonitor::EjectMedia(const QString &path)
276 {
277  MythMediaDevice *device = GetMedia(path);
278  if (device)
279  AttemptEject(device);
280 }
281 
282 
284 {
285  QString dev = DevName(device);
286 
287  if (device->getStatus() == MEDIASTAT_OPEN)
288  {
289  LOG(VB_MEDIA, LOG_INFO,
290  QString("Disk %1's tray is OPEN. Closing tray").arg(dev));
291 
292  if (device->eject(false) != MEDIAERR_OK)
293  {
294  QString msg =
295  QObject::tr("Unable to open or close the empty drive %1");
296  QString extra =
297  QObject::tr("You may have to use the eject button under its tray");
298  ShowNotificationError(msg.arg(dev), sLocation, extra);
299  }
300  return;
301  }
302 
303  if (device->isMounted())
304  {
305  LOG(VB_MEDIA, LOG_INFO,
306  QString("Disk %1 is mounted? Unmounting").arg(dev));
307  device->unmount();
308 
309 #if !CONFIG_DARWIN
310  if (device->isMounted())
311  {
312  ShowNotificationError(tr("Failed to unmount %1").arg(dev),
313  sLocation);
314  return;
315  }
316 #endif
317  }
318 
319  LOG(VB_MEDIA, LOG_INFO,
320  QString("Unlocking disk %1, then ejecting").arg(dev));
321  device->unlock();
322 
323  MythMediaError err = device->eject();
324 
325  if (err == MEDIAERR_UNSUPPORTED)
326  {
327  // Physical ejection isn't possible (there is no tray or slot),
328  // but logically the device is now ejected (ignored by the OS).
329  ShowNotification(tr("You may safely remove %1").arg(dev), sLocation);
330  }
331  else if (err == MEDIAERR_FAILED)
332  {
333  ShowNotificationError(tr("Failed to eject %1").arg(dev), sLocation);
334  }
335 }
336 
343 MediaMonitor::MediaMonitor(QObject* par, unsigned long interval,
344  bool allowEject)
345  : QObject(par), m_devicesLock(QMutex::Recursive),
346  m_monitorPollingInterval(interval), m_allowEject(allowEject)
347 {
348  // User can specify that some devices are not monitored
349  QString ignore = gCoreContext->GetSetting("IgnoreDevices", "");
350 
351  if (!ignore.isEmpty())
352  {
353 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
354  m_ignoreList = ignore.split(',', QString::SkipEmptyParts);
355 #else
356  m_ignoreList = ignore.split(',', Qt::SkipEmptyParts);
357 #endif
358  }
359  else
360  m_ignoreList = QStringList(); // Force empty list
361 
362  LOG(VB_MEDIA, LOG_NOTICE, "Creating MediaMonitor");
363  LOG(VB_MEDIA, LOG_INFO, "IgnoreDevices=" + ignore);
364 
365  // If any of IgnoreDevices are symlinks, also add the real device
366  QStringList::Iterator dev;
367  for (dev = m_ignoreList.begin(); dev != m_ignoreList.end(); ++dev)
368  {
369  auto *fi = new QFileInfo(*dev);
370 
371  if (fi && fi->isSymLink())
372  {
373  QString target = getSymlinkTarget(*dev);
374 
375  if (m_ignoreList.filter(target).isEmpty())
376  {
377  LOG(VB_MEDIA, LOG_INFO,
378  "Also ignoring " + target + " (symlinked from " +
379  *dev + ").");
380  m_ignoreList += target;
381  }
382  }
383  delete fi;
384  }
385 }
386 
388 {
389  if (m_thread)
390  {
391  StopMonitoring();
392  delete m_thread;
393  m_thread = nullptr;
394  }
395  QObject::deleteLater();
396 }
397 
406 bool MediaMonitor::RemoveDevice(const QString &dev)
407 {
408  QMutexLocker locker(&m_devicesLock);
409 
410  QList<MythMediaDevice*>::iterator it;
411  for (it = m_devices.begin(); it != m_devices.end(); ++it)
412  {
413  if ((*it)->getDevicePath() == dev)
414  {
415  // Ensure device gets an unmount
416  (*it)->checkMedia();
417 
418  if (m_useCount[*it] == 0)
419  {
420  m_useCount.remove(*it);
421  (*it)->deleteLater();
422  m_devices.erase(it);
423  }
424  else
425  {
426  // Other threads are still using this device
427  // postpone actual delete until they finish.
428  disconnect(*it);
429  m_removedDevices.append(*it);
430  m_devices.erase(it);
431  }
432 
433  return true;
434  }
435  }
436  return false;
437 }
438 
443 {
444  /* check if new devices have been plugged in */
446 
447  QMutexLocker locker(&m_devicesLock);
448 
449  QList<MythMediaDevice*>::iterator itr = m_devices.begin();
450  while (itr != m_devices.end())
451  {
452  MythMediaDevice* pDev = *itr;
453  if (pDev)
454  pDev->checkMedia();
455  ++itr;
456  }
457 }
458 
463 {
464  // Sanity check
465  if (m_active)
466  return;
467  if (!gCoreContext->GetBoolSetting("MonitorDrives", false)) {
468  LOG(VB_MEDIA, LOG_NOTICE, "MediaMonitor disabled by user setting.");
469  return;
470  }
471 
472  if (!m_thread)
474 
475  qRegisterMetaType<MythMediaStatus>("MythMediaStatus");
476 
477  LOG(VB_MEDIA, LOG_NOTICE, "Starting MediaMonitor");
478  m_active = true;
479  m_thread->start();
480 }
481 
486 {
487  // Sanity check
488  if (!m_active)
489  return;
490 
491  LOG(VB_MEDIA, LOG_NOTICE, "Stopping MediaMonitor");
492  m_active = false;
493  m_wait.wakeAll();
494  m_thread->wait();
495  LOG(VB_MEDIA, LOG_NOTICE, "Stopped MediaMonitor");
496 }
497 
509 {
510  QMutexLocker locker(&m_devicesLock);
511 
512  if (!m_devices.contains(pMedia))
513  return false;
514 
515  m_useCount[pMedia]++;
516 
517  return true;
518 }
519 
526 {
527  QMutexLocker locker(&m_devicesLock);
528 
529  if (!m_useCount.contains(pMedia))
530  return;
531 
532  m_useCount[pMedia]--;
533 
534  if (m_useCount[pMedia] == 0 && m_removedDevices.contains(pMedia))
535  {
536  m_removedDevices.removeAll(pMedia);
537  m_useCount.remove(pMedia);
538  pMedia->deleteLater();
539  }
540 }
541 
549 {
550  QMutexLocker locker(&m_devicesLock);
551 
552  for (auto *dev : qAsConst(m_devices))
553  {
554  if (dev->isSameDevice(path) &&
555  ((dev->getStatus() == MEDIASTAT_USEABLE) ||
556  (dev->getStatus() == MEDIASTAT_MOUNTED) ||
557  (dev->getStatus() == MEDIASTAT_NOTMOUNTED)))
558  {
559  return dev;
560  }
561  }
562 
563  return nullptr;
564 }
565 
572 QString MediaMonitor::GetMountPath(const QString& devPath)
573 {
574  QString mountPath;
575 
576  if (s_monitor)
577  {
578  MythMediaDevice *pMedia = s_monitor->GetMedia(devPath);
579  if (pMedia && s_monitor->ValidateAndLock(pMedia))
580  {
581  mountPath = pMedia->getMountPath();
582  s_monitor->Unlock(pMedia);
583  }
584  // The media monitor could be inactive.
585  // Create a fake media device just to lookup mount map:
586  else
587  {
588  pMedia = MythCDROM::get(nullptr, devPath.toLatin1(), true, false);
589  if (pMedia && pMedia->findMountPath())
590  mountPath = pMedia->getMountPath();
591  else
592  LOG(VB_MEDIA, LOG_INFO,
593  "MediaMonitor::GetMountPath() - failed");
594  // need some way to delete the media device.
595  }
596  }
597 
598  return mountPath;
599 }
600 
619 QList<MythMediaDevice*> MediaMonitor::GetMedias(unsigned mediatypes)
620 {
621  QMutexLocker locker(&m_devicesLock);
622 
623  QList<MythMediaDevice*> medias;
624 
625  for (auto *dev : qAsConst(m_devices))
626  {
627  if ((dev->getMediaType() & mediatypes) &&
628  ((dev->getStatus() == MEDIASTAT_USEABLE) ||
629  (dev->getStatus() == MEDIASTAT_MOUNTED) ||
630  (dev->getStatus() == MEDIASTAT_NOTMOUNTED)))
631  {
632  medias.push_back(dev);
633  }
634  }
635 
636  return medias;
637 }
638 
658 void MediaMonitor::RegisterMediaHandler(const QString &destination,
659  const QString &description,
660  void (*callback)
661  (MythMediaDevice*),
662  int mediaType,
663  const QString &extensions)
664 {
665  if (m_handlerMap.count(destination) == 0)
666  {
667  MHData mhd = { callback, mediaType, destination, description };
668  QString msg = MythMediaDevice::MediaTypeString((MythMediaType)mediaType);
669 
670  if (!extensions.isEmpty())
671  msg += QString(", ext(%1)").arg(extensions, 0, 16);
672 
673  LOG(VB_MEDIA, LOG_INFO,
674  "Registering '" + destination + "' as a media handler for " +
675  msg);
676 
677  m_handlerMap[destination] = mhd;
678 
679  if (!extensions.isEmpty())
680  MythMediaDevice::RegisterMediaExtensions(mediaType, extensions);
681  }
682  else
683  {
684  LOG(VB_GENERAL, LOG_INFO,
685  destination + " is already registered as a media handler.");
686  }
687 }
688 
697 {
698  QVector<MHData> handlers;
699  QMap<QString, MHData>::Iterator itr = m_handlerMap.begin();
700 
701  while (itr != m_handlerMap.end())
702  {
703  if (((*itr).MythMediaType & (int)pMedia->getMediaType()))
704  {
705  LOG(VB_GENERAL, LOG_NOTICE,
706  QString("Found a handler for %1 - '%2'")
707  .arg(pMedia->MediaTypeString()) .arg(itr.key()));
708  handlers.append(*itr);
709  }
710  itr++;
711  }
712 
713  if (handlers.empty())
714  {
715  LOG(VB_MEDIA, LOG_INFO, "No media handler found for event type");
716  return;
717  }
718 
719 
720  // TODO - Generate a dialog, add buttons for each description,
721  // if user didn't cancel, selected = handlers.at(choice);
722  int selected = 0;
723 
724  handlers.at(selected).callback(pMedia);
725 }
726 
732  MythMediaDevice* pMedia) const
733 {
734  // If we're not active then ignore signal.
735  if (!m_active)
736  return;
737 
738  MythMediaStatus stat = pMedia->getStatus();
739  QString msg = QString(" (%1, %2 -> %3)")
740  .arg(pMedia->MediaTypeString())
741  .arg(MythMediaDevice::kMediaStatusStrings[oldStatus])
743 
744  // This gets called from outside the main thread so we need
745  // to post an event back to the main thread.
746  // We now send events for all non-error statuses, so plugins get ejects
747  if (stat != MEDIASTAT_ERROR && stat != MEDIASTAT_UNKNOWN &&
748  // Don't send an event for a new device that's not mounted
749  !(oldStatus == MEDIASTAT_UNPLUGGED && stat == MEDIASTAT_NOTMOUNTED))
750  {
751  // Should we ValidateAndLock() first?
752  QEvent *e = new MythMediaEvent(stat, pMedia);
753 
754  LOG(VB_MEDIA, LOG_INFO, "Posting MediaEvent" + msg);
755 
756  // sendEvent() is needed here - it waits for the event to be used.
757  // postEvent() would result in pDevice's media type changing
758  // ... before the plugin's event chain would process it.
759  // Another way would be to send an exact copy of pDevice instead.
760  QCoreApplication::sendEvent((QObject*)GetMythMainWindow(), e);
761  delete e;
762  }
763  else
764  LOG(VB_MEDIA, LOG_INFO,
765  "Media status changed, but not sending event" + msg);
766 
767 
768  if (stat == MEDIASTAT_OPEN || stat == MEDIASTAT_NODISK
769  || stat == MEDIASTAT_UNPLUGGED)
770  {
771  pMedia->clearData();
772  }
773 }
774 
779 {
780  if (m_ignoreList.contains(device->getMountPath()) ||
781  m_ignoreList.contains(device->getRealDevice())||
782  m_ignoreList.contains(device->getDevicePath()) )
783  {
784  LOG(VB_MEDIA, LOG_INFO,
785  "Ignoring device: " + device->getDevicePath());
786  return true;
787  }
788 #if 0
789  else
790  {
791  LOG(VB_MEDIA, LOG_DEBUG,
792  "Not ignoring: " + device->getDevicePath() + " / " +
793  device->getMountPath());
794  LOG(VB_MEDIA, LOG_DEBUG,
795  "Paths not in: " + m_ignoreList.join(", "));
796  }
797 #endif
798 
799  return false;
800 }
801 
806 bool MediaMonitor::eventFilter(QObject *obj, QEvent *event)
807 {
808  if (event->type() == MythMediaEvent::kEventType)
809  {
810  auto *me = dynamic_cast<MythMediaEvent *>(event);
811  if (me == nullptr)
812  {
813  LOG(VB_GENERAL, LOG_ALERT,
814  "MediaMonitor::eventFilter() couldn't cast event");
815  return true;
816  }
817 
818  MythMediaDevice *pDev = me->getDevice();
819  if (!pDev)
820  {
821  LOG(VB_GENERAL, LOG_ALERT,
822  "MediaMonitor::eventFilter() got a bad media event?");
823  return true;
824  }
825 
826  if (pDev->isUsable())
827  JumpToMediaHandler(pDev);
828  else
829  {
830  // We don't want to jump around in the menus, but should
831  // call each plugin's callback so it can track this change.
832 
833  QMap<QString, MHData>::Iterator itr = m_handlerMap.begin();
834  while (itr != m_handlerMap.end())
835  {
836  if ((*itr).MythMediaType & (int)pDev->getMediaType() ||
837  pDev->getStatus() == MEDIASTAT_OPEN)
838  (*itr).callback(pDev);
839  itr++;
840  }
841  }
842 
843  return false; // Don't eat the event
844  }
845 
846  // standard event processing
847  return QObject::eventFilter(obj, event);
848 }
849 
850 /*
851  * These methods return the user's preferred devices for playing and burning
852  * CDs and DVDs. Traditionally we had a database setting to remember this,
853  * but that is a bit wasteful when most users only have one drive.
854  *
855  * To make it a bit more beginner friendly, if no database default exists,
856  * or if it contains "default", the code tries to find a monitored drive.
857  * If, still, nothing is suitable, a caller hard-coded default is used.
858  *
859  * Ideally, these would return a MythMediaDevice * instead of a QString
860  */
861 
862 QString MediaMonitor::defaultDevice(const QString &dbSetting,
863  const QString &label,
864  const char *hardCodedDefault)
865 {
866  QString device = gCoreContext->GetSetting(dbSetting);
867 
868  LOG(VB_MEDIA, LOG_DEBUG,
869  QString("MediaMonitor::defaultDevice(%1,..,%2) dbSetting='%3'")
870  .arg(dbSetting).arg(hardCodedDefault).arg(device));
871 
872  // No settings database defaults? Try to choose one:
873  if (device.isEmpty() || device == "default")
874  {
875  device = hardCodedDefault;
876 
877  if (!s_monitor)
879 
880  if (s_monitor)
881  {
882  MythMediaDevice *d = s_monitor->selectDrivePopup(label, false, true);
883 
884  if (d == (MythMediaDevice *) -1) // User cancelled
885  {
886  device.clear(); // If user has explicitly cancelled return empty string
887  d = nullptr;
888  }
889 
890  if (d && s_monitor->ValidateAndLock(d))
891  {
892  device = d->getDevicePath();
893  s_monitor->Unlock(d);
894  }
895  }
896  }
897 
898  LOG(VB_MEDIA, LOG_DEBUG,
899  "MediaMonitor::defaultDevice() returning " + device);
900  return device;
901 }
902 
907 {
908  return defaultDevice("CDDevice", tr("Select a CD drive"), DEFAULT_CD);
909 }
910 
915 {
916  return defaultDevice("VCDDeviceLocation",
917  tr("Select a VCD drive"), DEFAULT_CD);
918 }
919 
924 {
925  return defaultDevice("DVDDeviceLocation",
926  tr("Select a DVD drive"), DEFAULT_DVD);
927 }
928 
933 {
934  return defaultDevice("CDWriterDeviceLocation",
935  tr("Select a CD writer"), DEFAULT_CD);
936 }
937 
945 {
946  QString device = defaultDevice("MythArchiveDVDLocation",
947  tr("Select a DVD writer"), DEFAULT_DVD);
948 
949  return device;
950 }
951 
952 
957 {
958  QStringList list;
959 
960  for (const auto *dev : qAsConst(m_devices))
961  {
962  QString devStr;
963  QString model = dev->getDeviceModel();
964  const QString& path = dev->getDevicePath();
965  const QString& real = dev->getRealDevice();
966 
967  if (path != real)
968  devStr += path + "->";
969  devStr += real;
970 
971  if (model.isEmpty())
972  model = "unknown";
973  devStr += " (" + model + ")";
974 
975  list += devStr;
976  }
977 
978  return list.join(", ");
979 }
980 
988 {
990  if (mon)
991  mon->ChooseAndEjectMedia();
992  else
993  {
994  LOG(VB_MEDIA, LOG_INFO, "CD/DVD Monitor isn't enabled.");
995 #ifdef __linux__
996  LOG(VB_MEDIA, LOG_INFO, "Trying Linux 'eject -T' command");
997  myth_system("eject -T");
998 #elif CONFIG_DARWIN
999  QString def = DEFAULT_CD;
1000  LOG(VB_MEDIA, LOG_INFO, "Trying 'diskutil eject " + def);
1001  myth_system("diskutil eject " + def);
1002 #endif
1003  }
1004 }
1005 
1006 /*
1007  * vim:ts=4:sw=4:ai:et:si:sts=4
1008  */
MythMediaDevice::isUsable
bool isUsable() const
Is this device "ready", for a plugin to access?
Definition: mythmedia.h:84
MythMediaDevice::getMountPath
const QString & getMountPath() const
Definition: mythmedia.h:58
MediaMonitor::m_devices
QList< MythMediaDevice * > m_devices
Definition: mythmediamonitor.h:117
MonitorThread::MonitorThread
MonitorThread(MediaMonitor *pMon, unsigned long interval)
Definition: mythmediamonitor.cpp:40
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:324
e
QDomElement e
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1420
MediaMonitor::AttemptEject
static void AttemptEject(MythMediaDevice *device)
Definition: mythmediamonitor.cpp:283
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:288
myth_system
uint myth_system(const QString &command, uint flags, uint timeout)
Definition: mythsystemlegacy.cpp:501
MediaMonitor::m_wait
QWaitCondition m_wait
Definition: mythmediamonitor.h:125
MediaMonitor::ejectOpticalDisc
static void ejectOpticalDisc(void)
Eject a disk, unmount a drive, open a tray.
Definition: mythmediamonitor.cpp:987
MediaMonitor::eventFilter
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.
Definition: mythmediamonitor.cpp:806
ShowNotificationError
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
Definition: mythnotificationcenter.cpp:1428
MediaMonitor::GetMedias
QList< MythMediaDevice * > GetMedias(unsigned mediatypes)
Ask for available media.
Definition: mythmediamonitor.cpp:619
MediaMonitor::m_removedDevices
QList< MythMediaDevice * > m_removedDevices
Definition: mythmediamonitor.h:118
MediaMonitor::selectDrivePopup
MythMediaDevice * selectDrivePopup(const QString &label, bool showMounted=false, bool showUsable=false)
List removable drives, let the user select one.
Definition: mythmediamonitor.cpp:183
mediamonitor-windows.h
ShowNotification
void ShowNotification(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
Definition: mythnotificationcenter.cpp:1439
MythCoreContext::ResetSockets
void ResetSockets(void)
Definition: mythcorecontext.cpp:1807
DevName
static QString DevName(MythMediaDevice *d)
Definition: mythmediamonitor.cpp:129
MediaMonitor::GetMediaMonitor
static MediaMonitor * GetMediaMonitor(void)
Definition: mythmediamonitor.cpp:83
MonitorThread::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: mythmediamonitor.cpp:50
mythcdrom.h
MediaMonitor::GetRemovable
QList< MythMediaDevice * > GetRemovable(bool showMounted=false, bool showUsable=false)
Generate a list of removable drives.
Definition: mythmediamonitor.cpp:155
MediaMonitor::StartMonitoring
virtual void StartMonitoring(void)
Start the monitoring thread if needed.
Definition: mythmediamonitor.cpp:462
MediaMonitor::defaultDevice
static QString defaultDevice(const QString &setting, const QString &label, const char *hardCodedDefault)
Definition: mythmediamonitor.cpp:862
MediaMonitor::MediaMonitor
MediaMonitor(QObject *par, unsigned long interval, bool allowEject)
Lookup some settings, and do OS-specific stuff in sub-classes.
Definition: mythmediamonitor.cpp:343
MEDIASTAT_ERROR
@ MEDIASTAT_ERROR
Unable to mount, but could be usable.
Definition: mythmedia.h:13
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
arg
arg(title).arg(filename).arg(doDelete))
mythmediamonitor.h
MEDIASTAT_USEABLE
@ MEDIASTAT_USEABLE
Definition: mythmedia.h:19
getSymlinkTarget
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
Definition: mythmiscutil.cpp:497
MediaMonitor::m_devicesLock
QMutex m_devicesLock
Definition: mythmediamonitor.h:116
MythMediaDevice::getDevicePath
const QString & getDevicePath() const
Definition: mythmedia.h:61
MediaMonitor::m_monitorPollingInterval
unsigned long m_monitorPollingInterval
Definition: mythmediamonitor.h:127
MythMediaDevice::getStatus
MythMediaStatus getStatus() const
Definition: mythmedia.h:70
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:198
MediaMonitor::MonitorThread
friend class MonitorThread
Definition: mythmediamonitor.h:46
MythDialogBox::Closed
void Closed(QString, int)
MediaMonitor::mediaStatusChanged
void mediaStatusChanged(MythMediaStatus oldStatus, MythMediaDevice *pMedia) const
Slot which is called when the device status changes and posts a media event to the mainwindow.
Definition: mythmediamonitor.cpp:731
MediaMonitor::s_monitor
static MediaMonitor * s_monitor
Definition: mythmediamonitor.h:132
MediaMonitor::GetMedia
MythMediaDevice * GetMedia(const QString &path)
Get media device by pathname.
Definition: mythmediamonitor.cpp:548
MEDIASTAT_MOUNTED
@ MEDIASTAT_MOUNTED
Definition: mythmedia.h:21
sLocation
static const QString sLocation
Definition: mythmediamonitor.cpp:35
HasMythMainWindow
bool HasMythMainWindow(void)
Definition: mythmainwindow.cpp:113
MonitorThread::m_lastCheckTime
QDateTime m_lastCheckTime
Definition: mythmediamonitor.h:40
MediaMonitor::SetCDSpeed
static void SetCDSpeed(const char *device, int speed)
Definition: mythmediamonitor.cpp:101
MythMediaEvent::kEventType
static Type kEventType
Definition: mythmedia.h:193
MediaMonitor::CheckDevices
void CheckDevices(void)
Poll the devices in our list.
Definition: mythmediamonitor.cpp:442
MEDIASTAT_UNPLUGGED
@ MEDIASTAT_UNPLUGGED
Definition: mythmedia.h:15
mythsystemlegacy.h
MythMediaDevice::isMounted
bool isMounted(bool bVerify=true)
Tells us if m_devicePath is a mounted device.
Definition: mythmedia.cpp:358
MediaMonitor::RegisterMediaHandler
void RegisterMediaHandler(const QString &destination, const QString &description, void(*callback)(MythMediaDevice *), int mediaType, const QString &extensions)
Register a handler for media related events.
Definition: mythmediamonitor.cpp:658
mythdate.h
mythlogging.h
MythMediaDevice::setSpeed
virtual void setSpeed(int speed)
Definition: mythmedia.cpp:332
MythMediaDevice::getRealDevice
const QString & getRealDevice() const
Definition: mythmedia.h:63
MediaMonitor::StopMonitoring
void StopMonitoring(void)
Stop the monitoring thread if needed.
Definition: mythmediamonitor.cpp:485
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:167
MythMediaDevice::clearData
void clearData()
Definition: mythmedia.cpp:509
MythMediaEvent
Definition: mythmedia.h:184
MythMediaDevice::unlock
virtual MythMediaError unlock()
Definition: mythmedia.cpp:350
MediaMonitor::CheckDeviceNotifications
virtual void CheckDeviceNotifications(void)
Definition: mythmediamonitor.h:100
MonitorThread::m_monitor
QPointer< MediaMonitor > m_monitor
Definition: mythmediamonitor.h:38
MythMediaDevice::unmount
bool unmount()
Definition: mythmedia.h:108
MediaMonitor::Unlock
void Unlock(MythMediaDevice *pMedia)
decrements the MythMediaDevices reference count
Definition: mythmediamonitor.cpp:525
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:211
MythCDROM
Definition: mythcdrom.h:7
handlers
static QList< GameHandler * > * handlers
Definition: gamehandler.cpp:23
MythMainWindow::RestartInputHandlers
void RestartInputHandlers(void)
Definition: mythmainwindow.cpp:2145
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MediaMonitor::m_ignoreList
QStringList m_ignoreList
Definition: mythmediamonitor.h:122
MediaMonitor
Definition: mythmediamonitor.h:44
MediaMonitor::m_handlerMap
QMap< QString, MHData > m_handlerMap
Registered Media Handlers.
Definition: mythmediamonitor.h:130
MediaMonitor::listDevices
QString listDevices(void)
A string summarising the current devices, for debugging.
Definition: mythmediamonitor.cpp:956
MediaMonitor::RemoveDevice
bool RemoveDevice(const QString &dev)
Remove a device from the media monitor.
Definition: mythmediamonitor.cpp:406
MediaMonitor::shouldIgnore
bool shouldIgnore(const MythMediaDevice *device)
Check user preferences to see if this device should be monitored.
Definition: mythmediamonitor.cpp:778
MediaMonitorDarwin
This currently depends on Apple's DiskArbitration framework.
Definition: mediamonitor-darwin.h:22
MediaMonitor::defaultDVDWriter
static QString defaultDVDWriter()
MythArchiveDVDLocation, user-selected drive, or /dev/dvd.
Definition: mythmediamonitor.cpp:944
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:927
MediaMonitor::m_thread
MonitorThread * m_thread
Definition: mythmediamonitor.h:126
MythMediaDevice::eject
virtual MythMediaError eject(bool open_close=true)
Definition: mythmedia.cpp:307
MythMediaDevice::RegisterMediaExtensions
static void RegisterMediaExtensions(uint mediatype, const QString &extensions)
Used to register media types with extensions.
Definition: mythmedia.cpp:299
MediaMonitor::m_active
bool volatile m_active
Was MonitorThread started?
Definition: mythmediamonitor.h:124
MythCDROM::get
static MythCDROM * get(QObject *par, const QString &devicePath, bool SuperMount, bool AllowEject)
Definition: mythcdrom.cpp:35
MythMediaType
MythMediaType
Definition: mythmedia.h:24
MediaMonitor::m_useCount
QMap< MythMediaDevice *, int > m_useCount
Definition: mythmediamonitor.h:119
mythmiscutil.h
MEDIASTAT_NODISK
@ MEDIASTAT_NODISK
CD/DVD tray closed but empty, device unusable.
Definition: mythmedia.h:17
mythcorecontext.h
DEFAULT_DVD
#define DEFAULT_DVD
Definition: mediamonitor-darwin.h:4
MONITOR_INTERVAL
#define MONITOR_INTERVAL
Definition: mythmediamonitor.cpp:81
MediaMonitor::EjectMedia
void EjectMedia(const QString &path)
Definition: mythmediamonitor.cpp:275
MythMediaDevice::kMediaStatusStrings
static const std::array< const QString, 9 > kMediaStatusStrings
Definition: mythmedia.h:117
MonitorThread::m_interval
unsigned long m_interval
Definition: mythmediamonitor.h:39
MHData
Stores details of media handlers.
Definition: mythmediamonitor.h:21
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
MythMediaDevice::checkMedia
virtual MythMediaStatus checkMedia()=0
MythCDROM::setDeviceSpeed
void setDeviceSpeed(const char *devicePath, int speed) override
Definition: mythcdrom.cpp:132
MythMediaDevice::getMediaType
MythMediaType getMediaType() const
Definition: mythmedia.h:91
MediaMonitorWindows
I am assuming, for now, that everything on Windows uses drive letters (e.g.
Definition: mediamonitor-windows.h:10
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:108
MEDIASTAT_OPEN
@ MEDIASTAT_OPEN
CD/DVD tray open (meaningless for non-CDs?)
Definition: mythmedia.h:16
MediaMonitor::defaultCDWriter
static QString defaultCDWriter()
CDWriterDeviceLocation, user-selected drive, or /dev/cdrom.
Definition: mythmediamonitor.cpp:932
MediaMonitor::defaultDVDdevice
static QString defaultDVDdevice()
DVDDeviceLocation, user-selected drive, or /dev/dvd.
Definition: mythmediamonitor.cpp:923
MediaMonitor::ValidateAndLock
bool ValidateAndLock(MythMediaDevice *pMedia)
Validates the MythMediaDevice and increments its reference count.
Definition: mythmediamonitor.cpp:508
MEDIAERR_FAILED
@ MEDIAERR_FAILED
Definition: mythmedia.h:41
MythMediaError
MythMediaError
Definition: mythmedia.h:39
MythMediaDevice
Definition: mythmedia.h:49
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
mediamonitor-unix.h
MediaMonitor::deleteLater
virtual void deleteLater(void)
Definition: mythmediamonitor.cpp:387
MediaMonitor::JumpToMediaHandler
void JumpToMediaHandler(MythMediaDevice *pMedia)
Find a relevant jump point for this type of media.
Definition: mythmediamonitor.cpp:696
MThread::wait
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:305
MEDIAERR_OK
@ MEDIAERR_OK
Definition: mythmedia.h:40
MEDIASTAT_UNKNOWN
@ MEDIASTAT_UNKNOWN
Definition: mythmedia.h:14
MEDIAERR_UNSUPPORTED
@ MEDIAERR_UNSUPPORTED
Definition: mythmedia.h:42
mediamonitor-darwin.h
MediaMonitorUnix
Definition: mediamonitor-unix.h:17
MythMediaStatus
MythMediaStatus
Definition: mythmedia.h:12
mythmainwindow.h
DEFAULT_CD
#define DEFAULT_CD
Definition: mediamonitor-darwin.h:5
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
MediaMonitor::ChooseAndEjectMedia
void ChooseAndEjectMedia(void)
Unmounts and ejects removable media devices.
Definition: mythmediamonitor.cpp:256
MediaMonitor::defaultVCDdevice
static QString defaultVCDdevice()
VCDDeviceLocation, user-selected drive, or /dev/cdrom.
Definition: mythmediamonitor.cpp:914
MythMainWindow
Definition: mythmainwindow.h:35
MythMediaDevice::findMountPath
bool findMountPath()
Try to find a mount of m_devicePath in the mounts file.
Definition: mythmedia.cpp:366
MediaMonitor::defaultCDdevice
static QString defaultCDdevice()
CDDevice, user-selected drive, or /dev/cdrom.
Definition: mythmediamonitor.cpp:906
MEDIASTAT_NOTMOUNTED
@ MEDIASTAT_NOTMOUNTED
Definition: mythmedia.h:20
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:919
MediaMonitor::GetMountPath
static QString GetMountPath(const QString &devPath)
If the device is being monitored, return its mountpoint.
Definition: mythmediamonitor.cpp:572
MythMediaDevice::MediaTypeString
QString MediaTypeString()
Definition: mythmedia.cpp:516