CanJam
This was a project that I worked on with three other students for our Concurrency course; Skylar Gilfeather, Cecelia Crumlish, and Roger Burtonpatel. You can find our detailed final report here.
CanJam is a multiplayer melody maker that allows users to play music with each other across multiple laptop instances. We were inspired by the Chrome Music Lab Melody Maker. Our goal with this project is to build a fun, colorful and fun-to-play visual interface, including different musical instruments.
Project Goal
The minimum deliverable for CanJam was to display unique colors and play unique synth sounds for each user interacting with the canvas. This goal was achieved, supporting four different synth types. In the future, optimizing the synth generation process, or using a different sound library entirely, could allow us to generate a wider variety of sounds.
Additionally, our minimum deliverable required that users could connect CanJam canvases independent of a central server - i.e., CanJam should be peer-to-peer. In our protocol, users manage setup communications and share sound packets with their peers in a connected cluster of CanJam instances. However, because CanJam peers share sounds by unreliably broadcasting large batches of small Sound packets, it was difficult to achieve the illusion of continuously playing sound. It sounds more like short beats of sound. However, despite this drawback, our testing showed that at least six CanJam users could collaboratively play on the same canvas with no increase in these performance issues when playing a peer's incoming sounds.
The Jamsocket Module
One of my largest contributions to this project was the jamsocket
module - a socket wrapper that provides both reliable and unreliable UDP communication methods. I designed the jamsocket
protocol to provide speedy (but unreliable) message sending methods alongside slower (but reliable) message sending methods. Both features operate over the same UDP socket. Key features of the Jamsocket
class include:
- It uses the
socket
library to create and manage a UDP socket. - It provides methods to send and receive data, with optional reliability.
- It uses a separate thread that listens for incoming packets and handles timeouts for outstanding packets.
- It uses different types of packets, including
Ack
,Data
,DataNoAck
,Skip
,Die
,Hello
, andHelloAck
to send data and maintain connections with otherJamsocket
s.
The Jamsocket
class is used by the multithreaded InboundWorker
and OutboundWorker
classes to send and receive messages over the network. Sound
messages are sent unreliably to achieve low-latency, while all other messages are sent reliably to ensure a consistent room state.
Conclusion
I used many of the skills I gained from my other networking courses at Tufts for this project. It gave me full creative freedom to design a peer-to-peer protocol and a neat socket wrapper protocol, as well as learning tons about concurrency in Python! As four undergraduate seniors, it put our project management skills to the test to delegate work efficiently and design decoupled modules that interfaced well together.
If you're interested in the real nitty gritty, find our final report here, and find the full codebase here.
signpost care to venture further?
Projects
CanJam - a multithreaded peer-to-peer sound canvas
CyberGrape - a tactile spatial audio system
RPC - remote procedure calls in C
filecopy - copy files over a highly unreliable network