It’s my last week at TokBox after working here for two years. TokBox was the first company I worked for after graduating and it changed my attitude toward having a boss.

Cultural influences made me believe that having a boss is inherently unpleasant. Entrepreneurship is celebrated because it means having to directly answer to no one. My preconceptions were that nobody wants to have a boss, it’s just a fact of life that if you work for a company, you have a boss and hopefully they aren’t a jerk—that a boss is necessary to keep you in line, determine your tasks, and entice you to stay motivated.

Those things didn’t occur between my boss and I. My boss didn’t manage me. She was just there.

I was a midwestern kid starting a career in Silicon Valley, fresh out of school, riddled with some kind of inferiority complex. I wanted to make an impact and go beyond being a cog in a wheel, and to me that meant making my own decisions and being proactive in searching for problems. No extrinsic motivation was going to push me beyond the drive I already had. The tasks I needed to do and the things I needed to accomplish became obvious when I let curiosity and ambition drive me forward. I didn’t need to be managed, and my boss recognized and adjusted to that fact before I did.

I was motivated and proactive, but I lacked finesse. I was making rookie mistakes: unnerving coworkers, exhibiting arrogance, stirring up unproductive arguments, reacting slowly on my feet.

At the same time I was noticing the grace in which my boss seemed to perform her job. The things I struggled with, she made look effortless. When talking to customers, she knew what to say and how to say it. When dealing with coworkers, she communicated her point with just the right amount of force. She appeared rational and humble. She had a rhythm that I lacked.

Opportunities to observe her were so valuable. She was an example I wanted to emulate. Instead of pushing incentives and tasks to me, she was a source of motivation and information from which to pull.

When I saw her work hard, it made me want to work harder. I replicated the language she used and the attitude she expressed when speaking about our product. She gave me context and information as I became ready for it, and I swamped her with questions. Why do we give away our product free? How would you navigate this conflict? Why did we choose that feature? What customers are we targeting? What’s the rationale behind our strategy?

I was demanding with her for information and it made her tired, she often told me so, but she assured me my curiosity was encouraged and worth the effort. She was opinionated but she tried hard to not let that affect her answers.

But she had biases and flaws. She was, at times, cynical towards customers, unfair to coworkers, and temperamental with me. But she was usually the first person to point that fact out. Had she not done this so regularly, I wouldn’t have stopped to scrutinize her actions. She seemed so talented, and by comparison, I was so raw and inexperienced—it’s easy when you’re young to look up to your role model free of scrutiny. And when you’re inexperienced, it’s not always easy to discriminate good behavior from bad.

Looking for my next opportunity, I’ve met with a number of people that could be my next boss—several really smart, successful people. I try to imagine working for someone new, but so often I’m not enthused. I didn’t know what it was I thought they lacked until I consciously considered what I specifically appreciated about my boss.

My boss was shrewdly self-aware. She was aware of how she was perceived. Aware of her biases, flaws, and mistakes. It’s a trait I’ve sensed missing in other managers I’ve considered. To be fair, it’s a shallow judgement to say someone isn’t self-aware, but I get the impression seeing someone heedlessly frame an opinion, or humble-brag an accomplishment, that he’s not in the habit of stepping outside his own perspective to reflect on his opinions and self-image objectively.

My boss had that habit, and it made a difference in how I was able to absorb and learn from her. I emulated her in a lot of of ways. Inevitably, whomever I work for next I will emulate too. I’ll trust that person for context and information to make decisions and form opinions. But that person is going to, at times, be misguided, temperamental, and biased—as was my boss.

But when I can trust that person to know when that’s happening and say, I’m being unfair, or I’m being irrational, or you were right—it makes it easy to extract the good ideas and recognize the behaviors that I should emulate, and look past everything else.

And that ability she had that enabled me to trust and learn so much from her, constant self-awareness, is the same ability I hope to have gained from her most.

Thanks Janine~

 

It had been working, but it stopped. It stopped for no reason at all. It doesn’t make sense. It doesn’t freakin’ make sense. It’s literally impossible.

How many times have you been there? You’re after a bug for hours. You’ve traced through the code, inspected every line, tried a thousand different things, but the pest won’t go away. You’re convinced that you could not be wrong. It’s impossible, you say. Yet your code, the dictator of logic, tells you otherwise.

We know how this story ends. After a period of whining and cussing, you regain your composure, and as the angst fades, a stray idea makes its heroic arrival. You realize you mistyped a string. Facepalm ensues.

But there’s that moment, when you’re so completely sure, so absolutely convinced that your logic is correct, that serves as a humble reminder that it’s easy to get lost in a world of assumptions.

When you write a program, you make assumptions that each piece is going to work as expected. Debugging is the process of revisiting those assumptions. Your bug is fixed when you find the false assumption. But in order to find it, you have to be openminded enough to acknowledge that any single one of your assumptions could be wrong. And as soon as you say to yourself this is impossible, then you’re at the point where you’ve put too much trust in your assumptions.

Computers are nice because they tell you when your assumptions are wrong. Real life isn’t the same way, and that scares me.

Because even when the computer is shouting right in my face ERROR, DANGEROUS, WRONG, I still get sucked in to believing that my assumptions are correct. Imagine how wrong my assumptions are in real life when there’s nothing to tell me otherwise.

You might think your program behaves unexpectedly, but it doesn’t, it’s does exactly what you tell it to. People on the other hand, actually behave unexpectedly. They have emotions and make their own decisions, and you don’t know what they are. You can’t debug people and inspect their variables (though if I could choose a super power, that might be it).

In real life we don’t have nice exception stack traces and compilers yelling at us in bright red font telling us that we’re wrong. Maybe that’s why writing code can be so frustrating, because we’re constantly being told we’re wrong.

