Kirsle.net logo Kirsle.net

Tagged as: Apple

Journey to get WebRTC working well in Safari
May 9, 2024 by Noah

A while back (February 2023) I built an open source webcam chat room for one of my side project websites.

It was very much designed to resemble those classic, old school Adobe Flash based webcam chat rooms: where it is first and foremost a text based chat (with public channels and private messages), and where some people could go on webcam and they could be watched by other people in the chat room, in an asynchronous manner.

It didn't take terribly long to get the chat room basically up and running, and working well, for browsers such as Chrome and Firefox - but it was a whole other story to get it to work as well for Apple's web browsers: Safari, and iPads and iPhones.

This blog post will recount the last ~year and change of efforts to get Safari to behave nicely with my chat room, and the challenges faced and lessons learned along the way.

Screenshot of BareRTC

Description of the chat room's features

First, it will be helpful to describe the basic features of the chat room and how I designed it to work, to set some context to the Safari specific challenges I faced along the way.

  • Users can choose to turn on their webcam and microphone and allow others on the chat room to watch them.
  • Users who are not on camera themselves are able to passively watch those who are (receive-only video streaming).
  • A pair of users who are both on camera are able to watch each other's videos if they want (two-way video streaming).
  • Each user can decide which cameras they want to watch - it is 'asynchronous' meaning the calls don't need to be two-way, and users can watch each other in any combination available.

There are a few other features on top of these, but the above are the basic fundamentals that are relevant to this story about getting this all to work on Safari.

The additional features include:

  • If a user isn't comfortable with their camera being watched by somebody who isn't sharing their own camera, they can restrict it and make their cam only available to people sharing their own too (so that they could have a chance to open your camera in return and see what you look like as well).
  • And there's an option for "when somebody opens my camera, I'll also open their camera automatically" - so if somebody who is on webcam clicks to see yours, their camera too will appear on your screen, making it an instant two-way call without you needing to separately open their camera back.

WebRTC Crash Course

The underlying web browser standard that allows videos to be shared at all is called WebRTC, which stands for "Web Real Time Communication." It is supported in all major web browsers, including Safari, but the devil is in the details.

WebRTC basically enables two web browsers to connect to each other, directly peer-to-peer, and exchange data (usually, video and audio data but any kind of data is possible). It can get two browsers to connect even when both sides of the connection are behind firewalls or behind a NAT (as 99% of regular home Internet users are).

For my chat room, it means that webcam data is sent directly between the chat users and none of it needs to pass through my server (which could be expensive for me to pay for all that bandwidth!).

It's a rather complex, and poorly documented, system but for the sake of this blog post, I will try and distill it down to its bare essence. The following is massively simplified, but if curious to dive in to the weeds on it, the best resource I found online is this free e-book: WebRTC for the Curious.

How WebRTC Basically Works

When two users are logged on to my chat room, and one wants to open the other's camera, the basic ingredients that make the WebRTC magic work includes:

  1. You need a signaling server which is just any server that's able to pass messages back and forth between the two parties, so that they can communicate and negotiate how they'll directly connect to each other.
  2. With the signaling server available, the two clients will pass messages back and forth to negotiate their connection.
    • You don't need to worry too much about this part: the web browsers know what they're talking about and they speak their own language, all your signaling server needs to do is pass these messages along.
    • The two important message types are Session Description Protocol (SDP) where the clients negotiate the features they want (video, audio, codecs support, etc.), and ICE Candidate messages where they negotiate how they'll connect to each other.
  3. The two browsers establish a direct connection between themselves, with possibly video and audio channels enabled through which they can transmit data: the video call can be established.

Signaling Server

The signaling server in WebRTC is much simpler than it sounds: it is really just any server you write which is capable of passing messages along, back and forth between the two parties who want to connect. It could be a WebSocket server, it could be based on AJAX requests to a PHP script, it could even be printed out on a post card and delivered by snail mail (though that way would take the longest).

For my chat room's use case, I already had a signaling server to use: my WebSockets server that drives the rest of the chat room.

The server side of the chat room was a WebSockets server, where users would post their chat messages and the server would broadcast those back out to everybody else, and the server would push "Who's Online" list updates, etc. - so I just added support for this same WebSockets server to allow forwarding WebRTC negotiation messages between the two users.

Terminology: Offerer and Answerer

There are a couple of important terms used in WebRTC that are not super intuitive at first glance.

The two parties of a WebRTC connection are named the Offerer and the Answerer.

  • The Offerer is the one who first decides to initiate the connection. They are "offering to connect" to the other user.
    • On my chat room: this is the person who clicked the button to open your webcam.
  • The Answerer is the other person: they see your offer to connect and they answer it.
    • On my chat room: the answerer is the one whose webcam is active.

Both the Offerer and the Answerer are able to attach data channels to their side of the connection. Most obviously, the Answerer will attach their active webcam feed to the connection, so that the Offerer (who wanted to watch it) is able to receive it and show it on their screen.

The Offerer is also able to attach their own camera to that opening connection, as well, and their video data will be received automatically on the Answerer's side once the connection is established. But, more on that below.

Things learned during the earliest prototype

