Scott Hanselman

Cloud-Controlled Remote Pan Tilt Zoom Camera API for a Logitech BCC950 Camera with Azure and SignalR

October 23, '12 Comments [33] Posted in Hardware | Lync | Open Source | Remote Work
Sponsored By

I like my giant blog post titles. Nyah.

Logitech BCC950 ConferenceCam, HD 1080p Video at 30 fps, 78deg. Field of View, USB 2.0 CompliantAs a remote worker for almost 5 years now, I live in video conferences. I feel really strongly about the power of seeing someone's face rather than just being a voice on a scratchy speaker phone. I've build an AutoAnswer Kiosk for Lync with some friends that you can get for free at http://lyncautoanswer.com (and read about the code here), I've got a BusyLight so the kids know I'm on a call, and the Holy Grail for the last few years has been a reliable Pan Tilt Zoom camera that I could control remotely.

Related Reading

A few years ago I super-glued a LifeCam camera to an Eagletron TrackerPod and build a web interface to it. I wanted to do this on the cheap as I can't afford (and my boss is into) a $1500 Panasonic IP Camera.

The Solution...er, the Problem

I have found my camera and built my solution. The Logitech BCC950 Conference Cam is the best balance between cost and quality and it's got Pan Tilt and (digital) Zoom functionality. The Zoom is less interesting to me than the motorized Pan Tilt.

Let's think about the constraints.

  • A Logitech BCC950 PTZ camera is installed on a Windows machine in my office in Seattle.
  • I'm anywhere. I'm usually in Portland but could be in a hotel.
    • I may or may not be VPN'ed into work. This means I want to be able to communicate with the camera across networks, traverse NATs and generally not worry about being able to connect.
  • I want to be able to control the camera in a number of ways, Web API, whatever, but ideally with cool buttons that are (or look) integrated with my corporate instant messaging system.

There's three interesting parts here, then.

  1. Can I even control the camera's PTZ functions programmatically?
  2. Can I relay messages across networks to the camera?
  3. Can I make a slick client interface easily?

Let's figure them out one at a time.

Can I even control the camera's PTZ functions programmatically?

I looked all over and googled my brains out trying to find an API to talk to the Logitech camera. I emailed the Logitech people and they folks me that the camera would respond to DirectShow APIs. This means I can control the camera without any drivers!

MSDN showed me PROPSETID_VIDCAP_CAMERACONTROL which has an enumeration that includes things like:

This lead me to this seven year old DirectShow .NET library that wraps the hardest parts of the DirectShow COM API. There's a little utility called GraphEdt.exe (GraphEdit) that you can get in the Windows SDK that lets you look at all the DirectShow-y things and devices and filters on your system.

GraphEdit

This utility let me control the camera's Zoom but Pan and Tilt were grayed out! Why?

GraphEdit showing Pan and Tilt grayed out

Turns out that this Logitech Camera supports only relative Pan and Tilt, not absolute. Whatever code that creates this Properties dialog was never updated to support a relative pan and tilt but the API supports it via KSPROPERTY_CAMERACONTROL_PAN_RELATIVE!

That means I can send a start message quickly followed by a stop message to pan. It's not super exact, but it should work.

Here's the C# code for my move() method. Note the scandalous Thread.Sleep call.