But it’s those constant reminders that have taught me that I need to always revisit my assumptions. I need to be openminded and slow to judge, because as the code tells me, I am often wrong. And if I can’t trust my assumptions about code, I certainly can’t trust my assumptions about people.

 

Hackathons are awesome.

At TokBox we put our normal schedule aside for a couple days to run our first internal hackathon. The rules were simple: pitch an idea, form teams, build something, then demo it 30 hours later. The winning team would get a prize.

My team didn’t win (though we were proudly among the first losers), but it was a really positive experience. Here’s why I think every company should try doing an internal hackathon:

  • Give employees a chance to explore different technologies
    It’s easy to become attached to the technology stack you work with everyday and get trapped in the comfortable bubble of what you already know. Hackathon projects gives you the opportunity to get out of your comfort zone and explore different technologies, ultimately helping you learn new perspectives and different approaches for solving a problem.
  • Build synergy across different teams
    Similarly, hackathons gives you the opportunity to work with people outside of your normal team. Maniacally cranking out code to hack together the final pieces an hour before demos start is a true chemistry building process.
  • Spark renewed energy
    Competition is a powerful motivator. Even though our team is in no way yearning for motivation, the hackathon brought with it a refreshing collective energy and “who cares, just build it” spirit that I haven’t felt before. Building a new product, especially when jammed in to a high energy 30 hour period, is an intense, addictive, flow-like experience.
  • No expectations fosters innovations
    In daily work there is pressure and consequences associated with all your decisions, so on some level of consciousnesses you are limited to a sane set of safe ideas. In a hackathon, it doesn’t matter if the thing you make turns out to be a huge piece of crap. The fact that there are no expectations frees you from creative burdens — you can be as wacky or crazy as you want to be. Doesn’t that seem like a smarter way to innovate?

You can, if you would like, follow me on twitter here.

 

Originally posted on TokBox Developer Blog

Las Vegas Startup Weekend was this past weekend with a star-studded panel of judges, including Kevin Rose (tea enthusiast and Packer fan), Tom Anderson (everybody’s MySpace friend), Tony Hsieh (deliverer of happiness), Ryan Carson (ThinkVitamin founder), and Josh Reich (banking disrupter).

I’ve been to a lot of Startup Weekends. In terms of energy, team productivity, and tangible outcomes, the first Las Vegas Startup Weekend was the best one I have ever attended.

Here are some lessons I learned from some of the amazing Vegas teams:

Business people should be researching (a la Pop A Song@popasong)

Startup Weekends are mainly about building, thus, if you’re not a technical person it is sometimes unclear how you can contribute. Some biz people spend the weekend creating Launchrock, Twitter, and Facebook pages — which is okay, but ultimately meaningless if your product sucks.

Instead, the biz guys from Pop A Song spent their weekend researching customer segments to validate their idea and gather feedback in designing their product. Pop A Song makes it simple to queue songs at karaoke bars using a mobile web app.  The Pop A Song guys surveyed karaoke goers and DJs to see

  • What % of karaoke goers are smartphone users (i.e. could they use the app)?
  • Would karaoke goers find the app useful?
  • What % of the people that would use it pay for it?
  • How much would they pay?
  • Would DJs use it if it was free?
  • If DJs could accept tips through the app, what % of the revenue would be acceptable to take?

All of this data was really useful for designing, pitching, and validating their product.

Tell a story through questions and answers (a la rumgr - @rumgr)

By telling a story through questions and answers, Dylan Bathurst‘s pitch for rumgr turned me from a skeptic to a believer.

Rumgr is a stupid simple mobile app for selling used items.  It was described as if “garage sales and the internet had a baby”.

My first thoughts on rumgr were great, do we really need another Craigslist variant?  By the end however, I was sold.  In Dylan’s pitch, he did an oustanding job of identifying the questions skeptics may have, and then squashing them with well thought out answers to illustrate the features and intention of the product.  Here’s how it went down (between Dylan and my internal dialogue):

  • Dylan: “Selling things online is painful and time-consuming.”
  • I’m thinking: “Hmm.. I don’t know craigslist is pretty easy??”
  • Dylan: “Rumgr is super simple.  No prices, tags, titles, descriptions.  Just one click.  Take a picture and its online.” (shows the demo)
  • I’m thinking: “Okay, yes this looks easier, but it’s only a picture — how does this help me sell?”
  • Dylan: “Details get added through social interaction — bidding and bartering done by users.”
  • I’m thinking: “I see… so it’s more of an organic approach to selling.  Kind of neat.  But… ummm?”
  • Dylan: “If no tags, how will users find stuff?”
  • I’m thinking: “Ah, yes.  That was my next question.”
  • Dylan: “Items up for sale are browsed by how close they are to you.” (Shows demo of a beautiful photo grid of items being sold)
  • I’m thinking: “Okay, that’s dope.”

Dylan went on to illustrate the validity and usefulness of the app by continuing his Q&A format. A great way to handle tough questions is to prepare and tackle them head on.

Start selling, NOW (a la ClippPR@clippPR)

The best way to validate your product is to have people lined up to buy it.  Do what clipppr did — don’t wait until your app is finished to get it out there, start selling it now (oh yeah, they happened to win the event).

Forget complicated business models (a la Pictavote@pictavote)

A trap that too many Startup Weekend teams fall in to is trying to conceive elaborate business models without validating that anybody would even use their product first.

Pictavote is an app where people upload a photo, ask a question, and then vote on it in real-time. It’s a quick and fun little app with some viral potential.

After demoing their app, the pictavote crew transitioned to a slide titled Business Model, in which they were presumably going to cover their plans to monetize.  Instead, they hit next and the slide went up in flames after which they declared:

“We hate complicated business models.”

… and the audience cheered.

Your business plan will not survive past first contact with customers.

–Steve Blank

A common thread of feedback from the judges went along the lines of this: focus on building an awesome product that people use; if it makes sense to make money off it now, do it, otherwise figure it out later.

