<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Code Monkey vs. The World</title>
	<atom:link href="http://ermau.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://ermau.com</link>
	<description></description>
	<lastBuildDate>Mon, 02 Jan 2012 21:12:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Introducing the Xamarin Mobile API Preview</title>
		<link>http://ermau.com/introducing-xamarin-mobile-api-preview/</link>
		<comments>http://ermau.com/introducing-xamarin-mobile-api-preview/#comments</comments>
		<pubDate>Tue, 22 Nov 2011 23:28:24 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[Xamarin]]></category>
		<category><![CDATA[monoforandroid]]></category>
		<category><![CDATA[monotouch]]></category>
		<category><![CDATA[xamarin]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=332</guid>
		<description><![CDATA[Things have been a little quiet from me lately, both on blog series I started and projects I started. The reason is that I have been very busy starting an exciting new position with Xamarin. Today I&#8217;m happy to give &#8230; <a href="http://ermau.com/introducing-xamarin-mobile-api-preview/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Things have been a little quiet from me lately, both on <a title="Converting Tempest to run on WinRT: Part 1" href="http://ermau.com/converting-tempest-to-run-on-winrt-part-1/">blog series I started</a> and <a href="https://github.com/ermau/WinRT.NET">projects I started</a>. The reason is that I have been very busy starting an exciting new position with <a href="http://xamarin.com">Xamarin</a>. Today I&#8217;m happy to give a preview of my first project with Xamarin.</p>
<p>With <a href="http://xamarin.com/monotouch">MonoTouch</a> and <a href="http://android.xamarin.com/">Mono for Android</a>, you can already share a huge portion of your code across iOS, Android and Windows Phone. There is, however, this middle ground of APIs that are present in all three platforms, but you can&#8217;t share your code that utilizes them. You currently have to write separate sets of code to use geolocation, the accelerometer, contacts, etc on these various platforms and we want to fix that. The Xamarin Mobile API preview contains a new set of APIs designed and implemented to support these features evenly across iOS, Android and Windows Phone.</p>
<p>We want your feedback to help guide us in this endeavor, so today we&#8217;re releasing a preview. The preview contains a unified geolocation API with implementations on iOS and Android. We&#8217;ll be releasing a Windows Phone implementation at some point in the future. Try it out and give us your feedback, we want to know what you think! Let us know of any pain points in the API, if something doesn&#8217;t work, etc. We also want to know what other areas you care most about us unifying next, whether it be contacts, notifications, etc.</p>
<p>As this is a preview, please keep in mind that APIs may change, things may be broken and not all of the docs are filled out. For Android, currently a minimum API level of 7 is required. Additionally on Android, heading is disabled and Geolocator&#8217;s constructor takes an argument of Context.</p>
<p>You can <a href="http://xamarin.com/xamarinmobileapipreview.zip">download the preview here</a> and <a title="Xamarin Mobile API Preview Feedback" href="https://docs.google.com/a/xamarin.com/spreadsheet/viewform?formkey=dFBlbEtBZmZaT3pIYnBTRHZOQWV4cFE6MQ">let us know what you think or want to see here.</a> If you run into a bug, <a href="http://bugzilla.xamarin.com/enter_bug.cgi?product=Xamarin%20Mobile%20API%20Preview">please file it here</a>.</p>
<p><strong>Update 12/5:</strong> The package has been updated to work with Mono for Android 4.0 (and now requires it).</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/introducing-xamarin-mobile-api-preview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Avoiding callbacks to the UI thread with async and WinRT</title>
		<link>http://ermau.com/avoiding-callbacks-to-the-ui-thread-with-async-and-winrt/</link>
		<comments>http://ermau.com/avoiding-callbacks-to-the-ui-thread-with-async-and-winrt/#comments</comments>
		<pubDate>Tue, 20 Sep 2011 00:23:42 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[WinRT]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[winrt]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=296</guid>
		<description><![CDATA[You probably already know that async operates by using the SynchronizationContext of the call site to invoke its callback. This behavior is great and makes sense for the vast majority of scenarios. There are a few, however, that it is &#8230; <a href="http://ermau.com/avoiding-callbacks-to-the-ui-thread-with-async-and-winrt/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>You probably already know that async operates by using the <a href="http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.aspx">SynchronizationContext</a> of the call site to invoke its callback. This behavior is great and makes sense for the vast majority of scenarios. There are a few, however, that it is not ideal for and it centers mostly around library developers like myself. If you didn&#8217;t know this, you may want to go watch this fantastic talk that contains a deep dive of async: <a href="http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-829T">The zen of async: Best practices for best performance</a>. In fact, if you are interested in async with .NET, I recommend you watch it regardless.</p>
<p>I write a lot of socket based software, so I started <a title="Tempest on GitHub" href="http://github.com/ermau/Tempest" target="_blank">writing my own library</a> to provide a consistent (and higher level) API across all platforms and naturally <a title="Converting Tempest to run on WinRT: Part 1" href="http://ermau.com/converting-tempest-to-run-on-winrt-part-1/">I want it to work on WinRT</a>. One of the first things I looked into when I got my hands on the WinRT bits was the replacement Socket API, which contains several async methods. In Tempest, once you receive some data it constructs message objects from the data, performing hash checking and sometimes even decryption. This is not code I want to be running on the UI thread for every single message.</p>
<p>So, I started looking around for solutions. Most I came up with involved not using the async keyword, calling out to the ThreadPool from the continuation, or using an outside thread to initiate the call. The simplest and most efficient answer I could come up with is to just not use async, but I didn&#8217;t want to accept that. Both Task.ContinueWith and IAsyncInfo.Start() do not pay attention to the SynchronizationContext, that is a feature of await:</p>
<p><img class="alignnone size-full wp-image-297" title="iasync1" src="http://ermau.com/wp-content/uploads/2011/09/iasync1.png" alt="" width="629" height="157" /></p>
<p><img class="alignnone size-full wp-image-298" title="iasync2" src="http://ermau.com/wp-content/uploads/2011/09/iasync2.png" alt="" width="633" height="160" /></p>
<p>And, just as a reminder and proof:</p>
<p><img class="alignnone size-full wp-image-299" title="awaitiasync" src="http://ermau.com/wp-content/uploads/2011/09/awaitiasync.png" alt="" width="628" height="115" /></p>
<p>The same demonstration could be done for using .ContinueWith() vs. await on a Task. What I thought was that I&#8217;d be relegated to using these for advanced purposes, until I watched the talk I linked above. There&#8217;s a new method on Task, called ConfigureAwait(bool) which enables you to ignore the SynchronizationContext. What about IAsyncInfo though? There is a StartAsTask extension method on it after all, so let&#8217;s see if that works:</p>
<p><img class="alignnone size-full wp-image-300" title="taskawait" src="http://ermau.com/wp-content/uploads/2011/09/taskawait.png" alt="" width="593" height="131" /></p>
<p><img class="alignnone size-full wp-image-302" title="taskawait2" src="http://ermau.com/wp-content/uploads/2011/09/taskawait21.png" alt="" width="596" height="130" /></p>
<p>As it turns out, it does. Unfortunately there&#8217;s one small difference for which I can only speculate as to the reason. When you use the Task  and disable the captured context, you end up on a ThreadPool thread. However, when you use the IAsyncOperation returned directly, you still end up on a different thread, but not a ThreadPool one. One possible logical explanation is that it&#8217;s actually using <a title="MSDN: Windows.System.Threading.ThreadPool" href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.system.threading.threadpool.aspx">WinRT&#8217;s ThreadPool</a> to execute:</p>
<p><img class="alignnone size-full wp-image-303" title="winrttp" src="http://ermau.com/wp-content/uploads/2011/09/winrttp.png" alt="" width="595" height="100" /></p>
<p>We can see here that <a title="MSDN: Windows.System.Threading.ThreadPool" href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.system.threading.threadpool.aspx">WinRT&#8217;s ThreadPool</a> threads do not get identified by <a title="MSDN: Thread.IsThreadPoolThread" href="http://msdn.microsoft.com/en-us/library/system.threading.thread.isthreadpoolthread.aspx">Thread.IsThreadPoolThread</a>.</p>
<p>Getting back to the code, although still an improvement on using ContinueWith, it&#8217;s still quite long. Here&#8217;s a little extension method that combines the two by just adding an overload for StartAsTask to take the same argument as ConfigureAwait.</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> ConfiguredTaskAwaitable<span style="color: #008000;">&lt;</span>T<span style="color: #008000;">&gt;</span> StartAsTask<span style="color: #008000;">&lt;</span>T<span style="color: #008000;">&gt;</span> <span style="color: #008000;">&#40;</span>
	<span style="color: #0600FF; font-weight: bold;">this</span> IAsyncOperation<span style="color: #008000;">&lt;</span>T<span style="color: #008000;">&gt;</span> self, <span style="color: #6666cc; font-weight: bold;">bool</span> continueOnContext<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
	<span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>self <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span>
		<span style="color: #0600FF; font-weight: bold;">throw</span> <span style="color: #008000;">new</span> ArgumentNullException<span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;self&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #0600FF; font-weight: bold;">return</span> self<span style="color: #008000;">.</span><span style="color: #0000FF;">StartAsTask</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
		<span style="color: #008000;">.</span><span style="color: #0000FF;">ConfigureAwait</span> <span style="color: #008000;">&#40;</span>continueOnContext<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF; font-weight: bold;">private</span> async <span style="color: #6666cc; font-weight: bold;">void</span> Button_Click<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> sender, RoutedEventArgs e<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
	await DeviceInformation<span style="color: #008000;">.</span><span style="color: #0000FF;">FindAllAsync</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">StartAsTask</span> <span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">false</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>So we can see that it is possible to use async without dumping back to the UI thread for calls originating from the UI thread. In some scenarios it still may not be desirable, depending on what you&#8217;re doing and your desired performance. The async keyword introduces a non-trivial amount of extra code, so if you&#8217;re concerned with the performance, I once again recommend you watch <a title="The zen of async: Best practices for best performance" href="http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-829T">this talk</a>.</p>
<p><strong>TL;DR:</strong> Use await IAsyncInfo.StartAsTask().ConfigureAwait(false);</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/avoiding-callbacks-to-the-ui-thread-with-async-and-winrt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Converting Tempest to run on WinRT: Part 1</title>
		<link>http://ermau.com/converting-tempest-to-run-on-winrt-part-1/</link>
		<comments>http://ermau.com/converting-tempest-to-run-on-winrt-part-1/#comments</comments>
		<pubDate>Thu, 15 Sep 2011 23:16:21 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[WinRT]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[tempest]]></category>
		<category><![CDATA[winrt]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=269</guid>
		<description><![CDATA[First, a short introduction to Tempest. I had avoided posting about this project in the past because I wanted the first post to be a quick tutorial and announcement of a beta. However, this is a perfect opportunity to really &#8230; <a href="http://ermau.com/converting-tempest-to-run-on-winrt-part-1/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>First, a short introduction to <a href="http://github.com/ermau/tempest">Tempest</a>. I had avoided posting about this project in the past because I wanted the first post to be a quick tutorial and announcement of a beta. However, this is a perfect opportunity to really dive into some of the lower level APIs of WinRT and share the experience.</p>
<p>Tempest is designed to be a simple application protocol messaging library that works everywhere. This is to say that it gives you a simple way to define messages and lets you select how these messages are transported. Furthermore, the library is built to work on .NET 3.5, .NET 4, Mono 2.10, Silverlight 4 and Windows Phone 7.? &#8220;Mango&#8221;. Though, at this point in time, I&#8217;d consider Tempest to be an early alpha for .NET and Mono. Silverlight and Windows Phone 7 support compiles, but assuredly does not work yet.</p>
<h2>Getting it to compile</h2>
<p>For Part 1 we&#8217;ll talk about even getting Tempest to compile. Keep in mind that the vast majority of the code must still work on standard .NET, so converting over to WinRT APIs completely isn&#8217;t an option. To support the various platforms, there&#8217;s a number of compiler defines already present in Tempest:</p>
<ul>
<li>SAFE &#8211; Disables any unsafe optimizations (unsafe, System.Reflection.Emit)</li>
<li>NET_4 &#8211; Enables .NET 4 specific code. This is mostly optimizations from System.Collections.Concurrent and using SpinWait, but does include one very useful API based on Task.</li>
<li>SILVERLIGHT</li>
<li>WINDOWS_PHONE</li>
</ul>
<p>WinRT does not contain System.Reflection.Emit, so first I turned SAFE on. Type.IsValueType, which is used primarily in MutableLookup`2 from Cadenza, has been moved to TypeInfo. For a quick fix, I replaced the check for it with:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">default</span><span style="color: #008000;">&#40;</span>TKey<span style="color: #008000;">&#41;</span> <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span></pre></div></div>

<p>Simple enough change, but the error list at this point is still quite daunting. Here&#8217;s a short list of what was affecting me:</p>
<ul>
<li>System.Net.* is inaccessible (replaced by <a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.networking.sockets.aspx">Windows.Networking.Sockets</a> and <a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.networking.connectivity.aspx">Windows.Networking.Connectivity</a>).</li>
<li>System.Security.Cryptography.* is inaccessible (replaced by <a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.security.cryptography.core.aspx">Windows.Security.Cryptography.Core</a>).</li>
<li>Type has split into <a href="http://msdn.microsoft.com/en-us/library/windows/apps/system.type.aspx">Type</a> and <a href="http://msdn.microsoft.com/en-us/library/windows/apps/system.reflection.typeinfo.aspx">TypeInfo</a>.</li>
<li>System.Buffer is inaccessible.</li>
<li>System.Reflection.Emit is inaccessible.</li>
</ul>
<h2>Networking</h2>
<p>As you might imagine, for a networking library, the first is a huge blow. As WinRT has its own implementation of sockets, I&#8217;ll have to write a new transport provider. Fortunately Tempest is designed to be able to do this, so for the moment I&#8217;ll just remove the existing network implementation altogether.</p>
<p>Unfortunately that wasn&#8217;t the only usages I had, as System.Net.EndPoint was used throughout my contracts for connection targets. So either I can write WinRT only implementations of EndPoint, or I can write my own type and take control. I opted to write my own types (prototype design): <a href="https://github.com/ermau/Tempest/blob/WinRT/Desktop/Tempest/ConnectionTarget.cs">ConnectionTarget</a>, <a href="https://github.com/ermau/Tempest/blob/WinRT/Desktop/Tempest/DnsConnectionTarget.cs">DnsConnectionTarget</a>, <a href="https://github.com/ermau/Tempest/blob/WinRT/Desktop/Tempest/IPConnectionTarget.cs">IPConnectionTarget</a>.</p>
<h2>Reflection</h2>
<p>When I was working on this last night, I was under the impression that Type had simply been gutted. Today I know that many of the members I had been using were moved to TypeInfo. There is an extension method in System.Reflection on Type called GetTypeInfo() that will get you the TypeInfo instance. In order to facilitate code compatibility with normal .NET, I added my own little extension:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080;">#if !WINRT</span>
<span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> Type GetTypeInfo <span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">this</span> Type type<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
	<span style="color: #0600FF; font-weight: bold;">return</span> type<span style="color: #008000;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #008080;">#endif</span></pre></div></div>

<p>Using this, I can just call .GetTypeInfo() on my type instances in either framework and all should be well. It&#8217;s not terribly efficient as I can&#8217;t store instances to the proper type easily/cleanly most of the time, but it gets the ball rolling.</p>
<p>Despite TypeInfo containing most of what was originally on Type a few things are still missing, such as .GetMembers(). I was instead able to use <a href="http://msdn.microsoft.com/en-us/library/windows/apps/system.reflection.typeinfo.declaredproperties.aspx">TypeInfo.DeclaredProperties</a> and its <a href="http://msdn.microsoft.com/en-us/library/windows/apps/system.reflection.typeinfo.declaredfields.aspx">friends</a> with LINQ to get to the members I wanted, including filtering I was originally doing in LINQ after GetMembers().</p>
<h2>Serialization</h2>
<p>To be perfectly honest, where most of the reflection used and all of .NET&#8217;s built in serialization is, is in a custom automatic serialization system. This is probably the buggiest and worst designed aspect of Tempest. Last night I made the decision that for WinRT (thinking at the time reflection was gutted), I&#8217;d only support Tempest&#8217;s ISerializable and ISerializer&lt;T&gt; interfaces. For now I&#8217;m going to leave that restriction in place until I can get it sorted out.</p>
<p>While System.Runtime.Serialization is present with <a href="http://msdn.microsoft.com/en-us/library/windows/apps/system.runtime.serialization.datacontractattribute.aspx">DataContractAttribute</a> and friends, SerializableAttribute and System.Runtime.Serialization.Formatters.* are not. These portions of code were optional and already disabled for Silverlight, so I just added the WINRT flag to the check.</p>
<h2>Miscellaneous</h2>
<p>The types using System.Buffer weren&#8217;t used anywhere except for the existing networking implementation, so I simply removed them from the WinRT build for now. Having gotten things to compile at this point, I decided to see what would happen if I turned on NET_4, and to my surprise everything compiled as is. It appears that WinRT&#8217;s support of the baser types (like collections) is quite good. Where things start talking to the OS (Sockets) is where things start to get replaced, and old crufty systems (SerializableAttribute) seem to have been trimmed out.</p>
<p>Now that I have the basic system compiling, I need to implement a transport using Windows.Networking.Sockets, which will be Part 2.</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/converting-tempest-to-run-on-winrt-part-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using WinRT from .NET</title>
		<link>http://ermau.com/using-winrt-from-net/</link>
		<comments>http://ermau.com/using-winrt-from-net/#comments</comments>
		<pubDate>Thu, 15 Sep 2011 00:04:35 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[WinRT]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[winrt]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=247</guid>
		<description><![CDATA[As it turns out, it is possible to use the WinRT APIs from standard .NET. You&#8217;ll need the full Visual Studio 2011 preview installed on the Windows 8 Developer Preview. First, create a new WPF project. Then, go to add &#8230; <a href="http://ermau.com/using-winrt-from-net/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>As it turns out, it is possible to use the WinRT APIs from standard .NET. You&#8217;ll need the full Visual Studio 2011 preview installed on the Windows 8 Developer Preview.</p>
<p>First, create a new WPF project. Then, go to add references and press &#8220;browse&#8221;. Navigate to C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata</p>
<div id="attachment_248" class="wp-caption alignnone" style="width: 972px"><a href="http://ermau.com/wp-content/uploads/2011/09/reference.png"><img class="size-full wp-image-248" title="Add Reference" src="http://ermau.com/wp-content/uploads/2011/09/reference.png" alt="" width="962" height="604" /></a><p class="wp-caption-text">C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata</p></div>
<p>Make sure you select &#8220;All Files&#8221;. Note that VS11 gives you an error if you try to add more than one at a time, so you&#8217;ll have to add each individually. We&#8217;re going to show a quick app that lists devices, so we&#8217;ll need a couple of these namespaces: windows.foundation.winmd and windows.devices.enumeration.</p>
<p>First we&#8217;ll make a little view model:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">System</span><span style="color: #008000;">;</span>
<span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">System.Collections.Generic</span><span style="color: #008000;">;</span>
<span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">System.ComponentModel</span><span style="color: #008000;">;</span>
<span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">System.Linq</span><span style="color: #008000;">;</span>
<span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">System.Text</span><span style="color: #008000;">;</span>
<span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">System.Threading.Tasks</span><span style="color: #008000;">;</span>
<span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">Windows.Devices.Enumeration</span><span style="color: #008000;">;</span>
<span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">Windows.Foundation</span><span style="color: #008000;">;</span>
&nbsp;
<span style="color: #0600FF; font-weight: bold;">namespace</span> WpfApplication1
<span style="color: #008000;">&#123;</span>
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">class</span> MainWindowViewModel
        <span style="color: #008000;">:</span> INotifyPropertyChanged
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">event</span> PropertyChangedEventHandler PropertyChanged<span style="color: #008000;">;</span>
&nbsp;
        <span style="color: #0600FF; font-weight: bold;">public</span> MainWindowViewModel<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            var operation <span style="color: #008000;">=</span> DeviceInformation<span style="color: #008000;">.</span><span style="color: #0000FF;">FindAllAsync</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
            operation<span style="color: #008000;">.</span><span style="color: #0000FF;">Completed</span> <span style="color: #008000;">=</span> CompletedFindDevices<span style="color: #008000;">;</span>
            operation<span style="color: #008000;">.</span><span style="color: #0000FF;">Start</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #008000;">&#125;</span>
&nbsp;
        <span style="color: #0600FF; font-weight: bold;">public</span> IEnumerable<span style="color: #008000;">&lt;</span>DeviceInformation<span style="color: #008000;">&gt;</span> Devices
        <span style="color: #008000;">&#123;</span>
            get <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">this</span><span style="color: #008000;">.</span><span style="color: #0000FF;">devices</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
            <span style="color: #0600FF; font-weight: bold;">private</span> set
            <span style="color: #008000;">&#123;</span>
                <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">this</span><span style="color: #008000;">.</span><span style="color: #0000FF;">devices</span> <span style="color: #008000;">==</span> value<span style="color: #008000;">&#41;</span>
                    <span style="color: #0600FF; font-weight: bold;">return</span><span style="color: #008000;">;</span>
&nbsp;
                <span style="color: #0600FF; font-weight: bold;">this</span><span style="color: #008000;">.</span><span style="color: #0000FF;">devices</span> <span style="color: #008000;">=</span> value<span style="color: #008000;">;</span>
                OnPropertyChanged <span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;Devices&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #008000;">&#125;</span>
        <span style="color: #008000;">&#125;</span>
&nbsp;
        <span style="color: #0600FF; font-weight: bold;">private</span> IEnumerable<span style="color: #008000;">&lt;</span>DeviceInformation<span style="color: #008000;">&gt;</span> devices<span style="color: #008000;">;</span>
&nbsp;
        <span style="color: #0600FF; font-weight: bold;">private</span> <span style="color: #6666cc; font-weight: bold;">void</span> OnPropertyChanged <span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">string</span> propertyName<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            var changed <span style="color: #008000;">=</span> PropertyChanged<span style="color: #008000;">;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>changed <span style="color: #008000;">!=</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span>
                changed <span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">this</span>, <span style="color: #008000;">new</span> PropertyChangedEventArgs <span style="color: #008000;">&#40;</span>propertyName<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #008000;">&#125;</span>
&nbsp;
        <span style="color: #0600FF; font-weight: bold;">private</span> <span style="color: #6666cc; font-weight: bold;">void</span> CompletedFindDevices <span style="color: #008000;">&#40;</span>IAsyncOperation<span style="color: #008000;">&lt;</span>DeviceInformationCollection<span style="color: #008000;">&gt;</span> asyncInfo<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            Devices <span style="color: #008000;">=</span> asyncInfo<span style="color: #008000;">.</span><span style="color: #0000FF;">GetResults</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>And then the Xaml (don&#8217;t forget to hook up the datacontext to the view model in your code behind):</p>
<pre>&lt;Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"&gt;
    &lt;ListBox ItemsSource="{Binding Devices}"&gt;
        &lt;ListBox.ItemTemplate&gt;
            &lt;DataTemplate&gt;
                &lt;TextBlock Text="{Binding Name}" /&gt;
            &lt;/DataTemplate&gt;
        &lt;/ListBox.ItemTemplate&gt;
    &lt;/ListBox&gt;
&lt;/Window&gt;</pre>
<p>And voila:</p>
<p><a href="http://ermau.com/wp-content/uploads/2011/09/result.png"><img class="alignnone size-full wp-image-250" title="Result" src="http://ermau.com/wp-content/uploads/2011/09/result.png" alt="" width="348" height="693" /></a></p>
<p>This doesn&#8217;t cover being able to implement the various platform contracts, but it&#8217;s a start.</p>
<p><strong>Update:</strong> Apparently the opposite is true as well.. kind of. It&#8217;s possible to reference your existing .NET assemblies and use them in a WinRT application. It remains to be seen or heard whether that will be allowed for the App Store, but it does work in practice. The gotcha is that you can&#8217;t reference the missing pieces of the BCL, so if you need a type there (System.Net.EndPoint for example), you&#8217;re still out of luck.</p>
<p><strong>Update 2:</strong> The app certification utility fails WinRT apps calling unsupported .NET APIs. So, they&#8217;ll run, but you won&#8217;t get them on the store.</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/using-winrt-from-net/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Code Monkey vs. Silverlight Audio Capture</title>
		<link>http://ermau.com/code-monkey-vs-silverlight-audio-capture/</link>
		<comments>http://ermau.com/code-monkey-vs-silverlight-audio-capture/#comments</comments>
		<pubDate>Sun, 26 Jun 2011 04:20:26 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[Rant]]></category>
		<category><![CDATA[audio]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[silverlight]]></category>
		<category><![CDATA[symphony]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=203</guid>
		<description><![CDATA[I&#8217;ve been working on a new project (Symphony, https://github.com/ermau/Symphony) that is heavily media centric. The general idea is to provide better support to .NET for a whole range of multimedia scenarios, whether they&#8217;re recording and playing back audio, decoding a &#8230; <a href="http://ermau.com/code-monkey-vs-silverlight-audio-capture/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><font color="#000000" size="3">I&#8217;ve been working on a new project (Symphony, </font><a href="https://github.com/ermau/Symphony"><font color="#000000" size="3">https://github.com/ermau/Symphony</font></a><font color="#000000" size="3">) that is heavily media centric. The general idea is to provide better support to .NET for a whole range of multimedia scenarios, whether they&#8217;re recording and playing back audio, decoding a song, or what have you. In order to reach the broadest audience possible, I decided early on to include as much Silverlight support as I possibly could. Part of that supports is bringing Silverlight&#8217;s built in microphone support under Symphony&#8217;s unified API (which is, to say, wrapping it). My head and desk are no longer on speaking terms, but more to the point I&#8217;d love to know (at least in the case of Silverlight) if Microsoft bothers to get people who have experience in the area their assigned to write libraries for.</font></p>
<p><font color="#000000" size="3">A lesson I learned the hard way in developing <a href="http://gablarski.org" target="_blank">Gablarski</a> was that available audio devices change, a lot. Some enable/disable themselves automatically when detecting a 3.5mm being connected/disconnected, others are USB devices that get plugged in and removed at will, so on and so forth. As any logical person would deduce from this truth, it becomes important to be able to track what device is currently the default, when that default changes, and when a device is removed. So let&#8217;s look at Silverlight&#8217;s APIs and see what&#8217;s available; first we have the <font face="Consolas">CaptureDeviceConfiguration</font>:</font> </p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><span style="color: "><font color="#0000ff"><font style="font-size: 9.8pt">public</font></font></span><font style="font-size: 9.8pt"><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">class</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">CaptureDeviceConfiguration</font></span>
</font></font><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000">{
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">bool</font></span><font color="#000000"> AllowedDeviceAccess { </font><span style="color: "><font color="#0000ff">get</font></span></font><font face="Consolas"><font color="#000000">; }

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">bool</font></span></font><font face="Consolas"><font color="#000000"> RequestDeviceAccess();
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">ReadOnlyCollection</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">VideoCaptureDevice</font></span></font><font face="Consolas"><font color="#000000">> GetAvailableVideoCaptureDevices();
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">ReadOnlyCollection</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span></font><font face="Consolas"><font color="#000000">> GetAvailableAudioCaptureDevices();
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">VideoCaptureDevice</font></span></font></font><font face="Consolas"><font style="font-size: 9.8pt"><font color="#000000"> GetDefaultVideoCaptureDevice();
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000"> GetDefaultAudioCaptureDevice();
}</font></font></font></pre>
<p><font color="#000000" size="3">Ok, so this gives us a way to get the current default and a list of all available devices. As you’ll notice, however, it does not provide an event notifying you that the default device has changed. I’ve found that the best user experience for voice based applications is to default to the default audio device and to track that device. If I manually set another device, the application will gladly remember what I’ve selected, but I should be given the choice of “default” which follows the <em>current</em> default instead of just the default at selection time. Without a notification to tell the application when this has changed, the developer is left with no good way to provide an excellent user experience. The best I could come up with to work around this is to poll the current default device in order to provide the notification that Symphony’s API demands. Having the notification at all is a positive outcome, but having to balance between how much delay between polls and how many extra cycles we’re wasting checking is undesirable. Here’s what I came up with:</font></p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><span style="color: "><font color="#0000ff"><font style="font-size: 9.8pt">public</font></font></span><font style="font-size: 9.8pt"><font color="#000000"> </font><span style="color: "><font color="#0000ff">class</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">SilverlightAudioCaptureDeviceProvider</font></span>
</font></font><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000">{
	</font><span style="color: "><font color="#0000ff">public</font></span></font><font face="Consolas"><font color="#000000"> SilverlightAudioCaptureDeviceProvider()
	{
		</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (!</font><span style="color: "><font color="#2b91af">CaptureDeviceConfiguration</font></span></font><font face="Consolas"><font color="#000000">.AllowedDeviceAccess)
			</font><span style="color: "><font color="#2b91af">CaptureDeviceConfiguration</font></span></font><font face="Consolas"><font color="#000000">.RequestDeviceAccess();

		UpdateDevices();
		</font><span style="color: "><font color="#0000ff">this</font></span><font color="#000000">.pollTimer.Interval = </font><span style="color: "><font color="#2b91af">TimeSpan</font></span></font><font face="Consolas"><font color="#000000">.FromMilliseconds (250);
		</font><span style="color: "><font color="#0000ff">this</font></span></font><font face="Consolas"><font color="#000000">.pollTimer.Tick += PollTimerOnTick;
		</font><span style="color: "><font color="#0000ff">this</font></span></font><font face="Consolas"><font color="#000000">.pollTimer.Start();
	}

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">event</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">EventHandler</font></span></font><font face="Consolas"><font color="#000000"> DefaultDeviceChanged;

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span></font><font face="Consolas"><font color="#000000"> DefaultDevice
	{
		</font><span style="color: "><font color="#0000ff">get</font></span></font><font face="Consolas"><font color="#000000">;
		</font><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">set</font></span></font><font face="Consolas"><font color="#000000">;
	}

	</font><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">DispatcherTimer</font></span><font color="#000000"> pollTimer = </font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">DispatcherTimer</font></span></font><font face="Consolas"><font color="#000000">();
	</font><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span></font><font face="Consolas"><font color="#000000"> lastDefaultDevice;

	</font><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span><font color="#000000"> PollTimerOnTick (</font><span style="color: "><font color="#0000ff">object</font></span><font color="#000000"> sender, </font><span style="color: "><font color="#2b91af">EventArgs</font></span></font><font face="Consolas"><font color="#000000"> eventArgs)
	{
		UpdateDevices();
	}

	</font><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span></font><font face="Consolas"><font color="#000000"> UpdateDevices()
	{
		</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000"> defaultDevice = </font><span style="color: "><font color="#2b91af">CaptureDeviceConfiguration</font></span></font><font face="Consolas"><font color="#000000">.GetDefaultAudioCaptureDevice();
		</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (DefaultDevice != defaultDevice) </font><span style="color: "><font color="#008000">// This is actually a bug which I’ll explain later</font></span>
</font><font face="Consolas"><font color="#000000">		{
			DefaultDevice = defaultDevice;
			OnDefaultDeviceChanged (</font><span style="color: "><font color="#2b91af">EventArgs</font></span></font><font face="Consolas"><font color="#000000">.Empty);
		}
	}

	</font><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span><font color="#000000"> OnDefaultDeviceChanged (</font><span style="color: "><font color="#2b91af">EventArgs</font></span></font><font face="Consolas"><font color="#000000"> e)
	{
		</font><span style="color: "><font color="#0000ff">var</font></span></font><font face="Consolas"><font color="#000000"> changed = DefaultDeviceChanged;
		</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (changed != </font><span style="color: "><font color="#0000ff">null</font></span></font></font><font face="Consolas"><font style="font-size: 9.8pt"><font color="#000000">)
			changed (</font><span style="color: "><font color="#0000ff">this</font></span><font color="#000000">, e);
	}
}</font></font></font></pre>
<p><font color="#000000" size="3">(This is not the Symphony API, I’ve reduced it to a decorator off sorts to provide these functions for any Silverlight use for the reader.)</font></p>
<p><font color="#000000" size="3">Now that we have default device notifications, we need to check into notifications for devices becoming unavailable (which could be a user manually disabling the device in Windows, unplugging a USB mic, etc.) It’s obviously not on <font face="Consolas">CaptureDeviceConfiguration</font> class, so let’s check the <font face="Consolas">AudioCaptureDevice</font> class:</font></p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><span style="color: "><font color="#0000ff"><font style="font-size: 9.8pt">public</font></font></span><font style="font-size: 9.8pt"><font color="#000000"> </font><span style="color: "><font color="#0000ff">class</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">CaptureDevice</font></span>
<font color="#000000">	: </font><span style="color: "><font color="#2b91af">DependencyObject</font></span>
</font></font><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000">{
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">DependencyProperty</font></span></font><font face="Consolas"><font color="#000000"> FriendlyNameProperty;
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">DependencyProperty</font></span></font><font face="Consolas"><font color="#000000"> IsDefaultDeviceProperty;

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">string</font></span><font color="#000000"> FriendlyName { </font><span style="color: "><font color="#0000ff">get</font></span></font><font face="Consolas"><font color="#000000">; }
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">bool</font></span><font color="#000000"> IsDefaultDevice { </font><span style="color: "><font color="#0000ff">get</font></span></font><font face="Consolas"><font color="#000000">; }
}

</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">sealed</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">class</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span>
<font color="#000000">	: </font><span style="color: "><font color="#2b91af">CaptureDevice</font></span>
</font><font face="Consolas"><font color="#000000">{
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">DependencyProperty</font></span></font><font face="Consolas"><font color="#000000"> AudioFrameSizeProperty;

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">int</font></span><font color="#000000"> AudioFrameSize { </font><span style="color: "><font color="#0000ff">get</font></span><font color="#000000">; </font><span style="color: "><font color="#0000ff">set</font></span></font><font face="Consolas"><font color="#000000">; }
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">ReadOnlyCollection</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioFormat</font></span><font color="#000000">> SupportedFormats { </font><span style="color: "><font color="#0000ff">get</font></span></font></font><font face="Consolas"><font style="font-size: 9.8pt"><font color="#000000">; }
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioFormat</font></span><font color="#000000"> DesiredFormat { </font><span style="color: "><font color="#0000ff">get</font></span><font color="#000000">; </font><span style="color: "><font color="#0000ff">set</font></span><font color="#000000">; }
}</font></font></font></pre>
<h1></h1>
<p><font color="#000000" size="3" face="Georgia">So there’s no status changed events and there’s no properties to check if the device is even still alive. Let’s step back and take a look at a basic usage of this API. First you new up a <font face="Consolas">CaptureSource</font>:</font></p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><span style="color: "><font color="#0000ff"><font style="font-size: 9.8pt">public</font></font></span><font style="font-size: 9.8pt"><font color="#000000"> </font><span style="color: "><font color="#0000ff">sealed</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">class</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">CaptureSource</font></span>
<font color="#000000">	: </font><span style="color: "><font color="#2b91af">DependencyObject</font></span>
</font></font><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000">{
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">DependencyProperty</font></span></font><font face="Consolas"><font color="#000000"> VideoCaptureDeviceProperty;
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">DependencyProperty</font></span></font><font face="Consolas"><font color="#000000"> AudioCaptureDeviceProperty;

	</font><span style="color: "><font color="#0000ff">public</font></span></font><font face="Consolas"><font color="#000000"> CaptureSource();

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">event</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">EventHandler</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">ExceptionRoutedEventArgs</font></span></font><font face="Consolas"><font color="#000000">> CaptureFailed;
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">event</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">EventHandler</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">CaptureImageCompletedEventArgs</font></span></font><font face="Consolas"><font color="#000000">> CaptureImageCompleted;

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">VideoCaptureDevice</font></span><font color="#000000"> VideoCaptureDevice { </font><span style="color: "><font color="#0000ff">get</font></span><font color="#000000">; </font><span style="color: "><font color="#0000ff">set</font></span></font><font face="Consolas"><font color="#000000">; }
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000"> AudioCaptureDevice { </font><span style="color: "><font color="#0000ff">get</font></span><font color="#000000">; </font><span style="color: "><font color="#0000ff">set</font></span></font><font face="Consolas"><font color="#000000">; }
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">CaptureState</font></span><font color="#000000"> State { </font><span style="color: "><font color="#0000ff">get</font></span></font><font face="Consolas"><font color="#000000">; }

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span></font><font face="Consolas"><font color="#000000"> Start();
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span></font></font><font face="Consolas"><font style="font-size: 9.8pt"><font color="#000000"> Stop();
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span><font color="#000000"> CaptureImageAsync();
}</font></font></font></pre>
<p><font color="#000000" size="3">So, we take our audio device and assign <font face="Consolas">CaptureSource.AudioCaptureDevice</font> to it and call start. <font face="Consolas">CaptureFailed</font> looks promising, I would expect it to be raised if the device had disappeared before or after starting the capture. I can’t help but notice that there’s explicit methods for capturing a single image, but there’s no way from right here to get audio samples (or multiple images). In order to actually get the audio samples you then have to create (as there are no built-in implementations) and initialize an <font face="Consolas">AudioSink</font>:</font></p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><span style="color: "><font color="#0000ff"><font style="font-size: 9.8pt">public</font></font></span><font style="font-size: 9.8pt"><font color="#000000"> </font><span style="color: "><font color="#0000ff">abstract</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">class</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioSink</font></span>
</font></font><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000">{
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">CaptureSource</font></span><font color="#000000"> CaptureSource { </font><span style="color: "><font color="#0000ff">get</font></span><font color="#000000">; </font><span style="color: "><font color="#0000ff">set</font></span></font><font face="Consolas"><font color="#000000">; }

	</font><span style="color: "><font color="#0000ff">protected</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">abstract</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span></font><font face="Consolas"><font color="#000000"> OnCaptureStarted();
	</font><span style="color: "><font color="#0000ff">protected</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">abstract</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span></font><font face="Consolas"><font color="#000000"> OnCaptureStopped();
	</font><span style="color: "><font color="#0000ff">protected</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">abstract</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span><font color="#000000"> OnFormatChange (</font><span style="color: "><font color="#2b91af">AudioFormat</font></span></font><font face="Consolas"><font color="#000000"> audioFormat);
	</font><span style="color: "><font color="#0000ff">protected</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">abstract</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span><font color="#000000"> OnSamples ( </font><span style="color: "><font color="#0000ff">long</font></span><font color="#000000"> sampleTimeInHundredNanoseconds, </font><span style="color: "><font color="#0000ff">long</font></span></font></font><font face="Consolas"><font style="font-size: 9.8pt"><font color="#000000"> sampleDurationInHundredNanoseconds,
					</font><span style="color: "><font color="#0000ff">byte</font></span><font color="#000000">[] sampleData);
	~AudioSink();
}</font></font></font></pre>
<h1><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000"><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000"></font></font></font></font></font></font></h1>
<p><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000"><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000"></font></font></font></font></font></font></p>
<p><font style="font-size: 9.8pt"><font color="#000000" size="3"></p>
<p>Here are some more alternatives, <font face="Consolas">OnCaptureStopped()</font> might be called if the device goes away during capture. So, I set up a test with all of these components, put breakpoints everywhere, started the capture and disabled a device while it was running. Can you guess which event/callback breakpoint was hit? I asked a few different people that question when I was attempting to do all of this and the answer is so ridiculous that no one guessed it their first try. The answer is <strong>NONE</strong> of them. If the device you’re capturing with goes away while you’re capturing, you received no notification whatsoever. No event raised, no callback fired, no <font face="Consolas">0</font> value arguments to <font face="Consolas">OnSamples</font>, no <font face="Consolas">CaptureSource.State == CaptureState.Failed</font>, no exception, <strong>nothing</strong>.</p>
<p>As before, this is a pretty critical factor of user experience. The user may not even know that the device just went away. I can just imagine the “Hey, can anyone hear me?” and subsequent “I’ve been talking for 30 minutes and no one could hear me..”. If you’ve used a VoIP application while playing games, you’ve probably done this before with a mute switch on your headset. So, there are two alternatives: We can poll the complete list of devices to see if the device is listed anymore, or we can have a timeout for <font face="Consolas">OnSamples</font> calls (as it does stop being called when the device goes away). Since we already have a poll for the default device, I decided to go with polling.</p>
<p>First, we’ll need a decorator to hold the status and event:</p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><font size="2"><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">class</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span>
</font></font><font face="Consolas"><font size="2"><font color="#000000">{
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> AudioCaptureDeviceEx (</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> device)
	{
		</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (device == </font><span style="color: "><font color="#0000ff">null</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">)
			</font><span style="color: "><font color="#0000ff">throw</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">ArgumentNullException</font></span><font color="#000000"> (</font><span style="color: "><font color="#a31515">"device"</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">);

		</font><span style="color: "><font color="#0000ff">this</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">.device = device;
	}

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">event</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">EventHandler</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> IsAvailableChanged;

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">bool</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> IsAvailable
	{
		</font><span style="color: "><font color="#0000ff">get</font></span><font color="#000000"> { </font><span style="color: "><font color="#0000ff">return</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">this</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">.isAvailable; }
		</font><span style="color: "><font color="#0000ff">set</font></span>
</font></font><font face="Consolas"><font size="2"><font color="#000000">		{
			</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (</font><span style="color: "><font color="#0000ff">this</font></span><font color="#000000">.isAvailable == </font><span style="color: "><font color="#0000ff">value</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">)
				</font><span style="color: "><font color="#0000ff">return</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">;

			</font><span style="color: "><font color="#0000ff">this</font></span><font color="#000000">.isAvailable = </font><span style="color: "><font color="#0000ff">value</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">;
			</font><span style="color: "><font color="#0000ff">var</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> changed = IsAvailableChanged;
			</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (changed != </font><span style="color: "><font color="#0000ff">null</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">)
				changed (</font><span style="color: "><font color="#0000ff">this</font></span><font color="#000000">, </font><span style="color: "><font color="#2b91af">EventArgs</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">.Empty);
		}
	}

	</font><span style="color: "><font color="#008000">// 1:1 AudioCaptureDevice wrappings left out for brevity</font></span>
</font></font><font face="Consolas"><font size="2"><font color="#000000">
	</font><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span></font></font><font size="2"><font face="Consolas"><font color="#000000"> device;
	</font><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">bool</font></span><font color="#000000"> isAvailable = </font></font><font face="Consolas"><span style="color: "><font color="#0000ff">true</font></span></font></font><font face="Consolas"><font color="#000000" size="2">;
}</font></font></pre>
<p>We’ll want a list of devices with our additions in the device provider:</p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><font size="2"><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">Dictionary</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000">, </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">> devices =
	</font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">Dictionary</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000">, </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">>();

</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">IEnumerable</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">> AudioDevices
{
	</font><span style="color: "><font color="#0000ff">get</font></span>
</font></font><font face="Consolas"><font size="2"><font color="#000000">	{
		</font><span style="color: "><font color="#0000ff">lock</font></span><font color="#000000"> (</font><span style="color: "><font color="#0000ff">this</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">.devices)
			</font><span style="color: "><font color="#0000ff">return</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">this</font></span></font><font color="#000000" size="2">.devices.Values.Where (d => d.IsAvailable).ToList();
	}
}</font></font></pre>
<p>Now we need to update our polling routine:</p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><font size="2"><span style="color: "><font color="#0000ff">private</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> UpdateDevices()
{
	</font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span><font color="#000000"> currentDefault = </font><span style="color: "><font color="#0000ff">null</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">;

	</font><span style="color: "><font color="#0000ff">lock</font></span><font color="#000000"> (</font><span style="color: "><font color="#0000ff">this</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">.devices)
	{
		</font><span style="color: "><font color="#0000ff">var</font></span><font color="#000000"> newDevices = </font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">HashSet</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000">> (</font><span style="color: "><font color="#2b91af">CaptureDeviceConfiguration</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">.GetAvailableAudioCaptureDevices());
		</font><span style="color: "><font color="#0000ff">foreach</font></span><font color="#000000"> (</font><span style="color: "><font color="#0000ff">var</font></span><font color="#000000"> kvp </font><span style="color: "><font color="#0000ff">in</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">this</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">.devices)
		{
			</font><span style="color: "><font color="#0000ff">if</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> (kvp.Value.IsDefaultDevice)
				currentDefault = kvp.Value;

			</font><span style="color: "><font color="#0000ff">if</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> (newDevices.Remove (kvp.Key))
			{
				kvp.Value.IsAvailable = </font><span style="color: "><font color="#0000ff">true</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">;
				</font><span style="color: "><font color="#0000ff">continue</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">;
			}

			</font><span style="color: "><font color="#0000ff">this</font></span><font color="#000000">.devices[kvp.Key].IsAvailable = </font><span style="color: "><font color="#0000ff">false</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">;
		}

		</font><span style="color: "><font color="#0000ff">foreach</font></span><font color="#000000"> (</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000"> device </font><span style="color: "><font color="#0000ff">in</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> newDevices)
		{
			</font><span style="color: "><font color="#0000ff">var</font></span><font color="#000000"> d = </font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> (device);
			</font><span style="color: "><font color="#0000ff">if</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> (d.IsDefaultDevice)
				currentDefault = d;

			</font><span style="color: "><font color="#0000ff">this</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000">.devices.Add (device, d);
		}
	}

	</font><span style="color: "><font color="#0000ff">if</font></span></font></font><font face="Consolas"><font size="2"><font color="#000000"> (DefaultDevice != currentDefault)
	{
		DefaultDevice = currentDefault;
		OnDefaultDeviceChanged (</font><span style="color: "><font color="#2b91af">EventArgs</font></span></font><font color="#000000" size="2">.Empty);
	}
}</font></font></pre>
<p>Seems like it should work, right? Yeah, I thought so too. In my tests (on my machine anyway), I discovered <font face="Consolas">AudioCaptureDevice.IsDefaultDevice</font> <strong>always</strong> returns <strong>false</strong>. You’d think there’d be an <font face="Consolas">Assert.IsTrue (CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice().IsDefaultDevice)</font> somewhere in their tests. So, I need to instead go back to querying <font face="Consolas">CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice()</font> and then reconcile the <font face="Consolas">AudioCaptureDeviceEx</font> instances. This is where I was in for another surprise; remember that bug I said I’d tell you about later?<font face="Consolas"> AudioCaptureDevice</font> does not implement equality functions and new instances are returned on each of <font face="Consolas">CaptureDeviceConfiguration</font><font face="Georgia">’s methods, so there’s no other way to compare them but their “<font face="Consolas">FriendlyName</font>” (which is actually <strong>cut off</strong>, which makes it impossible to display an exact match to what’s in Windows). Comparing by their name will probably work <em>most</em> of the time, it’s definitely not ideal. So now we have:</font></p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><span style="color: "><font color="#0000ff"><font style="font-size: 9.8pt">private</font></font></span><font style="font-size: 9.8pt"><font color="#000000"> </font><span style="color: "><font color="#0000ff">class</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEqualityComparer</font></span>
<font color="#000000">	: </font><span style="color: "><font color="#2b91af">IEqualityComparer</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span></font></font><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000">>
{
	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">static</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEqualityComparer</font></span></font><font face="Consolas"><font color="#000000"> Instance
		= </font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEqualityComparer</font></span></font><font face="Consolas"><font color="#000000">();

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">bool</font></span><font color="#000000"> Equals (</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000"> x, </font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span></font><font face="Consolas"><font color="#000000"> y)
	{
		</font><span style="color: "><font color="#0000ff">if</font></span></font><font face="Consolas"><font color="#000000"> (x == y)
			</font><span style="color: "><font color="#0000ff">return</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">true</font></span></font><font face="Consolas"><font color="#000000">;
		</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (x == </font><span style="color: "><font color="#0000ff">null</font></span><font color="#000000"> || y == </font><span style="color: "><font color="#0000ff">null</font></span></font><font face="Consolas"><font color="#000000">)
			</font><span style="color: "><font color="#0000ff">return</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">false</font></span></font><font face="Consolas"><font color="#000000">;

		</font><span style="color: "><font color="#0000ff">return</font></span></font><font face="Consolas"><font color="#000000"> (x.FriendlyName == y.FriendlyName);
	}

	</font><span style="color: "><font color="#0000ff">public</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">int</font></span><font color="#000000"> GetHashCode (</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span></font><font face="Consolas"><font color="#000000"> obj)
	{
		</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (obj == </font><span style="color: "><font color="#0000ff">null</font></span></font><font face="Consolas"><font color="#000000">)
			</font><span style="color: "><font color="#0000ff">throw</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">ArgumentNullException</font></span><font color="#000000"> (</font><span style="color: "><font color="#a31515">"obj"</font></span></font></font><font face="Consolas"><font style="font-size: 9.8pt"><font color="#000000">);

		</font><span style="color: "><font color="#0000ff">return</font></span><font color="#000000"> obj.FriendlyName.GetHashCode();
	}
}</font></font></font></pre>
<p>We’ll need to update the dictionary holding the devices:</p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><span style="color: "><font color="#0000ff"><font style="font-size: 9.8pt">private</font></font></span><font style="font-size: 9.8pt"><font color="#000000"> </font><span style="color: "><font color="#0000ff">readonly</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">Dictionary</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000">, </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span></font></font><font face="Consolas"><font style="font-size: 9.8pt"><font color="#000000">> devices =
	</font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">Dictionary</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000">, </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span><font color="#000000">> (</font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEqualityComparer</font></span><font color="#000000">.Instance);</font></font></font></pre>
<p>And finally the updated <font face="Consolas">UpdateDevices</font>:</p>
<pre style="padding-bottom: 0px; line-height: normal; padding-left: 0px; padding-right: 0px; font-family: ; background: white; color: ; padding-top: 0px"><font face="Consolas"><span style="color: "><font color="#0000ff"><font style="font-size: 9.8pt">private</font></font></span><font style="font-size: 9.8pt"><font color="#000000"> </font><span style="color: "><font color="#0000ff">void</font></span></font></font><font style="font-size: 9.8pt"><font face="Consolas"><font color="#000000"> UpdateDevices()
{
	</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000"> currentDefault = </font><span style="color: "><font color="#2b91af">CaptureDeviceConfiguration</font></span></font><font face="Consolas"><font color="#000000">.GetDefaultAudioCaptureDevice();
	</font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span><font color="#000000"> currentDefaultEx = </font><span style="color: "><font color="#0000ff">null</font></span></font><font face="Consolas"><font color="#000000">;

	</font><span style="color: "><font color="#0000ff">lock</font></span><font color="#000000"> (</font><span style="color: "><font color="#0000ff">this</font></span></font><font face="Consolas"><font color="#000000">.devices)
	{
		</font><span style="color: "><font color="#0000ff">var</font></span><font color="#000000"> newDevices = </font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">HashSet</font></span><font color="#000000"><</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000">> (</font><span style="color: "><font color="#2b91af">CaptureDeviceConfiguration</font></span></font><font face="Consolas"><font color="#000000">.GetAvailableAudioCaptureDevices(),
							</font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEqualityComparer</font></span></font><font face="Consolas"><font color="#000000">.Instance);
		</font><span style="color: "><font color="#0000ff">foreach</font></span><font color="#000000"> (</font><span style="color: "><font color="#0000ff">var</font></span><font color="#000000"> kvp </font><span style="color: "><font color="#0000ff">in</font></span><font color="#000000"> </font><span style="color: "><font color="#0000ff">this</font></span></font><font face="Consolas"><font color="#000000">.devices)
		{
			</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (currentDefault != </font><span style="color: "><font color="#0000ff">null</font></span></font><font face="Consolas"><font color="#000000"> &#038;&#038; kvp.Value.FriendlyName == currentDefault.FriendlyName)
				currentDefaultEx = kvp.Value;

			</font><span style="color: "><font color="#0000ff">if</font></span></font><font face="Consolas"><font color="#000000"> (newDevices.Remove (kvp.Key))
			{
				kvp.Value.IsAvailable = </font><span style="color: "><font color="#0000ff">true</font></span></font><font face="Consolas"><font color="#000000">;
				</font><span style="color: "><font color="#0000ff">continue</font></span></font><font face="Consolas"><font color="#000000">;
			}

			</font><span style="color: "><font color="#0000ff">this</font></span><font color="#000000">.devices[kvp.Key].IsAvailable = </font><span style="color: "><font color="#0000ff">false</font></span></font><font face="Consolas"><font color="#000000">;
		}

		</font><span style="color: "><font color="#0000ff">foreach</font></span><font color="#000000"> (</font><span style="color: "><font color="#2b91af">AudioCaptureDevice</font></span><font color="#000000"> device </font><span style="color: "><font color="#0000ff">in</font></span></font><font face="Consolas"><font color="#000000"> newDevices)
		{
			</font><span style="color: "><font color="#0000ff">var</font></span><font color="#000000"> d = </font><span style="color: "><font color="#0000ff">new</font></span><font color="#000000"> </font><span style="color: "><font color="#2b91af">AudioCaptureDeviceEx</font></span></font><font face="Consolas"><font color="#000000"> (device);
			</font><span style="color: "><font color="#0000ff">if</font></span><font color="#000000"> (currentDefault != </font><span style="color: "><font color="#0000ff">null</font></span></font><font face="Consolas"><font color="#000000"> &#038;&#038; d.FriendlyName == currentDefault.FriendlyName)
				currentDefaultEx = d;

			</font><span style="color: "><font color="#0000ff">this</font></span></font><font face="Consolas"><font color="#000000">.devices.Add (device, d);
		}
	}

	</font><span style="color: "><font color="#0000ff">if</font></span></font></font><font face="Consolas"><font style="font-size: 9.8pt"><font color="#000000"> (DefaultDevice != currentDefaultEx)
	{
		DefaultDevice = currentDefaultEx;
		OnDefaultDeviceChanged (</font><span style="color: "><font color="#2b91af">EventArgs</font></span><font color="#000000">.Empty);
	}
}</font></font></font></pre>
<p>When I was wrapping <font face="Consolas">AudioCaptureDevice</font> for Symphony&#8217;s capture device contract, I discovered another fun bit. Symphony has it&#8217;s own definition for audio formats, so I have to keep a map of formats so I can pass the correct one to Silverlight. Ok, no problem, I&#8217;ll just call ToDictionary with a little conversion function I wrote, and.. ArgumentException. <font face="Consolas">AudioCaptureDevice.SupportedFormats</font> actually contains duplicates. I realize this is probably just directly reading from whatever API it&#8217;s sitting on, but when you&#8217;re trying to provide a simple API you should really clean up crap like this.</p>
<h2>Let’s review</h2>
<ul>
<li>No notifications for default device changed
<li>No notifications for devices added / removed
<li><font face="Consolas">AudioCaptureDevice.FriendlyName</font> is fixed width
<li><font face="Consolas">AudioCaptureDevice.IsDefaultDevice</font> just plain <strong>broken</strong>
<li><font face="Consolas">AudioCaptureDevice</font> isn’t equatable</li>
<li><font face="Consolas">AudioCaptureDevice.SupportedFormats</font> contains duplicates</li>
</ul>
<p>If someone handed me code like this for such a wide reaching project like Silverlight and told me it was done, I’d fire them. That it actually made it to production baffles me, somewhere a manager completely failed at their job. I’m really not sure how you can go this wrong, but the more I explore Silverlight, the more I come to the conclusion that it’s a hack job and that if it wasn’t for WP7 I really wouldn’t bother wasting my time trying to support it for <em>anything</em>. The Mono crew have unified platform support figured out, how is it that Microsoft with all its resources (or perhaps that’s exactly the reason?) has managed to create such different platforms. I very quickly ran out of votes on Silverlight’s UserVoice page: <a href="http://dotnet.uservoice.com/forums/4325-silverlight-feature-suggestions">http://dotnet.uservoice.com/forums/4325-silverlight-feature-suggestions</a></p>
<p>The complete final code for the device provider is available here: <a href="https://gist.github.com/1047203">https://gist.github.com/1047203</a></p>
<p>P.S. If I got this wrong, I’d <strong>love</strong> to be corrected.</p>
<p></font></font></p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/code-monkey-vs-silverlight-audio-capture/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Code Monkey vs. Elderly Preconditioning</title>
		<link>http://ermau.com/code-monkey-vs-elderly-preconditioning/</link>
		<comments>http://ermau.com/code-monkey-vs-elderly-preconditioning/#comments</comments>
		<pubDate>Mon, 06 Sep 2010 21:56:42 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[Rant]]></category>
		<category><![CDATA[elderly]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[ux]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=13</guid>
		<description><![CDATA[For anyone that&#8217;s given tech support to their parents, grandparents, or any older customers, one thing stands out: They don&#8217;t read what&#8217;s in front of them. Although the same could be said for most average computer users, it is my &#8230; <a href="http://ermau.com/code-monkey-vs-elderly-preconditioning/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>For anyone that&#8217;s given tech support to their parents, grandparents, or any older customers, one thing stands out: They don&#8217;t read what&#8217;s in front of them. Although the same could be said for most average computer users, it is my belief that is far more prevalent amongst the older generations. When these older people were growing up, computers weren&#8217;t expected household items. More importantly, they were easy to break software-wise.</p>
<p>As a result of this the older users, who&#8217;ve never taken the time to learn about their computer, have been preconditioned to never &#8220;try it and see&#8221;. When TIAS is likely to break possibly everything, it becomes easy to avoid doing anything you&#8217;re unsure of. This is especially true for those that don&#8217;t have tech support to go to (for those that do, that&#8217;d be you). As a result, it&#8217;s far less likely that these people will ever try to figure out how to do some things on their own, due to a fear of breaking things.</p>
<p>While it may sound ridiculous to think that uninstalling some simple program may break the whole computer, they have no clue how a computer works. Even as operating systems become more and more reliable, most will remain stuck in this preconditioned fear. Even on platforms like iOS where it&#8217;s extremely difficult to break by normal use, this behavior continues.</p>
<p>What can we do to stop this? Much to the dismay to this audience (or maybe not, depending on how much you get asked for support), I believe that platforms like iOS that are heavily locked down are the future of mainstream computing and gaming. We&#8217;re already seeing it with the rise of console gaming, and the old (and young) adopting the iPad. That&#8217;s not to say full fledged PCs are going anywhere anytime soon, but more and more they&#8217;ll be regulated to the office and the power user.</p>
<p>These locked down systems are decidedly easier to use. No, they&#8217;re not anywhere near as capable as a normal personal computer today, but that won&#8217;t stay the case for long. On top of that fact, the ones having issues with computers are generally those that only need very little from it. Advanced content creation will remain with more capable systems, but mass content consumption and simple content creation is the bulk of the average user&#8217;s use for computers and can easily be regulated to less capable systems. These generally less capable systems are even, in some cases, better suited to these tasks to begin with.</p>
<p>In the short term, for those annoyed by support requests, you can refuse to help. Demand they read before they ask, even make them recite what&#8217;s on the screen. Do not accept &#8220;well I don&#8217;t know&#8221; or &#8220;If I knew, I wouldn&#8217;t have to ask you&#8221; or even &#8220;You can figure it out a lot faster than me&#8221; as excuses. It may sound mean, but there&#8217;s few other ways to teach them that don&#8217;t require a significant portion of your time.</p>
<p>You can help them by teaching them how to find things. When we look for functionality in a program, we know to check context menus and program menus. These things are key to finding things, but right clicking things may not be all that apparent to those who don&#8217;t use the computer anywhere near as much as us.</p>
<p>For once, I don&#8217;t blame the application developers. Although some fail miserably at creating good user experiences, many are adequate. Despite developers&#8217; best efforts, people don&#8217;t read and sadly not every application can be created without needing description or instruction.</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/code-monkey-vs-elderly-preconditioning/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Code Monkey vs. iOS4</title>
		<link>http://ermau.com/code-monkey-vs-ios4/</link>
		<comments>http://ermau.com/code-monkey-vs-ios4/#comments</comments>
		<pubDate>Sun, 25 Jul 2010 14:37:52 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[Rant]]></category>
		<category><![CDATA[UX]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[ux]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=60</guid>
		<description><![CDATA[So having ranted about the hardware, it&#8217;s only fitting that I rant about the software on it. Like my article on the hardware, I&#8217;m only going to focus on what I think is wrong with it; there&#8217;s plenty of articles &#8230; <a href="http://ermau.com/code-monkey-vs-ios4/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>So <a href="http://ermau.com/?p=17">having ranted about the hardware</a>, it&#8217;s only fitting that I rant about the software on it. Like my article on the hardware, I&#8217;m only going to focus on what I think is wrong with it; there&#8217;s plenty of articles on the good stuff already.</p>
<h3>Multitasking</h3>
<h4>UI</h4>
<p>Apple&#8217;s implementation of multitasking, UI-wise, is nearly the worst I could think of. Not only did they fail completely at avoiding a task manager, they ended up implementing one that confuses users even more than a proper one would. On top of this, they broke the cardinal rule: they broke a users understanding of simply closing an app.</p>
<p>Previous to iOS4, pressing the home button was synonymous with closing an app. There was no fear of it continuing to drain the battery, continuing to monitor your location or what have you. This changed slightly with the introduction of push notifications, but the effect was the same, the app was dead and gone. iOS4 has broken this completely, worse than simply changing an expected behavior, they&#8217;ve made the old behavior annoyingly difficult to get to. Let&#8217;s compare, shall we?</p>
<p><strong>Really closing an app in iOS3-:</strong></p>
<ol>
<li>Press the home button.</li>
</ol>
<p><strong>Really closing an app in iOS4:</strong></p>
<ol>
<li>Press the home button.</li>
<li>Double press the home button.</li>
<li>Tap and hold on an icon.</li>
<li>Press the red minus above the app.</li>
</ol>
<p>I mean, <strong>really</strong>? What&#8217;s worse is this isn&#8217;t even remotely obvious; I&#8217;d be willing to bet that most users of iOS4 don&#8217;t even know about this. You may be wondering why this is even a problem since most apps don&#8217;t multitask anyway and state saving is a useful feature.</p>
<p>When introducing what is effectively just a MRU list, Steve Jobs said &#8220;These are all the apps that are running.&#8221; Problem is, that&#8217;s not even remotely true. It&#8217;s just a list if recently used apps, with absolutely no indication of wether they are actually still running or just in a suspended state (if that, since non-iOS4 apps are listed too). Beyond the fact that not actually closing the apps pollutes this terrible &#8216;multitasking UI&#8217;, I&#8217;m not even given a choice up front about whether an app should keep running in the background or not.</p>
<p>On the flip side of this, you could say that things like Skype and Pandora are now consistent to their core-feature counterparts. Except the fact that both of these apps use significant bandwidth and in the case of Pandora, more power. You could also say that 9.9 times out of 10, people will not want to actually close Skype while on a phone call, which I&#8217;d agree with. In the case of Pandora though, you have to weigh user expectations with consistency. Specifically for Pandora, consistency probably wins out because it&#8217;s more convenient than the alternative. However, I feel that core-feature alternatives are the exception and that we can&#8217;t even begin to apply this argument to all types of apps.</p>
<h4>UI Ideas</h4>
<p>The last time I was blogging, I posted an article proposing my solution for the UI of multitasking to avoid a task manager among other things. In it, I proposed that true multitasking be treated like GPS location, that you be asked by the OS whether or not to allow this app to keep draining battery. Having seen Apple&#8217;s solution now, I still think it&#8217;s a good idea and have some new ideas.</p>
<p>Part of the problem now is that the default behavior is completely up to the app developer who may or may not give you a choice. Sometimes when I exit Colloquy, I actually want to exit and sign out of Colloquy. Sure, Colloquy could likely add a dialog asking me in their task completion thread on whether to keep running or not (which I&#8217;d like, actually), but that doesn&#8217;t solve it for say Pandora or anything else.</p>
<p>Instead of having explicit closing, what about explicit multitasking? If I tap the home button, it would exit the app as it always has. If I double tap the home button, up would pop the multitasking UI. From there, I could either go to the home screen, or to another running app. Either way, exited through this multitasking UI, the running app would always be allowed to multitask. Options could be setup to allow this from the &#8216;normal&#8217; app exit, but it would be opt-in.</p>
<p>As for saved state, I&#8217;m on the fence. I&#8217;d still like to keep a way to explicitly clear it, as is sometimes necessary when apps get confused (I&#8217;m looking at you, Trillian.) If it wasn&#8217;t for this, I&#8217;d want them not in the multitasking list. Sadly the software world is imperfect and I suspect there will always be an app I have to beat with a stick. Non-iOS4 apps should never have shown in the list to begin with, but it won&#8217;t really matter for much longer.</p>
<h4>Actual possibilities</h4>
<p>Many have criticized Apple for not allowing &#8216;true multitasking&#8217; and instead watering it down to what they saw as important. However, I&#8217;m not going to do that, because I actually like the approach Apple has taken. Not only that, but the work to integrate things like Pandora and Skype to look and act like the similar core features of the phone impressed me.</p>
<p>Where Apple fell short though is their belief that Push Notifications was sufficient for all messaging clients. Problem is, not all of us tech informed people have a box running 24/7 they can use as a IRC proxy. Sure, I could probably set one up on my Linode VPS, but I shouldn&#8217;t have to. Persistent connections are an important but annoyingly missing piece. Everyone likes to use IRC as the example of this, but let&#8217;s use an example more relevant to the every day crowd.</p>
<p>Let&#8217;s take some multiplayer game you&#8217;re playing with your friend when you get a phone call. Now, a newly compiled single player game would happily have it&#8217;s state saved and then restored upon hanging up. Since it&#8217;s a multiplayer game however, one of two things just happened: 1. Because the developer took a ton of extra time, the game saved its state on its own and is now trying to reconnect. Or the more likely: 2. You&#8217;ve completely lost the connection and have to start the game over. Allowing the game to keep the connection would let it simply pause and then when the call is over it could simply un-pause and continue on it&#8217;s merry way with significantly less effort from the developer.</p>
<h3>Contacts</h3>
<p>I guess at this point it shouldn&#8217;t come as a shock to me that Apple seems to have no problem regressing features. Originally I&#8217;d planned to complain about the fact that I thought they&#8217;d removed custom labels from phone numbers and email addresses. When presented with the new interface that didn&#8217;t force me to select one and a preexisting label to the left, I assumed there was no way to change it. As it turns out however, it&#8217;s been moved to a menu that appears when you tap that label in edit mode.</p>
<p>Now, if I&#8217;d never used iOS 4 before, I&#8217;d probably have tried tapping on the label to change it. It seems like a pretty obvious spot to get to that menu on its own. However having been using iOS since 2.0, I was pretty used to it the way it was. When I saw the way I&#8217;d been used to was gone, I assumed the feature was gone and I bet I&#8217;m not alone.</p>
<p>On its own, the new design is simpler and has significantly less friction. However, as with multitasking, they&#8217;ve gone ahead and totally screwed with expected behavior.  I mean, was anyone really upset that adding a phone number or email address took a few seconds longer than it does now?</p>
<h3>Email</h3>
<h4>Threading</h4>
<p>Apple, if you&#8217;re going to steal/copy/whatever a feature, at least do it right. My biggest hope for email was that I&#8217;d get threaded messages from Gmail, where I love them to death. Upon setting up my email account on the new phone, I eagerly went into a 52 email thread and was promptly disappointed. Where are my own messages? Forum threads show my responses, Gmail shows my responses, but Mail does not. &#8220;Thread different&#8221;, perhaps?</p>
<p>Without seeing my own responses inline, the threading feature is all but useless. The point is to be able to see the entire conversation between parties, and that includes being able to see what you said. Being able to see them together should of helped avoid going into an email and backing out to try to find the previous one, but that hasn&#8217;t been remedied at all. Surely that must be an option I can enable, at least, right? Nope.</p>
<p>Worse still is the interface, the back and forth navigation is still just as annoying as it was before. Yes, sure, it&#8217;s an improvement because the messages are all together but the beauty of Gmail&#8217;s interface is that everything is <strong>right there</strong>. Even given the small size of the screen, I think that Gmail&#8217;s interface is totally doable. Simply pull the email down to reveal the subjects of the other messages, tap to expand. &#8220;But wait, that&#8217;s as just as many actions as before!&#8221; you say. Yes, but it skips the navigation animations that become time consuming quickly when compounded over several emails.</p>
<h4>Gmail Archive</h4>
<p>I guess at this point I really shouldn&#8217;t be surprised, but let us continue on this face-meets-palm quest pointing out where Apple broke user expectations. Previously setting up a Gmail account, delete would (insert surprise joke here) actually trash the email! In iOS4, Apple has added the &#8216;archive&#8217; feature for Gmail accounts, which is great. What is <strong>not</strong> great is that it&#8217;s now turned on by default. So let me get this straight, Apple introduces a feature (threading) that just affects presentation and has it off by default. When Apple introduces a feature that radically affects where your email goes, however, it&#8217;s now on by default even for existing accounts?</p>
<p>Now, granted, at least it&#8217;s not the reverse (going from archive to a delete) so at least it&#8217;s not more destructive. However, yet once again, Apple has taken existing behavior and decided that you&#8217;d rather have this other new behavior. I&#8217;m not sure who archives their Gmail messages instead of moving them to trash, but I certainly don&#8217;t. Maybe we could have both? Swipe right to delete, left to archive. We&#8217;ve already associated swipe right with delete pretty much everywhere, let&#8217;s take new completely different behavior and put it somewhere else instead of replacing things.</p>
<h3>Annoying Tidbits</h3>
<ul>
<li>Why is there a delay in opening a folder?</li>
<li>Still no bulk delete in MMS.</li>
<li>Safari, maybe I don&#8217;t <strong>want</strong> to go to something in my bookmarks if I don&#8217;t have an open page.</li>
</ul>
<h3>Conclusion</h3>
<p>Generally speaking, I&#8217;m quite happy with iOS4 and do not wish to go back to iOS3. As I said before though, this has just been about the bad.</p>
<p>Apple seems to have no regard for previous user expectations, which I find very disturbing. I don&#8217;t have the total sales numbers for iPhones previous to iPhone 4, but <a title="77% of iPhone 4 sales were upgrades" href="http://tech.fortune.cnn.com/2010/06/25/77-of-iphone-4-sales-were-upgrades/">this helps put it in perspective</a>. The thing is, when you have something that works and works well, there&#8217;s likely not a good enough justification for changing it. It&#8217;s only when expectations of users is to be frustrated, or for the feature to not even work, that it&#8217;s OK to go ahead and gut the feature.</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/code-monkey-vs-ios4/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Code Monkey vs. Antennagate Press Conference</title>
		<link>http://ermau.com/code-monkey-vs-antennagate-press-conference/</link>
		<comments>http://ermau.com/code-monkey-vs-antennagate-press-conference/#comments</comments>
		<pubDate>Mon, 19 Jul 2010 04:26:29 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[Rant]]></category>
		<category><![CDATA[apple]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[rant]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=83</guid>
		<description><![CDATA[I am honestly appalled at Apple, not that I wasn&#8217;t already. So much of their &#8220;hard data&#8221; is easily defeated by a simple explanation that it makes me wonder if people will be gullible enough to become apologists regurgitating their &#8230; <a href="http://ermau.com/code-monkey-vs-antennagate-press-conference/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I am honestly appalled at Apple, not that I wasn&#8217;t already. So much of their &#8220;hard data&#8221; is easily defeated by a simple explanation that it makes me wonder if people will be gullible enough to become apologists regurgitating their &#8220;hard data&#8221; as an excuse. It&#8217;s not even an explanation, it&#8217;s nothing but downplay with some numbers that sound impressive on their face. I was dissapointed (but not surprised) to hear nothing about the glass being more easily scratchable. I&#8217;m more worried about the glass, since there&#8217;s no workaround once it scratches, than the reception.</p>
<p>So first off, playing that YouTube video is not cute, it&#8217;s arrogant and offensive. While logically correct from a customer&#8217;s stand point, &#8220;don&#8217;t buy one or take it back&#8221; is hardly a &#8220;we love our customers&#8221; approach and certainly not something I want to hear from the product&#8217;s company. Customers have voiced a legitimate concern, and Apple has simply shrugged.</p>
<h3>&#8220;Hard Data&#8221;</h3>
<p>In the press conference, Jobs liked to keep coming back to sarcastically stating that because of the sheer amount of coverage this issue has received, it must be on a grande scale. After each reiteration, he mentions some very low number as the counter. Here&#8217;s the thing about Web 2.0, Steve: All the coverage <strong>is</strong> people complaining. Post after post, comment after comment, video after video, people <strong>are</strong> complaining in large numbers. Simply because they do not go through methods you can track, doesn&#8217;t mean the outcry isn&#8217;t there.</p>
<p>The percentage of iPhone 4 users who have called into AppleCare about the antenna or reception is reported to be 0.55%. For once, I&#8217;m glad Job&#8217;s took the time to share the current sales numbers with us: 3M iPhone 4s sold. 0.55% of 3M is <strong>16,500</strong> and that&#8217;s just the people who&#8217;ve bothered to contact support. I&#8217;m not sure what land Apple lives in, but 16,500 is a lot of people, especially given that out of the users experiencing a problem, only a fraction of those experiencing it will ever bother to complain about it. Many others, like myself, knew of the issue and were simply awaiting Apple&#8217;s public response.</p>
<p>Low return rates is easily explained by the fact that many have been waiting to see what Apple would do. Seeing if they&#8217;d eventually give away cases, have some form of recall, or if some software fix would correct the problem. On top of this, you have the 3G users like me who&#8217;ve been waiting for a newer faster device and are willing to put up with this to get the rest. &#8220;Put up with&#8221; is not something you really want your customers associating with your product. Where&#8217;s the &#8220;hard data&#8221; on customer annoyance?</p>
<p>Call drop rates are again easily explained and are just as troubling. Many reviews point to the iPhone 4 not dropping calls in areas their 3G or 3GS previously did. So, if it&#8217;s actually not dropping the same calls as before, and the delta is only between 0-1, wouldn&#8217;t that imply that dropping calls from this new issue is more than a &lt;1 delta? On top of this, people know about the issue and have begun (well, at least I have) holding their phone in less comfortable manners to ensure that we don&#8217;t drop the call. Where&#8217;s the &#8220;hard data&#8221; on hand comfort throughout calls? Admittedly, the lack of case theory may affect the numbers, but all this does is imply to me that a case is required.. which I have never wanted and shouldn&#8217;t be forced into.</p>
<h3>&#8220;Perspective&#8221;</h3>
<p>&#8220;.. but this does put it in perspective.&#8221; In your reality distortion field, maybe. The numbers cited sound great, until you actually stop and think about them. Job&#8217;s attitude throughout the presentation was dismissive and arrogant, which does put things into perspective.</p>
<p>All this being said, as far as the antenna issue itself goes, the free case solution is a good one. $29.99 was absurd for what the Bumper really was. Kudos to Apple for even going further and including other cases to ensure quantity, although I should probably wait until we see what the other selections are. The refund date, however, should have been extended for those waiting to see what Apple was going to do.</p>
<p>Yes, Apple made it extremely visible both in the bars issue and in where the spot to kill the signal is. However, what I would like to see if there&#8217;s any one spot on these other phones that you can kill the signal with a single finger. Somehow, I doubt it, but I certainly can on the iPhone 4 and <strong>that</strong> is why it&#8217;s still a bigger issue than with the other phones.</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/code-monkey-vs-antennagate-press-conference/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Code Monkey vs. iPhone 4</title>
		<link>http://ermau.com/code-monkey-vs-iphone-4/</link>
		<comments>http://ermau.com/code-monkey-vs-iphone-4/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 18:23:32 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[Rant]]></category>
		<category><![CDATA[UX]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[ux]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=17</guid>
		<description><![CDATA[I have one and I hate it just as much as I love it. I find that I can actually do what I want in a reasonable amount of time and minimal frustration due to the sheer speed and general &#8230; <a href="http://ermau.com/code-monkey-vs-iphone-4/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I have one and I hate it just as much as I love it. I find that I can actually do what I want in a reasonable amount of time and minimal frustration due to the sheer speed and general responsiveness of the device. Yet I find myself generally less happy with it than I was with my iPhone 3G when I got it. To have come this far, it&#8217;s sad to see how far Apple has fallen with this device.</p>
<p>Now, there&#8217;s been plenty of coverage on the various issues, many of which I feel completely miss the mark (that&#8217;s what we get for enabling everyone to have global soap boxes I guess). Some get close, but over complicate the issues with speculation that bring about more debate than consensus. I only plan to focus on what&#8217;s wrong, hardware wise; I&#8217;ll write about iOS4 separately.</p>
<h3>Comfort</h3>
<p>Awkward ways to hold the phone to get a signal aside, this is by far the most uncomfortable iPhone yet. Sure, it looks beautiful, but as a smart phone comfort should be on the top of the list. The iPhone has reached a point where thinner is not better, it doesn&#8217;t help consumers at this point and it only makes manufacturing and design that much harder. No one was really crying for a thinner iPhone, because the larger curved back was already comfortable. This new thinner design only makes it harder and more painful to hold on to, having to bring your fingers farther in, bending them even more. Honestly it reminds me greatly of the original NES controllers, turning your hands into painful fixed claws.</p>
<p>To add another to the &#8216;curved was better&#8217; category, the new sides are just downright painful. Especially when it comes to certain games, the sides actually become painful because the steel band is not the same thickness as the phone. This leaves a nice little crevice on either side of the band that your finger gets pushed into and it doesn&#8217;t take very long before this starts to hurt. I suppose I should just &#8216;avoid holding it that way&#8217;, but if we keep adding ways to hold it to the &#8216;avoid&#8217; list, I&#8217;m not going to be able to hold this thing at all.</p>
<p>There&#8217;s no doubt that the iPhone 4 looks and feels very solid and precise. The iPhone 3G / 3GS look like toys with their plastic parts in comparison. However, even with their slightly weaker feeling due to the plastic, there&#8217;s a comfort and solidity from the full curved back that fits more naturally into my hand. Being larger and filling your hand gives you a greater sense of having a good solid grip on the phone. If I could take the 4&#8242;s guts and stick them in a 3G case, I&#8217;d do it without hesitation.</p>
<h3>Glass</h3>
<p>I&#8217;ve had my iPhone 3G since the day after launch (2 years), it&#8217;s never worn a case and I just toss it in my pocket with my wallet. The plastic back is scratched up like crazy, but I&#8217;ve never really cared about that. The glass, however, only has a few minor scratches on the top and bottom, none through the screen. My iPhone 4 has more scratches all over its front glass in the two weeks than I&#8217;ve had it (treated exactly the same) than my 3G does. Think about that for a second, more scratches in two weeks than in two years. For what gain, exactly?</p>
<p>My guess is that it has something to do with the fact that they&#8217;re laminating the screen and glass together. There&#8217;s no doubt even just the lack of a gap between the glass and screen looks significantly better, but at what cost? Is it going to matter if there&#8217;s a gap or not when the screen is so covered in scratches that I can&#8217;t hardly use the device? Only time will tell, but my spidey sense tells me the answer is &#8216;no&#8217;.</p>
<p>Now, to be fair, the scratches are basically invisible while the screen is on but I wonder how long that will last as they accumulate. I think there&#8217;s a definite case for false advertising here; Apple&#8217;s own web page says &#8220;&#8230; the glass is ultradurable and more scratch resistant than ever&#8221;. <strong>More</strong> scratch resistant?! I&#8217;d have been perfectly happy if it was <strong>as</strong> scratch resistant as my 3G, but as it&#8217;s been demonstrated all over the web (and in my personal experience), it&#8217;s actually significantly <strong>worse</strong>.</p>
<h3>Antenna</h3>
<p>I have a hard time expressing just how ridiculous and unfathomable the whole ordeal has been. Speculation abounds, but I lack such guesses because I am completely dumbfounded. Suffice to say, Apple has lost my respect over this issue alone, let alone everything else that&#8217;s wrong with this device. I, personally, experience the death grip and it&#8217;s no exaggeration and it&#8217;s not simply that the bars are wrong. Web page loading can be paused and continued at will repeatedly just by touching and releasing a specific spot on the phone.</p>
<p>There&#8217;s been a lot of commenting about this being an issue for left handed people. Here&#8217;s the thing, this issue affects data just as much as phone calls. This means that when holding it in my left hand to touch and interact with using my right hand, that wonderful spot of death is firmly cupped in my hand. It&#8217;s not specific to just holding it in a way that you&#8217;d make a phone call. Please stop saying Apple hates lefties, it&#8217;s obvious Apple hates us all equally.</p>
<p>The absurdity of all this is mind boggling, despite the fact that some signal attenuation may happen with any cell phone, including previous iPhones. The simplest solution, even with the current overall design, would be to move the &#8216;death point&#8217; to the right side. You&#8217;re moving it from what&#8217;s always going to hit the palm, greatly increasing the chances that it&#8217;ll be bridged, to the side where only your fingers are present which would be far less likely to be bridged. During a right handed phone call (at least in my hands), I&#8217;m not cupping that gap, my thumb rises over and latches the right side of the phone.</p>
<p>Although Apple claims that there are no real issues beyond what affects a normal cell phone and says that a lot of the confusion stems from a bug in the software, I&#8217;m calling bullshit. For me, it doesn&#8217;t just degrade the signal, it removes it completely. Data transfers stop dead in their tracks, even simple webpages won&#8217;t continue loading. I wish I had a 3GS or something to record it, but I&#8217;ve paused web page loads multiple times in the same load just by pressing the &#8216;death point&#8217;. To be fair, I have seen some cases where I had to use more than finger to interrupt it, giving credence to the idea that it is actually just extreme attenuation.</p>
<p>However, other cell phones don&#8217;t put the antenna in the best possible place to be blocked/shorted/whatever is going on. They don&#8217;t take the most comfortable way to hold the phone and tell you not to just &#8220;avoid holding it that way&#8221; or to buy a case (for which they sell an insanely overpriced piece of plastic). Besides the cases meant to clip to a belt, who actually bought a case for their cell phone pre-smart phone? Nearly no one, so why is this different?</p>
<p>The response has varied wildly, anywhere from &#8220;calm down, buy a case and enjoy your iPhone&#8221; all the way to lawsuits. The expectation of us to buy a case just to be able to hold our phone in a comfortable manner and still have it work is just absurd, given what we&#8217;re already paying for it. What&#8217;s worse has been Apple&#8217;s-and Steve Jobs&#8217;, if email postings are to be believed-response to the whole ordeal. If this was such a nonissue that was present in old phones, there wouldn&#8217;t be a such a sudden and huge outcry over it, so downplaying and dismissing the issue is just an insult to Apple&#8217;s customers.</p>
<p>Apple should at least acknowledge that the design of the iPhone 4 does, in fact, make it easier to significantly drop a signal just by holding it. They really should be handing out free bumpers to appease customers, as they&#8217;re certainly not worth $29, and even more so would be worth the hit to help curb the large amount of negative press they&#8217;re getting.</p>
<h3>The Bad</h3>
<p>In a time where Android is starting to come under fire, this should of been the perfect time to surge ahead in positive mindshare. Instead, they&#8217;ve made several wrong turns with a phone that iPhone 3G customers have been waiting for every since they saw how fast the 3GS was. Now these customers are stuck, sure they could return their phones, but after seeing the beautiful display and just how fast it is, it&#8217;s unlikely they&#8217;ll do anything of the sort. On top of this, they&#8217;ve dismissed and insulted customers without so much as an olive branch.</p>
<p>I&#8217;ve always had a hate-love relationship with Apple, but this whole ordeal has left me bitter and hateful of Apple. The iPhone 4 now has, at least among the tech-informed (you know, the guys who recommend devices to the non-tech informed), a negative mindshare. It&#8217;s full of problems, and the Android users are sitting back and laughing with their relatively minor issues in comparison.</p>
<p>I will likely end up with a case to protect the antenna and glass, and hopefully round out the back some for more comfort. The fact that I now actually feel that I have to buy a case is, in my opinion, a complete failure on Apple&#8217;s part. It&#8217;s fragile and uncomfortable, a terrible combination if you want to keep something intact and not piss off your customers.</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/code-monkey-vs-iphone-4/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Code Monkey vs. Asynchronous Lists</title>
		<link>http://ermau.com/code-monkey-vs-asynchronous-lists/</link>
		<comments>http://ermau.com/code-monkey-vs-asynchronous-lists/#comments</comments>
		<pubDate>Mon, 28 Jun 2010 02:10:15 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[Rant]]></category>
		<category><![CDATA[UX]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[steam]]></category>
		<category><![CDATA[ux]]></category>
		<category><![CDATA[vs2010]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=23</guid>
		<description><![CDATA[I guess the theory is that a list that starts displaying its results immediately will allow the user to get to what they&#8217;re looking for quicker. The problem is that most of the time this couldn&#8217;t be farther from the &#8230; <a href="http://ermau.com/code-monkey-vs-asynchronous-lists/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I guess the theory is that a list that starts displaying its results immediately will allow the user to get to what they&#8217;re looking for quicker. The problem is that most of the time this couldn&#8217;t be farther from the truth.</p>
<div id="attachment_34" class="wp-caption alignnone" style="width: 521px"><a href="http://ermau.com/wp-content/uploads/2010/06/steamlist.png"><img class="size-full wp-image-34 " title="Steam's &quot;Add a Game List&quot;" src="http://ermau.com/wp-content/uploads/2010/06/steamlist.png" alt="Steam's &quot;Add a Game List&quot;" width="511" height="312" /></a><p class="wp-caption-text">Steam&#39;s &quot;Add a Game list&quot; dialog</p></div>
<p>When you open this, you already know what you&#8217;re looking for. The list is sorted alphabetically, so you start to scroll down to the letter the game starts with. However the list only serves to frustrate because it doesn&#8217;t actually load alphabetically, so when you find the letter you&#8217;re surprised to find that your game isn&#8217;t listed. You&#8217;re not given any indication that the list is still loading, so is the game just not going to be listed? Or has the dialog simply not gotten around to loading it yet?</p>
<p>The fun continues when the game finally shows up. Now that you see the game listed you go to select it so you can move on, no need for the list to finish loading, right? Just as you go to click on the item you were looking for, it moves clear out of view since something was just added many items up somewhere you don&#8217;t see or care about. Thus begins a game of cat and mouse trying to find and select your game before it moves out of view again. You could just give up in frustration and just wait for the list to load, but since the only indication you have is less reliable than listening for popcorn to finish popping, it&#8217;s equally frustrating as the cat and mouse.</p>
<p>Worse still, this design tricks users into trying to find what they&#8217;re looking immediately for because there&#8217;s items in the list to look through. Our interactions with computers are very action-reaction oriented, we issue a command and wait for the computer to respond. With this list, the computer starts to respond immediately, so we&#8217;re prompted to issue our next command prematurely and no one likes being premature.</p>
<p>This experience is the same for the .NET tab of the Add Reference dialog for Visual Studio 2010, as well as that of the &#8220;Programs and Features&#8221; list of Windows Vista and 7.  Someone, please tell me how this is preferable to simply waiting a second or two and then finding your item in a nice alphabetically sorted list. It usually takes no more time, and is significantly less frustrating. At the very least, provide some form of loading indicator so the user knows for sure when the least is complete. Otherwise you&#8217;re only pissing off your users and earning your place in my Hall of Shame.</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/code-monkey-vs-asynchronous-lists/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Code Monkey vs. Introductions</title>
		<link>http://ermau.com/code-monkey-vs-introductions/</link>
		<comments>http://ermau.com/code-monkey-vs-introductions/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 00:24:21 +0000</pubDate>
		<dc:creator>ermau</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://ermau.com/?p=5</guid>
		<description><![CDATA[I&#8217;m constantly told, once I complete some rant, that I should write it down and share it with the world. I&#8217;ve tried this before many a time and eventually ran out of things to say. Almost every time, I&#8217;ve written &#8230; <a href="http://ermau.com/code-monkey-vs-introductions/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m constantly told, once I complete some rant, that I should write it down and share it with the world. I&#8217;ve tried this before many a time and eventually ran out of things to say. Almost every time, I&#8217;ve written one of these introductions saying that I&#8217;ve tried this before too. I suppose this would classify me as insane, but it&#8217;s not like I&#8217;ve ever been accused of being sane in the first place.</p>
<p>I suspect I have a bit of a reputation of a harsh critic, or perhaps of a bitchy whiner, I&#8217;m not really sure which. Hopefully I will come across as the former, as that&#8217;s primarily my purpose here. I intend to do reviews of games, software, and tech in general. Expect spoilers when it comes to games, or movies if I go there. We&#8217;ll see how it goes.</p>
]]></content:encoded>
			<wfw:commentRss>http://ermau.com/code-monkey-vs-introductions/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

