Ticket #1753: mythmediamonitor-darwin.3.cpp

File mythmediamonitor-darwin.3.cpp, 7.5 KB (added by awk@…, 18 years ago)

Updated Darwin specific media monitor subclass

Line 
1#include "mythmediamonitor.h"
2#include "mythmediamonitor-darwin.h"
3#include "mythcdrom.h"
4#include "mythmedia.h"
5
6#include <mythtv/mythcontext.h>
7
8#include <IOKit/IOKitLib.h>
9#include <IOKit/storage/IOMedia.h>
10#include <IOKit/storage/IOCDMedia.h>
11#include <IOKit/storage/IODVDMedia.h>
12
13static mach_port_t            sMasterPort;
14
15MediaType FindDVDOrCDMedia(io_service_t service)
16{
17    kern_return_t    kernResult;
18    io_iterator_t    iter;
19    MediaType mediaType = MEDIATYPE_UNKNOWN;
20    bool isWholeMedia = false;
21   
22    // Create an iterator across all parents of the service object passed in.
23    kernResult = IORegistryEntryCreateIterator(service,
24                                               kIOServicePlane,
25                                               kIORegistryIterateRecursively | kIORegistryIterateParents,
26                                               &iter);
27   
28    if (KERN_SUCCESS != kernResult)
29    {
30        VERBOSE(VB_IMPORTANT, QString("FindDVDMedia - IORegistryEntryCreateIterator returned %1").arg(kernResult));
31    }
32    else if (!iter)
33    {
34        VERBOSE(VB_IMPORTANT, "FindDVDMedia - IORegistryEntryCreateIterator returned a NULL iterator");
35    }
36    else
37    {
38        // A reference on the initial service object is released in the do-while loop below,
39        // so add a reference to balance
40        IOObjectRetain(service);   
41       
42        do
43        {
44            isWholeMedia = false;
45            if (IOObjectConformsTo(service, kIOMediaClass))
46            {
47               
48                CFTypeRef wholeMedia;
49               
50                wholeMedia = IORegistryEntryCreateCFProperty(service,
51                                                             CFSTR(kIOMediaWholeKey),
52                                                             kCFAllocatorDefault,
53                                                             0);
54                                                           
55                if (NULL == wholeMedia)
56                {
57                    VERBOSE(VB_IMPORTANT, "IsDVDMedia - Could not retrieve Whole property");
58                }
59                else
60                {                                       
61                    isWholeMedia = CFBooleanGetValue((CFBooleanRef)wholeMedia);
62                    CFRelease(wholeMedia);
63                }
64            }
65       
66            if (isWholeMedia && (IOObjectConformsTo(service, kIODVDMediaClass)))
67            {
68                mediaType = MEDIATYPE_DVD;
69            }
70            else if (isWholeMedia && (IOObjectConformsTo(service, kIOCDMediaClass)))
71            {
72                mediaType = MEDIATYPE_AUDIO;
73            }
74            IOObjectRelease(service);
75        } while ((service = IOIteratorNext(iter)) && (mediaType == MEDIATYPE_UNKNOWN));
76
77        IOObjectRelease(iter);
78    }
79    return mediaType;
80}
81
82MediaType MediaTypeForBSDName(const char *bsdName)
83{
84    CFMutableDictionaryRef    matchingDict;
85    kern_return_t        kernResult;
86    io_iterator_t         iter;
87    io_service_t        service;
88    MediaType mediaType = MEDIATYPE_UNKNOWN;
89   
90    matchingDict = IOBSDNameMatching(sMasterPort, 0, bsdName);
91    if (NULL == matchingDict)
92    {
93        VERBOSE(VB_IMPORTANT, QString("IsDVDMediaForName(%1) - IOBSDNameMatching returned a NULL dictionary.").arg(bsdName));
94    }
95    else
96    {
97        // Return an iterator across all objects with the matching BSD node name. Note that there
98        // should only be one match!
99        kernResult = IOServiceGetMatchingServices(sMasterPort, matchingDict, &iter);   
100   
101        if (KERN_SUCCESS != kernResult)
102        {
103            VERBOSE(VB_IMPORTANT, QString("IIsDVDMediaForName - IOServiceGetMatchingServices returned %1").arg(kernResult));
104        }
105        else if (!iter)
106        {
107            VERBOSE(VB_IMPORTANT, "IIsDVDMediaForName - IOServiceGetMatchingServices returned a NULL iterator");
108        }
109        else
110        {
111            service = IOIteratorNext(iter);
112           
113            // Release this now because we only expect the iterator to contain
114            // a single io_service_t.
115            IOObjectRelease(iter);
116           
117            if (!service)
118            {
119                VERBOSE(VB_IMPORTANT, "IIsDVDMediaForName - IOIteratorNext returned a NULL iterator");
120            }
121            else
122            {
123                mediaType = FindDVDOrCDMedia(service);
124                IOObjectRelease(service);
125            }
126        }
127    }
128    return mediaType;
129}
130
131
132void diskAppearedCallback(DADiskRef disk, void *context)
133{
134    // Find out if the new disk is a DVD (or CD)
135    MediaType mediaType = MediaTypeForBSDName(DADiskGetBSDName(disk));
136    if (context && ((mediaType == MEDIATYPE_DVD) || (mediaType == MEDIATYPE_AUDIO)))
137    {
138        // Add new device
139        reinterpret_cast<MonitorThreadDarwin*>(context)->diskAppeared(DADiskGetBSDName(disk));
140    }
141}
142
143void diskDisappearedCallback(DADiskRef disk, void *context)
144{
145    if (context)
146        reinterpret_cast<MonitorThreadDarwin *>(context)->diskDisappeared(DADiskGetBSDName(disk));
147}
148
149MonitorThreadDarwin::MonitorThreadDarwin( MediaMonitor* pMon,  unsigned long interval) :
150    MonitorThread(pMon, interval)
151{
152}
153
154// Nice and simple, as long as our monitor is valid and active,
155// loop and check it's devices.
156void MonitorThreadDarwin::run(void)
157{
158    registerDiskArbitrationCallbacks();
159
160    while (m_Monitor && m_Monitor->IsActive())       
161    {
162        m_Monitor->CheckDevices();
163        // Run the run loop for interval (milliseconds) - this will handle any disk arbitration
164        // appeared/dissappeared events
165        CFRunLoopRunInMode(kCFRunLoopDefaultMode, (float) m_Interval / 1000.0f, false );
166    }
167
168    unregisterDiskArbitrationCallbacks();
169}
170
171void MonitorThreadDarwin::diskAppeared(QString devName)
172{
173        MythMediaDevice *media = MythCDROM::get(m_Monitor, devName, true, m_Monitor->m_AllowEject);
174        m_Monitor->AddDevice(media);
175}
176
177void MonitorThreadDarwin::diskDisappeared(QString devName)
178{
179        m_Monitor->RemoveDevice(devName);
180}
181
182void MonitorThreadDarwin::registerDiskArbitrationCallbacks()
183{
184    m_DiskArbitrationSession = (void *) DASessionCreate(kCFAllocatorDefault);
185    DARegisterDiskAppearedCallback( (DASessionRef) m_DiskArbitrationSession, kDADiskDescriptionMatchVolumeMountable, diskAppearedCallback, this);
186    DARegisterDiskDisappearedCallback( (DASessionRef) m_DiskArbitrationSession, kDADiskDescriptionMatchVolumeMountable, diskDisappearedCallback, this);
187
188    DASessionScheduleWithRunLoop((DASessionRef) m_DiskArbitrationSession, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
189}
190
191void MonitorThreadDarwin::unregisterDiskArbitrationCallbacks()
192{
193    CFRelease((DASessionRef) m_DiskArbitrationSession);
194}
195
196/** \fn MediaMonitor::StartMonitoring(void)
197 *  \brief Start the monitoring thread if needed.
198 */
199void MediaMonitorDarwin::StartMonitoring(void)
200{
201    // Sanity check
202    if (m_Active)
203        return;
204
205    if (!m_Thread)
206    {
207        m_Thread = new MonitorThreadDarwin(this, m_MonitorPollingInterval);
208    }
209    m_Active = true;
210    m_Thread->start();
211}
212
213// Given a media device add it to our collection.
214bool MediaMonitorDarwin::AddDevice(MythMediaDevice* pDevice)
215{
216    if ( ! pDevice )
217    {
218        VERBOSE(VB_IMPORTANT, "Error - MediaMonitor::AddDevice(null)");
219        return false;
220    }
221
222    QMutexLocker locker(&m_DevicesLock);
223
224    connect(pDevice, SIGNAL(statusChanged(MediaStatus, MythMediaDevice*)),
225            this, SLOT(mediaStatusChanged(MediaStatus, MythMediaDevice*)));
226    m_Devices.push_back( pDevice );
227    m_UseCount[pDevice] = 0;
228
229    return true;
230}
231