Be awesome (a la Autoplay@autoplayapp)

Hard to pick just one lesson learned from the guys who made Autoplay. Watch their pitch here for How to Make a Slide Deck 101.

You can, if you would like, follow me on twitter here.

 

Originally posted on TokBox Developer Blog

This tutorial will create a simple chat roulette app using node.js, socket.io and OpenTok. Socket.io allows us to pass data between clients in real-time using only javascript and eliminate the need for a database. OpenTok allows us to quickly publish and subscribe to webcam streams without having to worry about server requirements and bandwidth usage — all we have to do is implement a simple and free javascript API.

Here is a high-level overview of the application architecture:

You can check out the app running here: http://fierce-sword-182.herokuapp.com
You can view the GitHub repo here: https://github.com/jonmumm/RouletteTok

The Setup

If you don’t already have node.js and npm (node package manager), install them now.

The first thing we want to do is install express. Express is a node.js framework that abstracts the low level details of creating a web app, allowing us to get started quickly. Use the following command to install express globally so you can run it from the command line:

npm install -g express

Once express is installed, use the following commands to create the application we are going to build:

express RouletteTok
cd RouletteTok

This command create a new directory called RouletteTok that contains the basic structure of our application.

Next, edit package.json (in your root application directory) to include the modules we will need, which are express, jade, socket.io, and opentok.

{
	"name": "RouletteTok",
	"version": "0.0.1",
	"dependencies": {
		"express": "2.3.11",
		"jade": "0.12.1",
		"opentok": "0.1.0",
		"socket.io": "0.6.18"
	}
}

Now run the following command to install the dependencies:

npm install

That should be it for setting up. You should now be able to run your node server with the following command

node app.js

The Application

Our app consists of four main files, which are:

Let’s go through each of these four files to see what they do.

app.js

This is the main file used to start our app. The majority of the code here was generated by Express when we created our project, however I did add some things to it (explained below). Essentially what this file does is sets up our app, creates the routes, and starts the socket server at the very last line.

var express = require('express');
var io = require('socket.io');

var app = module.exports = express.createServer();

// Configuration
app.configure(function() {
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function() {
  app.set('address', 'localhost');
  app.use(express.errorHandler({
    dumpExceptions: true,
    showStack: true
  }));
});

app.configure('production', function() {
  app.set('address', 'fierce-sword-182.herokuapp.com');
  app.use(express.errorHandler());
});

// Routes
app.get('/', function(req, res) {
  res.render('index', {
    title: 'RouletteTok',
    address: app.settings.address,
    port: app.settings.port
  });
});

if (!module.parent) {
  app.listen(app.settings.port);
  console.log("Server listening on port %d", app.settings.port);
}

// Start my Socket.io app and pass in the socket
require('./socketapp').start(io.listen(app));

The most important thing here is at line 31, where we set up our root route (at ‘/’) to render our index template (which we will create later). We pass our template the server address and port so that we can connect to the socket.io server from the client. At line 45, we start the socketapp module that we are going to write next.

socketapp.js

This file implements the socket server logic. In this file, we set up the event handlers for when clients connect and send messages to the socket server. When a client sends a message, the server parses it for the event value, performs some logic, and then sends a message back to the client or clients. Here is the complete file, we will discuss it in detail below:

// Require and initialize OpenTok SDK
var opentok = require('opentok');
var ot = new opentok.OpenTokSDK('413302', 'fc512f1f3c13e3ec3f590386c986842f92efa7e7');

// An array of users that do not have a chat partner
var soloUsers = [];

// Sets up the socket server
exports.start = function(socket) {
  socket.on('connection', function(client) {

    client.on('message', function(message) {

      // Parse the incoming event
      switch (message.event) {

        // User requested initialization data
        case 'initial':
          // Create an OpenTok session for each user
          ot.createSession('localhost', {}, function(session) {

            // Each user should be a moderator for their own session
            var data = {
              sessionId: session.sessionId,
              token: ot.generateToken({
                sessionId: session.sessionId,
                role: opentok.Roles.MODERATOR
              })
            };

            // Send initialization data back to the client
            client.send({
              event: 'initial',
              data: data
            });
          });
        break;

        // User requested next partner
        case 'next':

          // Create a "user" data object for me
          var me = {
            sessionId: message.data.sessionId,
            clientId: client.sessionId
          };

          var partner;
          var partnerClient;
          // Look for a user to partner with in the list of solo users
          for (var i = 0; i < soloUsers.length; i++) {
            var tmpUser = soloUsers[i];

            // Make sure our last partner is not our new partner
            if (client.partner != tmpUser) {
              // Get the socket client for this user
              partnerClient = socket.clientsIndex[tmpUser.clientId];

              // Remove the partner we found from the list of solo users
              soloUsers.splice(i, 1);

              // If the user we found exists...
              if (partnerClient) {
                // Set as our partner and quit the loop today
                partner = tmpUser;
                break;
              }
            }
          }

          // If we found a partner...
          if (partner) {

            // Tell myself to subscribe to my partner
            client.send({
              event: 'subscribe',
              data: {
                sessionId: partner.sessionId,
                token: ot.generateToken({
                  sessionId: partner.sessionId,
                  role: opentok.Roles.SUBSCRIBER
                })
              }
            });

            // Tell my partner to subscribe to me
            partnerClient.send({
              event: 'subscribe',
              data: {
                sessionId: me.sessionId,
                token: ot.generateToken({
                  sessionId: me.sessionId,
                  role: opentok.Roles.SUBSCRIBER
                })
              }
            });

            // Mark that my new partner and me are partners
            client.partner = partner;
            partnerClient.partner = me;

            // Mark that we are not in the list of solo users anymore
            client.inList = false;
            partnerClient.inList = false;

          } else {

            // Delete that I had a partner if I had one
            if (client.partner) {
              delete client.partner;
            }

            // Add myself to list of solo users if I'm not in the list
            if (!client.inList) {
              client.inList = true;
              soloUsers.push(me);
            }

            // Tell myself that there is nobody to chat with right now
            client.send({
              event: 'empty'
            });
          }

        break;
      }
    });
  });
};

There are two events that the socket server listens for and responds to: 1) the initial event on line 18 and 2) the next event on line 40.