private void MoveInternal(KSProperties.CameraControlFeature axis, int value)
{
// Create and prepare data structures
var control = new KSProperties.KSPROPERTY_CAMERACONTROL_S();

IntPtr controlData = Marshal.AllocCoTaskMem(Marshal.SizeOf(control));
IntPtr instData = Marshal.AllocCoTaskMem(Marshal.SizeOf(control.Instance));

control.Instance.Value = value;

//TODO: Fix for Absolute
control.Instance.Flags = (int)CameraControlFlags.Relative;

Marshal.StructureToPtr(control, controlData, true);
Marshal.StructureToPtr(control.Instance, instData, true);
var hr2 = _ksPropertySet.Set(PROPSETID_VIDCAP_CAMERACONTROL, (int)axis,
instData, Marshal.SizeOf(control.Instance), controlData, Marshal.SizeOf(control));

//TODO: It's a DC motor, no better way?
Thread.Sleep(20);

control.Instance.Value = 0; //STOP!
control.Instance.Flags = (int)CameraControlFlags.Relative;

Marshal.StructureToPtr(control, controlData, true);
Marshal.StructureToPtr(control.Instance, instData, true);
var hr3 = _ksPropertySet.Set(PROPSETID_VIDCAP_CAMERACONTROL, (int)axis,
instData, Marshal.SizeOf(control.Instance), controlData, Marshal.SizeOf(control));

if (controlData != IntPtr.Zero) { Marshal.FreeCoTaskMem(controlData); }
if (instData != IntPtr.Zero) { Marshal.FreeCoTaskMem(instData); }
}

All the code for this PTZDevice wrapper is here. Once that library was working, creating a little console app to move the camera around with a keyboard was trivial.

var p = PTZDevice.GetDevice(ConfigurationManager.AppSettings["DeviceName"], PTZType.Relative);
while (true)
{
ConsoleKeyInfo info = Console.ReadKey();
if (info.Key == ConsoleKey.LeftArrow)
{
p.Move(-1, 0);
}
else if (info.Key == ConsoleKey.RightArrow)
{
p.Move(1, 0);
}
else if (info.Key == ConsoleKey.UpArrow)
{
p.Move(0, 1);
}
else if (info.Key == ConsoleKey.DownArrow)
{
p.Move(0, -1);
}
else if (info.Key == ConsoleKey.Home)
{
p.Zoom(1);
}
else if (info.Key == ConsoleKey.End)
{
p.Zoom(-1);
}
}

Also easy was a simple WebAPI. (I put the name of the camera to look for in a config file in both these cases.)

[HttpPost]
public void Move(int x, int y)
{
var p = PTZDevice.GetDevice(ConfigurationManager.AppSettings["DeviceName"], PTZType.Relative);
p.Move(x,y);
}

[HttpPost]
public void Zoom(int value)
{
var p = PTZDevice.GetDevice(ConfigurationManager.AppSettings["DeviceName"], PTZType.Relative);
p.Zoom(value);
}

At this point I've got the camera moving LOCALLY. Next, I mail it to Damian (my office buddy) in Seattle and he hooks it up to my office computer. But I need something to control it running on THAT machine...and talking to what?

Can I relay messages across networks to the camera?

Here's the architecture. Since I can't talk point to point via TCP between wherever I am and wherever the camera is, I need a relay. I could use a Service Bus Relay which would be great for something larger but I wanted to see if I could make something even simpler. I'd like to use HTTP since it's, well, it's HTTP.

A Diagram showing my laptop talksk via SignalR through Azure to the camera in Seattle

Since Azure lets me have 10 free websites and automatically supports SSL via a wildcard cert for sites at the *.azurewebsites.net domain, it was perfect for what I needed. I want to use SSL because it's the best way to guarantee that my traffic not be affected by corporate proxy servers.

There's three parts. Let's start in the middle. What's the Relay look like? I'm going to use SignalR because it will let me not only call methods easily and asynchronously but, more importantly, it will abstract away the connection details from me. I'm looking to relay messages over a psuedo-persistent connection. 

So what's the code look like for a complex relay system like this? ;)

using System;
using SignalR.Hubs;

namespace PTZSignalRRelay
{
public class RelayHub : Hub
{
public void Move(int x, int y, string groupName)
{
Clients[groupName].Move(x, y); //test
}

public void Zoom(int value, string groupName)
{
Clients[groupName].Zoom(value);
}

public void JoinRelay(string groupName)
{
Groups.Add(Context.ConnectionId, groupName);
}
}
}

