CS 422 Spring 2026

Lab 5: Congestion Control for Audio Streaming [250 pts]

Due: 4/9/2026 (Thu), 11:59 PM

Objective

The aim of this lab is to implement feedback congestion control for pseudo real-time multimedia streaming. To not get sidetracked by video/audio coding standards and related issues, we will utilize audio representation close to raw audio streaming which allows us to focus on the networking components.

This problem may be tackled as a group effort involving up to 3 people. If going the group effort route, please specify in lab5ans.pdf on a separate cover page who did what work including programming the various software components, performance evaluation, and write-up. Designate one member as the contact person who will run turnin to submit the work. This person must email (xia170@purdue.edu) by April 2, 5pm, with subject line "CS 422 lab5 group members" specifying who the members are (full name and username). Please CC all members of the group. No changes to group membership are allowed after 4/2/2026 but for dropping members of a group. If so, please send email by 4/9/2026 noting the change. Whether you implement lab5 as an individual effort or make it a group effort is up to you. Keep in mind the trade-offs: group effort incurs coordination overhead which can slow down execution. Benefits include collaborative problem solving, fun (or not), and potential parallel speed-up if well executed. Regarding late days, for a group to use late days, every member of the group must have the same late days left.


Reading

Read chapters 5 and 6 from Peterson & Davie.


Problem 1 (250 pts)

1.1 Audio playback on lab machines

Prior to CS Linux lab machines transitioning to Ubuntu Linux, our Linux distros supported /dev/audio that provided a simple interface to play audio. For example, to play an audio file in .au format calling open() on /dev/audio and writing the content of the .au file sufficed. On command line, % cat somefile.au > /dev/audio, sufficed for playback on the default audio device of a lab machine running Linux or UNIX. With cessation of /dev/audio support in Ubuntu on our lab machines, we will use a slightly more complicated interface to play the content of an .au audio file on the default ALSA audio device of the Linux PCs. To get familiar with performing audio playback, copy two sample audio files pp.au (short piece) and kj.au (longer piece) from the course directory, and run

% /usr/bin/aplay pp.au

with an earphone plugged into an amber machine. If you don't hear anything, check that audio is not muted (under System -> Preferences -> Hardware -> Sound configuration tab) Do the same for kj.au which is a bit longer. If you don't have access to an earphone, please contact the TAs or me.

Playback of the two audio files serves as a reference for the quality of the stored audio without consideration of networking issues which we will tackle in the lab. After playback is confirmed using aplay, you will need to implement code to playback within the client code of the pseudo real-time audio streaming app. To do so, inspect the code muaudio.c in the course directory. Similar to aplay, muaudio.c takes an audio filename as command-line argument and plays the content of the file on the ALSA audio device. A second command-line argument specifies the time interval (in microseconds) between successive writes to the audio device. Set this to default value 313 msec (i.e., 313000). Test that it works by compiling muaudio.c with library -lasound and running it with the two .au audio files. Perceived audio quality should be similar to /usr/bin/aplay.

To port the playback component to your audio streaming client, copy the code pertaining to library functions mulawopen(), mulawclose(), mulawwrite() including header files and variable declarations to your client app. The code in muaudio.c reads the content of an .au file in unit of 4096 bytes (bufsiz) into main memory (buf), then writes the 4096 bytes contained in buf to the audio device by calling mulawwrite(). Between successive calls to mulawwrite(), muaudio.c calls usleep() to sleep for a fixed period specified by the argument slptime. The parameter slptime (in unit of microseconds) is provided as the second command-line argument of muaudio.c. Relating slptime to the playback rate gamma in the pseudo real-time streaming model, the larger slptime the smaller gamma since the latter is a rate. The recommended value of slptime to use in your client is 313000 microseconds. Use nanosleep() instead of usleep() to sleep between successive read/write of 4096 bytes to the audio device in the client.

1.2 Client/server interaction during streaming session set-up