The initial event is sent by clients when they load the page (shown later in public/javascripts/app.js). All this event does is create an OpenTok session for this client to publish its webcam to, and then sends the session information and token back to the client.

The next event is sent by clients when they request to talk to a new person. This event maintains an array (called “soloUsers”) of users who do not currently have a partner. Every time a client triggers this event, it checks the array to see if there is a suitable partner to chat with — if there is a match it sends both clients the other client’s OpenTok session to connect and subscribe to, otherwise it adds the requesting client to the soloUsers array.

views/index.jade

This is the view file that is loaded at at our root route. It uses the Jade syntax language. Essentially it it is is a few divs for holding the video streams and the scripts necessary for our app.

h1 #{title}

div#streams
  div#publisherContainer
  div#subscriberContainer

div#controls
  div#notificationContainer
  button#nextButton Next

script(src='./socket.io/socket.io.js')
script(src='http://staging.tokbox.com/v0.91/js/TB.min.js')
script
  var config = {};
  config.address = '#{address}';
  config.port = '#{port}';
script(src='./javascripts/app.js')

Notice at line 13 in the template we create a config object which we will use in public/javascripts/app.js to connect to the socket server from the client. We set these variables using the variables passed in to our template from the route set up in our app.js server file at line 34.

public/javascripts/app.js

The last file is the client-side javascript that connects to the socket server and sends requests based on user actions, then listens for and reacts to responses sent from the server. This file is separated in to two logical parts: 1) the socket code that connects the server, parses received events, and gets the new data and 2) the RouletteApp code that handles the DOM manipulation, user interaction, and OpenTok publishing and subscribing.

(function() {

	var socket = new io.Socket(config.address, {port: config.port, rememberTransport: false});

	socket.on('connect', function() {
		socket.send({ event: 'initial' });
	});

	socket.on('message', function (message) {
		var sessionId;
		var token;

		switch(message.event) {
			case 'initial':
				sessionId = message.data.sessionId;
				token = message.data.token;

				RouletteApp.init(sessionId, token);
			break;

			case 'subscribe':
				sessionId = message.data.sessionId;
				token = message.data.token;

				RouletteApp.subscribe(sessionId, token);
			break;

			case 'empty':
				RouletteApp.wait();

			break;
		}
	});

	socket.connect();

	var SocketProxy = function() {

		var findPartner = function(mySessionId) {
			socket.send({
				event: 'next',
				data: {
					sessionId: mySessionId
				}
			});
		};

		return {
			findPartner: findPartner
		};
	}();

	var RouletteApp = function() {

		var apiKey = 413302;

		var mySession;
		var partnerSession;

		var partnerConnection;

		// Get view elements
		var ele = {};

		TB.setLogLevel(TB.DEBUG);

		var init = function(sessionId, token) {
			ele.publisherContainer = document.getElementById('publisherContainer');
			ele.subscriberContainer = document.getElementById('subscriberContainer');
			ele.notificationContainer = document.getElementById('notificationContainer');
			ele.nextButton = document.getElementById('nextButton');

			ele.notificationContainer.innerHTML = "Connecting...";

			ele.nextButton.onclick = function() {
				RouletteApp.next();
			};

			mySession = TB.initSession(sessionId);
			mySession.addEventListener('sessionConnected', sessionConnectedHandler);
			mySession.addEventListener('connectionCreated', connectionCreatedHandler);
			mySession.addEventListener('connectionDestroyed', connectionDestroyedHandler);
			mySession.connect(apiKey, 'moderator_token');

			function sessionConnectedHandler(event) {
				ele.notificationContainer.innerHTML = "Connected, press allow.";

				var div = document.createElement('div');
				div.setAttribute('id', 'publisher');
				ele.publisherContainer.appendChild(div);

				var publisher = mySession.publish(div.id);
				publisher.addEventListener('accessAllowed', accessAllowedHandler);
			};

			function accessAllowedHandler(event) {
				SocketProxy.findPartner(mySession.sessionId);
			};

			function connectionCreatedHandler(event) {
				partnerConnection = event.connections[0];
			};

			function connectionDestroyedHandler(event) {
				partnerConnection = null;
			}
		};

		var next = function() {
			if (partnerConnection) {
				mySession.forceDisconnect(partnerConnection);
			}

			if (partnerSession) {
				partnerSession.disconnect();
			}
		};

		var subscribe = function(sessionId, token) {
			ele.notificationContainer.innerHTML = "Have fun !!!!";

			partnerSession = TB.initSession(sessionId);

			partnerSession.addEventListener('sessionConnected', sessionConnectedHandler);
			partnerSession.addEventListener('sessionDisconnected', sessionDisconnectedHandler);
			partnerSession.addEventListener('streamDestroyed', streamDestroyedHandler);

			partnerSession.connect(apiKey, token);

			function sessionConnectedHandler(event) {
				var div = document.createElement('div');
				div.setAttribute('id', 'subscriber');
				ele.subscriberContainer.appendChild(div);

				partnerSession.subscribe(event.streams[0], div.id);
			}

			function sessionDisconnectedHandler(event) {
				partnerSession.removeEventListener('sessionConnected', sessionConnectedHandler);
				partnerSession.removeEventListener('sessionDisconnected', sessionDisconnectedHandler);
				partnerSession.removeEventListener('streamDestroyed', streamDestroyedHandler);

				SocketProxy.findPartner(mySession.sessionId);
				partnerSession = null;
			}

			function streamDestroyedHandler(event) {
				partnerSession.disconnect();
			}
		};

		var wait = function() {
			ele.notificationContainer.innerHTML = "Nobody to talk to.  When someone comes, you'll be the first to know!";
		};

		return {
			init: init,
			next: next,
			subscribe: subscribe,
			wait: wait
		};

	}();

})();