Crazy, eh? That's it. Clients call JoinRelay with a name. The name is the name of the computer with the camera attached. (More on this later) This means that this single relay can handle effectively any number of clients. When a client calls to Relay with a message and group name, the relay then broadcasts to clients that have that group name.

Can I make a slick client interface easily?

I created a super basic WPF app that's just a transparent window with buttons. In fact, the background isn't white or black, it's transparent. It's a SolidColorBrush that is all but invisible. It's not totally transparent or I wouldn't be able to grab it with the mouse!

<SolidColorBrush x:Key="NotQuiteTransparent" Color="#01000000"></SolidColorBrush>

The buttons use the .NET SignalR library and call it like this.

HubConnection connection = null;
IHubProxy proxy = null;
string remoteGroup;
string url;

private void MainWindow_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
this.DragMove();
}

private async void MoveClick(object sender, RoutedEventArgs e)
{
var ui = sender as Control;
Point p = Point.Parse(ui.Tag.ToString());
await proxy.Invoke("Move", p.X, p.Y, remoteGroup);
}

private async void ZoomClick(object sender, RoutedEventArgs e)
{
var ui = sender as Control;
int z = int.Parse(ui.Tag.ToString());
await proxy.Invoke("Zoom", z, remoteGroup);
}

private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
url = ConfigurationManager.AppSettings["relayServerUrl"];
remoteGroup = ConfigurationManager.AppSettings["remoteGroup"];
connection = new HubConnection(url);
proxy = connection.CreateProxy("RelayHub");
await connection.Start();
await proxy.Invoke("JoinRelay", remoteGroup);
}

The client app just needs to know the name of the computer with the camera it wants to control. That's the "GroupName" or in this case, from the client side, the "RemoteGroup." Then it knows the Relay Server URL, like https://foofooserver.azurewebsites.net. The .NET client uses async and await to make the calls non-blocking so the UI remains responsive.

Here's a bunch of traffic going through the Relay while I was testing it this afternoon, as seen by the Azure Dashboard.

Traffic as shown in a graph on the Azure Dashboard

The client calls the Relay and the Relay broadcasts to connected clients. The Remote Camera Listener responds to the calls. We get the machine name, join the relay and setup two methods that will respond to Move and Zoom.

The only hard thing we ran into (Thanks David Fowler!) was that the calls to the DirectShow API actually have to be on a UI thread rather than a background thread, so we have to get the current SynchronizationContext and post our messages with it. This results in a little indirection but it's not too hard to read. Note the comments.

private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var deviceName = ConfigurationManager.AppSettings["DeviceName"];
device = PTZDevice.GetDevice(deviceName, PTZType.Relative);

url = ConfigurationManager.AppSettings["relayServerUrl"];
remoteGroup = Environment.MachineName; //They have to hardcode the group, but for us it's our machine name
connection = new HubConnection(url);
proxy = connection.CreateProxy("RelayHub");

//Can't do this here because DirectShow has to be on the UI thread!
// This would cause an obscure COM casting error with no clue what's up. So, um, ya.
//proxy.On<int, int>("Move",(x,y) => device.Move(x, y));
//proxy.On<int>("Zoom", (z) => device.Zoom(z));

magic = SynchronizationContext.Current;

proxy.On<int, int>("Move", (x, y) => {
//Toss this over the fence from this background thread to the UI thread
magic.Post((_) => {
Log(String.Format("Move({0},{1})", x,y));
device.Move(x, y);
}, null);
});

proxy.On<int>("Zoom", (z) => {
magic.Post((_) =>
{
Log(String.Format("Zoom({0})", z));
device.Zoom(z);
}, null);
});

try {
await connection.Start();
Log("After connection.Start()");
await proxy.Invoke("JoinRelay", remoteGroup);
Log("After JoinRelay");
}
catch (Exception pants) {
var foo = (WebException)pants.GetBaseException();
StreamReader r = new StreamReader(foo.Response.GetResponseStream());
string yousuck = r.ReadToEnd();
Log(yousuck);
throw;
}
}