So, going back to the original design goals of my chat room above, I wanted video sharing to be "asynchronous": it must be possible for Alice, who is not sharing her video, to be able to watch Bob's video in a one-directional manner.

The first interesting thing I learned about WebRTC was that this initially was not working!

  • When Alice created her offer to connect to Bob, she didn't request video or audio channels to be opened, because she was not sharing a video stream of her own on that connection.
    • So, even though Bob did add his video stream to his answer, Alice did not receive it because she didn't negotiate for those channels to be available.
  • However, if Alice turned her webcam on and she attached her video feed to the offer, then those channels were opened (because she would be using them herself), and she did receive Bob's video correctly then.
    • As a very interesting quirk: when this happened, Alice's video automatically opened on Bob's screen as well! Bob did not click to see Alice's video, and yet her video opened itself anyway, because Alice sent her video during the initial offer!

So the conundrum at first, was this: I wanted Alice to be able to receive video, without sharing her own video.

I found that I could do this by setting these parameters on the initial offer that she creates:

pc.createOffer({
    offerToReceiveVideo: true,
    offerToReceiveAudio: true,
});

Then Alice will offer to receive video/audio channels despite not sharing any herself, and this worked OK.

But, I came to find out that this did not work with Safari, but only for Chrome and Firefox!

I learned that there were actually two major iterations of the WebRTC API, and the above hack was only supported by the old, legacy version. Chrome and Firefox were there for that version, so they still support the legacy option, but Safari came later to the game and Safari only implemented the modern WebRTC API, which caused me some problems that I'll get into below.

Safari Problems

So, in February 2023 I officially launched my chat room and it worked perfectly on Firefox, Google Chrome, and every other Chromium based browser in the world (such as MS Edge, Opera, Brave, etc.) - asynchronous webcam connections were working fine, people were able to watch a webcam without needing to share a webcam, because Firefox and Chromium supported the legacy WebRTC API where the above findings were all supported and working well.

But then, there was Safari.

Safari showed a handful of weird quirks, differences and limitations compared to Chrome and Firefox, and the worst part about trying to debug any of this, was that I did not own any Apple device on which I could test Safari and see about getting it to work. All I could do was read online (WebRTC stuff is poorly documented, and there's a lot of inaccurate and outdated information online), blindly try a couple of things, and ask some of my Apple-using friends to test once in a while to see if anything worked.

Slowly, I made some progress here and there and I'll describe what I found.

First, Safari couldn't log into my chat room AT ALL

The first problem with Safari wasn't even about WebRTC yet! Safari did not like my WebSockets server for my chat room.

What I saw when a Safari user tried to connect was: they would connect to the WebSockets server, send their "has entered the room" message, and the chat server would send Safari all the welcome messages (listing the rules of the chat room, etc.), and it would send Safari the "Who's Online" list of current chatters, and... Safari would immediately close the connection and disconnect.

Only to try and reconnect a few seconds later (since the chat web page was programmed to retry the connection a few times). The rest of the chatters online would see the Safari user join/leave, join/leave, join/leave before their chat page gave up trying to connect.

The resolution to this problem turned out to be: Safari did not support compression for WebSockets. The WebSockets library I was using had compression enabled by default. Through some experimentation, I found that if I removed all the server welcome messages and needless "spam", that Safari was able to connect and stay logged on -- however, if I sent a 'long' chat message (of only 500 characters or so), it would cause Safari to disconnect.

The root cause came down to: Safari didn't support WebSocket compression, so I needed to disable compression and then Safari could log on and hang out fine.

So, finally on to the WebRTC parts.

Safari supports only the New WebRTC API

Safari browsers were able to log on to chat now, but the WebRTC stuff simply was not working at all. The Safari user was able to activate their webcam, and they could see their own local video feed on their page, but this part didn't involve WebRTC yet (it was just the Web Media API, accessing their webcam and displaying it in a <video> element on the page). But in my chat room, the Safari user was able to tell the server: "my webcam is on!", and other users would see a clickable video button on the Who List, but when they tried to connect to watch it, nothing happened.

So, as touched on above, WebRTC is an old standard and it had actually gone through two major revisions. Chrome and Firefox were there for both, and they continue to support both versions, but Safari was newer to the game and they only implemented the modern version.

The biggest difference between the old and new API is that functions changed from "callback based" into "promise based", e.g.:

// Old API would have callback functions sent as parameters
pc.setLocalDescription(description, onSuccess, onFailure);

// New API moved to use Promises (".then functions") instead of callback functions
pc.setLocalDescription(description).then(onSuccess).catch(onFailure);

The WebRTC stuff for Safari wasn't working because I needed to change these function calls to be Promise-based instead of the legacy callback function style.

Then, cameras could "sometimes" connect in Safari

By updating to the modern WebRTC API, Safari browsers could sometimes get cameras to connect, but only under some very precise circumstances:

  1. First, the Safari browser needed to turn its own local webcam on.
  2. Then, the Safari browser could sometimes connect to somebody else's camera, but only if that person had the option enabled "When somebody opens my camera, I also open their camera automatically."

This was rather inconvenient and confusing to users, though: the Safari user was never able to passively watch somebody else's camera without their own camera being on, but even when they turned their camera on first, they could only open about half of the other cameras on chat (only the users who wanted to auto-open Safari's camera in return).