The client-side application script works like this:

  1. Client initializes socket connection and connects to server (line 3 and line 35).
  2. When client connects to socket server, it sends an initial event to the server (line 5).
  3. Client will receive an initial event response from the server that contains an OpenTok session for the user to publish to (line 16). Then we call RouletteApp.init() and pass in the OpenTok session ID to connect to the session and publish the webcam stream (line 67).
  4. When the user clicks the next button (line 75), it disconnects the current partner from his session and disconnects himself from his partner’s session (line 109). In turn this triggers the sessionDisconnectedHandler (line 138) which then calls a method that asks the server to find them a new partner (line 39).
  5. In response, the client will receive either a subscribe event or an empty event from the server (line 21, line 28). On an empty event, the app will do nothing other than set a message saying there is nobody to talk to (line 152). On a subscribe event, the client will connect to his partner’s session and subscribe to her stream (line 119).

Conclusion

That sums up the implementation. I deployed the app using Heroku, which recently added official support for Node.js — you can learn how to set this up here.

If you have any questions, comments, or ideas related to node, socket.io, chat roulette, or OpenTok — please post them here.

You can check out the app running here.
You can view the GitHub repo here.
You can, if you would like, follow me on twitter here.

 

I have began to create a set of OpenTok JavaScript plugins to provide boilerplate solutions for some common use cases.

The first plugin is the _OT.widget, which makes it simple to create a videochat widget similar to the HTML embed widget seen here.

The widget pictured above is produced by the following code:

<div id='widgetContainer'></div>

<script type='text/javascript'>

	// Set OpenTok variables
	var sessionId = '28757622dbf26a5a7599c2d21323765662f1d436';
	var api_key = '1127';
	var token = 'devtoken';

	// Get OpenTok objects
	var session = TB.initSession(sessionId);
	var widget = _OT.widget;

	// Initialize the widget
	widget.init(session, 'widgetContainer');

	// Connect to the session
	session.connect(api_key, token);

</script>

When initialized, the widget will subscribe to all sessions in the stream, publish the users stream to the session, and automatically re-position streams as they are added or removed. You can also pass in a list of properties (e.g. size, name, auto publish, etc.) to change how the widget should behave.

To use the _OT.widget plugin, head over to the GitHub repo where full documentation and more sample code is available.

 

Problem

You are developing a multi-user OpenTok application and you need a way to pass data between user in real-time.

Solution

Use Session.signal() to notify user when there is new data on the server to be retrieved.

Tutorial Overview

In this tutorial I will show you how to implement this solution by creating a simple chat app that uses OpenTok signals to pass data between users in an OpenTok session. The app will allow connected users to communicate through both video chat and text chat.

I will use Rails for the backend portion of the app, however this technique can be applied to any server-side technology. I also use jQuery for DOM manipulation and AJAX and the OT_LayoutContainer class created and explained in this blog post for managing the layout of the video streams.

Part One: Server set up

The first thing we are going to do is set up our server. This involves 1) creating our app, 2) creating the model to hold chat entries, and 3) creating the controller that we are going to make AJAX calls to. We can do this all with the following rails commands

rails new ChatTok
rails generate model ChatEntry body:text connectionId:string
rake db:migrate
rails generate controller ChatEntries

We create a ChatEntry model that holds the body of the chat message and the connectionId of the user that submitted the message.

Next we are going to define two methods for our controller. The add method will simply create a new chat_entry by parsing for the body and connectionId from a POST request. The latest method will get the latest chat entry from a given connectionId.

class ChatEntriesController < ApplicationController

  # GET /chat_entries/latest/:connectionId
  def latest
    # Get the last chat entry from this connectionId
    @chat_entry = ChatEntry.where("connectionId = ?", params[:connectionId]).last

    render :json => @chat_entry
  end

  #POST /chat_entries/add
  def add
    # Create a new chat entry
    @chat_entry = ChatEntry.new
    @chat_entry.connectionId = params[:connectionId]
    @chat_entry.body = params[:body]

    @chat_entry.save

    render :json => @chat_entry
  end

end

Finally we add the routes to these methods to our routes.rb file.

  get '/chat_entries/latest/:connectionId' , :to => 'chat_entries#latest'

  post '/chat_entries/add' , :to => 'chat_entries#add'

Part Two: Client set up

First we do standard OpenTok initialization stuff. I use the OT_Widget class I created previously which basically takes care of all the stream publishing and subscribing for us.

The important thing to notice here is that we have set up an event handler for the signalReceived event.

			// Public vars
			var session;

			// Initialize OpenTok stuff
			(function() {
				var apiKey = 1127;
				var sessionId = '287a9e4ad0aa8e501309df11fe53831452fa1167';
				var token = 'devtoken';

				session = TB.initSession(sessionId);

				// This class does all the video publishing and subscribing for us
				OT_Widget.init(session, "streamContainer", 800, 300);

				// Set up event handler to listen for signals
				session.addEventListener("signalReceived", signalReceivedHandler);

				session.connect(apiKey, token);
			})();

Now anytime a connection in the session calls Session.signal(), signalReceivedHandler is going to execute and is passed a SignalEvent where we can get the connectionId of the connection that sent the signal.

			// Event handler for receiving signals called
			// by session.signal() from other clients in session
			function signalReceivedHandler(event) {
				getChatEntry(event.fromConnection.connectionId);
			}

