Scott Hanselman

Many Raspberry Pi projects - How can you not love a tiny computer?

November 8, '12 Comments [23] Posted in Hardware | Open Source | Reviews
Sponsored By

Picade Raspberry Pi ArcadeHow can you not love a tiny computer? I posted about Top 10 Raspberry Pi Myths and Truths and since then I'm up to four Raspberry Pi devices. The most recent is the new Raspberry Pi "Model B" that includes 512 megs of RAM.

Sure, Raspberry Pis aren't fast, but what they lack in performance they make up for with chutzpah. They have a nice GPU as well which will decode 1080p MP4 video in hardware and play it just fine. Even better, for about $4 you can get a license to unlock MPEG-2 or VC-1 decoding in hardware.

I also have a Netduino and Netduino Plus as well as an Arduino that I use with the greatest FPS Controller in history, the SpaceTec SpaceOrb along with a custom OrbShield that provides a bridge between the RS-232 Serial Port and the Arduino.

All these devices are very reasonably priced and a great fun for kids or adults.  Next I'm looking at the PIX-6T4 "game console" that lets you write tiny games in C# on a Netduino Mini or perhaps a Netduino Go.

Don't listen to the folks who write negative headlines about the Raspberry Pi. Sure, it's the wild west but with a little patience you'll do fine. There's an amazing community around the Raspberry Pi.

The amount of excitement around these tiny machines is amazing. There's even a Kickstarter for a "Picade" tiny arcade cabinet.

To make things easier once you get your Pi, I do recommend the Adafruit Raspberry Pi Budget Pack if you don't want to go hunting for parts. This kit includes a great little clear case, a 4 gig SD Card (actually a mini with an adapter, which is great since the Netduino Plus has a mini SD slot), cables and power, but best of all, a breadboard, wires and a lovely little ribbon cable and "cobbler" that makes it super easy to keep things tidy while still messing with the Raspberry Pi's GPIO (General Purpose Input Output) connections.

Related posts you might like

LEGO Raspberry Pi CaseWhat's great about the Raspberry Pi and small devices like it isn't the price -although that's great - it's that the Raspberry Pi has a GPIO and HDMI. This means it's the easiest and cheapest little PC that can talk to the outside world's many hardware devices. Having the combination of  HDMI out (for your TV) and GPIO (for everything else) means it's extremely accessible to the beginner.

That GPIO port along with its ease of programming gives rise to such fun as as the RetroPie GPIO Adapter that let you hook up your old Super Nintendo (SNES) controllers to a Pi! You can order a RetroPie GPIO Adapter here. Here is Video of the RetroPie in action. I am not affiliated with this creative person at all, I just dig the idea.

So I've got four now. Some friends have tweeted me saying that they bought one Raspberry Pi and haven't gotten around to doing antyhing with it, usually because they aren't sure WHAT to use it for.

Here's what my Pi's are currently doing:

I'm sure there are more reasons to buy more Raspberry Pis. Here's a few.

Seventeen Awesome Raspberry Pi Projects

These are some exciting and fun projects for you to explore with Raspberry Pi that might make your Pi feel more useful and get you playing today!

Be sure to check out the Element 14 Community Site for Raspberry Pi. I also love AdaFruit and their Pi-related products like the Adafruit Pi Box (I have 2) or the Budget Pack (I have 1).

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

Reactive Extensions (Rx) is now Open Source

November 6, '12 Comments [10] Posted in LINQ | Open Source
Sponsored By

A few years back I did a podcast with Erik Meijer about Reactive Extensions for .NET (Rx). Since then thousands of people have enjoyed using Rx in the projects and a number of open source projects like ReactiveUI (also on the podcast) have popped up around it. Even GitHub for Windows uses Reactive Extensions. In fact, GitHub uses Rx a LOT in their Windows product. My friend Paul at GitHub says they liked the model so much they made a Mac version!

“GitHub for Windows uses the Reactive Extensions for almost everything it does, including network requests, UI events, managing child processes (git.exe). Using Rx and ReactiveUI, we've written a fast, nearly 100% asynchronous, responsive application, while still having 100% deterministic, reliable unit tests. The desktop developers at GitHub loved Rx so much, that the Mac team created their own version of Rx and ReactiveUI, called ReactiveCocoa, and are now using it on the Mac to obtain similar benefits.” – Paul Betts, GitHub

Today, Microsoft Open Technologies announced the open sourcing of Reactive Extensions! You can get the code with git up on Codeplex at https://rx.codeplex.com. You can’t stop the open source train! Congrats to the team!