It All Works Together

Now I've got all the parts. Buttons that call a Relay that then call back - through NAT and networks - to the Remote Camera Listener which uses the Camera library to move it.

It's ALIVE and it's awesome

It works like a champ. And, because the buttons are transparent, I can put them over the Lync window and pretend it's all integrated.

TODO: I'm hoping that someone who knows more about Windows Internals will volunteer to create some code that will automatically move the buttons as the Lync Window moves and position them over the video window in the corner. Ahem.

The buttons look integrated. But they aren't.The buttons look integrated. But they aren't.

You can set this up yourself, but I haven't gotten around to making an install or anything. If you have a Logitech BCC950 you are welcome to use my Relay until it costs me something. There's a preliminary download up here so you'd only need the Listener on one side and the Buttons on the other. No drivers are needed since we're using DirectShow itself.

This was great fun, and more importantly, I use this PanTiltZoom System ever day and it makes my life better. The best was that I was able to do the whole thing in C#. From client UI to cloud-based relay to device control to COM wrapper, it was all C#. It makes me feel very empowered as a .NET developer to be able to make systems like this with a minimal amount of code.

Lync Developer Resources

Related Links


Sponsor: Big thanks to this week's sponsor. Check them out, it's a great program, I've done it and spoken to actual live humans who help you get started writing an app! Begin your 30-day journey to creating a Windows Store app or game for Windows 8 or Windows Phone today. Your Idea. Your App. 30 Days.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Instapaper delivered to your Kindle changes how you consume web content - Plus IFTTT, blogs and more

October 18, '12 Comments [29] Posted in Reviews
Sponsored By

I've talked about Instapaper before when I tease folks of having 42 tabs open.

Instapaper - Google Chrome

Remember that "open in new tab" rarely means "read it later." It usually means "use up memory and let this page run in the background until eventually declare tab-bankruptcy and close them all."

Kindle Instapaper Photo by Joshua Kaufman via Flickr under CC BY-SA 2.0 http://www.flickr.com/photos/joshuakaufman/5020686891/So if Open In New Tab doesn't mean Read Later, what does? Why, READ LATER does! This gets even better when you combine a Read Later tool like Instapaper with an Amazon Kindle like my new Kindle Paperwhite (I reviewed the Paperwhite last week.)

Inserting a Kindle into your Life's Workflow

Here's the idea. You get a bunch of links that flow through your life all week long. These are often in the form of what I call "long-form reading." Hackernews links, NYTimes studys, academic papers, etc. Some folks make bookmarks, have folders called "Links" on their desktops, or email themselves links.

I have these websites, papers and interesting links rolled up and delivered automatically to my Kindle every week. Think about how amazing that is and how it can change your relationship with content on the web. The stress and urgency (and open tabs) are gone. I am naturally and organically creating a personalized book for weekend reading.

I have a bookmarklet from Instapaper that says "Read Later" on my browser toolbar. I've put it in every browser I use, even Mobile Safari. I've also logged into Instapaper from all my social apps so that I can Read Later from my iPhone Twitter Client for example. You'd be surprised how many apps support Instapaper once you start looking for this.

Workflow Flow Chart - sorry if you are blind. There's text about this soon.What this means it is that Instapaper is ready and waiting for me in every location where an interesting piece of long-form reading could present itself. I don't stress, I click Read Later and the document is shipped off to Instapaper.

I even made a flowchart a few years back. You can get more details on that in my blog post Two Must-Have Tools for a More Readable Web.

Instapaper delivered to your Kindle

So you're building a queue of links that is sent to Instapaper. Perhaps you've tried this  before but then never visited the Instapaper App or Website. This is a common complaint and why I like document delivery to the Kindle. I use my Kindle all the time so I appreciate a "no clicks required" workflow. If books show up on my Kindle I'll read them.

