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