There’s a LOT included, so be stoked. It’s not just Rx.NET, but also the C++ library as well as RxJS for JavaScript! Now everyone gets to play with IObservable<T> and IObserver<T>.

  • Reactive Extensions:
    • Rx.NET: The Reactive Extensions (Rx) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators.
    • RxJS: The Reactive Extensions for JavaScript (RxJS) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators in JavaScript which can target both the browser and Node.js.
    • Rx++: The Reactive Extensions for Native (RxC) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators in both C and C++.
  • Interactive Extensions
    • Ix: The Interactive Extensions (Ix) is a .NET library which extends LINQ to Objects to provide many of the operators available in Rx but targeted for IEnumerable<T>.
    • IxJS: An implementation of LINQ to Objects and the Interactive Extensions (Ix) in JavaScript.
    • Ix++: An implantation of LINQ for Native Developers in C++

A great way to learn about why Rx is useful is to check out the Rx Koan’s project or to read the IntroToRx online e-book.

Why do I think Rx matters? It’s a way to do asynchronous operations on event streams. Rather than hooking up click events and managing state with event handlers all over, you effectively “query” an infinite stream of events with LINQ. You can declaratively sequence events…no flags, no state machine.

For example, here’s a dragging event created (composed) via Mouse button and Mouse move events:

IObservable<Event<MouseEventArgs>> draggingEvent =
from mouseLeftDownEvent in control.GetMouseLeftDown()
from mouseMoveEvent in control.GetMouseMove().Until(control.GetMouseLeftUp())
select mouseMoveEvent;

Even better, Rx makes it easier (or possible!) to create event-based tests that are asynchronous, like this example from Jafar Husain:

Rating rating = new Rating();
IObservable<Unit> test = // Unit is an object that represents null.
ObservableExtensions
.DoAsync(() => TestPanel.Children.Add(rating))
.WaitFor(TestPanel.GetLayoutUpdated()) // Extension method GetLayoutUpdated converts the event to observable
.DoAsync(() => rating.Value = 1.0) // Calls the Ignite EnqueueCallback method
.WaitFor( // waits for an observable to raise before going on
// listen to all the actual value change events and filters them until ActualValue reaches Value
rating
.GetActualValueChanged() // extension method that converts ActualValueChanged event to IObservable
.SkipWhile(actualValueChangedEvent => actualValueChangedEvent.EventArgs.NewValue != rating.Value))
// check to make sure the actual value of the rating item is set appropriately now that the animation has completed
.Assert(() => rating.GetRatingItems().Last().ActualValue == 1.0) // crawls the expression tree and makes a call to the appropriate Assert method

Test.Subscribe(() => TestPanel.Children.Remove(rating)); //run the test and clean up at the end.

There’s amazing Time-related operators that let you simulate events over time. Note the Buffer and Subscribe calls.

var myInbox = EndlessBarrageOfEmail().ToObservable();

// Instead of making you wait 5 minutes, we will just check every three seconds instead. :)
var getMailEveryThreeSeconds = myInbox.Buffer(TimeSpan.FromSeconds(3)); // Was .BufferWithTime(...

getMailEveryThreeSeconds.Subscribe(emails =>
{
Console.WriteLine("You've got {0} new messages! Here they are!", emails.Count());
foreach (var email in emails)
{
Console.WriteLine("> {0}", email);
}
Console.WriteLine();
});

You can use await and async, like in this example returning the number 42 after 5 seconds:

static async void button_Click()
{
int x = await Observable.Return(42).Delay(TimeSpan.FromSeconds(5));
// x with value 42 is returned after 5 seconds
label.Text = x.ToString();
}
I’m just showing you the parts that tickle me, but one could easily teach a 10 week university course on Rx, and I’m still a beginner myself!

Here’s some more resources to check out about Rx. Congrats to the team for their contribution to Open Source!

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

Videos of talks from the 2012 BUILD Conference - Angle Brackets and Curly Braces

November 5, '12 Comments [14] Posted in ASP.NET | Azure | Speaking
Sponsored By

It was an insane week at BUILD. Much of my schedule was my own fault as I continue to treat Microsoft Outlook as if it were a game of Tetris, franticly packing appointments ten-deep.

The "Angle Brackets" team (ASP.NET, Azure, and Web Tools) had a good showing and lots of fun. We chose to create a little two day mini-conf by scheduling our talks on Thursday and Friday and I think it worked great. There was a Day 1 and Day 2 Keynote. I had a small 10 minute coding segment before ScottGu in the Day 2 Keynote. I kicked if off on Day 3 (Thursday) with an un-keynote at 8:30am called Angle Brackets, Curly Braces, One ASP.NET and the Cloud. Then the team had their talks on Thursday and Friday and finally Jon Galloway and I ended the show with the very LAST talk  on Friday afternoon called "Bleeding edge ASP.NET."