Just visit http://www.instapaper.com/user/kindle once you've got an Instapaper account and put in your Kindle's email address. Did you know every Kindle has one? It's either something@free.kindle.com for free WiFi delivery or just something@kindle.com for 3G delivery with a small fee. I use the free one. You can find out your Kindle's Email Address here under Personal Document Settings.

The key is to allow your Kindle to receive email from the unique Instapaper email address. It's a whitelist.

image

Then, back over in the Instapaper Settings, I set a delivery time if at least 5 things are in the "book":

image

Pulling Links and Content from other Locations with IFTTT

Perhaps you pull your content from elsewhere, or you Like things on Facebook, put them in Dropbox, email them to a special address or something else. You can use If This Then That as the social workflow glue to route those links to Instapaper - and ultimately to your Kindle!

For example, I also use the Delicious social bookmarking service to hold things I want to save. But, I also want to read them and I don't want to stop using Delicious just because I use Instapaper. Instead, I use an IFTTT Recipe to  take newly bookmarked things and send them to Instapaper (and my Kindle!) as well.

Here's my Delicious to Kindle Recipe. You can make any recipe you want to pull links from wherever you find them and send them into your long-form reading queue.

image

You can even have blogs - like this one! - sent automatically to your Kindle via Instapaper with an IFTTT recipe like this:

image

The possibilities are endless.

Conclusion

It can't be overstated how useful this is if you have a Kindle. Rather than opening "guilt-tabs" that you'll never read, have them delivered to yourself in a way that will encourage you TO READ THEM!

If your system isn't working for you, change it. If you already have a system that works, well, great job making it all the way to the end of this blog post!

For more personal productivity ideas watch my video on Scaling Yourself and visit the Productivity section of this blog.


This Week's Sponsor: Your Idea. Your App. 30 Days. Begin your 30-day journey to creating a Windows Store app or game for Windows 8 or Windows Phone today.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

How to call WinRT APIs in Windows 8 from C# Desktop Applications - WinRT Diagram

October 12, '12 Comments [28] Posted in Win8 | Windows Client
Sponsored By

I was trying to access some of the sensors that are built into this Intel Ultrabook that runs Windows 8. However, while there's support for Location Sensors built into the .NET 4 libraries on Windows 7 and up, I want to access the complete Sensor and Location Platform that is built into Windows 8 itself. Those APIs are available via COM and I could call them via COM, but calling them via the WinRT layer is so much nicer. Plus, this is kind of why WinRT exists.

This got me thinking about WinRT and what it means. I did a podcast a few months ago that really cleared things up but I've always found all the various diagrams that attempted to explain how things fit together to be WAY TOO COMPLEX.

DISCLAIMER: All diagrams are, by their nature, oversimplifications. I work on Web Stuff, not Windows Stuff, so this is all my opinion and conjecture, done on my own time. I'm not in the Windows org, I'm just a dude trying to write an app for babies.

I figure it can't be as complicated as all these diagrams. I drew this to help myself understand.

WinRT Diagram

Just like the C Language has the C Runtime that provides a bunch of supporting functions and defines a calling convention for them, so the Windows Runtime (WinRT) does for Windows and its languages. These APIs and runtime includes metadata about calling conventions that make WinRT APIs easier to call than COM.

See how in the diagram I can call any API from the .NET CLR? In the case of the Sensors APIs I want to call, while they are ultimately Win32 APIs or COM APIs, I would like to call them using the highest level calling convention available and that's the very friendly Windows RT ones.

Calling WinRT APIs from C# Desktop Applications

I like to test things using small Console Apps, but those aren't "Windows Store Applications," so am I allowed to call WinRT APIs from my Desktop or Console application?

Sure. There's actually a section of the MSDN Documentation that lists out all the WinRT APIs for Windows 8 that are able to be called from the Desktop. I can specifically check the LightSensor class itself within the documentation and make sure it's allowed to be called from Desktop applications.

