A modern, real-time Teams meeting recording bot powered by Azure Communication Services
This project demonstrates how to build an intelligent Teams meeting recording bot using Azure Communication Services (ACS). The bot can automatically join Teams meetings, record high-quality audio streams, and provide interactive features like text-to-speech announcements.
Built with modern technologies including NestJS, TypeScript, and WebSockets, this example showcases best practices for developing communication applications on Azure.
- ποΈ Automatic Meeting Recording: Seamlessly joins Teams meetings and records audio in real-time
- π Text-to-Speech Integration: Powered by OpenAI TTS for natural-sounding announcements
- π Real-time Dashboard: Beautiful web interface for monitoring active calls and recordings
- π WebSocket Streaming: Low-latency audio streaming and real-time event updates
- π± DTMF Support: Interactive touch-tone responses during calls
- π§ High-Quality Audio: 24kHz PCM audio recording with unmixed channel support
- π Live Analytics: Real-time statistics and call monitoring
- π¨ Modern UI: Dark/light theme support with responsive design
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β Teams Meeting β β ACS Bot β β Dashboard β
β βββββΊβ βββββΊβ β
β β’ Audio Stream β β β’ Call Control β β β’ Live Stats β
β β’ Participants β β β’ Recording β β β’ Audio Player β
β β’ Events β β β’ TTS/DTMF β β β’ Controls β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β WebSocket β
β β
β β’ Real-time β
β β’ Audio Data β
β β’ Events β
βββββββββββββββββββ
- Node.js 18+ and npm
- Azure Communication Services resource
- OpenAI API key (for TTS functionality)
- Teams meeting to test with
git clone https://github.com/Azure-Samples/acs-teams-recording.git
cd acs-teams-recordingnpm installCopy the example environment file and configure your settings:
cp .env.example .envEdit .env with your Azure and OpenAI credentials:
# Azure Communication Services Configuration
ACS_CONNECTION_STRING=endpoint=https://your-acs-resource.communication.azure.com/;accesskey=your-access-key
# Optional: Display name for the bot when joining Teams meetings
ACS_DISPLAY_NAME=ACS Audio Recording Bot
# Base URL for webhook callbacks (update this for production deployment)
BASE_URL=http://localhost:3000
# OpenAI API Configuration for Text-to-Speech
OPENAI_API_KEY=sk-your-openai-api-key-here
OPENAI_TTS_ENDPOINT=https://your-cognitive-services-resource.cognitiveservices.azure.com/openai/deployments/gpt-4o-mini-tts/audio/speech?api-version=2025-03-01-preview
# Optional: Enable debug logging
DEBUG_TEAMS_CALLING=trueSince Azure Communication Services needs to send webhook events to your application, your local server must be accessible from the internet. Use Visual Studio Dev Tunnels to expose port 3000:
# Install Dev Tunnels (if not already installed)
# For macOS with Homebrew:
brew install --cask devtunnel
# Create and start a tunnel to port 3000
devtunnel create --allow-anonymous
devtunnel port create -p 3000
devtunnel hostCopy the public URL provided by devtunnel (e.g., https://abc123.devtunnels.ms) and update your .env file:
# Update BASE_URL with your devtunnel URL
BASE_URL=https://abc123.devtunnels.msπ‘ Important: The devtunnel URL is required because Azure Communication Services needs to send EventGrid webhooks to your
/acs/eventsendpoint from the internet.
# Development mode with hot reload
npm run start:dev
# Production mode
npm run start:prodOpen your browser and navigate to:
- Dashboard: http://localhost:3000/dashboard.html
- API Endpoints: http://localhost:3000/acs/
When a Teams meeting invitation is sent to your ACS resource, the bot automatically:
- Receives the incoming call event via EventGrid webhook
- Answers the call and joins the meeting
- Sets up audio streaming configuration
- Establishes WebSocket connection for real-time audio streaming
- Receives unmixed audio streams from meeting participants
- Processes and saves audio as WAV files in the
recordings/directory - Provides real-time feedback through the dashboard
- DTMF Tones: Send touch-tone signals during calls
- Text-to-Speech: Convert text to natural speech using OpenAI TTS
- Call Management: Hang up, transfer, or manage call states
- WebSocket-powered dashboard for live updates
- Call statistics and participant information
- Audio session management and playback
This example is perfect for learning how to build:
- π Call Center Solutions: Automated call handling and recording
- π Meeting Assistants: AI-powered meeting bots with transcription
- π Compliance Recording: Legal and regulatory call recording systems
- π€ Customer Support: Automated support with TTS responses
- π Analytics Platforms: Real-time call analysis and monitoring
src/
βββ call-automation/ # ACS call handling and automation
β βββ call-automation.service.ts
β βββ call-automation.controller.ts
β βββ call-events.types.ts
βββ websocket/ # Real-time communication
β βββ websocket.gateway.ts
β βββ audio-streaming.service.ts
β βββ websocket.service.ts
βββ main.ts # Application entry point
public/
βββ dashboard.html # Real-time monitoring dashboard
recordings/ # Audio recordings storage
# Docker & Deployment
Dockerfile # Multi-stage production Dockerfile
.dockerignore # Optimized Docker build context
Makefile # Automated deployment commands
deployment.env # ACR configuration
deployment.env.example # Configuration template
The project includes a production-optimized Dockerfile with the following features:
# Stage 1: Build stage (Node.js 22 Alpine)
FROM node:22-alpine AS builder
# Install dependencies and build application
# Stage 2: Production stage (Node.js 22 Alpine)
FROM node:22-alpine AS production
# Copy only production files and dependencies- Non-root user: Runs as
nestjsuser (UID 1001) - Minimal attack surface: Alpine Linux base image
- Proper signal handling: Uses
dumb-initfor graceful shutdowns - File permissions: Secure ownership and permissions
- Layer caching: Optimized layer order for faster rebuilds
- Production dependencies: Only installs runtime dependencies
- Clean builds: Removes build artifacts and caches
- Health checks: Built-in container health monitoring
# Development
npm run start:dev # Start with hot reload
npm run start:debug # Start with debugging
# Production
npm run build # Build for production
npm run start:prod # Run production build
# Code Quality
npm run lint # Run ESLint
npm run format # Format code with Prettier
npm run test # Run unit tests
npm run test:e2e # Run end-to-end tests
# Docker & Deployment
make help # Show all deployment commands
make validate # Validate ACR configuration
make build-and-push # Build and push to Azure Container Registry
make dev-build # Local development build
make run-local # Build and run locally| Method | Endpoint | Description |
|---|---|---|
POST |
/acs/events |
EventGrid webhook for ACS events |
GET |
/calls |
List active calls |
POST |
/calls/{id}/tts |
Send text-to-speech |
POST |
/calls/{id}/hangup |
Hang up call |
GET |
/recordings |
List audio recordings |
GET |
/ws |
WebSocket endpoint |
The included dashboard provides:
- π Real-time Statistics: Active calls, connected clients, audio sessions
- π Call Management: View active calls, send TTS, hang up calls
- π΅ Audio Playback: Listen to recorded audio files
- π± Interactive Controls: Send DTMF tones, manage call states
- π Theme Support: Beautiful dark and light modes
- π Live Charts: Visual representation of activity over time
const DEFAULT_MEDIA_STREAMING_CONFIG = {
transportType: 'websocket',
contentType: 'audio',
audioChannelType: 'unmixed', // Separate audio streams per participant
enableBidirectional: true, // Enable both sending and receiving audio
audioFormat: 'Pcm24KMono', // High-quality 24kHz mono audio
startDelayMs: 500 // Delay before starting recording
};const DEFAULT_TTS_CONFIG = {
text: 'Hello, this is a test message from Azure Communication Services.',
voice: 'en-US-JennyNeural', // OpenAI voice mapping
language: 'en-US',
waitTimeMs: 3500 // Wait time before starting recording
};This project includes production-ready Docker configuration and automated deployment tools for Azure.
The project includes a multi-stage Dockerfile optimized for production deployment with multi-architecture support.
- Configure your Azure Container Registry details:
# Copy and edit the deployment configuration
cp deployment.env.example deployment.env
# Edit deployment.env with your ACR details
ACR_NAME=your-acr-name
ACR_LOGIN_SERVER=your-acr-name.azurecr.io- Build and push to Azure Container Registry:
# Make sure you're logged into Azure
az login
# Build and push multi-architecture image (AMD64 + ARM64)
make build-and-push- Deploy to Azure Container Instances or App Service:
# Example: Deploy to Azure Container Instances
az container create \
--resource-group myResourceGroup \
--name acs-teams-recording \
--image your-acr-name.azurecr.io/acs-teams-recording:latest \
--environment-variables \
ACS_CONNECTION_STRING="$ACS_CONNECTION_STRING" \
OPENAI_API_KEY="$OPENAI_API_KEY" \
BASE_URL="https://your-container-instance.region.azurecontainer.io"The included Makefile provides automated deployment workflows:
# Show all available commands
make help
# Validate your configuration
make validate
# Build and push multi-platform image (recommended)
make build-and-push
# Development commands
make dev-build # Quick local build
make run-local # Build and run locally
make clean # Clean up build resources- Multi-stage build: Optimized for smaller production images
- Multi-architecture support: AMD64 and ARM64 (Apple Silicon compatible)
- Security: Non-root user, proper file permissions
- Health checks: Built-in container health monitoring
- Signal handling: Proper graceful shutdown with dumb-init
Set these environment variables in your deployment environment:
# Required: Azure Communication Services
ACS_CONNECTION_STRING=your-production-acs-connection-string
# Required: Public URL for webhooks
BASE_URL=https://your-app-name.azurewebsites.net
# Required: OpenAI Configuration
OPENAI_API_KEY=your-openai-api-key
OPENAI_TTS_ENDPOINT=your-openai-tts-endpoint
- Azure Communication Services Documentation
- Call Automation Overview
- Teams Interoperability
- NestJS Documentation
- OpenAI Text-to-Speech API
A: Create a Teams meeting and add your ACS resource's phone number or user ID as a participant. The bot will automatically join when the meeting starts.
A: Yes! Modify the audioFormat in the media streaming configuration. Options include Pcm16KMono and Pcm24KMono.
A: This is a sample application for learning purposes. For production use, add proper error handling, authentication, and security measures.
A: Currently, this example focuses on audio recording. Video recording would require additional ACS features and storage solutions.
A: Make sure the public/ directory is not excluded in .dockerignore. The included .dockerignore has been optimized to include necessary files while excluding development artifacts.
A: Ensure you have:
- Docker with buildx support installed
- Azure CLI installed and logged in (
az login) - Proper values set in
deployment.env - Run
make validateto check your configuration
A: Use these commands to troubleshoot:
# Build locally for testing
make dev-build
# Run container locally with logs
make run-local
# Check container health
docker ps
docker logs <container-id>This project is licensed under the MIT License - see the LICENSE file for details.
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Azure Support: Azure Communication Services Support
Happy coding! π
Built with β€οΈ by the Azure Communication Services team