Implement and evaluate an UDP-based pseudo real-time audio streaming application following the congestion control framework for multimedia streaming discussed in class. The client, musac, sends a TCP request packet to the server containing the name of the file to be streamed which cannot exceed 12 characters. The filename must be from lower-case or numeric characters, and end with postfix ".au" where the postfix is not included in the 12-byte length limitation. If a request does not conform to the required format, the streaming server, musas, sends a response that contains the single character 'q' then closes the socket returned by accept(). Describe in lab5ans.pdf what conditions you will check to determine if a request is invalid. If a request is deemed valid, the parent process (part of server musas) forks a child process that handles streaming of the requested audio file to the client. It outputs a message to stdout indicating that a new streaming session has been accepted along with the audio file name, client's IPv4 address and port number. The parent transmits 'K' to the client over the TCP connection then goes back to waiting for the next client request after closing the socket returned by accept().

The musas child process creates a UDP socket and binds to an ephemeral port number. It will use the UDP socket to transmit audio packets to the client using sendto(), and receive feedback packets from the client using recvfrom(). The client, musac, upon receiving a response on the SOCK_STREAM socket containing 'K' opens a UDP socket and binds to an unused port number starting at 51234. It sends the 2-byte port number over the TCP socket to the server (i.e., read by the musas child process). The server's child process saves the port number received so that audio packets can be sent using sendto() to the client's IPv4 address and port number.

1.3 Server structure

The server musas is invoked with command-line arguments

% musas server-IP server-port ilambda logfile.dat

where the first two arguments denote the server's IPv4 address and TCP port number where musas waits for client requests to arrive. The third argument ilambda (of type float) specifies the inverse of the initial sending rate. That is, whereas lambda is in unit of pps (packets per second), ilambda is 1/lambda so that it specifies the time interval between successive packets in unit of second. For example, ilambda = 0.000225 means that time interval between successive packets is 225 microseconds. logfile.dat is a log file where the time varying sending rates (i.e., ilambda) are recorded for diagnosis at the end of a streaming session. For simplicity we will limit the number of concurrent client sessions to 2. If a third streaming session arrives at musas while two sessions are on-going, the request is rejected. Since the server can handle two concurrent clients, logfile.dat of the first client should be prepended with character '1', 1logfile.dat, the second client's log file with '2', 2logfile.dat. If a third sequential client connects after one of the previous two has terminated (meaning it is accepted), its log file should be named 3logfile.dat.

To reduce influence of system overhead when carrying out measurement operations, save the time varying ilambda values in an array in main memory until a streaming session has ended before writing the data to the log file. Save the ilambda values, one per line, preceded by a timestamp from gettimeofday(). Subtract the first timestamp from successive timestamps so that time is normalized to start at 0 for the first logged ilambda value. Time stamps should be recorded in unit of millisecond with fractions truncated after 3 digits for microsecond resolution.

1.4 Client structure

For our audio streaming app, we will adopt a dumb sender/smart receiver design where the receiver (i.e., client) will command how the sender should adjust its audio data sending rate. The client, musac, runs with command-line arguments

% musac audiofile server-IP server-port igamma bufsize targetbf ctrace.dat