LightSensor is allowed to be called from Desktop Apps

There isn't super-clear but there IS documentation on how to add WinRT references to non-Windows Store applications.

Adding a Reference to WinRT from a Desktop App

The docs say, somewhat obscurely:

In the desktop projects, the Core tab doesn’t appear by default. The user can choose to code against the Windows Runtime by opening the shortcut menu for the project node, choosing Unload Project, adding the following snippet, opening the shortcut menu for the project node again, and then choosing Reload Project. Now, when the user invokes the Reference Manager dialog box from the project, the Core tab will appear.

   <propertygroup>
    <targetplatformversion>8.0</targetplatformversion>
  </propertygroup>

I'll make a .NET 4.5 C# Console Application. I'll edit the .csproj and add the TargetPlatformVersion line. I'll select Add Reference from the context menu on the References node of Solution Explorer.

Windows Core References

I'll add a little code to check the status of the Light Sensor on my laptop:

LightSensor light = LightSensor.GetDefault();
if (light != null)
{
uint minReportInterval = light.MinimumReportInterval;
uint reportInterval = minReportInterval > 16 ? minReportInterval : 16;
light.ReportInterval = reportInterval;

light.ReadingChanged += light_ReadingChanged; //event hander
}

However, when I compile the app, I get an error on the line where I'm trying to hook up an event handler. The "+=" language sugar for adding a multicast delegate isn't working.

Error    1    Property, indexer, or event 
'Windows.Devices.Sensors.LightSensor.ReadingChanged'
is not supported by the language; try directly calling accessor
methods 'Windows.Devices.Sensors.LightSensor.add_ReadingChanged
(Windows.Foundation.TypedEventHandler
Windows.Devices.Sensors.LightSensorReadingChangedEventArgs>)'
or 'Windows.Devices.Sensors.LightSensor.remove_ReadingChanged
(System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken)'

To fix this and get the appropriate assemblies loaded within my application support calling WinRT from my Desktop Application I need to add a reference to System.Runtime and System.Runtime.InteropServices.WindowsRuntime.dll. It's in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5 on my system.

System.Runtime.InteropServices.WindowsRuntime.dll in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5

Now my app compiles. I'll even change out the delegate and make it a Anders lambda because that's fancy.

light.ReadingChanged += (s, a) =>
{
Console.WriteLine(String.Format("There was light! {0}", a.Reading.IlluminanceInLux));
};

Now I can run my little console app, sense some light and check it out in action. Here's a screenshot showing the results of me shining a light at my laptop. You can see the Ambient LightSensor picks it up and outputs to the Console.

The ambient light sensor reacting

While the tooling to make non-Windows Store applications call Windows RT applications is a little manual within Visual Studio right now, the underlying ability and runtime have work very nicely for me. Hopefully these few manual setups will turn into a checkbox at some point.

It's also nice to see the MSDN documentation includes the details about which APIs actually can be called from the Desktop and which can be called from Windows Store apps.


This week's sponsor: Your Idea. Your App. 30 Days. Begin your 30-day journey to creating a Windows Store app or game for Windows 8 or Windows Phone today.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Intel Ultrabook hardware prototype - Windows 8 and the Sensor Platform

October 12, '12 Comments [9] Posted in Reviews | Win8
Sponsored By

What better time to test the Sensors in this Intel Ultrabook prototype then while in the air? I'm on a flight right now from Krakow, Poland to Munich, Germany, and I realized this was the perfect time to bring out this little 3 pound wonder. Even better because I received an email just a few days before with updated Sensor Firmware for this device.

I did an initial review of this non-production Ultrabook last month as well as an unboxing and initial impressions video on YouTube. Check the video out below. I've recently added closed-captioning.