This was due to a couple of fundamental issues:

  1. The option to set up a receive-only video offer was only available in the legacy WebRTC API (that offerToReceiveVideo: true option), which Safari did not support.
    • So the only way for Safari, as the offerer, could get a video channel open was by offering its own local video on that connection as well.
  2. However, by offering Safari's local video, it would force that video to open on the other person's screen. This is why I needed to limit it to only people who wanted to automatically open Safari's video, so that it appearing on their screen is expected behavior for them.

For a while, this was the status quo. Users on an iPad or iPhone were encouraged to try switching to a laptop or desktop PC and to use a browser other than Safari if they could.

And only if Safari initiated the connection

There was another bug on my chat room at this point, too: the Safari browser had to be the one to initiate the WebRTC connection for anything to work at all. If somebody else were to click to view Safari's camera, nothing would happen and the connection attempt would time out and show an error.

This one, I found out later, was due to the same "callback-based vs. promise-based" API for WebRTC: I had missed a spot before! The code path where Safari is the answerer and it tries to respond with its SDP message was using the legacy API and so wasn't doing anything, and not giving any error messages to the console either!

Safari only supported two-way video calls?

At this stage, I still had no access to an Apple device to actually test on, so the best I could do was read outdated and inaccurate information online. It seems the subset of software developers who actually work with WebRTC at this low of a level are exceedingly rare (and are all employed by large shops like Zoom who make heavy use of this stuff).

I had found this amazing resource called Guide to WebRTC with Safari in the Wild which documented a lot of Safari's unique quirks regarding WebRTC.

A point I read there was that Safari only supported two-way video calls, where both sides of the connection are needing to exchange video. I thought this would be a hard blocker for me, at the end of the day, and would fly in the face of my "asynchronous webcam support" I wanted of my chat room.

So the above quirky limitations: where Safari needed to have its own camera running, and it needed to attach it on the outgoing WebRTC offer, seemed to be unmoveable truths that I would have to just live with.

And indeed: since Safari didn't support offerToReceiveVideo: true to set up a receive-only video channel, and there was no documentation on what the modern alternative to that option should be, this was seeming to be the case.

But, it turned out even that was outdated misinformation!

A hack to allow Safari to "receive-only" videos from others

Seeing what Safari's limitations appeared to be, in my chat room I attempted a sort of hack, that I called "Apple compatibility mode".

It seemed that the only way Safari could receive video, was to offer its own video on the WebRTC connection. But I wanted Safari to at least, be able to passively watch somebody's camera without needing to send its own video to them too. But if Safari pushed its video on the connection, it would auto-open on the other person's screen!

My hacky solution was to do this:

  • If you (on Firefox) are on webcam, and you do not want to auto-open your viewer's videos, but your viewer gave you a video stream anyway: your page would just ignore their video, and not show it on your screen.
  • For Safari users, then: when they click to watch your video, they would always offer their local video too, so that from Safari's perspective, it was a "two-way video call:" Safari is sending video (which you ignore), and it receives your video in exchange.

But, this is obviously wasteful of everyone's bandwidth, to have Safari stream video out that is just being ignored. So the chat room would only enable this behavior if it detected you were using a Safari browser, or were on an iPad or iPhone, so at least not everybody was sending video wastefully all the time.

And then I bought a Macbook Air

Recently, I broke my old laptop on accident when I spilled a full cup of coffee over its keyboard, and when weighing my options for a replacement PC, I decided to go with a modern Macbook Air with the Apple Silicon M3 chip.

It's my first Apple device in a very long time, and I figured I would have some valid use cases for it now:

  • To be able to actually test my chat room in Safari first hand and debug this nightmare properly.
  • As an aside, to be able to release proper Mac ARM ports of my videogame side project, Sketchy Maze.

The first bug that I root caused and fixed was the one I mentioned just above: when somebody else was trying to connect in to Safari, it wasn't responding. With that bug resolved, I was getting 99% to where I wanted to be with Safari support on my chat room:

  • A user (on e.g. Firefox), who is not on webcam himself, is able to click and open a Safari user's camera and watch it (one-way video).
  • The Safari user (who is on camera themself) was able to open anybody else's video, even those who didn't want to auto-open Safari's back, by always giving them their video anyway and having them ignore it.
  • If the Safari user did open someone's video who wanted to auto-open theirs back, it would work as expected.

The only remaining, unfortunate limitation was: the Safari user always had to have its local webcam shared before it could connect in any direction, because I still didn't know how to set up a receive-only video connection without offering up a video to begin with. This was the last unique quirk that didn't apply to Firefox or Chrome users on chat.

How to actually set up a receive-only video channel in Safari

So, the other day I sat down to properly debug this and get it all working.

I had to find this out from a thorough Google search and landing on a Reddit comment thread where somebody was asking about this question: since the offerToReceiveVideo option was removed from the legacy API and no alternative is documented in the new API, how do you get the WebRTC offerer to request video channels be opened without attaching a video itself?

It turns out the solution is to add what are called "receive-only transceiver" channels to your WebRTC offer.

// So instead of calling addTrack() and attaching a local video:
stream.getTracks().forEach(track => {
    pc.addTrack(track);
});

