Forráskód Böngészése

Monitor and update the display color profile to match the projector color mode

Zachary Kotlarek 13 éve
szülő
commit
1e33c47352
2 módosított fájl, 161 hozzáadás és 31 törlés
  1. 121 31
      dmx/color.pl
  2. 40 0
      dmx/launchd/com.uberzach.color.plist

+ 121 - 31
dmx/color.pl

@@ -12,8 +12,11 @@ use lib dirname(abs_path($0));
 use DMX;
 use DMX;
 
 
 # Config
 # Config
-my $LOW  = 'Epson-Low';
-my $HIGH = 'Epson-High';
+my $DISPLAY  = 1;
+my %PROFILES = (
+	'HIGH' => 'Epson-High',
+	'LOW'  => 'Epson-Low'
+);
 
 
 # App config
 # App config
 my $DATA_DIR     = DMX::dataDir();
 my $DATA_DIR     = DMX::dataDir();
@@ -21,7 +24,13 @@ my $OUTPUT_FILE  = $DATA_DIR . 'COLOR';
 my $STATE_SOCK   = $OUTPUT_FILE . '.socket';
 my $STATE_SOCK   = $OUTPUT_FILE . '.socket';
 my $PUSH_TIMEOUT = 20;
 my $PUSH_TIMEOUT = 20;
 my $PULL_TIMEOUT = $PUSH_TIMEOUT * 3;
 my $PULL_TIMEOUT = $PUSH_TIMEOUT * 3;
-my $DELAY        = 1;
+my $DELAY        = $PULL_TIMEOUT / 2;
+
+# Prototypes
+sub runApplescript($);
+sub getProfile($);
+sub setProfile($$);
+sub profileExists($$);
 
 
 # Debug
 # Debug
 my $DEBUG = 0;
 my $DEBUG = 0;
@@ -36,26 +45,34 @@ DMX::stateSubscribe($STATE_SOCK);
 # State
 # State
 my $state     = 'OFF';
 my $state     = 'OFF';
 my $stateLast = $state;
 my $stateLast = $state;
+my $color     = 'OFF';
+my $colorLast = $color;
 my %exists    = ();
 my %exists    = ();
 my $pushLast  = 0;
 my $pushLast  = 0;
 my $pullLast  = time();
 my $pullLast  = time();
 my $update    = 0;
 my $update    = 0;
 
 