Since that time I've been using this Ultrabook almost exclusively as my main machine, even preferring it over my giant (but super powerful) Lenovo W520. I've always been one to prefer the heavier laptop over a lighter one as long as it's got the power I need. However the i7-3667 Ivy Bridge in this system has been just fine for everything I could throw at it - even running Windows 7 and Ubuntu  in a Hyper-V virtual machine while running Visual Studio 2012 under Windows 8. My only real complain so far has been that this model I was provided for review purposes has only 4 gigs of RAM and not 8 or 12. I feel like 4gigs is a real minimum for the kinds of computing I'm doing. That said, the 160 gig Intel SSD has been so fast that I haven't really noticed the lack of memory except when pushing two VMs really hard.

Anyway, I wanted to focus on the sensors as this prototype has all the possible sensors an Ultrabook can have, the most initially interesting sensor to me being the GPS and Location Services.

You can get sensor data in a number of ways. I figured I'd try a few.

There's a Windows 8 Bing Maps Geolocation Sample you can get. It is C# and XAML and uses the Bing Map SDK. You have a little work to do in that you need to:

  • Make sure you have a version of Visual Studio that can make Windows 8 apps. There's a free Express version.
  • Get the Bing Maps SDK for Windows 8 . This just came out last week. There's JavaScript, C#, C++ andVB support.
  • Register at http://bingmapsportal.com for a free Trial key for your Windows 8 Store app.
    • Take the resulting key and put it in the XAML markup under "Credentials" of the bm:Map control.

There's also a much simpler (no map) Geolocation Sample that you can just download and run. It includes three scenarios: ongoing tracking of your position, a one time "get" of your position, and a background task that gets your position even after your application has been shutdown. As with all Windows 8-type apps you'll automatically get a permission popup when an application asks for something sensitive like your location.