// You instead add receive-only transceivers:
pc.addTransceiver('video', { direction: 'recvonly' });
pc.addTransceiver('audio', { direction: 'recvonly' });

And now: Safari, while not sharing its own video, is able to open somebody else's camera and receive video in a receive-only fashion!

No more hacks or workarounds needed!

At this point, Safari browsers were behaving perfectly well like Chrome and Firefox were. I also no longer needed that "Apple compatibility mode" hack I mentioned earlier: Safari doesn't need to superfluously force its own video to be sent on the offer, since it can attach a receive-only transciever instead and receive your video normally.

In retrospect, what actually were the issues?

There were really only two quirks about Safari at the end of the day:

  1. Safari only implemented the modern (Promise-based) WebRTC API.
  2. To set up a receive-only video channel for Safari, you needed to add transceivers to the WebRTC offer when the connection begins.

And that second bit ties into the first: the only way I knew initially to get a receive-only video connection was to use the legacy offerToReceiveVideo option which isn't supported in the new API.

And even in Mozilla's MDN docs about createOffer, they point out that offerToReceiveVideo is deprecated but they don't tell you what the new solution is!

Honorable mentions (related rants)

One of the more annoying aspects of this Safari problem had been, that iPad and iPhone users have no choice in their web browser engine.

For every other device, I can tell people: switch to Chrome or Firefox, and the chat works perfectly and webcams connect fine! But this advice doesn't apply to iPads and iPhones, because on iOS, Apple requires that every mobile web browser is actually just Safari under the hood. Chrome and Firefox for iPad are just custom skins around Safari, and they share all its same quirks.

And this is fundamentally because Apple is scared shitless about Progressive Web Apps and how they might compete with their native App Store. Apple makes sure that Safari has limited support for PWAs, and they do not want Google or Mozilla to come along and do it better than them, either. So they enforce that every web browser for iPad or iPhone must use the Safari engine under the hood.

Recently, the EU is putting pressure on Apple about this, and will be forcing them to allow competing web browser engines on their platform (as well as allowing for third-party app stores, and sideloading of apps). I was hopeful that this meant I could just wait this problem out: eventually, Chrome and Firefox can bring their proper engines to iPad and I can tell my users to just switch browsers.

But, Apple isn't going peacefully with this and they'll be playing games with the EU, like: third-party app stores and sideloading will be available only to EU citizens but not the rest of the world. And, if Apple will be forced to allow Chrome and Firefox on, Apple is more keen to take away Progressive Web App support entirely from their platform: they don't want a better browser to out-compete them, so they'd rather cripple their own PWA support and make sure nobody can do so. It seems they may have walked back that decision, but this story is still unfolding so we'll see how it goes.

At any rate: since I figured out Safari's flavor of WebRTC and got it all working anyway, this part of it is a moot point, but I include this section of the post because it was very relevant to my ordeal of the past year or so working on this problem.

Safari wasn't actually quirky after all

Early on with this ordeal, I was thinking that Safari's implementation of WebRTC was quirky and contrarian just because they had different goals or ideas about WebRTC. For example, the seeming "two-way video calls only" requirement appeared to me like a lack of imagination on Apple's part: like they only envisioned FaceTime style, one-on-one video calls (or maybe group calls, Zoom style, where every camera is enabled), and that use cases such as receive-only or send-only video channels were just not supported for unknowable reasons.

But, having gotten to the bottom of it, it turns out that actually Safari was following the upstream WebRTC standard to a tee. They weren't there for the legacy WebRTC API like Firefox and Chrome were, so they had never implemented the legacy API; by the time Safari got on board, the modern API was out and that's what they went with.

The rest of it came down to my own lack of understanding combined with loads of outdated misinformation online about this stuff!

Safari's lack of compression support for WebSockets, however, I still hold against them for now. 😉

Further Reading

If you ever have the misfortune one day to work with WebRTC at a low level like I have, here are a couple of the best resources I had found along the way:

Tags: 1 comment | Permalink
Is Safari the new Internet Explorer - or worse?
March 30, 2023 by Noah

So I haven't posted a good rant on my blog in quite some time - I had chilled out a lot in my older years, but I just have to tell this story about Safari and my struggles in getting it to work with my chat room I had built recently.

My chat room is a fairly basic app - it's open source and written "from scratch" using WebSockets to handle the client/server communication and they pass basic JSON messages around. All fairly standard stuff and shouldn't be a big ask for any modern web browser that supports modern web standards. It works flawlessly in Google Chrome as well as all other Chromium derivatives (including Edge, Brave, etc.), and it works flawlessly on Firefox, and when you run either browser on your Windows, Linux or Mac OS computer. It even works great on all Androids, too - using Chromium or Firefox browser engines.

But then there's Safari. Safari "supports" WebSockets but it doesn't do so very well and I've been fighting this for weeks now trying to chip away at this problem. Both when you run Safari on your Mac OS Ventura desktop or on your iPhone or iPad, Safari is very easy to overwhelm and it will disconnect from the chat room at the slightest hiccup of an issue.