So whenever we receive a signal, we are going to take the connectionId of the user that sent the signal, and make an AJAX call to the latest method we defined on the server to get the latest chat entry from the connection that sent the signal. Then once we receive the entry, we add it to the page.

			// Gets the latest chat entry from the database
			// given somebody's connectionId
			function getChatEntry(connectionId) {
				$.ajax({
					url: '/chat_entries/latest/' + connectionId,
					success: function(data) {
						$("#chat").append("<li><strong>"
							+ data.chat_entry.connectionId
							+ ":</strong> " + data.chat_entry.body + "</li>")
					}
				})
			}

The last thing we need to do is define how we send new chat entries to the server. We make an AJAX call and pass our add method the entry body and connectionId.

The most important thing to notice here is that we call session.signal() after we get a successful result from the server. This is what tells the other connections in the session that new data is available.

			// Posts a new chat entry in to the database
			function postChatEntry(body) {
				var data = {
					connectionId: session.connection.connectionId,
					body: body
				}

				$.ajax({
					url: '/chat_entries/add',
					data: data,
					type: 'POST',
					success: function(data) {
						// Signal to other clients that we have inserted new data
						session.signal();
					}
				})
			}

Conclusion

To use signals to pass data between connections in a session, follow these four general steps:

  1. Post data to the server and associate it with a connectionId.
  2. After the data is stored, call session.signal() to notify all connections in the session that there is new data.
  3. Listen for the signalReceived event.
  4. When a client receives a signalReceived event, use the connectionId from the event to get the latest entry on the server

You can see the source code for this tutorial and the complete chat application on the github repo.

 

Problem

When developing an OpenTok application, one choice developers must make is to decide how to generate new sessions. Should all publishers get their own session? Should only X number of people be allowed in a given session? How do you decide what person goes in to what session?

Since there is no direct way of querying how many clients are in a given session (and who those clients are), it is difficult to implement session management logic. One solution is to track session/client information in a database. Before joining a session, you could query a database that stores client information, however constantly maintaining this database can become slow and complicated, and dealing with client disconnects is non-trivial.

Solution

The solution that I decided on was to use Node.js to create a simple HTTP and socket server that collects information about connected clients (who they are and how many are connected). With that information I can then generate sessions based on whatever logic I would like.

The server works by accepting an incoming client, processing the logic to determine which session the client should be placed in, and then sending all the relevant session data back to the client. This is a fast, scalable, and lightweight solution that broadcasts in real-time, doesn’t require a database, and is created entirely in JavaScript.

Tutorial Overview

In this tutorial I will discuss how I implemented the server using Node.js and the OpenTok Node.js SDK created by Brian Stoner.

Assumptions

This tutorial assumes that you are familiar with the OpenTok API. If you are not please first read through the Getting Started Guide.

This tutorial also assumes that you have installed Node.js and the node package manager. I will try to walk through each part without any assumed knowledge beyond the Hello World tutorial from Node.js. If you would like to learn more about using Node.js, I recommend reading this outstanding tutorial.

Use Case

The particular use case that this tutorial will solve is the following:

  • Each session can have a maximum number of 3 users
  • When a new user connects, the user is put in to the first session that is not full
  • If all sessions are full, a new session will be generated

While this tutorial uses the above logic to solve this particular use case, the techniques discussed here can be applied to several other cases.

Part One: Download Required Modules

The server uses three Node modules:

  • opentok: OpenTok Server-Side SDK used for generating sessions and tokens.
  • socket.io: Enables easy two-way, real-time connection between server and client.
  • connect: Middleware framework for adding features to HTTP server.

Install these modules using Node Package Manager with the following commands:

npm install opentok
npm install socket.io
npm install connect

Once you have modules installed, download the project code from the github repo with this command:

git clone https://github.com/jonmumm/OpenTok-Node-Session.git

Once you have the repository downloaded, cd to that directory and run this command to start the server:

node server.js

This will start the server on port 3000. You should now be able to view the application at http://localhost:3000.

Notice that our node server is actually serving the HTTP content, it contains its own HTTP server. This is done in only a few lines of code. This is pretty cool.

I will go in to more detail of how this works, however, you should know that while node can serve our HTTP content, it does not have to. For our purposes, we could just as easily use an existing HTTP server and use the node server for doing other things (like for sockets, which is what we use it for).

The project consists of two files:

  • server.js: the node server-side code.
  • index.html: the client that connects to the node server.

I will go through both files and discuss how each works.

Part Two: Server-Side Code

The server-side code can be separated into two parts. The first part initializes the HTTP server, socket server, and event handlers and the second part implements the OpenTok session generation logic for my particular use case.

Here is the first part of the server:

// Import the Node modules we need
var connect = require('connect'),
	io = require('socket.io'),
	opentok = require('opentok');

// Set up the HTTP server for serving our static files
var server = connect(
	connect.static(__dirname + "/web")
);
server.listen(3000); // Start server on port 3000

// Set up Socket listener and initialize event handlers
var socket = io.listen(server);
socket.on('connection', function(client) {

	// When a client connects, figure out which session to join
	getSession(client);

	client.on('disconnect', function() {
		// When a client disconnects, drop that client from the session
		leaveSession(client);
	});
});

First we import the required modules we need. Then we initialize the HTTP server. For that I am using the Connect middleware framework which allows you to quickly specify middleware modules to run on your HTTP server. In this case I am simply specifying what directory to serve the static content out of (i.e. my html and javascript files). For our purposes, using the HTTP server to serve your content is optional; you could serve your files elsewhere and just use the node server for sockets.

Once our HTTP server is created and listening on port 3000, we create the socket server. The socket server is what will allow us to send messages back and forth between client and server in real-time.

Notice that we pass the HTTP server as a parameter when initializing our socket. This makes it so that the HTTP and socket servers are both listening on the same port. However neither server takes over the other. What will happen is, any socket request will be automatically intercepted by the socket server, and all other requests will go to the HTTP server.

After our socket server is initialized, we set up event handlers for when a client connects and disconnects. Essentially what we are doing here is saying “when a client connects, get that client a session to connect to” and “when a client disconnects, remove that client from the session”.