+# Validate our profiles
+foreach my $profile (keys(%PROFILES)) {
+	if (!profileExists($DISPLAY, $PROFILES{$profile})) {
+		die('Invalid profile: ' . $profile . ' => ' . $PROFILES{$profile} . "\n");
+	}
+}
+
 # Loop forever
 # Loop forever
 while (1) {
 while (1) {
 
 
-	# Grab the current audio output device
-	$deviceLast = $device;
-	$device     = capture(@AUDIO_GET);
-	$device =~ s/\n$//;
+	# Grab the current color profile
+	$colorLast = $color;
+	$color     = getProfile($DISPLAY);
 
 
-	# If the device has changed, save the state to disk
-	if ($deviceLast ne $device) {
+	# If the color profile has changed, save the state to disk
+	if ($colorLast ne $color) {
 		if ($DEBUG) {
 		if ($DEBUG) {
-			print STDERR 'New output device: ' . $deviceLast . ' => ' . $device . "\n";
+			print STDERR 'New color profile: ' . $colorLast . ' => ' . $color . "\n";
 		}
 		}
 		my ($fh, $tmp) = tempfile($OUTPUT_FILE . '.XXXXXXXX', 'UNLINK' => 0);
 		my ($fh, $tmp) = tempfile($OUTPUT_FILE . '.XXXXXXXX', 'UNLINK' => 0);
-		print $fh $device . "\n";
+		print $fh $color . "\n";
 		close($fh);
 		close($fh);
 		rename($tmp, $OUTPUT_FILE);
 		rename($tmp, $OUTPUT_FILE);
 	}
 	}
@@ -77,18 +94,16 @@ while (1) {
 
 
 	# Calculate the new state
 	# Calculate the new state
 	$stateLast = $state;
 	$stateLast = $state;
-	if ($exists{'RAVE'}) {
-		$state = 'RAVE';
-	} elsif ($exists{'AUDIO_AMP'}) {
-		$state = 'AMP';
+	if ($exists{'PROJECTOR_COLOR'} eq 'DYNAMIC') {
+		$state = 'HIGH';
 	} else {
 	} else {
-		$state = 'DEFAULT';
+		$state = 'LOW';
 	}
 	}
 
 
 	# Force updates on a periodic basis
 	# Force updates on a periodic basis
 	if (!$update && time() - $pushLast > $PUSH_TIMEOUT) {
 	if (!$update && time() - $pushLast > $PUSH_TIMEOUT) {
 
 
-		# Not for the audio output device
+		# Not for the color profile
 		#if ($DEBUG) {
 		#if ($DEBUG) {
 		#	print STDERR "Forcing periodic update\n";
 		#	print STDERR "Forcing periodic update\n";
 		#}
 		#}
@@ -96,21 +111,21 @@ while (1) {
 	}
 	}
 
 
 	# Force updates when there is a physical state mistmatch
 	# Force updates when there is a physical state mistmatch
-	if (!$update && $DEVS{$state} ne $device) {
+	if (!$update && $PROFILES{$state} ne $color) {
 		if ($DEBUG) {
 		if ($DEBUG) {
-			print STDERR 'State mismatch: ' . $device . ' => ' . $DEVS{$state} . "\n";
+			print STDERR 'State mismatch: ' . $color . ' => ' . $PROFILES{$state} . "\n";
 		}
 		}
 		$update = 1;
 		$update = 1;
 	}
 	}
 
 
-	# Update the audio output device
+	# Update the color profile
 	if ($update) {
 	if ($update) {
 
 
 		# Update
 		# Update
 		if ($DEBUG) {
 		if ($DEBUG) {
-			print STDERR 'Setting output to: ' . $DEVS{$state} . "\n";
+			print STDERR 'Setting output to: ' . $PROFILES{$state} . "\n";
 		}
 		}
-		system(@AUDIO_SET, $DEVS{$state});
+		setProfile($DISPLAY, $PROFILES{$state});
 
 
 		# Update the push time
 		# Update the push time
 		$pushLast = time();
 		$pushLast = time();
@@ -118,15 +133,90 @@ while (1) {
 		# Clear the update flag
 		# Clear the update flag
 		$update = 0;
 		$update = 0;
 	}
 	}
+}
 
 
-	# If the state has changed and the device has responded, save to disk
-	if (!$update && $stateLast ne $state) {
-		if ($DEBUG) {
-			print STDERR 'New output state: ' . $stateLast . ' => ' . $state . "\n";
-		}
-		my ($fh, $tmp) = tempfile($OUTPUT_STATE . '.XXXXXXXX', 'UNLINK' => 0);
-		print $fh $state . "\n";
-		close($fh);
-		rename($tmp, $OUTPUT_STATE);
+sub runApplescript($) {
+	my ($script) = @_;
+	if ($DEBUG) {
+		print STDERR 'Running AppleScript: ' . $script . "\n";
+	}
+
+	my $retval = capture('osascript', '-e', $script);
+	if ($DEBUG) {
+		print STDERR "\tAppleScript result: " . $retval . "\n";
+	}
+
+	return $retval;
+}
+
+sub getProfile($) {
+	my ($display) = @_;
+	if ($DEBUG) {
+		print STDERR "getProfile()\n";
+	}
+
+	# Validate the input
+	$display = int($display);
+	if (!$display) {
+		die('Invalid display ID: ' . $display . "\n");
+	}
+
+	# Ask SwitchResX what color profile is installed
+	my $profile = runApplescript('tell application "SwitchResX Daemon" to get display profile of display ' . $display);
+
+	# Cleanup the name
+	$profile =~ s/^\s*profile //;
+	$profile =~ s/\s+$//;
+
+	return $profile;
+}
+
+sub setProfile($$) {
+	my ($display, $profile) = @_;
+	if ($DEBUG) {
+		print STDERR "setProfile()\n";
+	}
+
+	# Validate the input
+	$profile =~ s/\"/\\\"/g;
+	$profile = '"' . $profile . '"';
+	$display = int($display);
+	if (!$display) {
+		die('Invalid display ID: ' . $display . "\n");
+	}
+
+	# Tell SwitchResX to change our color profile
+	my @cmd = ('tell application "SwitchResX Daemon"');
+	push(@cmd, 'set prof to profile ' . $profile . ' of display ' . $display);
+	push(@cmd, 'set display profile of display ' . $display . ' to prof');
+	push(@cmd, 'end tell');
+
+	return runApplescript(join("\n", @cmd));
+}
+
+sub profileExists($$) {
+	my ($display, $profile) = @_;
+	if ($DEBUG) {
+		print STDERR "profileExists()\n";
+	}
+
+	# Validate the input
+	$profile =~ s/\"/\\\"/g;
+	$profile = '"' . $profile . '"';
+	$display = int($display);
+	if (!$display) {
+		die('Invalid display ID: ' . $display . "\n");
+	}
+
+	# Ask SwitchResX if the named color profile exists
+	my @cmd = ('tell application "SwitchResX Daemon"');
+	push(@cmd, 'set profs to get name of every profile of display ' . $display);
+	push(@cmd, 'get profs contains ' . $profile);
+	push(@cmd, 'end tell');
+
+	my $result = runApplescript(join("\n", @cmd));
+	if ($result =~ /true/i) {
+		return 1;
 	}
 	}
+	return 0;
 }
 }

+ 40 - 0
dmx/launchd/com.uberzach.color.plist

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>LimitLoadToSessionType</key>
+	<string>Aqua</string>
+	<key>LimitLoadToHosts</key>
+	<array>
+		<string>loki.uberzach.com</string>
+		<string>Loki.local</string>
+	</array>
+	<key>RunAtLoad</key>
+	<true/>
+	<key>Label</key>
+	<string>com.uberzach.color</string>
+	<key>KeepAlive</key>
+	<dict>
+		<key>OtherJobEnabled</key>
+		<dict>
+			<key>com.uberzach.projector</key>
+			<true/>
+			<key>com.uberzach.state</key>
+			<true/>
+		</dict>
+	</dict>
+	<key>ProgramArguments</key>
+	<array>
+		<string>/Users/tv/bin/video/dmx/color.pl</string>
+	</array>
+	<!--
+		<key>EnvironmentVariables</key>
+		<dict>
+			<key>DEBUG</key>
+			<string>1</string>
+		</dict>
+		<key>StandardErrorPath</key>
+		<string>/Users/tv/com.uberzach.color_errlog.txt</string>
+	-->
+</dict>
+</plist>