My rant here actually is about three different problems that have made my life difficult trying to get Safari to work:

  1. The way that Safari just has to "do things differently" and have kneecapped limitations and quirky bugs that Chrome and Firefox don't experience at all.
  2. The way that all web browsers on iOS are really just Safari and so iPhones and iPads simply can not use my chat room regardless of browser.
  3. The way Apple designed their closed ecosystem where, if I want to debug this on iOS and see what kind of error message Safari is even throwing, I am required to purchase an iPad + a Macbook because only Apple's hardware can do iOS development and pair with one another (where by comparison, I can debug an Android browser using any kind of PC I want).

Safari and WebSockets: "Protocol errors"

I don't own a Macbook or an iOS device and so would have no way to even debug or look into this problem, but at least there is an option to run Mac OS inside of a virtual machine (using something like OSX-KVM) so at least I can look into the desktop Safari browser and see what its deal is.

First - here is how my chat basically works: you connect, send your username to log in, the chat tells everyone you joined, sends everyone the new Who's Online roster, and sends some "welcome messages" to the one who joined where I can send my rules or new feature announcements to you.

What I would see when a Safari user logged in was: they'd connect, log in, receive all those welcome messages and then they would immediately hangup the connection and log off. On their side, the web browser gives a very unhelpful error message regarding the WebSocket:

Protocol error.

That's it - it doesn't say what the error was. Even when I have a Safari browser in front of me, they give me no help at all to find out what's wrong!

Through trial and error, I found out:

  • If I remove all the welcome messages (to reduce the noise I send to Safari on join), it was able to log in to chat OK and send and receive messages!
  • From more poking, I found that there seems to be a length limitation!? And I'm not even talking about huge messages either - if I just type about 500 characters of text and send it, Safari will immediately disconnect with "Protocol error"!
  • So I also root caused: in those welcome messages, where I listed some rules or new features, those messages were "too long" for Safari and scared it away!

...and that kind of thoroughly sucks. I can remove all the welcome messages so as to allow Safari to at least log on, but then just one user posting a paragraph of text will kick all the Safari users out of the chat room!

Chrome and Firefox don't experience this issue. A while ago I added picture sharing in chat - you send your picture over WebSocket and it echoes it as a data: URL to all the chatters, passing those bytes directly back out; Firefox and Chrome can cope with this perfectly, but that would for sure kick Safari users off for too long of a message!

All web browsers on iOS are Safari

So, when it comes to Mac OS users I can tell them: Chrome and Firefox work better. But this advice does not fly on iPads or iPhones because, per Apple's rules, web browsers on iOS are not allowed to bring their own browser engines - they all are just custom wrappers around Mobile Safari.

And you guessed it: Mobile Safari doesn't like my WebSockets either!

I am hoping that with EU pressure placed on Apple to where they will allow competing browser engines to join their platform, that at least some of my iOS users will have a way to use my chat room. But how it stands currently is: iPads and iPhones simply can't use my chat room at all, or if they can get on (maybe it's the "too long of message" issue with them as well), they will be fragile and easy to boot offline just by writing too long of a message.

Apple will not innovate on Safari and make it support modern web standards, and they've made sure that nobody else can innovate either. The Blink engine from Chromium and Gecko from Firefox both work great with WebSockets and if only they were allowed to exist in their true forms on Apple mobiles, I wouldn't be ranting about this right now, I could just say "don't use Safari."

And side rant: the reason Apple won't allow Chrome or Firefox to compete with them is because they are scared shitless about Progressive Web Apps, which could compete with their native app store. They won't innovate on Safari at all until their feet are held to the fire (thanks for that as well, EU!), their web browser sucks (as this WebSockets thing illustrates), they're holding everybody back - the new Internet Explorer 6.0!

Vendor lock-in means I can't even debug this properly

Even if I owned an iPad, it wouldn't help - you can't get to the browser logs on an iPad browser to even see what kind of error message it's throwing. Though I imagine the error message would be just as helpful as desktop Safari, anyway: "Protocol error."

In order to get logs off an iOS web browser, you need to pair it with a Macbook computer -- the only kind of device that is allowed to run the iOS development kits and is the only way to debug anything that happens on your iPad.

With Mac OS, at least there is a way I can spin up a virtual machine and get my hands on Safari. There is no way to do this for iOS. There's no virtual machine where I can run the genuine Mobile Safari app and have a look at this issue myself. I wish Apple weren't so closed in their ecosystem - comparing it to Android for example, you can debug an Android app using any kind of computer: Windows, Linux, Mac OS, even another Android, even on-device on the same Android.

I am not an iOS developer, I don't care to be an iOS developer, and I don't own any Apple hardware, and it really sucks when I run into a web app issue that should have nothing to do with Apple specific software, and I simply can not even get in and look at the error messages.

I'd been chipping away at this for weeks, basically blindly trying things and throwing shit at the walls and hoping one of my Apple using friends tries my chat room once in a while to see if any of my efforts have worked (spoiler: they haven't worked).

I've also tried reaching out to developers on Mastodon and other social media: my chat room is open source, could somebody with Apple hardware help me debug and see if they can find out what I can do better to get Safari to like my chat room. Maybe I didn't reach the right ears because I've gotten only crickets in response. Meanwhile about a third of my users still can not get onto my chat room at all.

