MythTV master
mediamonitor.cpp
Go to the documentation of this file.
1#include "mediamonitor.h"
2
3// Standard C headers
4#include <cstdio>
5
6// C++ headers
7#include <iostream>
8#include <typeinfo>
9
10// Qt headers
11#include <QtGlobal>
12#include <QCoreApplication>
13#include <QFile>
14#include <QList>
15#include <QDir>
16
17// MythTV headers
19#include "libmythbase/mythconfig.h"
27
28#if CONFIG_DARWIN_DA
29#include "mediamonitor-darwin.h"
30#elif defined(Q_OS_WIN)
32#else
33#include "mediamonitor-unix.h"
34#endif
35
36static const QString sLocation = QObject::tr("Media Monitor");
37
39
40// Nice and simple, as long as our monitor is valid and active,
41// loop and check it's devices.
43{
44 RunProlog();
45 QMutex mtx;
46 mtx.lock();
47 while (m_monitor && m_monitor->IsActive())
48 {
49 m_monitor->CheckDevices();
50 m_monitor->m_wait.wait(&mtx, m_interval);
51 QDateTime now(QDateTime::currentDateTimeUtc());
52 // if 10 seconds have elapsed instead of 5 seconds
53 // assume the system was suspended and reconnect
54 // sockets
55 if (m_lastCheckTime.secsTo(now) > 120)
56 {
59 {
60 LOG(VB_GENERAL, LOG_INFO, "Restarting LIRC handler");
62 }
63 }
64 m_lastCheckTime = now;
65 }
66 mtx.unlock();
67 RunEpilog();
68}
69
71// MediaMonitor
72
73static constexpr unsigned long MONITOR_INTERVAL { 5000 };
74
76{
77 if (s_monitor)
78 return s_monitor;
79
80#if CONFIG_DARWIN_DA
81 s_monitor = new MediaMonitorDarwin(nullptr, MONITOR_INTERVAL, true);
82#elif defined(Q_OS_WIN)
84#else
85 s_monitor = new MediaMonitorUnix(nullptr, MONITOR_INTERVAL, true);
86#endif
87
88 return s_monitor;
89}
90
91void MediaMonitor::SetCDSpeed(const char *device, int speed)
92{
94 if (mon)
95 {
96 MythMediaDevice *pMedia = mon->GetMedia(device);
97 if (pMedia && mon->ValidateAndLock(pMedia))
98 {
99 pMedia->setSpeed(speed);
100 mon->Unlock(pMedia);
101 return;
102 }
103 }
104
105 MythCDROM *cd = MythCDROM::get(nullptr, device, false, false);
106 if (cd)
107 {
108 cd->setDeviceSpeed(device, speed);
109 delete cd;
110 return;
111 }
112
113 LOG(VB_MEDIA, LOG_INFO,
114 QString("MediaMonitor::setSpeed(%1) - Cannot find/create CDROM?")
115 .arg(device));
116}
117
118// When ejecting one of multiple devices, present a nice name to the user
119static QString DevName(MythMediaDevice *d)
120{
121 QString str = d->getVolumeID(); // First choice, the name of the media
122
123 if (str.isEmpty())
124 {
125 str = d->getDeviceModel(); // otherwise, the drive manufacturer/model
126
127 if (!str.isEmpty()) // and/or the device node
128 str += " (" + d->getDevicePath() + ')';
129 else
130 str = d->getDevicePath();
131 }
132 // We could add even more information here, but volume names
133 // are usually descriptively unique (i.e. usually good enough)
134 //else
135 // str += " (" + d->getDeviceModel() + ", " + d->getDevicePath() + ')';
136
137 return str;
138}
139
145QList<MythMediaDevice*> MediaMonitor::GetRemovable(bool showMounted,
146 bool showUsable)
147{
148 QList <MythMediaDevice *> drives;
149 QMutexLocker locker(&m_devicesLock);
150
151 for (MythMediaDevice *dev : std::as_const(m_devices))
152 {
153 // By default, we only list CD/DVD devices.
154 // Caller can also request mounted drives to be listed (e.g. USB flash)
155
156 if (showUsable && !dev->isUsable())
157 continue;
158
159 if (QString(typeid(*dev).name()).contains("MythCDROM") ||
160 (showMounted && dev->isMounted(false)))
161 drives.append(dev);
162 }
163
164 return drives;
165}
166
173 bool &canceled,
174 bool showMounted,
175 bool showUsable)
176{
177 canceled = false;
178 QList <MythMediaDevice *> drives = GetRemovable(showMounted,
179 showUsable);
180
181 if (drives.count() == 0)
182 {
183 QString msg = "MediaMonitor::selectDrivePopup() - no removable devices";
184
185 LOG(VB_MEDIA, LOG_INFO, msg);
186 return nullptr;
187 }
188
189 if (drives.count() == 1)
190 {
191 LOG(VB_MEDIA, LOG_INFO,
192 "MediaMonitor::selectDrivePopup(" + label +
193 ") - One suitable device");
194 return drives.front();
195 }
196
198 if (!win)
199 return nullptr;
200
201 MythScreenStack *stack = win->GetMainStack();
202 if (!stack)
203 return nullptr;
204
205 // Ignore MENU dialog actions
206 int btnIndex = -2;
207 while (btnIndex < -1)
208 {
209 auto *dlg = new MythDialogBox(label, stack, "select drive");
210 if (!dlg->Create())
211 {
212 delete dlg;
213 return nullptr;
214 }
215
216 // Add button for each drive
217 for (auto *drive : std::as_const(drives))
218 dlg->AddButton(DevName(drive));
219
220 dlg->AddButton(tr("Cancel"));
221
222 stack->AddScreen(dlg);
223
224 // Wait in local event loop so events are processed
225 QEventLoop block;
226 connect(dlg, &MythDialogBox::Closed,
227 &block, [&](const QString& /*resultId*/, int result) { block.exit(result); });
228
229 // Block until dialog closes
230 btnIndex = block.exec();
231 }
232
233 // If the user cancelled, return a special value
234 if (btnIndex < 0 || btnIndex >= drives.size())
235 {
236 canceled = true;
237 return nullptr;
238 }
239 return drives.at(btnIndex);
240}
241
242
252{
253 bool canceled { false };
254 MythMediaDevice *selected =
255 selectDrivePopup(tr("Select removable media to eject or insert"), canceled, true);
256
257 // If the user cancelled, no need to display or do anything more
258 if (canceled)
259 return;
260
261 if (!selected)
262 {
263 ShowNotification(tr("No devices to eject"), sLocation);
264 return;
265 }
266
267 AttemptEject(selected);
268}
269
270
271void MediaMonitor::EjectMedia(const QString &path)
272{
273 MythMediaDevice *device = GetMedia(path);
274 if (device)
275 AttemptEject(device);
276}
277
278
280{
281 QString dev = DevName(device);
282
283 if (device->getStatus() == MEDIASTAT_OPEN)
284 {
285 LOG(VB_MEDIA, LOG_INFO,
286 QString("Disk %1's tray is OPEN. Closing tray").arg(dev));
287
288 if (device->eject(false) != MEDIAERR_OK)
289 {
290 QString msg =
291 QObject::tr("Unable to open or close the empty drive %1");
292 QString extra =
293 QObject::tr("You may have to use the eject button under its tray");
294 ShowNotificationError(msg.arg(dev), sLocation, extra);
295 }
296 return;
297 }
298
299 if (device->isMounted())
300 {
301 LOG(VB_MEDIA, LOG_INFO,
302 QString("Disk %1 is mounted? Unmounting").arg(dev));
303 device->unmount();
304
305#ifndef Q_OS_DARWIN
306 if (device->isMounted())
307 {
308 ShowNotificationError(tr("Failed to unmount %1").arg(dev),
309 sLocation);
310 return;
311 }
312#endif
313 }
314
315 LOG(VB_MEDIA, LOG_INFO,
316 QString("Unlocking disk %1, then ejecting").arg(dev));
317 device->unlock();
318
319 MythMediaError err = device->eject();
320
321 if (err == MEDIAERR_UNSUPPORTED)
322 {
323 // Physical ejection isn't possible (there is no tray or slot),
324 // but logically the device is now ejected (ignored by the OS).
325 ShowNotification(tr("You may safely remove %1").arg(dev), sLocation);
326 }
327 else if (err == MEDIAERR_FAILED)
328 {
329 ShowNotificationError(tr("Failed to eject %1").arg(dev), sLocation);
330 }
331}
332
339MediaMonitor::MediaMonitor(QObject* par, unsigned long interval, bool allowEject)
340 : QObject(par),
341 m_monitorPollingInterval(interval),
342 m_allowEject(allowEject)
343{
344 // User can specify that some devices are not monitored
345 QString ignore = gCoreContext->GetSetting("IgnoreDevices", "");
346
347 if (!ignore.isEmpty())
348 {
349 m_ignoreList = ignore.split(',', Qt::SkipEmptyParts);
350 }
351
352 LOG(VB_MEDIA, LOG_NOTICE, "Creating MediaMonitor");
353 LOG(VB_MEDIA, LOG_INFO, "IgnoreDevices=" + ignore);
354
355 // If any of IgnoreDevices are symlinks, also add the real device
356 QStringList symlinked;
357 for (const auto & ignored : std::as_const(m_ignoreList))
358 {
359 if (auto fi = QFileInfo(ignored); fi.isSymLink())
360 {
361 if (auto target = getSymlinkTarget(ignored); m_ignoreList.filter(target).isEmpty())
362 {
363 symlinked += target;
364 LOG(VB_MEDIA, LOG_INFO, QString("Also ignoring %1 (symlinked from %2)")
365 .arg(target, ignored));
366 }
367 }
368 }
369
370 m_ignoreList += symlinked;
371}
372
374{
375 if (m_thread)
376 {
378 delete m_thread;
379 m_thread = nullptr;
380 }
381 QObject::deleteLater();
382}
383
392bool MediaMonitor::RemoveDevice(const QString &dev)
393{
394 QMutexLocker locker(&m_devicesLock);
395
396 QList<MythMediaDevice*>::iterator it;
397 for (it = m_devices.begin(); it != m_devices.end(); ++it)
398 {
399 if ((*it)->getDevicePath() == dev)
400 {
401 // Ensure device gets an unmount
402 (*it)->checkMedia();
403
404 if (m_useCount[*it] == 0)
405 {
406 m_useCount.remove(*it);
407 (*it)->deleteLater();
408 m_devices.erase(it);
409 }
410 else
411 {
412 // Other threads are still using this device
413 // postpone actual delete until they finish.
414 disconnect(*it);
415 m_removedDevices.append(*it);
416 m_devices.erase(it);
417 }
418
419 return true;
420 }
421 }
422 return false;
423}
424
429{
430 /* check if new devices have been plugged in */
432
433 QMutexLocker locker(&m_devicesLock);
434
435 QList<MythMediaDevice*>::iterator itr = m_devices.begin();
436 while (itr != m_devices.end())
437 {
438 MythMediaDevice* pDev = *itr;
439 if (pDev)
440 pDev->checkMedia();
441 ++itr;
442 }
443}
444
449{
450 // Sanity check
451 if (m_active)
452 return;
453 if (!gCoreContext->GetBoolSetting("MonitorDrives", false)) {
454 LOG(VB_MEDIA, LOG_NOTICE, "MediaMonitor disabled by user setting.");
455 return;
456 }
457
458 if (!m_thread)
460
461 qRegisterMetaType<MythMediaStatus>("MythMediaStatus");
462
463 LOG(VB_MEDIA, LOG_NOTICE, "Starting MediaMonitor");
464 m_active = true;
465 m_thread->start();
466}
467
472{
473 // Sanity check
474 if (!m_active)
475 return;
476
477 LOG(VB_MEDIA, LOG_NOTICE, "Stopping MediaMonitor");
478 m_active = false;
479 m_wait.wakeAll();
480 m_thread->wait();
481 LOG(VB_MEDIA, LOG_NOTICE, "Stopped MediaMonitor");
482}
483
495{
496 QMutexLocker locker(&m_devicesLock);
497
498 if (!m_devices.contains(pMedia))
499 return false;
500
501 m_useCount[pMedia]++;
502
503 return true;
504}
505
512{
513 QMutexLocker locker(&m_devicesLock);
514
515 if (!m_useCount.contains(pMedia))
516 return;
517
518 m_useCount[pMedia]--;
519
520 if (m_useCount[pMedia] == 0 && m_removedDevices.contains(pMedia))
521 {
522 m_removedDevices.removeAll(pMedia);
523 m_useCount.remove(pMedia);
524 pMedia->deleteLater();
525 }
526}
527
535{
536 QMutexLocker locker(&m_devicesLock);
537
538 for (auto *dev : std::as_const(m_devices))
539 {
540 if (dev->isSameDevice(path) &&
541 ((dev->getStatus() == MEDIASTAT_USEABLE) ||
542 (dev->getStatus() == MEDIASTAT_MOUNTED) ||
543 (dev->getStatus() == MEDIASTAT_NOTMOUNTED)))
544 {
545 return dev;
546 }
547 }
548
549 return nullptr;
550}
551
558QString MediaMonitor::GetMountPath(const QString& devPath)
559{
560 QString mountPath;
561
562 if (s_monitor)
563 {
564 MythMediaDevice *pMedia = s_monitor->GetMedia(devPath);
565 if (pMedia && s_monitor->ValidateAndLock(pMedia))
566 {
567 mountPath = pMedia->getMountPath();
568 s_monitor->Unlock(pMedia);
569 }
570 // The media monitor could be inactive.
571 // Create a fake media device just to lookup mount map:
572 else
573 {
574 pMedia = MythCDROM::get(nullptr, devPath.toLatin1(), true, false);
575 if (pMedia && pMedia->findMountPath())
576 mountPath = pMedia->getMountPath();
577 else
578 LOG(VB_MEDIA, LOG_INFO,
579 "MediaMonitor::GetMountPath() - failed");
580 // need some way to delete the media device.
581 }
582 }
583
584 return mountPath;
585}
586
605QList<MythMediaDevice*> MediaMonitor::GetMedias(unsigned mediatypes)
606{
607 QMutexLocker locker(&m_devicesLock);
608
609 QList<MythMediaDevice*> medias;
610
611 for (auto *dev : std::as_const(m_devices))
612 {
613 if ((dev->getMediaType() & mediatypes) &&
614 ((dev->getStatus() == MEDIASTAT_USEABLE) ||
615 (dev->getStatus() == MEDIASTAT_MOUNTED) ||
616 (dev->getStatus() == MEDIASTAT_NOTMOUNTED)))
617 {
618 medias.push_back(dev);
619 }
620 }
621
622 return medias;
623}
624
644void MediaMonitor::RegisterMediaHandler(const QString &destination,
645 const QString &description,
646 MediaCallback callback,
647 int mediaType,
648 const QString &extensions)
649{
650 if (!m_handlerMap.contains(destination))
651 {
652 MHData mhd = { callback, mediaType, destination, description };
653 QString msg = MythMediaDevice::MediaTypeString((MythMediaType)mediaType);
654
655 if (!extensions.isEmpty())
656 msg += QString(", ext(%1)").arg(extensions);
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.isEmpty())
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
681void MediaMonitor::JumpToMediaHandler(MythMediaDevice* pMedia, bool forcePlayback)
682{
683 QVector<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(), 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, forcePlayback);
710}
711
717 MythMediaDevice* pMedia) const
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(),
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 {
750 LOG(VB_MEDIA, LOG_INFO,
751 "Media status changed, but not sending event" + msg);
752 }
753
754
755 if (stat == MEDIASTAT_OPEN || stat == MEDIASTAT_NODISK
756 || stat == MEDIASTAT_UNPLUGGED)
757 {
758 pMedia->clearData();
759 }
760}
761
766{
767 if (m_ignoreList.contains(device->getMountPath()) ||
768 m_ignoreList.contains(device->getRealDevice())||
769 m_ignoreList.contains(device->getDevicePath()) )
770 {
771 LOG(VB_MEDIA, LOG_INFO,
772 "Ignoring device: " + device->getDevicePath());
773 return true;
774 }
775#if 0
776 else
777 {
778 LOG(VB_MEDIA, LOG_DEBUG,
779 "Not ignoring: " + device->getDevicePath() + " / " +
780 device->getMountPath());
781 LOG(VB_MEDIA, LOG_DEBUG,
782 "Paths not in: " + m_ignoreList.join(", "));
783 }
784#endif
785
786 return false;
787}
788
793bool MediaMonitor::eventFilter(QObject *obj, QEvent *event)
794{
795 if (event->type() == MythMediaEvent::kEventType)
796 {
797 auto *me = dynamic_cast<MythMediaEvent *>(event);
798 if (me == nullptr)
799 {
800 LOG(VB_GENERAL, LOG_ALERT,
801 "MediaMonitor::eventFilter() couldn't cast event");
802 return true;
803 }
804
805 MythMediaDevice *pDev = me->getDevice();
806 if (!pDev)
807 {
808 LOG(VB_GENERAL, LOG_ALERT,
809 "MediaMonitor::eventFilter() got a bad media event?");
810 return true;
811 }
812
813 if (pDev->isUsable())
814 JumpToMediaHandler(pDev);
815 else
816 {
817 // We don't want to jump around in the menus, but should
818 // call each plugin's callback so it can track this change.
819
820 QMap<QString, MHData>::Iterator itr = m_handlerMap.begin();
821 while (itr != m_handlerMap.end())
822 {
823 if ((*itr).MythMediaType & (int)pDev->getMediaType() ||
824 pDev->getStatus() == MEDIASTAT_OPEN)
825 (*itr).callback(pDev, false);
826 itr++;
827 }
828 }
829
830 return false; // Don't eat the event
831 }
832
833 // standard event processing
834 return QObject::eventFilter(obj, event);
835}
836
837/*
838 * These methods return the user's preferred devices for playing and burning
839 * CDs and DVDs. Traditionally we had a database setting to remember this,
840 * but that is a bit wasteful when most users only have one drive.
841 *
842 * To make it a bit more beginner friendly, if no database default exists,
843 * or if it contains "default", the code tries to find a monitored drive.
844 * If, still, nothing is suitable, a caller hard-coded default is used.
845 *
846 * Ideally, these would return a MythMediaDevice * instead of a QString
847 */
848
849QString MediaMonitor::defaultDevice(const QString &dbSetting,
850 const QString &label,
851 const char *hardCodedDefault)
852{
853 QString device = gCoreContext->GetSetting(dbSetting);
854
855 LOG(VB_MEDIA, LOG_DEBUG,
856 QString("MediaMonitor::defaultDevice(%1,..,%2) dbSetting='%3'")
857 .arg(dbSetting, hardCodedDefault, device));
858
859 // No settings database defaults? Try to choose one:
860 if (device.isEmpty() || device == "default")
861 {
862 device = hardCodedDefault;
863
864 if (!s_monitor)
866
867 if (s_monitor)
868 {
869 bool canceled { false };
870 MythMediaDevice *d = s_monitor->selectDrivePopup(label, canceled, false, true);
871
872 if (canceled)
873 {
874 device.clear(); // If user has explicitly cancelled return empty string
875 d = nullptr;
876 }
877
878 if (d && s_monitor->ValidateAndLock(d))
879 {
880 device = d->getDevicePath();
882 }
883 }
884 }
885
886 LOG(VB_MEDIA, LOG_DEBUG,
887 "MediaMonitor::defaultDevice() returning " + device);
888 return device;
889}
890
895{
896 return defaultDevice("CDDevice", tr("Select a CD drive"), DEFAULT_CD);
897}
898
903{
904 return defaultDevice("VCDDeviceLocation",
905 tr("Select a VCD drive"), DEFAULT_CD);
906}
907
912{
913 return defaultDevice("DVDDeviceLocation",
914 tr("Select a DVD drive"), DEFAULT_DVD);
915}
916
921{
922 return defaultDevice("CDWriterDeviceLocation",
923 tr("Select a CD writer"), DEFAULT_CD);
924}
925
933{
934 QString device = defaultDevice("MythArchiveDVDLocation",
935 tr("Select a DVD writer"), DEFAULT_DVD);
936
937 return device;
938}
939
940
945{
946 QStringList list;
947
948 for (const auto *dev : std::as_const(m_devices))
949 {
950 QString devStr;
951 QString model = dev->getDeviceModel();
952 const QString& path = dev->getDevicePath();
953 const QString& real = dev->getRealDevice();
954
955 if (path != real)
956 devStr += path + "->";
957 devStr += real;
958
959 if (model.isEmpty())
960 model = "unknown";
961 devStr += " (" + model + ")";
962
963 list += devStr;
964 }
965
966 return list.join(", ");
967}
968
976{
978 if (mon)
979 mon->ChooseAndEjectMedia();
980 else
981 {
982 LOG(VB_MEDIA, LOG_INFO, "CD/DVD Monitor isn't enabled.");
983#ifdef __linux__
984 LOG(VB_MEDIA, LOG_INFO, "Trying Linux 'eject -T' command");
985 myth_system("eject -T");
986#elif defined(Q_OS_DARWIN)
987 QString def = DEFAULT_CD;
988 LOG(VB_MEDIA, LOG_INFO, "Trying 'diskutil eject " + def);
989 myth_system("diskutil eject " + def);
990#endif
991 }
992}
993
994/*
995 * vim:ts=4:sw=4:ai:et:si:sts=4
996 */
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
This currently depends on Apple's DiskArbitration framework.
I am assuming, for now, that everything on Windows uses drive letters (e.g.
QList< MythMediaDevice * > GetRemovable(bool showMounted=false, bool showUsable=false)
Generate a list of removable drives.
unsigned long m_monitorPollingInterval
Definition: mediamonitor.h:132
void JumpToMediaHandler(MythMediaDevice *pMedia, bool forcePlayback=false)
Find a relevant jump point for this type of media.
virtual void CheckDeviceNotifications(void)
Definition: mediamonitor.h:104
static void AttemptEject(MythMediaDevice *device)
friend class MonitorThread
Definition: mediamonitor.h:50
void mediaStatusChanged(MythMediaStatus oldStatus, MythMediaDevice *pMedia) const
Slot which is called when the device status changes and posts a media event to the mainwindow.
static MediaMonitor * GetMediaMonitor(void)
bool ValidateAndLock(MythMediaDevice *pMedia)
Validates the MythMediaDevice and increments its reference count.
MonitorThread * m_thread
Definition: mediamonitor.h:131
static void SetCDSpeed(const char *device, int speed)
static QString defaultDVDWriter()
MythArchiveDVDLocation, user-selected drive, or /dev/dvd.
bool RemoveDevice(const QString &dev)
Remove a device from the media monitor.
MythMediaDevice * GetMedia(const QString &path)
Get media device by pathname.
void Unlock(MythMediaDevice *pMedia)
decrements the MythMediaDevices reference count
MediaMonitor(QObject *par, unsigned long interval, bool allowEject)
Lookup some settings, and do OS-specific stuff in sub-classes.
void ChooseAndEjectMedia(void)
Unmounts and ejects removable media devices.
QRecursiveMutex m_devicesLock
Definition: mediamonitor.h:121
static QString defaultDVDdevice()
DVDDeviceLocation, user-selected drive, or /dev/dvd.
bool shouldIgnore(const MythMediaDevice *device)
Check user preferences to see if this device should be monitored.
QList< MythMediaDevice * > m_removedDevices
Definition: mediamonitor.h:123
QWaitCondition m_wait
Definition: mediamonitor.h:130
void CheckDevices(void)
Poll the devices in our list.
static MediaMonitor * s_monitor
Definition: mediamonitor.h:137
static QString defaultDevice(const QString &setting, const QString &label, const char *hardCodedDefault)
QStringList m_ignoreList
Definition: mediamonitor.h:127
static void ejectOpticalDisc(void)
Eject a disk, unmount a drive, open a tray.
bool volatile m_active
Was MonitorThread started?
Definition: mediamonitor.h:129
void StopMonitoring(void)
Stop the monitoring thread if needed.
QMap< QString, MHData > m_handlerMap
Registered Media Handlers.
Definition: mediamonitor.h:135
void RegisterMediaHandler(const QString &destination, const QString &description, MediaCallback callback, int mediaType, const QString &extensions)
Register a handler for media related events.
QList< MythMediaDevice * > m_devices
Definition: mediamonitor.h:122
virtual void deleteLater(void)
static QString defaultCDdevice()
CDDevice, user-selected drive, or /dev/cdrom.
QMap< MythMediaDevice *, int > m_useCount
Definition: mediamonitor.h:124
static QString GetMountPath(const QString &devPath)
If the device is being monitored, return its mountpoint.
static QString defaultVCDdevice()
VCDDeviceLocation, user-selected drive, or /dev/cdrom.
void EjectMedia(const QString &path)
virtual void StartMonitoring(void)
Start the monitoring thread if needed.
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.
MythMediaDevice * selectDrivePopup(const QString &label, bool &canceled, bool showMounted=false, bool showUsable=false)
List removable drives, let the user select one.
QList< MythMediaDevice * > GetMedias(unsigned mediatypes)
Ask for available media.
QString listDevices(void)
A string summarising the current devices, for debugging.
static QString defaultCDWriter()
CDWriterDeviceLocation, user-selected drive, or /dev/cdrom.
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
QDateTime m_lastCheckTime
Definition: mediamonitor.h:44
unsigned long m_interval
Definition: mediamonitor.h:43
QPointer< MediaMonitor > m_monitor
Definition: mediamonitor.h:42
static MythCDROM * get(QObject *par, const QString &devicePath, bool SuperMount, bool AllowEject)
Definition: mythcdrom.cpp:43
void setDeviceSpeed(const char *devicePath, int speed) override
Definition: mythcdrom.cpp:140
QString GetSetting(const QString &key, const QString &defaultval="")
bool GetBoolSetting(const QString &key, bool defaultval=false)
Basic menu dialog, message and a list of options.
void Closed(QString, int)
MythScreenStack * GetMainStack()
const QString & getMountPath() const
Definition: mythmedia.h:58
MythMediaStatus getStatus() const
Definition: mythmedia.h:70
QString MediaTypeString()
Definition: mythmedia.cpp:518
bool unmount()
Definition: mythmedia.h:108
const QString & getRealDevice() const
Definition: mythmedia.h:63
bool isUsable() const
Is this device "ready", for a plugin to access?
Definition: mythmedia.h:84
static void RegisterMediaExtensions(uint mediatype, const QString &extensions)
Used to register media types with extensions.
Definition: mythmedia.cpp:303
const QString & getDevicePath() const
Definition: mythmedia.h:61
static const std::array< const QString, 9 > kMediaStatusStrings
Definition: mythmedia.h:117
virtual MythMediaStatus checkMedia()=0
virtual MythMediaError unlock()
Definition: mythmedia.cpp:352
MythMediaType getMediaType() const
Definition: mythmedia.h:91
bool findMountPath()
Try to find a mount of m_devicePath in the mounts file.
Definition: mythmedia.cpp:368
virtual MythMediaError eject(bool open_close=true)
Definition: mythmedia.cpp:311
virtual void setSpeed(int speed)
Definition: mythmedia.cpp:334
bool isMounted(bool bVerify=true)
Tells us if m_devicePath is a mounted device.
Definition: mythmedia.cpp:360
static const Type kEventType
Definition: mythmedia.h:193
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
static QList< GameHandler * > * handlers
Definition: gamehandler.cpp:28
static const iso6937table * d
#define DEFAULT_DVD
#define DEFAULT_CD
static constexpr unsigned long MONITOR_INTERVAL
static QString DevName(MythMediaDevice *d)
static const QString sLocation
void(*)(MythMediaDevice *, bool) MediaCallback
Definition: mediamonitor.h:15
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
bool HasMythMainWindow(void)
MythMainWindow * GetMythMainWindow(void)
MythMediaType
Definition: mythmedia.h:24
MythMediaError
Definition: mythmedia.h:39
@ MEDIAERR_UNSUPPORTED
Definition: mythmedia.h:42
@ MEDIAERR_OK
Definition: mythmedia.h:40
@ MEDIAERR_FAILED
Definition: mythmedia.h:41
MythMediaStatus
Definition: mythmedia.h:12
@ MEDIASTAT_UNKNOWN
Definition: mythmedia.h:14
@ MEDIASTAT_NODISK
CD/DVD tray closed but empty, device unusable.
Definition: mythmedia.h:17
@ MEDIASTAT_USEABLE
Definition: mythmedia.h:19
@ MEDIASTAT_UNPLUGGED
Definition: mythmedia.h:15
@ MEDIASTAT_OPEN
CD/DVD tray open (meaningless for non-CDs?)
Definition: mythmedia.h:16
@ MEDIASTAT_NOTMOUNTED
Definition: mythmedia.h:20
@ MEDIASTAT_MOUNTED
Definition: mythmedia.h:21
@ MEDIASTAT_ERROR
Unable to mount, but could be usable.
Definition: mythmedia.h:13
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
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
void ShowNotification(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
Stores details of media handlers.
Definition: mediamonitor.h:23