Here we only set up event handlers for the “connection” and “disconnect” events from the client, however you could also set up a listener for the “message” event for when the client sends a message to the server, however we have no need for that here.

That is all the code you need for setting up the basics of the server. Now we will dive in to the logic for generating OpenTok sessions.

// OpenTok Variables
var OPENTOK_API_KEY = '413302',		// Replace with your API key
	OPENTOK_API_SECRET = 'fc512f1f3c13e3ec3f590386c986842f92efa7e7',		// Replace with your API secret

	// OpenTok SDK
	ot = new opentok.OpenTokSDK(OPENTOK_API_KEY, OPENTOK_API_SECRET),

	// NOTE: Uncomment for production, defaults to "staging.tokbox.com"
	// ot.setEnvironment("api.tokbox.com"),

	// Variables for managing OpenTok Sessions
	MAX_SESSION_CONNECTIONS = 3,	// Maximum number of client connections we want in a given session
 	session_map = {},				// Hash for getting the session of a given client
	ot_sessions = new Array();		// Array for holding all sessions we have generated

// Finds an available session for the client to connect to
function getSession(client) {

	var session;
	// Look through all sessions to find a session that has less than the max number of sessions
	// NOTE: We start searching from the top of the array since it is more likely a non-full session is there
	for (var i = ot_sessions.length - 1; i >= 0; i--) {
		var tmp_session = ot_sessions[i];
		if (tmp_session.clients.length < MAX_SESSION_CONNECTIONS) {
			session = tmp_session;
			break;
		}
	}

	if (!session) {
		// If we didn't find a session, generate one and enter it
		ot.createSession('localhost',{},function(session) {
			ot_sessions.push(session);
			enterSession(session,client);
		})
	} else {
		// Otherwise enter the session we found
		enterSession(session, client);
	}
}

// Sends the session info back to the client for the client to join
function enterSession(session, client) {
	// Construct info object to pass back to client then send it
	var opentok_info = {
		sessionId: session.sessionId,
		apiKey: OPENTOK_API_KEY,
		token: ot.generateToken()
	}
	client.send(opentok_info);

	// Create array to hold all the clients in the session
	if (!session.clients) {
		session.clients = new Array();
	}

	// Add the client to the session
	session.clients.push(client.sessionId);
	session_map[client.sessionId] = session;	// Use map later to identify what session client was in
}

// Finds which session the client was in and removes the client from that session.
function leaveSession(client) {
	// Find the session that the client was in
	var session = session_map[client.sessionId];

	// Find the position of the client in the session
	var index = session.clients.indexOf(client.sessionId);

	// Remove the client from the session
	session.clients.splice(index, 1);
}

All we are doing here is implementing the logic from the use case I described above. We first look to see if there are any sessions that have less than 3 people in it, if so we use the first session that does. Otherwise we generate a new session. Once we have the sessionId, we package it into a JSON object along with a token and the apiKey and send it through the socket to the client.

Part Three: Client-Side Code

Since the node server takes care of all the session logic, it makes our client implementation very simple.

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
	<title>OpenTok Node.js</title>

	<script src="http://cdn.socket.io/stable/socket.io.js" type="text/javascript"></script>
	<script src="http://jonmumm.github.com/OpenTok-JS-LayoutContainer/OT_LayoutContainer.js" type="text/javascript"></script>
	<script src="http://staging.tokbox.com/v0.91/js/TB.min.js" type="text/javascript" ></script>
	<script src="OT_Widget.js" type="text/javascript" ></script>

	<script>
		// Initialize the socket, set up event handler, and connect
		var socket = new io.Socket(null, {port: 3000, rememberTransport: false});
		socket.on("message",messageHandler);
		socket.connect();

		function messageHandler(message) {
			var opentok_info = message;

			OT_Widget.startWidget("widgetContainer", 700, 400,
				opentok_info.apiKey, opentok_info.sessionId, opentok_info.token);
		}
	</script>
</head>

<body>
	<div id="widgetContainer"></div>
</body>
</html>

Here we connect to the socket server, listen for messages from it, and then use the message we receive to set up our OpenTok session. Very simple.

Notice here I use a class called OT_Widget which is just a wrapper for the example that uses the LayoutContainer class from my previous blog post on layout management.

Conclusion

Using Node.js with socket.io gives us a flexible option for implementing session generation logic. If you have other ideas on how to use Node.js with OpenTok, post your thoughts here or tweet them @tokboxdev.

Tutorial GitHub Repo
OpenTok Node.js SDK created by Brian Stoner.

 

Problem

A common challenge developers face when creating video chat applications is how to lay out the video streams on the page in an elegant manner. Many video chat applications involve a variable number of streams, users are constantly joining and leaving the chat session—dealing with these changes so that the streams do not affect other elements on the page can be difficult.

Solution

One way of dealing with this challenge is to define a fixed-size container where you want all your streams to live and then dynamically resize the streams within the container so that all the streams can fit. This is the approach the TokBox team took when developing the OpenTok HTML Embed Widget. You can see this approach in action in the sample app we are going to build here.

Tutorial Overview

In this tutorial I will cover the LayoutContainer class, a javascript class created for the HTML Embed Widget which makes it simple for OpenTok developers to lay out a variable number of streams on the page in a way that minimizes empty space and does not affect other elements on the page. This tutorial assumes that you have a basic knowledge of how an OpenTok application works. If you do not, please first read the basic tutorial on how to get started.

The first part of this tutorial will go over the LayoutContainer class and explain its methods. The second part will go over usage of the LayoutContainer class within a simple OpenTok application. I suggest that you first try the LayoutContainer Sample app we are going to build to understand the problem and how this approach solves it before continuing.

Before we start, if you would like to download the LayoutContainer.js class and the sample code for what we are going to build, you can download both from the Github repository here.