Where I've landed so far is: it seems Safari can connect, but that < 500 character limit issue seems horribly broken and I don't want Safari users getting kicked off left and right by surprise, it's a bad user experience.

Maybe I'll just wait until Chrome and Firefox can come to iOS properly

If I wait it out long enough (and if the EU is successful), Apple may permit actually good web browser engines on their platform and then my chat will work perfectly on them. It may just take a couple of years though - first Apple would have to be successfully sued into submission, and then Google/Mozilla would have to port their browser engines over which could be its own long tail of development work.

Maybe as a consequence of that regulation, Apple will actually put some new work into Safari instead of just neglecting it and they'll fix their shit. Currently it seems like my WebSocket messages need to be smaller than a tweet on Twitter, and it honestly won't be worth all the effort it would take me to reimagine my whole chat room and come up with a clever protocol to break messages apart into tiny bite sized chunks when it's only one, non-standards compliant web browser, which drags its stick thru the mud as badly as Internet Explorer ever did, that has the issue here.

So are they the new Internet Explorer, or somehow even worse?


I have sometimes had people visit my blog because they were Googling around in general about Apple and they like to fight me in the comments because I dissed their favorite brand. If this is you, at least say something constructive in the comments: have you ever built a WebSockets app and do you have experience to share in how to get Safari to behave? If you're simply an end user fanboy and never installed Xcode in your life, save your comments, please.

Tags: 1 comment | Permalink
On iOS Vulnerabilities
January 18, 2017 by Noah

It seems there's a new iOS vulnerability where receiving a certain text message can crash your phone (forcing a reboot), and then lock you out of the Messages app--presumably because attempting to display the offending message will crash the phone again. Also, apparently, you don't even have to read the text message; the notification for the message alone will crash the phone too.