where audiofile is the name of an .au audiofile comprised of lower-case characters plus the postfix ".au"; server-IP and server-port specify the coordinate of the audio server. igamma is the inverse of the playback rate parameter gamma, by default, set to 313 msec for our testing and benchmarking purposes. bufsize specifies the size (in bytes) of the audio buffer at the client where audio packets received from the server will be kept before playback, targetbf (i.e., Q*) which specifies the desired occupancy of client buffer (e.g., if bufsize is 16 KB and targetbf 8 KB then the aim of streaming control is to keep the client's buffer half full). The last command-line argument, ctrace.dat, specifies a log file where the time varying audio buffer occupancy (ranging between 0 and bufsize) buffer size is recorded. Three control parameters ilambda, epsilon and beta, all of type float, are contained in a text file, control-param.dat (file name should be hardcoded), where ilambda is the same initial packet spacing provided as command-line argument of musas, epsilon and beta are control parameters of congestion control method D.

1.5 Client/server interaction during feedback control

A UDP feedback packet sent from client to server specifies up updated packetspacing, a 4-byte value of type float, which commands the server how fast it should transmit subsequent audio packets until the next feedback packet from the client is received. Upon receiving a feedback packet, the server updates ilambda accordingly. The client computes the updated packetspacing value using control law D: first, subtract the desired/target buffer occupancy Q* from the current audio buffer occupancy Q, then multiply the difference by parameter epsilon; second, subtract the previous igamma from ilambda which is then multiplied by control parameter beta. Since we are working with packet spacing as the control variable instead of sending rate, the direction of update in control law D is reversed. For example, if Q falls below Q* (there is too little buffered future audio) then Q - Q* is negative which implies that the updated ilambda value will be decreased thus increasing the rate at which future audio packets are sent aimed at increasing buffer occupancy. The second term is more subtle where, if igamma - ilambda is negative (sending rate is too slow), the updated ilambda is decreased thus increasing sending rate so that Q approaches Q* from below. On the other hand, if igamma - ilambda > 0 then sending rate lambda is already faster than playback rate gamma which, in conjunction with Q being below Q*, indicates that Q previously exceeded Q*. Hence the second term works in the opposite direction of the first term which acts as a dampening factor that contributes to convergence of the system to optimum buffer size Q = Q* and ilambda = igamma.

The client logs current buffer occupancy Q along with a normalized timestamp in main memory which, as in the server, is output to log file ctrace.dat when streaming has terminated to mitigate disk I/O overhead. Since all amber machines in our lab use a networked file system to mount user home directories, write the log file in /tmp which will be part of the local file system of a specific amber machine. Otherwise, two concurrent clients will write to the same file ctrace.dat. Note that files in /tmp may be deleted by the system during cleanup operations, hence use the mv command to relocate its content to a safe place in your home directory following testing. After the last data packet has been transmitted, musas (i.e., child process) transmits character 'Q' using the TCP socket which notifies the client that streaming has ended.

1.6 Data size in mulaw library

Default block size is fixed to 4096 bytes to be compatible with the internal parameters that mulawopen() and mulawwrite() are configured with. If blocksize is smaller than 4096, it can introduce complications that are best avoided for the scope of lab5. All audio data related parameters including targetbf and blocksize should be in multiples of 4096. Hardcode the buffer size using preprocessor directive #define.

1.7 musac/musas software architecture

Describe the software architecture of your client/server implementation and its rationale (over alternative implementations) in lab5ans.pdf. In lab2 and lab3 our software design focused on handling asynchronous events using signal handlers. In lab4 the tunneling server (i.e., child process) implemented a blocking design using select(). It is up to you to determine which design, including a hybrid design, may be suited for lab5. If your design involves blocking, you may use epoll() or poll() in place of select() that provide more scalable file descriptor monitoring capability.

1.8 Performance evaluation

To evaluate how well the pseudo real-time streaming app performs, plot the client and server log files which will show if the system is converging to the target buffer occupancy targetbf, and, if so, how fast. Run the server and client(s) on different amber machines. Configure buffersize in the mid 60 KB (multiple of 4096 bytes) range, and targetbf half its size as the default starting point. Experiment with different initial lambda values and other control parameters. Plot the the time series measurement logs using tools such as gnuplot (freeware), MatLab (free license at Purdue), or graph plotting software of your choice. The plots will help diagnose how your streaming control performs. gnuplot is very easy to use and produces professional quality graphical output in various formats for inclusion in documents. Discuss your findings in lab5ans.pdf. Submit your work in v1/ following the convention of previous labs along with README and Makefile.

Bonus problem (30 pts)

Add method B as an additional control law selected by setting a macro CONTROLMETHOD to 2 in the client. Setting CONTROLMETHOD to 1 reverts to method D. Submit the modified code in v2/. Plot the performance results of method B and compare them against the results of method D. Discuss your finding in lab5ans.pdf. If you choose to implement the bonus problem, it must be done as a group.


Turn-in instructions

Electronic turn-in instructions:

i) For problems that require answering/explaining questions, submit a write-up as a pdf file called lab5ans.pdf. Place lab5ans.pdf in your directory lab5/. You can use your favorite editor subject to that it is able to export pdf files which several freeware editors do. Files submitted in any other format will not be graded.

ii) We will use turnin to manage lab assignment submissions. Please check that relevant source code including Makefile are included in the relevant subdirectories of lab5. In the parent directory of lab5, run the command

turnin -c cs422 -p lab5 lab5

You can check/list the submitted files using

turnin -c cs422 -p lab5 -v


Back to the CS 422 web page