The code is pretty simple, in fact. There's a Windows.Devices.Geolocation namespace with a Geolocator class. It has both PositionChanged and StatusChanged events. Since you can't physically move your device every time (although I'm flying now) you can actually run your application inside the Windows "Simulator" and effectively LIE about the location.

In the screenshot below I've taken my actual location that was reported by the physical GPS inside this Ultrabook and moved it a few thousand miles using the black menu popup from the Simulator and saw the underlying value reported change. Note the "use simulated location" checkbox. You can change between the sensor subsystem and the faked GPS values.

Running a geolocation sample in the simulator and lying about the location

Here you can see me flying over the Atlantic Ocean while on my flight.

I'm the Mayor of this part of the Atlantic

Accessing the Sensors are very easy from Windows 8 as there's now a unified Sensor and Location Platform. You don't have to sweat 3rd party drivers, just ask Windows if it knows things like brightness or location and it will tell you if it knows.

You can access at least Location Services via System.Device under .NET on Windows 7 as well. Here's a quick example Console app I did to prove it to myself:

GeoCoordinateWatcher foo = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
foo.MovementThreshold = 10;

foo.StatusChanged += (sensor, changed) =>
{
Console.WriteLine(changed.Status);
};
foo.PositionChanged += (sensor, changed) => {

Console.WriteLine(changed.Position.Timestamp.ToString("G"));
Console.WriteLine(String.Format("Location: {0}, {1}",
changed.Position.Location.Latitude.ToString("0.000"),
changed.Position.Location.Longitude.ToString("0.000")));

} ;

foo.Start();
Console.ReadLine();
foo.Stop(); //Say you're done to save batteries!

So that means Desktop apps can use System.Device.Location and Windows Store (sandboxed) apps use Microsoft.Devices.GeoLocation, as well as all the other sensors made available via WinRT. If you find WinRT confusing I'd encourage you to listen to my podcast on the topic. I had WinRT explained to me by a WinRT developer and I feel much better about it.

Also worth noting with GPS data you can get ahold of it even from inside a modern browser. Just a little bit of JavaScript:

<script>
navigator.geolocation.getCurrentPosition(
function myfunction(data) {
alert(data.coords.longitude + " " + data.coords.latitude);
});
</script>

Then your browser will warn you and ask permission, similar to this:

This site wants to track your physical location

I'd like to see all possible sensors become available to the browser, similar to the way the Firefox OS proposes to allow access to hardware from JavaScript.

Of course, within Windows 8 applications I can access any Sensor data at all - regardless of language (JS, VB, C#, C++) - with similar APIs. You instantiate the Sensor class, hook up a few events and you're set, like this LightSensor example. I can even call these WinRT APIs from Desktop Applications.

private LightSensor _lightsensor; // Our app's lightsensor object

private void ReadingChanged(object sender, LightSensorReadingChangedEventArgs e)
{
Dispatcher.InvokeAsync(CoreDispatcherPriority.Normal, (s, a) =>
{
LightSensorReading reading = (a.Context as LightSensorReadingChangedEventArgs).Reading;
txtLuxValue.Text = String.Format("{0,5:0.00}", reading.IlluminanceInLux);
}, this, e);
}

//Then, whenever you need to, just...
_lightsensor = LightSensor.GetDefault(); // Get the default light sensor object

// Assign an event handler for the ALS reading-changed event
if (_lightsensor != null)
{
// Establish the report interval for all scenarios
uint minReportInterval = _lightsensor.MinimumReportInterval;
uint reportInterval = minReportInterval > 16 ? minReportInterval : 16;
_lightsensor.ReportInterval = reportInterval;

// Establish the event handler
_lightsensor.ReadingChanged += new TypedEventHandler<LightSensor, LightSensorReadingChangedEventArgs>(ReadingChanged);
}

It's pretty straightforward. These Ultrabooks have a PILE of sensors, as you can see using the Sensor Diagnostic Tool below.

All the Sensors built into the Intel Ultrabook

The really interesting question to me is: How can we use these for games? Sure, there's the obvious utilities for dimming the screen and what not, but what kinds of really creative stuff could be done? What would a Contre Jour look like with compasses and inclinometers feeding information to the game and affecting not just active animations but subtle background ones as well?

What do YOU think? Do we need need these sensor arrays in our portable computers? Have we just not come up with the really creative uses for them?


Disclosure of Material Connection: Intel sent me this Ultrabook for free in the hope that I would review it on my blog. Regardless, I only recommend products or services I I would use and think you would find useful. I am disclosing this in accordance with the Federal Trade Commission’s 16 CFR, Part 255: “Guides Concerning the Use of Endorsements and Testimonials in Advertising.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Help your users record and report bugs with the Problem Steps Recorder

October 9, '12 Comments [43] Posted in Bugs | Tools
Sponsored By

A few weeks back I ranted in Everything's broken and nobody's upset and it found its way around the web. Some called it a poorly  organized straw man and others felt it was a decent jumping-off point for a larger discussion about software quality. It was likely both of these and more.

On the subject of bug reporting, there's a wonderful gem of a program that ships with Windows 7 and Windows 8 that you and your users can use to report and record bugs. It's the Problem Steps Recorder and it's like TiVo for bugs.

Hit the Start button and type either "Steps" or even "PSR" or to run the Problem Steps Recorder.

Problem Steps Recorder

Click Start Record and reproduce your bug. You can even click "Add Comment" to highlight an area of the screen as a call-out.

Problem Steps Recorder records your clicks

It's kind of a poor-man's screencasting tool. Rather than a heavy full screen video, the Steps Recorder is taking a screenshot on each click or action.

The user can then save the whole thing as as ZIP or just click "Email." I plan on using this the next time my non-technical parents have an issue they want to report.

Since this little app ships with Windows, why not launch it directly from your product's interface or 'Send Feedback' link? Then you could automate the receipt of these recorded problems and directly inject the resulting files into your bug reporting system.

What do you think?

Related Posts in this Three Part series on Software Quality

  1. Everything's broken and nobody's upset
  2. A Bug Report is a Gift
  3. Help your users record and report bugs with the Problem Steps Recorder

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.