I heard of it from this article on Cult of Mac, and I have various thoughts on the matter (and about iOS vulnerabilities in general and how people handle them once discovered--the long story short is they're handled very poorly).

The article mentions that if you found yourself a victim to this exploit, you can "fix" it by visiting a web page in Mobile Safari which then offers to "Open this page in Messages" and then finds some way to allow safely deleting the text without crashing the phone.

I tried inspecting the source code of the "fix" page with the curl command line HTTP client (because you should never check out a possibly shady web page in your normal browser, as they might try and exploit some zero-day vulnerability in your browser and compromise your computer). But, it seems that the domain the fix was hosted on no longer exists: it gave me some DoubleClick "inquire about this domain" nonsense and tons of advertisements.

Either this is an extraordinary coincidence that the site is down now (given that the article was written today, and presumably the site worked when the author wrote the article), or the site was up to something shady and got reported and terminated by its host/registrar. My guess is that it was basically a jailbreak exploit, as iOS tends to be very locked down compared to Android (for example, no "Intents" system for apps to communicate with each other, and iOS doesn't allow replacing the default Messages app for managing your text messages).

Which brings me to how iOS vulnerabilities are handled in general by the users: very badly. Somebody discovered that they can crash iOS by sending a certain text message to an iPhone user, and instead of doing the responsible thing of privately informing Apple about it and not disclosing it publicly, they make YouTube videos being like "Text your friend these 3 characters and crash their phone! It's hilarious! Fun prank!"

It's not a fun prank. Short of using a shady as fuck web page that probably gains root privileges on the phone in order to fix your Messages app, the other way to fix it would probably be to factory reset the entire phone.

To compare with Android, vulnerabilities get disclosed in vague terms, like "somebody can craft a special audio file and text you it", but with no specific details, and the users are more concerned with updating their OS to patch the problem as soon as possible; rather than being, "I can crash all my friends' phones! I know exactly how to do it because blogs and YouTube videos are telling me how; and I'll use it to 'prank' as many of my friends as I can before Apple can fix it!"

One reason I'm glad not to be an iPhone user. I'd have to unfriend people IRL if they intentionally abused such a dangerous exploit against me.

Tags: 0 comments | Permalink
Principle of Least Astonishment
March 22, 2016 by Noah

In user interface and software design, the principle of least astonishment states that "if a necessary feature has a high astonishment factor, it may be necessary to redesign the feature." It means that your user interface should behave in a way that the user expects, based on their prior knowledge of how similar interfaces behave.

This is a rant about Mac OS X.

Read more...

Tags: 0 comments | Permalink
Fedora 21 on the 2015 Macbook Air
May 2, 2015 by Noah

Today I picked up a Macbook Air (13", early 2015 model) because I wanted a new laptop, as my old laptop (the Samsung Series 5) has a horrible battery life, where it barely lasts over an hour and gives up early (powering down at 40% and not coming back up until I plug it in). This is also my first Apple computer. I'm the furthest thing from an Apple fanboy, but the choices I was throwing around in my head were between an Apple computer and a Lenovo Thinkpad.

I was given a Thinkpad as my work laptop, and it's by far the most impressive PC laptop I've ever used; it can drive three displays and run lots of concurrent tasks and has an insane battery life. Every PC laptop I've owned in the past have sucked in comparison. I hear people compare Apple computers to Thinkpads, so that's why the choice came down to one of these, and I didn't want another Thinkpad sitting around the house. ;)

Months before getting a Macbook I was looking into what kind of effort it takes to install Linux on a Macbook. There's a lot of information out there, and most of it suggests that the best way to go is to install a boot manager like rEFIt (or rEFInd, since rEFIt isn't maintained anymore). I saw some pages about not using rEFIt and installing Grub directly, which were from a Debian and Arch Linux perspective, and it sounded really complicated.

It seems that nowadays, with a user friendly Linux distribution like Fedora, a lot of this works much more flawlessly than the dozens of tutorials online would suggest. I just made a Fedora LiveUSB in the usual way (as if installing on a normal PC), rebooted the Macbook while holding the Option key, so that I was able to select the USB to boot from.

When installing Fedora to disk, the process was very much the same as doing it on a normal PC. I let Fedora automatically create the partition layout, and it created partitions and mount points for /, /boot and /home like usual, but it also created a partition and mount point for /boot/efi (for installing itself as the default bootloader in the EFI firmware on the Macbook). After installation was completed, I rebooted and the grub boot screen comes up immediately, with options to boot into Fedora.

One weird thing is, the grub screen apparently sees something related to Mac OS X (there were two entries, like "Mac OS X 32-bit" and "Mac OS X 64-bit", but both options would give error messages when picked).

If I want to boot into OS X, I hold down the Option key on boot and pick the Macintosh HD from the EFI boot menu. Otherwise, if the Macbook boots normally it goes into the grub menu and then Fedora. So, the whole thing is very similar to a typical PC dual-boot setup (with Windows and Linux), just with one extra step to get into OS X.

Update: I'm keeping a wiki page with miscellaneous setup notes and tips here: Fedora on Macbook

Tags: 8 comments | Permalink
Standing on the Shoulders of Android
July 20, 2010 by Noah
I saw on Digg today that Google discontinued sales of their Nexus One phone, following "disappointing sales."

What it really means from what I've read is that Google is just not selling the phone themselves directly but it can still be obtained via other means (developers can still buy them and they're still being sold in other countries), but that Google still intends to support the phone for the foreseeable future -- it will still be the first in line to get Android updates, for example.

I have a Nexus One and I like it and this news is a bit worrisome to me, but not in the way you might expect. Rather, because the Nexus One is one of the few Android phones that is truly open.

Apparently, the very first Android phone (the G1), the first Droid, and the Nexus One are pretty much the only Android phones that ship with the stock, vanilla, Android firmware. All the other HTC phones out there for example run the "HTC Sense" UI on top of Android, and the Motorola phones run the "Motoblur" UI; some people don't like these add-ons on top of Android and would rather run Android the way Google intended, using the stock vanilla release of the ROM. Or, some people just like to hack their phones and have root access on them.

The Nexus One phone made it really easy to unlock your bootloader and install custom/unsigned Android ROMs onto the phone if you wanted to (it would even provide a nice screen warning you that you're about to void your warranty). The Nexus One allows you to install whatever you want on it, and both Google and the phone itself fully supports this. But, other phones, notably the Motorola phones that come with an eFuse that will practically "brick" your phone if you try to modify its firmware, aren't so open.

There seems to be a trend in Android phones in which companies are trying to play Apple; Apple's iPhone devices are super locked down, and Apple tries to patch all the security holes to stop people from jailbreaking their devices - with each firmware release Apple tries to make it harder and harder to hack the iPhones. In Apple's ideal world, their hardware would be completely 100% impenetrable from hackers and nobody could modify their devices. It seems Android vendors want to copy this business model, which I for one do not like.

It seems Android vendors are "standing on the shoulders of giants," they look at Android and all they see is a free open source Linux-based mobile operating system, and they wanna just take all that hard work, add a few things to make their devices a major pain in the ass to hack (in their ideal world, absolutely impossible to hack) and then jerk their customers around in exactly the same way that Apple does. Is this really what Android was supposed to be all about? Just giving greedy megacorporations the cheap tools they need to strongarm part of the cell phone monopoly in their favor?

Hopefully the Nexus One won't be the last developer phone that can be bought by non-developers. I got mine specifically because it ran the stock unmodified Android firmware and because it was completely open to customization. As I ranted about before, I don't like how Apple is able to just slow down your old phones and force you to upgrade; at least I have the comfort of knowing I can easily flash any Android ROM onto my Nexus One and nobody can force me to upgrade by slowing my phone down or doing anything else malicious to it.

God help us if this is the future and we're stuck with many Apple-like companies all forcing us to use their locked-down devices that we're not allowed to touch at all for fear of permanently bricking our devices.

Tags: 1 comment | Permalink
My Problem with Apple
April 15, 2010 by Noah
I've told parts of this story to various people and posted about it in notes on Facebook but here's finally a blog post that sums up all the reasons I don't like Apple.

I didn't care one way or another about Apple until I got an iPhone 3G about a year ago. I got it about a month before the iPhone 3GS model came out; I heard the 3GS was on its way but nobody knew when, but I figured, "a smartphone is a smartphone, who really cares if mine doesn't have a compass built in?" How wrong I was.

I didn't know then what Apple was planning to do in the following month. Basically, they release the 3.0 firmware upgrade for iPhone 3G users. The new firmware gives the 3G customers a taste of some of the new features and would encourage them to buy the upcoming 3GS phone to get the rest. But, one more thing, the 3.0 firmware slows your shit down! So, the customers who were fine with the 3G and didn't plan to upgrade to the 3GS, now, would probably want to buy the 3GS just because they get sick of the 3G being so slow.

If you take an iPhone 3G running the 2.x firmware and compare it side-by-side with the 3GS phone running the 3.0 firmware... the differences in speed and "snappiness" is negligible.

So basically, the 3G was slowed down, on purpose, and then when the Apple fanboys stopped complaining and got used to this new slowness... Apple releases the iPhone 3GS and "ohh my godd, it's SO fast and snappy!"

I've been telling everyone my prediction for the last year but now I'm writing it for my blog: my prediction is that this upcoming summer 2010, Apple will release the 4.0 iPhone OS firmware upgrade, which will slow down all the 3GS phones (Apple's currently latest model of iPhone), and then this will be followed a week or two later by Apple unveiling the iPhone 4, which will be OH-SO-FAST now compared to the crippled, slowed-down 3GS phones.

Let's just wait and see if I'm right.

For this reason, my iPhone 3G is the first, and last, Apple product I ever intend to own. Well, the only closed device, anyway; I do like the Mac OS X operating system, and with a Macbook you can always reinstall the operating system from the CD that came with your computer. But with locked-down devices, once you make the mistake of upgrading, you can't go back; modern iTunes versions make sure of this: when you try to restore your devices in iTunes now, iTunes insists on getting the very latest firmware from Apple and doesn't let you browse and choose an older firmware image.

Because of the way Apple abuses their iPhone and iPod Touch customers, you'd better believe they'll pull the same shit with iPad customers too. I hope all you iPad early adopters love your iPad now, but just wait and, approximately a year from now there will inevitably be a new model, and Apple will really want to slow your shit down to force you to either deal with the artificial slowness, or pay another $500+ to upgrade to the latest model.

So I'm not a fan of Apple's closed devices. But I'm also not a fan of Apple's policies in terms of their app store approvals and rejections.

It was all over the blogosphere when Apple banned the Google Voice application from the app store, and even started an FCC investigation about whether Apple had any legal right to do so. Why did Apple ban Google Voice? Because it competed with Apple's very own phone application.

Similarly, there have been other apps Apple has killed because Apple is anti-competitive, including an e-mail app that was better than Apple's built-in e-mail app. Apple likes to maintain a complete monopoly--nay, a dictatorship--over its app store, and it would rather completely exterminate any hint of competition than to actually, you know, compete back. If somebody made an e-mail app that kicks the ass of Apple's e-mail app, Apple should make their e-mail app better than the competition; it shouldn't just throw a bitchfit and say "BAWWWWW this app isn't approved for the app store!"

Apple, in this regard, comes off to me as being like an immature little child, who would rather throw the chess board on the floor and scatter all the pieces than to even think about dealing with any form of competition whatsoever.

In the "App Store Competition" boat also sits Adobe Flash. It's highly speculated that the real reason Apple has a vendetta against Flash is because Flash applications can be just as feature-rich, interactive and animated as native iPhone applications. If Mobile Safari had a Flash player, nothing would stop people from creating web applications, that consist of a Flash object, that users could bookmark as Home Screen icons, that would be just as full-featured as native iPhone applications.

Similarly, Apple's latest developer agreement says you must originally write your app in C, C++ or Objective-C. Why did Apple decide to add this clause just now? Because Adobe's latest Flash beta includes the capability to export your Flash application into Objective-C code, which would enable one to basically use Adobe Flash to create iPhone applications.

Apple hates Flash for one reason: it directly competes with the app store and the native iPhone applications. If you could use Flash to create Objective-C code to author iPhone applications, Apple may lose some market share since Mac OS X is no longer required to create iPhone apps, among other things.

Anyway, this is where I stand on my views about Apple. Frankly, Apple is evil, in the sense of the term as it is used in Google's company slogan, "Don't be evil." Apple is this kind of evil.

So, I have no plans to ever own another closed Apple device, and would never consider developing an iPhone application. Nothing could be worse than spending weeks or months developing an application, only to have Apple dictate at the last minute that your app won't be allowed on the app store.

When I get an Android, I'll do Android app development. It has a plus of being Java-based. This means if I decided to make, say, a game, I could program the game once and then very trivially make many different ports of it: a desktop application, "full version" of the game; a Java applet, "try online before you download" light version of the game; and an Android application, "mobile version" of the game.

I know Apple fanboys like to google for anyone talking shit about Apple and I welcome the comments. I just know however from speaking with Apple fanboys I know in real life that they all were fully aware that Apple slows down their old devices (a co-worker fanboy has an iPhone 3G and agreed that it was slowed down with the 3.0 firmware). But, as expected of Apple fanboys, they try to justify it and defend Apple even though Apple is blatantly screwing them over and extorting them for as much money as possible. But by all means, post your comments anyway; entertain me with your blind dedication to Apple and how you believe they could do no wrong.

Because from where I stand, holding my iPhone 3G that takes 40 seconds to load the SMS app from a sleep state (and you 3G users know exactly what I'm talking about), Apple is doing nothing good here.

Tags: 4 comments | Permalink