Here's video of my talks, as well as links to all the talks our team did! Remember that you can download these talks in various formats and watch them at your leisure!

Angle Brackets, Curly Braces, One ASP.NET and the Cloud

I'm very happy with how this talk turned out and I hope you enjoy it. If you do, let me know and share it with your friends.

Downloads:


Bleeding edge ASP.NET: See what is next for MVC, Web API, SignalR and more…

I played code monkey in this talk with Jon Galloway. We had great fun, showed lots of demos and generally picked on each other throughout.

Downloads


Talks from the Web Team

There were some amazing talks this year.

See how we're BUILDing stuff? Each of these talks is code-heavy and focused on getting you working and building great stuff and hopefully having fun while you do it.

Be sure to check out all the BUILD talks. They are up on http://channel9.msdn.com/Events/Build/2012 in their entirety, with both speaker cameras via Picture-in-Picture and high-def video. Hope you enjoy them!

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

Podcast Update with Guest Spots and a New Show - October 2012

October 30, '12 Comments [5] Posted in Podcast
Sponsored By

I've been on a podcasting kick lately. Not for any particular reason, but a number of things have come together that have found me as a guest on a number of podcasts. I've also had the good fortune to have a number of great guests on Hanselminutes lately.

Lots of folks who listen to podcasts are doing it while commuting. I hope you enjoy these additional podcasts and perhaps they'll edutain you during your daily commute.

I hope you take a few minutes and download a few of these shows.


imageStackExchange Podcast #35

Just last week my buddy Joel Spolsky had me on the 35th episode of the new StackExchange Podcast. I've complained about podcasts that are "just talk" before and brought my prejudice to Joel's show, but we have so much fun just beating each other up that I have to admit defeat. Not ever podcast has to be dense with information and content - and this episode is no exception. ;)

I hope they'll have me back soon.


ratchetandthegeeksquareAnnouncing - Ratchet and The Geek #1

Just a few days ago I launched my third podcast as a collaboration with my good friend Luvvie. Luvvie is a social media consultant and popular humor blogger that I've known for years. We've been kicking around the idea of a podcast since early this Spring. We have such fun when we call each other on the phone, why don't we start recording our calls? (and adding a little structure.)

Luvvie has blogging, social media and marketing expertise, while I'm a coder and teacher. We both like the same music, pop culture, TV shows, movies, gadget and technology so we have mashed it all together into Ratchet and The Geek.

We'll be doing the show late late on Thursday nights every two weeks.


image

Fanboy Radio #616

I've been REALLY getting into Digital Comics via Comixology over the last year and blogged about it in some detail (with animated gifs!) and earlier this year I was a guest on an episode of Fanboy Radio.

Fanboy Radio (or 'FbR') is a radio talk show all about pop culture and entertainment from the fan's perspective. It's also broadcast on the radio in Fort Worth, Texas.

We had a great chat, covering the rise of digital comics, Comixology, GuidedView technology and lots more. The guys were a lot of fun and it was an opportunity for me to geek out about something that isn't programming or computers. (I DO have other interests, you know.)


imageSimple Mobile Review (SMRPodcast) #136

Last month I was on Simple Mobile Review at the invitation of Chris Ashley. We talked about phones and NFC technology and if it will ever take off. We discussed the new iPhone 5 and teased Robb for sticking with his BlackBerry.

It was a great time and we spent a bunch of time teasing each other, which is an important part of any good podcast.


dramaThis Developer's Life - Drama

Some of you may have missed the most recent episode of This Developer's Life from last month. Rob and I asked ourselves where does drama come from? How do we react to it? How much drama can be created by simple semicolon? We explore The Great JavaScript Semicolon Affair with guests like

  • Peter Cooper Friendly publisher, programmer and author
  • Derick Bailey Consultant and aspiring microprenuer
  • H. Alan Stevens Father, Geek & Speaker
  • Dave Ward Software developer focusing on jQuery and web application usability.
  • Sara Chipps Just a girl, standing in front of a compiler, asking it to love her.
  • Tenderlove When I'm not trimming my beard, I'm hanging out with my lady.

This Developer's Life is sponsored out of kindness by the epic win that is DevExpress.


Hansel-Minutes-LogoHanselminutes Podcast Rollup

If I may be so bold as to say Hanselminutes has been pretty good lately. I've had some great guests - many suggested by listeners! - and some great conversations. Here's just this month:

This week's show has a special offer for listeners from DNSimple, my DNS service of choice. Four months free at http://dnsimple.com/hm. Did you miss one of these shows perhaps? Why not subscribe now so you don't miss another show?


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

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

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