Benchmarks, comments and forum posts have been circulating over past week concerning the quality and speed of Valve’s Mac Steam digital distribution client. Many users seem frustrated, some confused, and others even exclaim the superiority of Windows as an operating system. At the heart of this is the issue that porting an application from Windows to the Mac OS (Snow Leopard) is very difficult.
At imVOX, we’ve been working for several months on such a port of our voice communications platform from Windows to Mac. It hasn’t been as easy as we had hoped. We’re a small company and our expertise is firmly in the Windows platform. While we have very talented individuals I don’t think any of us had fully developed a Mac application prior, and certainly not one of this complexity. I’d like to share a bit of what made this far harder than we anticipated.
A few points first however: I am not the lead PM, nor am I a developer by trade. I’m a Director of Marketing who happens to be able to code in Ruby. Other people at imVOX are writing the code- not me. I’m just writing this blog post. Also, like I said in the prior paragraph, we are n00bs to developing on the Mac. There are likely several things were did wrong that a Mac ninja wouldn’t have run into. These are our experiences. Advice, ideas and offers to help are welcome.
Mono Makes it Easy- Right?
Our Windows client was written in Microsoft’s .NET 2.0 with C#. While .NET exists only on Windows there is an open source technology called Mono that allows for cross-platform .NET development, in theory making it possible to reuse most of our .NET code to create a Mac (and potentially even Linux) client. We put our code through the Mono Migration Analyzer and things looked generally good. This lead us to belief that this process would be smooth sailing, taking no more than a month at most.
The main idea here was to be able to have one set of code that we were using. No major forks/divisions in the code and reusing almost everything. That would make it easier, cheaper and faster right? Right…?
Workflow Woes
Around the same time as we were starting heavy work on the Mac client we made some other changes to our workflow. We moved from Microsoft’s aging Visual Source Safe to Git. We tried using Github at first, but then shortly after moved to our own self-hosted Git server. For Windows-centric developers who were used to having controls in Visual Studio that integrated with VSS, this was a bit of a stumbling block. Git isn’t hard, but if you’ve been building software for 5+ years using a centralized repo it certainly is a change.
Our developers were still using Visual Studio to develop the Mac software, instead of working in XCode. This required us having a Mac and a PC in front of each developer. I’m honestly not sure why we’re doing this, aside from our developers being deeply familiar and comfortable with Visual Studio as their development environment. If I had to write a Windows piece of software, I’d probably be using TextMate and doing the inverse myself so I can’t blame them.
Everyone had lots to learn. New tools, new ways of debugging crashes and just understanding the OS at a reasonably deep level took some time.
Interfaces
Our Windows interface was written using .NET forms. It was highly Windows-like and also was made to look very ‘gamer’ oriented. This had a few problems. First, the interface barely worked on the Mac. We were doing all sorts of things for transparency, collapsable areas, and to draw the screen overall. When they did work, it was slow and buggy. Debugging these was slow and tedious. Things just didn’t seem right.
After much effort, we decided to go with a native Mac interface instead using Interface Builder. We used MonoObjC as an Objective C to .NET/C# bridge. Thankfully Steve Jobs hasn’t gotten around to killing all translation middleware on the Mac itself (yet). This worked well overall and made our workflow much more manageable. Now myself or our graphic designer could easily check the most recent build out of Git, open up the interface in Interface Builder and rearrange things as needed without breaking anything. Overall MonoObjC was a great idea that I wish we had known about from day 1.
Developing an interface for the Mac however presents several interesting problems. Do you try to keep the exact same interface that you had on Windows for consistency? That pisses off Mac owners due to all the Window-isms present. But if you make a totally native UI you now have a lack of consistency between products. For games, this is less of an issue, but for a piece of desktop software your users notice either way.
If we were writing both Windows and Mac software again from day 1, I suppose we could have gone with a cross-platform interface solution like QT (or just used Java), but I still feel as though we would have been missing something on a usability level.
Feature Parity
One of our major goals from the outset has been to achieve complete feature parity between the Windows and Mac applications when possible. This has been a lot harder than we anticipated. We aren’t far off, but this doesn’t happen automatically for sure. Our main competitor Ventrilo does a rather poor job of this and we’d like to do better. With the next (still beta) release we’ll be missing a few things but we will catch up on that soon. I’d rather release early, release often than wait forever.
Audio and Network
Our program is mainly about voice chat, and obviously deals quite heavily on the audio layer. Since we are transmitting over the network it gets a little more complex with various codecs, echo cancelers and other gremlins.
To begin, audio on the Mac is totally different than audio on the PC side to a degree that I won’t even elaborate. We were using a proprietary licensed codec on the Windows side, but the cost for the Mac was prohibitive (and the quality/flexibility wasn’t what we wanted). Temporarily we’re using a PCMU codec until we can implement SILK/CELT on our servers. We had an echo canceler licensed from the same people on the Windows side so we had to rewrite our own on the Mac side. Our still isn’t perfect, but we’ve implemented an Audio Units chain as to get consistent and stable timing across the board (allowing for inverting of waves to cancel echo). That took quite a bit of time.
Push to Talk and Keyboard Access
Steam users have commented on the setup procedure of their Mac client being less than perfectly smooth. It requires you going to Universal Access under your System Preferences and enabling access for assistive devices in order to get the overlay to work. Guess what? We do the same thing. It isn’t because Valve (or our) programmers are lazy, but rather has to do with how Apple has protected the keyboard on a security level. I don’t know if I’d call it great security, but it certainly is a setting that 99% of users don’t toggle or are aware of.
Accessing keystrokes from an application when another application is focused is rather difficult under OS X and requires some trickery. It ended up that we had to write a separate driver (launches when imVOX does) that intercepts all keystrokes and then passes them back out to their original destination. As you’d imagine, this is roughly the same technique that a keyloggerwould do, and we’ve taken precautions to make sure that nothing is being logged, recorded or stored. This is why Apple doesn’t turn on assistive devices automatically. In our estimate, Valve is doing the exact same thing with Steam so this isn’t an uncommon technique. Should anyone have a better idea, please let us know. We’ve been ripping our hair out over this one.
Odds and Ends
We’ve got a bit more to do on the Mac to make it really Mac-like. We need to write help files that are specific to the Mac. More testing is needed overall. We have a TON of conditional statements in our code now checking if we are running the Mac or PC version. Shortcuts need to be polished. Installation process is far different from the PC. The way we built the application is also different (using nant or Xcode).
Final Thoughts
We thought this would be a simple process. Unfortunately we got bit by our lack of expertise, interface issues and the 1-10-100 rule. Anyone critiquing Valve for their results so far on Steam/Portal should remember that they’ve been at this for several years on the Windows side and programming on the Mac is different.
Even using something like Mono does not make for an easy transition unless your application is dead simple. Also using Mono holds you back a bit for your Windows development. Using .NET 4.0 or Expression Studio will force you to split your code even moreso. I think the best way around this is to create a few shared libraries, and build everything else natively on each OS from the beginning. Sounds harder, but it will probably serve you better in the long term.


