summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/webrtc/base/maccocoasocketserver.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/webrtc/base/maccocoasocketserver.mm')
-rw-r--r--chromium/third_party/webrtc/base/maccocoasocketserver.mm140
1 files changed, 140 insertions, 0 deletions
diff --git a/chromium/third_party/webrtc/base/maccocoasocketserver.mm b/chromium/third_party/webrtc/base/maccocoasocketserver.mm
new file mode 100644
index 00000000000..123ffdc5255
--- /dev/null
+++ b/chromium/third_party/webrtc/base/maccocoasocketserver.mm
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2012 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#import "webrtc/base/maccocoasocketserver.h"
+
+#import <Foundation/Foundation.h>
+#import <AppKit/AppKit.h>
+#include <assert.h>
+
+#include "webrtc/base/scoped_autorelease_pool.h"
+
+// MacCocoaSocketServerHelperRtc serves as a delegate to NSMachPort or a target for
+// a timeout.
+@interface MacCocoaSocketServerHelperRtc : NSObject {
+ // This is a weak reference. This works fine since the
+ // rtc::MacCocoaSocketServer owns this object.
+ rtc::MacCocoaSocketServer* socketServer_; // Weak.
+}
+@end
+
+@implementation MacCocoaSocketServerHelperRtc
+- (id)initWithSocketServer:(rtc::MacCocoaSocketServer*)ss {
+ self = [super init];
+ if (self) {
+ socketServer_ = ss;
+ }
+ return self;
+}
+
+- (void)timerFired:(NSTimer*)timer {
+ socketServer_->WakeUp();
+}
+
+- (void)breakMainloop {
+ [NSApp stop:self];
+ // NSApp stop only exits after finishing processing of the
+ // current event. Since we're potentially in a timer callback
+ // and not an NSEvent handler, we need to trigger a dummy one
+ // and turn the loop over. We may be able to skip this if we're
+ // on the ss' thread and not inside the app loop already.
+ NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined
+ location:NSMakePoint(0,0)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:nil
+ subtype:0
+ data1:0
+ data2:0];
+ [NSApp postEvent:event atStart:NO];
+}
+@end
+
+namespace rtc {
+
+MacCocoaSocketServer::MacCocoaSocketServer() {
+ helper_ = [[MacCocoaSocketServerHelperRtc alloc] initWithSocketServer:this];
+ timer_ = nil;
+ run_count_ = 0;
+
+ // Initialize the shared NSApplication
+ [NSApplication sharedApplication];
+}
+
+MacCocoaSocketServer::~MacCocoaSocketServer() {
+ [timer_ invalidate];
+ [timer_ release];
+ [helper_ release];
+}
+
+// ::Wait is reentrant, for example when blocking on another thread while
+// responding to I/O. Calls to [NSApp] MUST be made from the main thread
+// only!
+bool MacCocoaSocketServer::Wait(int cms, bool process_io) {
+ rtc::ScopedAutoreleasePool pool;
+ if (!process_io && cms == 0) {
+ // No op.
+ return true;
+ }
+ if ([NSApp isRunning]) {
+ // Only allow reentrant waiting if we're in a blocking send.
+ ASSERT(!process_io && cms == kForever);
+ }
+
+ if (!process_io) {
+ // No way to listen to common modes and not get socket events, unless
+ // we disable each one's callbacks.
+ EnableSocketCallbacks(false);
+ }
+
+ if (kForever != cms) {
+ // Install a timer that fires wakeup after cms has elapsed.
+ timer_ =
+ [NSTimer scheduledTimerWithTimeInterval:cms / 1000.0
+ target:helper_
+ selector:@selector(timerFired:)
+ userInfo:nil
+ repeats:NO];
+ [timer_ retain];
+ }
+
+ // Run until WakeUp is called, which will call stop and exit this loop.
+ run_count_++;
+ [NSApp run];
+ run_count_--;
+
+ if (!process_io) {
+ // Reenable them. Hopefully this won't cause spurious callbacks or
+ // missing ones while they were disabled.
+ EnableSocketCallbacks(true);
+ }
+
+ return true;
+}
+
+// Can be called from any thread. Post a message back to the main thread to
+// break out of the NSApp loop.
+void MacCocoaSocketServer::WakeUp() {
+ if (timer_ != nil) {
+ [timer_ invalidate];
+ [timer_ release];
+ timer_ = nil;
+ }
+
+ // [NSApp isRunning] returns unexpected results when called from another
+ // thread. Maintain our own count of how many times to break the main loop.
+ if (run_count_ > 0) {
+ [helper_ performSelectorOnMainThread:@selector(breakMainloop)
+ withObject:nil
+ waitUntilDone:false];
+ }
+}
+
+} // namespace rtc