Lee Martin
Netmaker
Queens of the Stone Age

...Like Phonework

2013-05-05

I apologize that it has been a minute since I’ve written here. I recently moved back to New Orleans to take a break from Los Angeles and restart my career as a freelancer. It’s been a lot of fun getting to make internets with the likes of Rian Rochford, Leda Chang, Jason Feinberg, Harold Gutierrez, and many others again. Today I want to share some details on a Queens of the Stone Age campaign I launched last week in support of their soon to be released record, …Like Clockwork.


If you’re in the United States, you can try the experience here before reading this blog. Just type your US number in the blank provided with a 1 in front and click the phone icon to dial.


I met Josh Homme about five years ago while working at SAM. He called me “pubes” because my voice cracked during the meeting, and while we’ve created a lot of mischief together during Era Vulgaris and Them Crooked Vultures, we haven’t worked an entire record cycle together. To say I’m excited is an understatement. Not to mention the new album is a fucking masterpiece.

Josh’s visual aesthetic mimics his musical style: dark, mysterious, crass… and he always seems to surround himself with the best talent to make his fucked up visions a reality. This record is no different as he employed the help of Liverpool based illustrator Boneface to create the album artwork and a series of Liam Brazier animated videos set to songs from the record.

Concept

Two weeks ago I jumped on a Skype call with Boneface and Liam to discuss my vision for hyping this series of videos based on an idea I had that actually came from a defunct Tom Petty proposal I wrote recently.

The concept involved allowing the user to feel attached to what they were seeing on screen via a phone call initiated by the subject. So what started as Tom Petty standing in a phone booth, turned into an evil clown mask wearing figure… I love ideas, like Call Drops, which feel like magic but are actually simple builds technically. Fucking with someone’s phone is a surefire way to grab their attention and force them into the story you’re telling.

Boneface and Liam agreed. So I wrote them a scripted grocery list of assets I needed to pull it off.

Script

  1. INTRO -Pan into room where clown is sitting.
  2. IDLE - Clown sits patiently waiting for user interaction. (Loop)
  3. PICKUP - Switch to close up of clown, picks up phone from receiver.
  4. DIAL - Clown dials each digit 0-9 of users number. (Click sound)
  5. TALK - Clown “talks” to user. (Loop)
  6. OUTRO - Clown hangs up and camera pans out of room.

Within three days, Boneface and Liam had delivered all the assets I needed while also simultaneously working on our animated series. That’s some serious hustle. With the assets on hand, it was time for me to get nerdy.

Tech

HTML5 Video

I began development by including each video file within an HTML5 <video> element. All were given the setting of preload to load them automatically (on desktop.) The idle and talk videos were set to loop as they would play continuously until that particular phase was finished.

<video id='intro' preload autoplay>
  <source src='/video/intro.mp4' />
</video>

<video id='idle' preload loop>
  <source src='/video/idle.mp4' />
</video>

In order for the HTML5 video to work cross browser and, you’ll need to include several formats of each video. Check out Rob Walsh’s tutorial for creating these formats using Quicktime and ffmpeg2theora.

Using jQuery, I was able to bind a listener for each videos “ended” event and jump to the next scripted video. For example, when the intro ended, I wanted the idle video to play. So in Coffeescript I wrote:

$("#intro").bind("ended", function() {
  $("#intro").hide();
  $("#idle").show().get(0).play();
});

These were layered and binded in a way to script the entire scene, and also adjust other elements on the page as needed.

I expiremented by creating a sort of video sprite sheet, and setting the play position to each section in a similar manner, but I couldn’t get the millisecond precision I needed, causing things to look glitchy. However, I feel like that could technically work if done correctly.

Twilio

User phone numbers were obtained via a simple input form on the page and were asynchronously sent to an action on the server. This function made sure the input was a phone number and then normalized and formatted it accordingly using the excellent Phony gem.

if Phony.plausible?(params["phone_number"])
  phone_number = Phony.normalize(params["phone_number"])
  phone_number = Phony.formatted(phone_number, format: :international, spaces: '')
end

I then used Twilio to initiate a call, and if successful, create a new user in my local database with the newly obtained phone number.

call = twilio.account.calls.create(
  from: ENV['TWILIO_NUMBER'],
  to: phone_number,
  application_sid: ENV['TWILIO_APP_ID'],
  if_machine: 'Hangup'
)

user = User.first_or_create(phone_number: call.to)

Finally, the unique “sid” of the call was sent back to the client application. I’ll tell you why in a bit. ;-)

{ sid: call.sid }.to_json

The actual application which is ran for each placed call is part of a seperate action which I specified in my Twilio account. Using Twilio’s XML friendly markup, TwiML, I tell the app to Play the clown’s dialog and Sms a message once the call is completed. Pretty simple.

response = Twilio::TwiML::Response.new do |r|
  r.Play '/phone.wav'
  r.Sms 'Return. May 6th. http://likeclockwork.tv', to: phone_number, from: ENV['TWILIO_NUMBER']
end

For US numbers, this only cost us $0.02 per call and we were able to pull geographical data (city, state, zip) about each caller. International was more expensive and some countries, like Brazil, cost as much as $0.33 per call. Next time I would probably stick to US, UK, and those countries that were less than $0.05. Sorry Brazil! You can check Twilio’s pricing here.

Pusher

Given the varying times it takes for a phone call to be placed and received, I couldn’t show the talking animation for a set time and then transition into the outro. Instead I needed a way to know exactly when a call ended. Luckily Twilio provides a status callback URL, which can notify my app of each completed call. Combine this with a real-time API like Pusher and you’ve got a 1 to 1 representation of the actual call.

It all starts with that unique “sid” the Twilio call response provides. We’ll want to receive that one the client and subscribe to a Pusher event of the same name. When that event is triggered, the hang up animation should be shown.

pusher  = new Pusher(PUSHER_ID);
channel = pusher.subscribe(CHANNEL);

channel.bind(sid, function(data) {
  $("#talk").hide();
  $("#outro").show().get(0).play();
});

Then we simply tell our Twilio status function to trigger the event of the same “sid” after each completed call.

Pusher[CHANNEL].trigger(params['CallSid'], { sid: params['CallSid'] })

This works so well that if you hang up on the clown prematurely, he’ll react accordingly on screen almost instantly. It would be bad ass if he reacted differently to dropped calls and bad numbers also, but we didn’t get that far this time.

Howler.js

Since the app had two audio files, background ambience and dial clicks, I needed a way to play two sounds simultaneously which also worked on mobile. Typically I would use Scott Schiller’s excellent SoundManager2 but I didn’t think it would handle web audio the way I needed so I found a new library called Howler.js that did exactly what I needed.

Setting up each sound was easy enough:

background = new Howl({
  urls: ['loop.mp3'],
  autoplay: true,
  loop: true,
  volume: 0.5
});

click = new Howl({
  urls: ['click.wav'],
  volume: 1.0
});

And playing the click after each dial is a simple:

click.play();

Looking back, perhaps I could have just added the click audio to each of the dial videos… in fact, maybe I’m an idiot for not doing that… Whatever. It worked.

Outro

If you’re in the United States, you can still try the clown dialer here. And be sure to check out “I Appear Missing” the first of our animated videos below:

As always, thanks for reading and checking out the work. You can expect much more open-sourced knowledge here over the summer. Follow me on Twitter for the latest and please let me know if you have any questions or comments.