OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2012 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 #import "webrtc/base/maccocoasocketserver.h" | |
11 | |
12 #import <Foundation/Foundation.h> | |
13 #import <AppKit/AppKit.h> | |
14 | |
15 #include "webrtc/base/scoped_autorelease_pool.h" | |
16 | |
17 // MacCocoaSocketServerHelperRtc serves as a delegate to NSMachPort or a target
for | |
18 // a timeout. | |
19 @interface MacCocoaSocketServerHelperRtc : NSObject { | |
20 // This is a weak reference. This works fine since the | |
21 // rtc::MacCocoaSocketServer owns this object. | |
22 rtc::MacCocoaSocketServer* socketServer_; // Weak. | |
23 } | |
24 @end | |
25 | |
26 @implementation MacCocoaSocketServerHelperRtc | |
27 - (id)initWithSocketServer:(rtc::MacCocoaSocketServer*)ss { | |
28 self = [super init]; | |
29 if (self) { | |
30 socketServer_ = ss; | |
31 } | |
32 return self; | |
33 } | |
34 | |
35 - (void)timerFired:(NSTimer*)timer { | |
36 socketServer_->WakeUp(); | |
37 } | |
38 | |
39 - (void)breakMainloop { | |
40 [NSApp stop:self]; | |
41 // NSApp stop only exits after finishing processing of the | |
42 // current event. Since we're potentially in a timer callback | |
43 // and not an NSEvent handler, we need to trigger a dummy one | |
44 // and turn the loop over. We may be able to skip this if we're | |
45 // on the ss' thread and not inside the app loop already. | |
46 NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined | |
47 location:NSMakePoint(0,0) | |
48 modifierFlags:0 | |
49 timestamp:0 | |
50 windowNumber:0 | |
51 context:nil | |
52 subtype:0 | |
53 data1:0 | |
54 data2:0]; | |
55 [NSApp postEvent:event atStart:NO]; | |
56 } | |
57 @end | |
58 | |
59 namespace rtc { | |
60 | |
61 MacCocoaSocketServer::MacCocoaSocketServer() { | |
62 helper_ = [[MacCocoaSocketServerHelperRtc alloc] initWithSocketServer:this]; | |
63 timer_ = nil; | |
64 run_count_ = 0; | |
65 | |
66 // Initialize the shared NSApplication | |
67 [NSApplication sharedApplication]; | |
68 } | |
69 | |
70 MacCocoaSocketServer::~MacCocoaSocketServer() { | |
71 [timer_ invalidate]; | |
72 [timer_ release]; | |
73 [helper_ release]; | |
74 } | |
75 | |
76 // ::Wait is reentrant, for example when blocking on another thread while | |
77 // responding to I/O. Calls to [NSApp] MUST be made from the main thread | |
78 // only! | |
79 bool MacCocoaSocketServer::Wait(int cms, bool process_io) { | |
80 rtc::ScopedAutoreleasePool pool; | |
81 if (!process_io && cms == 0) { | |
82 // No op. | |
83 return true; | |
84 } | |
85 if ([NSApp isRunning]) { | |
86 // Only allow reentrant waiting if we're in a blocking send. | |
87 ASSERT(!process_io && cms == kForever); | |
88 } | |
89 | |
90 if (!process_io) { | |
91 // No way to listen to common modes and not get socket events, unless | |
92 // we disable each one's callbacks. | |
93 EnableSocketCallbacks(false); | |
94 } | |
95 | |
96 if (kForever != cms) { | |
97 // Install a timer that fires wakeup after cms has elapsed. | |
98 timer_ = | |
99 [NSTimer scheduledTimerWithTimeInterval:cms / 1000.0 | |
100 target:helper_ | |
101 selector:@selector(timerFired:) | |
102 userInfo:nil | |
103 repeats:NO]; | |
104 [timer_ retain]; | |
105 } | |
106 | |
107 // Run until WakeUp is called, which will call stop and exit this loop. | |
108 run_count_++; | |
109 [NSApp run]; | |
110 run_count_--; | |
111 | |
112 if (!process_io) { | |
113 // Reenable them. Hopefully this won't cause spurious callbacks or | |
114 // missing ones while they were disabled. | |
115 EnableSocketCallbacks(true); | |
116 } | |
117 | |
118 return true; | |
119 } | |
120 | |
121 // Can be called from any thread. Post a message back to the main thread to | |
122 // break out of the NSApp loop. | |
123 void MacCocoaSocketServer::WakeUp() { | |
124 if (timer_ != nil) { | |
125 [timer_ invalidate]; | |
126 [timer_ release]; | |
127 timer_ = nil; | |
128 } | |
129 | |
130 // [NSApp isRunning] returns unexpected results when called from another | |
131 // thread. Maintain our own count of how many times to break the main loop. | |
132 if (run_count_ > 0) { | |
133 [helper_ performSelectorOnMainThread:@selector(breakMainloop) | |
134 withObject:nil | |
135 waitUntilDone:false]; | |
136 } | |
137 } | |
138 | |
139 } // namespace rtc | |
OLD | NEW |