The LayoutContainer Class

The LayoutContainer class is made up of four methods. I will go through each of these four methods and explain when and how to use them.

LayoutContainer.init(divId, width, height)

The LayoutContainer.init() method initializes the div where you want your streams to be displayed and should be called once at the beginning of your application. This method takes as parameters the div id of the div to be used to manage the streams, and the height and width that you would like that div to be (Note: you do not need to set this height and width in the markup or CSS, the LayoutContainer class will do it for you).

LayoutContainer.addStream(divId, publisher)

The LayoutContainer.addStream() method adds a stream to be managed by the LayoutContainer. This method will usually be called right before you subscribe or publish a stream. This method takes as parameters the id that you pass in to the Session.publish() or Session.subscribe() methods and also a boolean variable publisher that is true if the id you are passing in is from a publisher or false if the id is from a subscriber.

LayoutContainer.removeStream(subscriberId)

The LayoutContainer.removeStream() method removes a stream from being managed by the LayoutContainer. This method takes one parameter, the subscriber id of the subscriber from the stream to be removed.

LayoutContainer.layout()

The LayoutContainer.layout() method lays out the LayoutContainer to display changes from any streams that were added or removed. This method calculates the optimal row and column configuration to use to arrange the videos to minimize the amount of wasted space within the container (i.e. makes each stream as large as possible without going beyond the edge of the LayoutContainer). This method should usually be called after you have added or removed streams from the LayoutContainer to update the display.

Using the LayoutContainer Class

The first thing we must do is include the appropriate JavaScript files. We are going to include the LayoutContainer.js for the LayoutContainer and TB.min.js which is the OpenTok JavaScript API.

<script src="OT_LayoutContainer.js" type="text/javascript" charset="utf-8"></script>
<script src="http://staging.tokbox.com/v0.91/js/TB.min.js" type="text/javascript" charset="utf-8"></script>

Next we will initialize the session object and set up the event handlers we need.

var apiKey = 1127; // OpenTok sample API key. Replace with your own API key.
var sessionId = '287a9e4ad0aa8e501309df11fe53831452fa1167'; // Replace with your session ID.
var token = 'devtoken'; // Should not be hard-coded.

session = TB.initSession(sessionId);

session.addEventListener('sessionConnected', sessionConnectedHandler);
session.addEventListener('streamCreated', streamCreatedHandler);
session.addEventListener('streamDestroyed', streamDestroyedHandler);

We initialize our layout container (and we have a div with id “streamContainer” in the HTML). In this example I picked a resolution of 500px by 340px—you can adjust this to whatever size you would like your container to be.

OT_LayoutContainer.init("streamContainer", 500, 340);

Now before we define our sessionConnected, streamCreated, and streamDestroyed event handlers, we are going to create two helper methods for publishing and subscribing to streams.

function publishStream() {
	// Make up an id for our publisher
	var divId = 'opentok_publisher';

	// Pass in TRUE since this is a publisher
	OT_LayoutContainer.addStream(divId, true);

	session.publish(divId);
}

In the previous method we define an id, pass it to the LayoutContainer which will create the div for us and manage it for us, and then publish with it.

function subscribeToStreams(streams) {
	// For each stream
	for (var i = 0; i < streams.length; i++) {
		// Check if this is the stream that I am publishing, and if so do not subscribe.
		if (streams[i].connection.connectionId != session.connection.connectionId) {
			// Make a unique div id for this stream
			var divId = 'stream_' + streams[i].streamId;

			// Pass in FALSE since this is a subscriber
			OT_LayoutContainer.addStream(divId, false);

			session.subscribe(streams[i], divId);
		}
	}
}

In the previous method we take an array of streams, define unique ids for each one, and then again pass those ids to the LayoutContainer which takes care of creating and managing the divs for us. Finally, we subscribe to each stream.

Now that we have our helper methods set up and the session and LayoutContainer initialized, all that is left to do is set up our sessionConnected, streamCreated, and streamDestroyed event handlers.

function sessionConnectedHandler(event) {
    // Publish my stream to the session
	publishStream();			

	// Subscribe to all streams currently in the Session
	subscribeToStreams(event.streams);

	// Re-layout the container with the new streams
	OT_LayoutContainer.layout();
}

function streamCreatedHandler(event) {
	// Subscribe to the newly created streams
	subscribeToStreams(event.streams);

	// Re-layout the container with the new streams
	OT_LayoutContainer.layout();
}

function streamDestroyedHandler(event) {
	// Get all destroyed streams
	for (var i = 0; i < event.streams.length; i++) {
		// For each stream get the subscriber to that stream
		var subscribers = session.getSubscribersForStream(event.streams[i]);
		for (var j = 0; j < subscribers.length; j++) {
			// Then remove each stream
			OT_LayoutContainer.removeStream(subscribers[j].id);
		}
	}

	// Re-layout the container without the removed streams
	OT_LayoutContainer.layout();

}

These event handlers are pretty straight-forward. Whenever somebody connects they first publish and then subscribe to all existing streams. We subscribe to new streams when they are created and remove streams whenever they are destroyed. Notice that we call OT_LayoutContainer.layout() at the end of each event handler to update the display of the LayoutContainer with changes.

Now when we connect to the session we will have a div that contains all our streams. As people join and leave the session, the streams within the container will re-arrange themselves to make the most efficient use of the available space. Since all streams are contained within a fixed-size div, we do not need to worry about how the the varying number of streams might affect the rest of the page.

Conclusion

The LayoutContainer class is a simple solution for solving a common problem when it comes to video chat applications. Using this class is one solution, but it is certainly not the only one. If you have any ideas or are interested in hacking together your own classes and modules for other OpenTok developers to use, I would love you to post your thoughts here or tweet them @tokboxdev.

The LayoutContainer class, sample application, and documentation is available for download here.