Help us shape the future of Go! Take the 2026 Go Developer Survey

xk6mediasoup

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2026 License: MIT Imports: 36 Imported by: 0

README

xk6-mediasoup

Đổi tên từ xk6-webrtc-ptt ngày 2026-10-09: module github.com/nguyendan07/xk6-mediasoup, import k6/x/mediasoup. Script cũ chỉ cần đổi dòng import. Metric ptt_* và biến môi trường PTT_* giữ nguyên.

Extension cho k6 (thông qua xk6) dùng để kiểm thử tải (load test) và đo lường hiệu năng hệ thống đàm thoại nhóm PTT (Push-to-Talk) chạy trên mediasoup SFU (Core v3).

Được xây dựng bằng Pure Go với Pion WebRTC v4 (Zero-CGO), extension này thay thế hoàn toàn stack Node.js cũ (node-wrtc), cho phép 1 tiến trình k6 duy trì hàng nghìn kết nối WebRTC đồng thời với mức tiêu thụ tài nguyên cực thấp (ước lượng ~2–4 MB RAM / peer, chưa đo).


🚀 Tính Năng Chính

  • Pure Go & Zero-CGO: Không phụ thuộc trình duyệt hay thư viện C++ native, build gọn nhẹ bằng xk6.
  • Chuẩn Signaling mediasoup v3: Bắt tay hai chiều qua WebSocket Protoo JSON-RPC 2.0 (getRouterRtpCapabilities, join, createWebRtcTransport, connectWebRtcTransport, produce, newConsumer).
  • Phát Audio Thời Gian Thực: Đọc file Ogg/Opus trực tiếp, nạp bộ nhớ đệm (shared memory cache) và phát đều đặn từng frame 20ms qua TrackLocalStaticSample.
  • Mô Phỏng Nghiệp Vụ PTT: Kích hoạt nói theo khoảng thời gian đặt trước (15s / 30s / 60s), hỗ trợ nhiều người nghe trong cùng một nhóm hoặc chồng lấn nhóm (group overlap).
  • Phân Loại & Ưu Tiên SOS (SOS Priority): Tách biệt toàn bộ metric đo lường giữa cuộc gọi khẩn cấp priority: "sos" và cuộc gọi thường priority: "normal".
  • Tích Hợp Sẵn Metrics k6:
    • ptt_join_duration (Trend): Thời gian kết nối và bắt tay WebRTC.
    • ptt_audio_jitter (Trend): Độ trễ biến thiên gói tin (ms).
    • ptt_audio_packet_loss_rate (Trend, %): Tỷ lệ mất gói tin âm thanh.
    • ptt_audio_mos (Trend): Điểm chất lượng âm thanh Mean Opinion Score (1.0 - 4.5) ước lượng theo mô hình ITU-T E-model rút gọn từ Loss % và Jitter.
    • ptt_audio_bitrate (Trend, bps): Tốc độ truyền tải âm thanh thực tế.
    • ptt_audio_packets_lost / ptt_audio_packets_received (Counter): Số lượng gói tin mất / nhận.
    • ptt_sessions_active (Gauge): 1/0 theo từng VU. Gauge của k6 chỉ giữ giá trị cuối, nên đây không phải tổng số session đang kết nối.
    • ptt_errors (Counter): Số lỗi phát sinh.
    • ptt_floor_request_duration (Trend): thời gian từ floorRequest tới khi server đồng ý (chỉ khi bật floorControl).
    • ptt_producer_score (Trend, 0–10): Điểm mediasoup chấm cho luồng speaker gửi lên (notification producerScore, mỗi encoding một mẫu), tag kind, priority.
    • ptt_consumer_score / ptt_consumer_producer_score (Trend, 0–10): Điểm của luồng SFU gửi tới listener và điểm của producer mà nó nhận (notification consumerScore, cộng điểm ban đầu kèm newConsumer), tag kind, priority. Server chỉ gửi khi điểm thay đổi, nên đây là các mẫu theo sự kiện, không phải trung bình theo thời gian.
    • ptt_audio_residual_loss_rate / ptt_video_residual_loss_rate (Trend, %): Mất gói còn lại sau khi NACK/RTX đã sửa, đo trên sequence number ứng dụng thực sự đọc được (mỗi gói được tính sau khi trễ 50 gói để chờ gói sửa). ptt_*_packet_loss_rate lấy từ stats của Pion: với video đây là mất gói trước khi RTX sửa, vì Pion gỡ RTX sau chuỗi interceptor.
    • ptt_server_loss_rate (Trend, %), ptt_server_jitter (Trend, ms, đổi từ đơn vị RTP timestamp theo clock rate), ptt_server_rtt (Trend, ms, chỉ khi server có giá trị), ptt_server_bitrate (Trend, bps), ptt_server_nacks, ptt_server_retransmitted, ptt_server_plis (Counter, theo delta): stats phía server khi bật serverStatsIntervalMs. Tag side=producer là luồng server nhận từ speaker, side=consumer là luồng server gửi tới listener (loss và jitter của phía này do listener báo qua RTCP), cùng kind, priority.
    • ptt_consumer_spatial_layer (Trend): Layer simulcast server đang gửi cho consumer, ghi mỗi khi consumerLayersChanged (-1 khi không có layer). Stats phía server của producer simulcast có thêm tag rid.
    • ptt_audio_quality_samples (Counter, tag priority): Số mẫu chất lượng audio (loss, MOS) đã ghi. Dùng làm ngưỡng độ phủ: case có SOS phải có mẫu sos.
    • ptt_ice_restarts (Counter, tag transport, trigger auto/manual, result), ptt_transport_recovery_time (Trend, từ lúc disconnected/failed tới khi connected lại), ptt_session_rejoins (Counter, tag result) và ptt_rejoin_duration (Trend).
    • ptt_server_transport_recv_bitrate, ptt_server_transport_send_bitrate, ptt_server_probation_bitrate, ptt_server_available_outgoing_bitrate (Trend, bps, tag transport): getTransportStats khi bật serverStatsIntervalMs. Hai metric sau là bitrate dò băng thông server gửi tới listener (nhận qua m-section probator) và ước lượng băng thông của server.
    • ptt_consumer_layers_changed (Counter): Số lần nhận consumerLayersChanged (chỉ có ý nghĩa khi có simulcast/SVC).

📦 Yêu Cầu & Cài Đặt

1. Yêu cầu môi trường
  • Go: $\ge 1.26$ (yêu cầu của k6 v2). Nên dùng Go 1.26.6 trở lên: govulncheck báo 11 lỗ hổng thư viện chuẩn ở Go 1.26.4, đã sửa ở 1.26.5/1.26.6.
  • k6: v2 (go.k6.io/k6/v2, đã thử với v2.3.0). xk6 tự chọn k6 v2 theo go.mod của extension.
  • xk6: đã build được với xk6 1.4.14. xk6 1.3.6 không build được k6 v2. Cài đặt bằng lệnh:
    go install go.k6.io/xk6/cmd/xk6@latest
    
2. Biên dịch k6 binary
# Di chuyển vào thư mục extension
cd xk6-mediasoup

# Build k6 binary với extension
xk6 build \
  --with github.com/nguyendan07/xk6-mediasoup=. \
  -o k6-mediasoup

Kiểm tra binary sau khi build:

./k6-mediasoup version
# k6-mediasoup v2.3.0 (...)
# Extensions:
#   github.com/nguyendan07/xk6-mediasoup (devel), k6/x/mediasoup [js]

# Smoke test không cần server (chạy từ thư mục gốc của repo)
./k6-mediasoup run examples/smoke.js

Kiểu TypeScript của toàn bộ API nằm ở index.d.ts.


📖 Hướng Dẫn Sử Dụng API (JavaScript)

Import Module
import mediasoup from "k6/x/mediasoup";
1. mediasoup.loadSample(filePath)

Nạp và phân giải file âm thanh .ogg (Opus) vào bộ nhớ RAM dùng chung giữa tất cả các Virtual Users (VUs). Đường dẫn tính từ thư mục chạy k6 (khác open() của k6, vốn tính từ thư mục của script). Đối tượng trả về có id, path, frameCount, levelsDecoded. mediasoup.loadVideo(filePath) tương tự cho VP8 IVF, trả về id, path, fourcc, width, height, fps, numFrames.

const sampleAudio = mediasoup.loadSample("sample/vi_ptt.ogg"); // giọng nói tiếng Việt, xem sample/OVERVIEW.md
const sampleVideo = mediasoup.loadVideo("sample/sample.ivf");
2. new mediasoup.Client(options)

Khởi tạo một client WebRTC cho Virtual User.

Bảng tham số cấu hình & Biến môi trường tương ứng:

[!WARNING] Giá trị đang chờ xác nhận thực tế — cần thử nhiều giá trị trước khi chốt default: Các giá trị mặc định dưới đây được thiết lập theo chuẩn WebRTC/mediasoup thông dụng và đặc tả CSV kịch bản, nhưng chưa được xác nhận chính thức từ backend GTalk thực tế (ví dụ: GTalk Node tool tham khảo đang dùng mono audio channels: 1, payload type / clock rate, có relay appData.priority hay không). Người chạy test cần linh hoạt điều chỉnh các biến môi trường PTT_* để kiểm chứng.

Thuộc tính (JS Option) Biến môi trường (__ENV) Kiểu dữ liệu Mặc định Ý nghĩa & Vị trí ánh xạ
serverUrl PTT_SERVER_URL / SERVER_URL string "ws://localhost:4443" URL WebSocket kết nối Mediasoup Protoo SFU.
roomId PTT_GROUP_BASE_ID number / string 1000 ID phòng/nhóm PTT đàm thoại.
peerId - string Tự sinh theo VU Định danh duy nhất của user (bot_<groupId>_vu<VU>).
token PTT_TOKEN / TOKEN string "TEST_JWT_TOKEN" JWT token xác thực phiên.
priority - string "normal" Mức ưu tiên luồng thoại ("sos" hoặc "normal").
insecureSkipVerify - bool true Bỏ qua xác thực SSL chứng chỉ tự ký.
dumpAudioPath PTT_DUMP_DIR (chỉ loadtest_gtalk.js) string "" (không ghi) Đường dẫn file .ogg để lưu audio thực nhận (Hướng B tính MOS/PESQ). Go không đọc biến môi trường. loadtest_gtalk.js ghi <PTT_DUMP_DIR>/g<group>_vu<vu>.ogg cho một listener mỗi nhóm đang nói. Một file cho mỗi client: luồng audio mới (ví dụ sau closeProducer) ghi đè file cũ.
audioChannels PTT_AUDIO_CHANNELS int 2 Số kênh âm thanh Opus (1: Mono, 2: Stereo). Ánh xạ vào a=rtpmap:111 opus/48000/<channels> và TrackLocalStaticSample.
opusPayloadType PTT_OPUS_PAYLOAD_TYPE int 111 RTP Dynamic Payload Type cho Opus audio codec.
opusClockRate PTT_OPUS_CLOCK_RATE int 48000 Sampling clock rate của Opus (48000 Hz).
enableAudioLevelExt PTT_ENABLE_AUDIO_LEVEL_EXT bool false Bật header extension urn:ietf:params:rtp-hdrext:ssrc-audio-level trong SDP.
enableRtx PTT_ENABLE_RTX bool false Bật RTP retransmission (rtx codec) trong SDP.
forceTcp PTT_FORCE_TCP bool false Ép buộc dùng WebRTC qua giao thức TCP thay vì UDP khi tạo WebRtcTransport.
strictPriority PTT_STRICT_PRIORITY bool false Khi true: Nếu appData.priority bị thiếu trong newConsumer, trả về lỗi và ghi nhận vào ptt_errors để fail test rõ ràng.
simulateSendLossPercent PTT_SIM_SEND_LOSS float 0 Bỏ ngẫu nhiên % gói RTP gửi đi ngay trước mạng (dưới bộ đệm NACK) để kiểm tra NACK/retransmit. Chỉ dùng cho kiểm thử, không bật khi đo benchmark thật.
controlMode PTT_CONTROL_MODE string "request" Cách gửi pauseProducer/resumeProducer/closeProducer/pauseConsumer/resumeConsumer: "request" (nhiều ứng dụng mediasoup) hoặc "notification" (mediasoup-demo 3.x). Cần xác nhận với GTalk.
floorControl PTT_FLOOR_CONTROL bool false Gửi floorRequest ({timestamp}) trước khi produce và floorRelease khi stopSpeaking (mọi mode), theo tool Node của GTalk. Bị từ chối thì startSpeaking ném lỗi và ghi ptt_errors{error_type:floor_request}. Payload và cách server báo từ chối cần GTalk xác nhận.
- PTT_MIC_RELEASE string "stop" (loadtest_gtalk.js) Cách nhả mic khi hết lượt nói: stop (chỉ ngừng gửi RTP), pause (pauseProducer), close (closeProducer).
autoRestartIce - bool true Tự gửi restartIce và áp iceParameters mới khi transport chuyển disconnected/failed (chờ 2 giây, tối đa 3 lần).
rejoinOnReconnect - bool true Join lại sau khi WebSocket tự reconnect (server mediasoup thường đóng peer cũ trùng peerId). Speaker đang nói sẽ nói tiếp phần thời gian còn lại.
iceDisconnectedTimeoutMs / iceFailedTimeoutMs - int 0 (5000 / 25000) Thời gian chờ ICE của Pion trước khi coi là disconnected / failed.
simulateRecvLossPercent PTT_SIM_RECV_LOSS float 0 Bỏ ngẫu nhiên % gói RTP nhận vào trước khi client thấy (dưới NACK generator) để kiểm tra NACK/RTX phía nhận. Khi bật, chống replay SRTP bị tắt vì gói gửi lại cùng sequence sẽ bị coi là replay. Chỉ dùng kiểm thử.
nackMaxPerPacket - int 0 (10) Số NACK tối đa cho mỗi gói thiếu (âm là không giới hạn). Extension dùng NACK generator riêng thấy cả gói sửa qua RTX, nên gói đã sửa không bị NACK lại.
serverStatsIntervalMs PTT_SERVER_STATS_MS int 0 (tắt) Chu kỳ (ms) gửi getProducerStats/getConsumerStats cho producer và consumer của client để ghi metric ptt_server_*. Tắt mặc định vì mediasoup-client không tự poll, bật sẽ tăng tải server (mỗi chu kỳ một request cho mỗi producer/consumer). Tool Node cũ của GTalk poll mỗi 1 giây.
simulcastLayers PTT_SIMULCAST_LAYERS int 0 (tắt) Số layer simulcast cho video (2–3, RID r0 thấp nhất). Các layer dùng chung frame của mẫu, layer thấp gửi ít frame hơn (với 3 layer: r0 1/4, r1 1/2) nên chỉ khác bitrate, không khác độ phân giải.
scalabilityMode PTT_SCALABILITY_MODE string "" Ghi vào encodings của video (ví dụ L1T3). SVC thật (VP9 L3T3) cần mẫu đã mã hóa SVC.
iceServers - array [] STUN/TURN cho cả hai PeerConnection, dạng RTCIceServer (urls, username, credential). Đổi lúc chạy bằng updateIceServers().
iceTransportPolicy - string "all" "relay": chỉ dùng candidate TURN, như option cùng tên của createSendTransport/createRecvTransport trong mediasoup-client. Dùng với iceServers để đo đường đi qua TURN.
opusStereo, opusFec, opusDtx, opusMaxPlaybackRate, opusMaxAverageBitrate, opusPtime - bool/int không khai báo codecOptions Opus của mediasoup-client, ghi vào tham số codec của produce (sprop-stereo, useinbandfec, usedtx, ptime). Như mediasoup-client, opusMaxPlaybackRate/opusMaxAverageBitrate không gửi trong produce (chỉ điều khiển bộ mã hóa của trình duyệt), nên không có tác dụng. Mẫu đã mã hóa sẵn nên mọi option này chỉ là khai báo, không đổi nội dung.
opusNack - bool false codecOptions.opusNack của mediasoup-client: khai báo nack cho producer audio để server NACK speaker. Mặc định tắt như trình duyệt dùng mediasoup-client. Khi tắt, rtpCapabilities gửi lên server cũng bỏ nack của codec audio (trình duyệt không khai báo), nên server không gửi lại audio bị mất cho listener. Bật để có NACK audio cả hai chiều (speaker và listener).
- PTT_DEBUG_PION 0/1 0 1 bật log debug của Pion và hiện lại các log đã xác định là nhiễu (Failed to handle DCEP).
transportFirst PTT_TRANSPORT_FIRST bool false Tạo recv transport trước join (đúng thứ tự mediasoup-client). Mặc định join trước, theo luồng GTalk đã xác nhận. mediasoup-demo chỉ gửi consumer sẵn có cho peer vào muộn ở thứ tự transport trước.
sendTransportOnJoin - bool false Tạo transport gửi cùng lúc với transport nhận (theo thứ tự transportFirst, cả khi rejoin), như ứng dụng mediasoup-client thường tạo cả hai transport lúc join. Khi tắt, transport gửi được tạo ở lần startSpeaking/startDataChannel đầu tiên, nên lần nói đầu phải chờ ICE/DTLS (khoảng 2 giây khi đi qua TURN). Bật thì mỗi listener cũng giữ một transport gửi trên server. Muốn gọi startDataChannel sau đó thì cần enableDataChannel: true, vì transport gửi tạo lúc join chỉ có SCTP khi bật cờ này.
joinPriority - bool false Gửi priority trong request join. Mặc định tắt vì backend chưa xác nhận field này (giao thức đã xác nhận chỉ có displayName/device/rtpCapabilities).
enablePtv PTT_ENABLE_PTV bool true Cờ bật tính năng Push-To-Video (PTV) theo kịch bản CSV.
ptvWidth PTT_PTV_WIDTH int 640 Chiều rộng khung hình video PTV.
ptvHeight PTT_PTV_HEIGHT int 480 Chiều cao khung hình video PTV.
ptvFps PTT_PTV_FPS int 15 Tốc độ khung hình video PTV (fps).
videoCodec PTT_VIDEO_CODEC string "VP8" Codec video sử dụng cho PTV ("VP8", "VP9", "H264").
enableDataChannel PTT_ENABLE_DATA_CHANNEL bool false Cờ bật truyền nhận dữ liệu DataChannel (chat / vị trí theo CSV).
dataIntervalMs PTT_DATA_INTERVAL_MS int 5000 Chu kỳ gửi tọa độ/tin nhắn DataChannel (ms).
- PTT_MOS_MIN_THRESHOLD float "" (không đặt cứng) Ngưỡng MOS tối thiểu (ví dụ: 3.5) để kích hoạt threshold ptt_audio_mos (TODO: chờ đội GTalk xác nhận ngưỡng chấp nhận).
3. Các phương thức của Client
  • client.connect(): Kết nối WebSocket, join room, khởi tạo WebRTC RecvTransport. Trả về true nếu thành công.
  • client.startSpeaking(opts): Khởi tạo SendTransport và phát âm thanh.
    • durationMs (number): Thời gian bấm mic PTT (ms), vd: 15000 (15s).
    • audio (AudioSample): Đối tượng sample audio tải từ mediasoup.loadSample().
    • priority (string): Ghi đè priority cho luồng phát ("sos" / "normal").
  • client.stopSpeaking(opts): Nhả mic PTT. opts.mode: "stop" (mặc định, chỉ ngừng gửi RTP), "pause" (gửi pauseProducer) hoặc "close" (gửi closeProducer).
  • client.pauseSpeaking() / client.resumeSpeaking(opts) / client.closeSpeaking(): Tạm dừng, tiếp tục (nhận cùng tham số như startSpeaking) hoặc đóng producer audio/video, tương ứng Producer.pause/resume/close của mediasoup-client cộng message pauseProducer/resumeProducer/closeProducer. Sau closeSpeaking, lần startSpeaking tiếp theo tạo producer mới.
  • client.setConsumerPreferredLayers({ spatialLayer, temporalLayer }) / client.requestKeyFrame(): Chọn layer simulcast hoặc xin keyframe cho mọi consumer video (setConsumerPreferredLayers/requestConsumerKeyFrame, gửi theo controlMode). Phía gửi trả lời PLI/FIR bằng cách quay về frame đầu (keyframe) của mẫu video.
  • client.startDataChannel(opts): opts tùy chọn như produceData của mediasoup-client: label, protocol, ordered, maxPacketLifeTime, maxRetransmits. Không truyền gì thì là kênh chat tin cậy, có thứ tự. Lần gọi đầu mở kênh mặc định và bộ gửi định kỳ (dataIntervalMs), gọi lại với label khác mở thêm một DataProducer trên cùng transport (như gọi produceData nhiều lần). Kênh gửi là kênh negotiated với stream id tự tăng, như mediasoup-client.
  • client.sendData(payload, label?): chuỗi và object (JSON) gửi dạng text (PPID 51) như send(string) của trình duyệt, mảng byte gửi dạng nhị phân. label chọn kênh đã mở, mặc định là kênh đầu tiên. ptt_data_messages_sent/ptt_data_messages_received có tag channel (label của kênh).
  • client.dataBufferedAmount(): Số byte đang chờ gửi trên DataChannel (DataProducer.bufferedAmount).
  • client.getStats(): Report stats WebRTC của transport gửi và nhận ({send: {...}, recv: {...}}), như getStats của mediasoup-client.
  • client.updateIceServers(list): Đổi STUN/TURN của các transport đang mở (Transport.updateIceServers).
  • client.setMaxSpatialLayer(n) / client.setRtpEncodingParameters({ encodings: [{ active }] }): Chỉ gửi layer simulcast 0..n, hoặc bật/tắt từng layer. Chỉ trường active có tác dụng vì mẫu đã mã hóa sẵn.
  • client.setConsumerPriority(priority): Gửi setConsumerPriority cho mọi consumer (thông điệp ứng dụng của mediasoup-demo).
  • client.canProduce(kind): true nếu router có một codec của "audio"/"video" mà client gửi được (Opus, VP8, VP9, H264), như Device.canProduce lấy giao với khả năng của thiết bị. Chỉ có ý nghĩa sau connect().
  • client.restartIce(): Gửi restartIce cho từng transport và áp iceParameters mới (như transport.restartIce của mediasoup-client). Tự động khi autoRestartIce bật.
  • client.pauseConsumers() / client.resumeConsumers(): Tạm dừng/tiếp tục nhận mọi consumer đang mở (gửi pauseConsumer/resumeConsumer, server tự ngừng và gửi lại luồng, SDP cục bộ không đổi).
  • Khi server gửi consumerPaused/consumerResumed, extension ghi nhận trạng thái và đếm vào ptt_consumer_state_changes{state,origin,kind}. dataConsumerClosed được đếm với state:closed, kind:data. Mỗi lệnh producer thành công được đếm vào ptt_producer_control{action}. Khác mediasoup-client, m-section không chuyển sang inactive: SDP phía nhận chỉ dùng nội bộ cho Pion, và việc đổi section làm Pion dựng lại receiver rồi mất luồng khi resume audio và video liên tiếp.
  • client.listen(opts): Duy trì kết nối phòng và thu thập metric thống kê dòng nhận:
    • durationMs (number): Thời gian lắng nghe (ms).
  • client.close(): Đóng sạch tất cả PeerConnections và WebSocket.

🎧 Dữ Liệu Mẫu Audio/Video

Benchmark không dùng micro hay webcam thật mà phát lại file mẫu: nội dung lặp lại được giữa các lần chạy và máy tải không tốn CPU để mã hóa. Extension đọc audio Ogg/Opus (mỗi gói 20 ms, loadSample) và video VP8 trong IVF (loadVideo). Dùng examples/prepare_media.sh để chuyển file nguồn sang đúng định dạng, xem examples/README.md.

Danh sách dưới đây là gợi ý, link và điều khoản giấy phép chưa được kiểm tra lại. Đọc giấy phép gốc trước khi dùng.

Audio (giọng nói)
Nguồn Nội dung Giấy phép Dùng cho
Open Speech Repository Câu Harvard, WAV 8/16 kHz, giọng Anh-Mỹ và Anh-Anh Miễn phí cho mục đích thử nghiệm File gốc cho PESQ (examples/calculate_mos.py), bộ mẫu quen thuộc của ngành VoIP
ITU-T P.501 Tín hiệu thử cho viễn thông: giọng nói nhiều ngôn ngữ, tín hiệu giả giọng Tải miễn phí từ ITU Đo chất lượng theo chuẩn
Mozilla Common Voice Câu ngắn do cộng đồng đọc, có tiếng Việt CC0 Câu ngắn giống lượt bấm nói PTT
Google FLEURS Đọc câu, 102 ngôn ngữ, có tiếng Việt CC BY 4.0 Mẫu tiếng Việt sạch
VIVOS (AILAB, ĐH KHTN TP.HCM) Khoảng 15 giờ giọng đọc tiếng Việt CC BY-NC-SA 4.0 Chỉ dùng nội bộ, không dùng thương mại
LibriSpeech Sách nói tiếng Anh CC BY 4.0 Mẫu dài
MUSAN, DEMAND Tiếng ồn, nhạc, tạp âm môi trường CC BY 4.0 Trộn vào giọng nói cho giống bộ đàm ngoài hiện trường
Video (PTV)
Nguồn Nội dung Giấy phép Ghi chú
Xiph.org Derf's collection Chuỗi kiểm thử .y4m chưa nén: akiyo, news, foreman, mother_daughter Dùng tự do cho nghiên cứu và kiểm thử akiyo/news là người nói ít chuyển động, gần với PTV nhất. foreman chuyển động nhiều, dùng để thử bitrate cao
Blender open movies (Big Buck Bunny, Sintel, Tears of Steel) Phim hoạt hình hoặc người đóng, độ phân giải cao CC BY Chuyển động nhiều, tải nặng
Pexels, Pixabay Clip ngắn có người nói trước camera Giấy phép riêng, miễn phí Giống camera điện thoại hoặc camera đeo người
ffmpeg -f lavfi (testsrc2, smptebars, mandelbrot) Video tổng hợp, không cần tải Không ràng buộc Nhanh cho smoke test, nhưng nén khác nhiều so với cảnh thật
Chọn mẫu
  • Đo PESQ: dùng Open Speech Repository hoặc ITU-T P.501, giữ bản WAV 16 kHz gốc làm file đối chiếu.
  • Giống người dùng GTalk: mẫu tiếng Việt từ Common Voice hoặc FLEURS, cắt thành đoạn 3–15 giây như một lượt bấm nói.
  • Nếu file mẫu được đưa vào repo hoặc gửi cho đối tác: chọn nguồn CC0 hoặc CC BY và ghi nguồn. Tránh VIVOS (không dùng thương mại) và Pexels/Pixabay nếu cần phân phối lại.

🧪 Ví Dụ Kịch Bản Kiểm Thử

Kịch bản Smoke Test nhanh (examples/test_smoke.js)
import mediasoup from "k6/x/mediasoup";
import { check } from "k6";

export const options = { vus: 1, iterations: 1 };

export default function () {
  const client = new mediasoup.Client({
    serverUrl: "wss://127.0.0.1:4445",
    roomId: 1001,
    peerId: "test_user_01",
    token: "test_token",
    priority: "sos",
    insecureSkipVerify: true,
  });

  check(client, { "client ready": (c) => c !== null });
}

Chạy lệnh:

./k6-mediasoup run examples/test_smoke.js

Kịch bản Tải GTALK Phân Tách SOS vs Normal (examples/loadtest_gtalk.js)

Đây là ví dụ rút gọn để minh họa API. Kịch bản thật (examples/loadtest_gtalk.js) dùng chế độ steady, residual loss, MOS p5 và ngưỡng độ phủ theo priority, xem examples/README.md.

import mediasoup from "k6/x/mediasoup";
import { check, sleep } from "k6";

export const options = {
  scenarios: {
    gtalk_load: {
      executor: "ramping-vus",
      startVUs: 0,
      stages: [
        { duration: "10s", target: 50 }, // Ramp-up 50 users
        { duration: "60s", target: 50 }, // Giữ tải
        { duration: "5s", target: 0 },
      ],
    },
  },
  thresholds: {
    "ptt_audio_packet_loss_rate{priority:sos}": ["p(95)<1.0"], // SOS: Mất gói < 1%
    "ptt_audio_packet_loss_rate{priority:normal}": ["p(95)<3.0"], // Thường: Mất gói < 3%
    "ptt_audio_jitter{priority:sos}": ["p(95)<30"], // SOS Jitter < 30ms
  },
};

export default function () {
  const groupId = 1000 + Math.floor(__VU / 10);
  const peerId = `user_${groupId}_vu${__VU}`;
  const isSpeaker = __VU % 10 === 1; // 1 người nói / nhóm 10 người
  const isSos = groupId % 5 === 0; // 20% số nhóm là SOS
  const priority = isSos ? "sos" : "normal";

  const client = new mediasoup.Client({
    serverUrl: __ENV.SERVER_URL || "wss://<gtalk-host>:<port>",
    roomId: groupId,
    peerId: peerId,
    token: __ENV.TOKEN || "JWT_TOKEN",
    priority: priority,
    insecureSkipVerify: true,
  });

  try {
    if (client.connect()) {
      if (isSpeaker) {
        client.startSpeaking({ durationMs: 15000, priority });
        sleep(16);
        client.stopSpeaking();
      } else {
        client.listen({ durationMs: 30000 });
      }
    }
  } finally {
    client.close();
  }
}

📐 Design Decisions (Đơn Giản Hóa Có Chủ Đích)

  1. Codec Cố Định (Opus 48000/2ch - Payload 111):
    • Lý do: Hệ thống PTT chỉ xử lý giọng nói mono/stereo. Việc cố định cấu hình Opus loại bỏ hàng trăm dòng code thương lượng SDP/ORTC phức tạp mà vẫn tương thích 100% với mediasoup router mặc định.
    • Upgrade path: Có thể đọc động routerRtpCapabilities.codecs nếu SFU thay đổi payload type trong tương lai.
  2. Zero-CGO Audio Streaming:
    • Lý do: Tránh phụ thuộc libopus qua CGO để đảm bảo xk6 build chạy được trên mọi môi trường CI/CD mà không cần cài đặt toolchain C++. File audio mẫu được chuyển thành định dạng .ogg (Opus) trước khi chạy test.
  3. Phân Tách Dữ Liệu Phía Client (Client-side SOS Isolation):
    • Lý do: Bất kể server mediasoup có thuật toán ưu tiên gói tin SOS hay không, client luôn gắn tag priority: "sos" | "normal" vào mọi metric k6 để phục vụ báo cáo chất lượng độc lập.

📄 Giấy phép

MIT. Mẫu giọng nói sample/vi_ptt.* lấy từ Mozilla Common Voice (CC0), xem sample/OVERVIEW.md.

Documentation

Overview

Package xk6mediasoup registers the mediasoup load-testing extension (k6/x/mediasoup) with k6.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CalculateMOS

func CalculateMOS(lossPercent float64, jitterMs float64) float64

CalculateMOS estimates Mean Opinion Score (MOS) using simplified ITU-T G.107 E-model proxy.

NOTE: This is a proxy derived from RTP-layer stats (loss % and jitter ms), not MOS measured directly on received audio content — it does not replace listening tests in edge cases (Full load, SOS full load).

func CreateSyntheticIVFBytes

func CreateSyntheticIVFBytes(width, height uint16, fps int, numFrames int) ([]byte, error)

CreateSyntheticIVFBytes creates a valid in-memory IVF VP8 container byte slice for testing.

func CreateWebRTCAPI

func CreateWebRTCAPI(profiles ...mediasoup.SDPProfile) (*webrtc.API, stats.Getter, error)

CreateWebRTCAPI initializes the Pion WebRTC API instance with stats interceptor and media engines. If an SDPProfile is provided, custom Opus channels, clock rate, and payload type are registered.

func GenerateSilentOpusFrames

func GenerateSilentOpusFrames(count int) [][]byte

GenerateSilentOpusFrames returns valid Opus silent frames (1-byte TOC + silence).

func GenerateTestPatternVP8Frames

func GenerateTestPatternVP8Frames(width, height uint16, count int) [][]byte

GenerateTestPatternVP8Frames creates minimal valid VP8 keyframe payloads for testing / fallback.

func MakeTags

func MakeTags(base *metrics.TagSet, tags map[string]string) *metrics.TagSet

MakeTags builds a k6 TagSet with sorted keys.

func RecordValue

func RecordValue(ctx context.Context, samples chan<- metrics.SampleContainer, metric *metrics.Metric, val float64, tags *metrics.TagSet, t time.Time)

RecordValue pushes a sample point to k6 metrics engine. Many callers are background goroutines (notifications, DataChannel, recovery, stats polls) that outlive the run: once ctx (the VU's context) is done k6 stops draining samples, so the send gives up instead of blocking forever.

Types

type AudioSample

type AudioSample struct {
	ID     uint64   `json:"id" js:"id"`
	Path   string   `json:"path" js:"path"`
	Frames [][]byte `json:"-" js:"-"` // not exposed: large, only Go reads it
	// LevelsDecoded is how many frames got a real level from decoding (the rest use the size heuristic).
	LevelsDecoded int `json:"levelsDecoded" js:"levelsDecoded"`
	// FrameCount is len(Frames), for scripts.
	FrameCount int `json:"frameCount" js:"frameCount"`
}

AudioSample represents pre-parsed Opus frames loaded in RAM.

func LoadAudio

func LoadAudio(filePath string) (*AudioSample, error)

LoadAudio loads an Ogg/Opus file into memory: one entry per Opus packet (20 ms), with the OpusHead/OpusTags header packets skipped, plus a per-frame audio level. Ponytail note: Read once into shared memory, reuse across thousands of VUs.

func ResolveAudioSample

func ResolveAudioSample(val any) (*AudioSample, error)

ResolveAudioSample safely extracts or loads an AudioSample from various JS representations.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client represents a single virtual user PTT endpoint.

func NewClient

func NewClient(vu modules.VU, m *Metrics, opts ClientOptions) *Client

NewClient instantiates a new Client.

func (*Client) CanProduce

func (c *Client) CanProduce(kind string) bool

CanProduce reports whether the router has a codec for the kind ("audio"/"video"), like mediasoup-client Device.canProduce. False before connect.

func (*Client) Close

func (c *Client) Close() error

Close closes all transports and connections.

func (*Client) CloseSpeaking

func (c *Client) CloseSpeaking() (bool, error)

CloseSpeaking closes the producers on the SFU, the next startSpeaking produces new ones.

func (*Client) Connect

func (c *Client) Connect() (bool, error)

Connect performs the signaling handshake, joins the room, and initializes RecvTransport.

func (*Client) DataBufferedAmount

func (c *Client) DataBufferedAmount() uint64

DataBufferedAmount is the bytes queued on the data producer (DataProducer.bufferedAmount).

func (*Client) GetStats

func (c *Client) GetStats() map[string]any

GetStats returns the WebRTC stats reports of both transports ({send: {...}, recv: {...}}), like Transport/Producer/Consumer.getStats in mediasoup-client.

func (*Client) Listen

func (c *Client) Listen(opts map[string]any)

Listen keeps the client active and polls stats periodically for the specified duration.

func (*Client) PauseConsumers

func (c *Client) PauseConsumers() (bool, error)

PauseConsumers pauses receiving for every open consumer, locally and on the SFU (pauseConsumer).

func (*Client) PauseSpeaking

func (c *Client) PauseSpeaking() (bool, error)

PauseSpeaking pauses the audio/video producers (mic released, producers kept on the SFU).

func (*Client) RequestKeyFrame

func (c *Client) RequestKeyFrame() (bool, error)

RequestKeyFrame asks the SFU for a key frame on every video consumer (requestConsumerKeyFrame).

func (*Client) RestartIce

func (c *Client) RestartIce() (bool, error)

RestartIce restarts ICE on every transport, like calling mediasoup-client's transport.restartIce after the app's restartIce request.

func (*Client) ResumeConsumers

func (c *Client) ResumeConsumers() (bool, error)

ResumeConsumers resumes every consumer paused with PauseConsumers or by the SFU.

func (*Client) ResumeSpeaking

func (c *Client) ResumeSpeaking(opts map[string]any) (bool, error)

ResumeSpeaking resumes paused producers and streams again with the same options as startSpeaking.

func (*Client) SendData

func (c *Client) SendData(payload any, label string) error

SendData sends a payload on the data channel of label ("" or omitted = the first one opened). Strings and objects (as JSON) go as text like a browser's send(string), bytes as binary.

func (*Client) SetConsumerPreferredLayers

func (c *Client) SetConsumerPreferredLayers(opts map[string]any) (bool, error)

SetConsumerPreferredLayers asks the SFU for a spatial/temporal layer on every video consumer (mediasoup-client Consumer.setPreferredLayers plus the app's setConsumerPreferredLayers).

func (*Client) SetConsumerPriority

func (c *Client) SetConsumerPriority(priority int) (bool, error)

SetConsumerPriority sends setConsumerPriority for every consumer (app-level message of mediasoup-demo, the SFU uses it to share bandwidth between consumers).

func (*Client) SetMaxSpatialLayer

func (c *Client) SetMaxSpatialLayer(n int) (bool, error)

SetMaxSpatialLayer sends simulcast layers 0..n only (Producer.setMaxSpatialLayer).

func (*Client) SetRtpEncodingParameters

func (c *Client) SetRtpEncodingParameters(params map[string]any) (bool, error)

SetRtpEncodingParameters applies {encodings: [{active}]} per simulcast layer (Producer.setRtpEncodingParameters). Only "active" applies: the media is pre-encoded, so bitrate or resolution fields cannot change the stream.

func (*Client) StartDataChannel

func (c *Client) StartDataChannel(opts map[string]any) (bool, error)

StartDataChannel opens the data producer. opts (optional) are mediasoup-client produceData options: label, protocol, ordered, maxPacketLifeTime, maxRetransmits.

func (*Client) StartSpeaking

func (c *Client) StartSpeaking(opts map[string]any) (bool, error)

StartSpeaking initializes SendTransport if needed, registers producer, and transmits audio.

func (*Client) StopSpeaking

func (c *Client) StopSpeaking(opts map[string]any)

StopSpeaking releases the mic. opts.mode: "stop" (default, only stops sending), "pause" (pauseProducer) or "close" (closeProducer). Which one GTalk uses is still to be confirmed. With floorControl, floorRelease follows in every mode.

func (*Client) StreamVideo

func (c *Client) StreamVideo(opts map[string]any) (bool, error)

StreamVideo starts standalone video streaming for PTV speaker.

func (*Client) UpdateIceServers

func (c *Client) UpdateIceServers(list []map[string]any) (bool, error)

UpdateIceServers replaces the STUN/TURN servers of both transports (Transport.updateIceServers).

type ClientOptions

type ClientOptions struct {
	ServerURL          string `json:"serverUrl"`
	RoomID             any    `json:"roomId"`
	PeerID             string `json:"peerId"`
	Token              string `json:"token"`
	Priority           string `json:"priority"`
	InsecureSkipVerify bool   `json:"insecureSkipVerify"`
	DumpAudioPath      string `json:"dumpAudioPath"`

	// Media & Protocol Tuning
	AudioChannels            int                   `json:"audioChannels"`
	OpusPayloadType          int                   `json:"opusPayloadType"`
	OpusClockRate            int                   `json:"opusClockRate"`
	EnableAudioLevelExt      bool                  `json:"enableAudioLevelExt"`
	EnableRTX                bool                  `json:"enableRtx"`
	ForceTCP                 bool                  `json:"forceTcp"`
	StrictPriority           bool                  `json:"strictPriority"`
	SimulcastLayers          int                   `json:"simulcastLayers"`    // video simulcast encodings r0..rN-1 (0/1 = off, max 3)
	ScalabilityMode          string                `json:"scalabilityMode"`    // copied into video encodings (e.g. "L1T3")
	IceServers               []mediasoup.IceServer `json:"iceServers"`         // STUN/TURN servers (RTCIceServer: urls, username, credential)
	IceTransportPolicy       string                `json:"iceTransportPolicy"` // "all" (default) or "relay": media only through TURN
	mediasoup.OpusOptions                          // opusStereo, opusFec, opusDtx, opusMaxPlaybackRate, opusMaxAverageBitrate, opusPtime
	ServerStatsIntervalMs    int                   `json:"serverStatsIntervalMs"`    // poll getProducerStats/getConsumerStats (0 = off)
	NackMaxPerPacket         int                   `json:"nackMaxPerPacket"`         // NACKs per missing packet (0 = 10, negative = unlimited)
	SimulateRecvLossPercent  float64               `json:"simulateRecvLossPercent"`  // drop % of incoming RTP to exercise NACK/RTX towards the client
	SimulateSendLossPercent  float64               `json:"simulateSendLossPercent"`  // drop % of outgoing RTP to exercise NACK
	SendTransportOnJoin      bool                  `json:"sendTransportOnJoin"`      // create the send transport with the recv one, not at the first startSpeaking
	TransportFirst           bool                  `json:"transportFirst"`           // create the recv transport before join (mediasoup-client order)
	IceDisconnectedTimeoutMs int                   `json:"iceDisconnectedTimeoutMs"` // Pion ICE disconnected timeout (0 = 5000)
	IceFailedTimeoutMs       int                   `json:"iceFailedTimeoutMs"`       // Pion ICE failed timeout after disconnected (0 = 25000)
	AutoRestartIce           *bool                 `json:"autoRestartIce"`           // restart ICE when a transport goes disconnected/failed (default true)
	RejoinOnReconnect        *bool                 `json:"rejoinOnReconnect"`        // join again after the WebSocket reconnected (default true)
	ControlMode              string                `json:"controlMode"`              // "request" (default) or "notification" for pause/resume/close messages
	JoinPriority             bool                  `json:"joinPriority"`             // send priority in the join request (unconfirmed by backend)
	FloorControl             bool                  `json:"floorControl"`             // GTalk floorRequest before speaking, floorRelease at stopSpeaking

	// PTV & DataChannel Options (CSV Scenario parameters)
	EnablePTV         *bool  `json:"enablePtv"`
	PTVWidth          int    `json:"ptvWidth"`
	PTVHeight         int    `json:"ptvHeight"`
	PTVFPS            int    `json:"ptvFps"`
	VideoCodec        string `json:"videoCodec"`
	EnableDataChannel *bool  `json:"enableDataChannel"`
	DataIntervalMs    int    `json:"dataIntervalMs"`
}

ClientOptions represents options passed from JS to new Client().

func (ClientOptions) IsAutoRestartIce

func (o ClientOptions) IsAutoRestartIce() bool

func (ClientOptions) IsEnableDataChannel

func (o ClientOptions) IsEnableDataChannel() bool

func (ClientOptions) IsEnablePTV

func (o ClientOptions) IsEnablePTV() bool

func (ClientOptions) IsRejoinOnReconnect

func (o ClientOptions) IsRejoinOnReconnect() bool

type ConsumerStats

type ConsumerStats struct {
	ConsumerID   string
	Kind         string
	SSRC         uint32
	Priority     string
	PacketsLost  int64
	PacketsTotal uint64
	DeltaPackets uint64 // packets received since previous poll
	DeltaLost    int64  // packets lost since previous poll
	// Residual loss after NACK/RTX repairs, as read by the application (see seqTracker).
	ResidualExpected, ResidualLost int64
	Jitter                         float64
	Bitrate                        float64 // in bps
}

ConsumerStats holds extracted metrics from an active consumer.

type ConsumerTrack

type ConsumerTrack struct {
	ID         string
	ProducerID string
	PeerID     string
	Kind       string // "audio" | "video"
	SSRC       uint32
	Priority   string
	Mid        string // SFU-assigned rtpParameters.mid (arrival index when absent)
	Exts       []mediasoup.RtpHeaderExtension

	RtxPT    uint8
	RtxSSRC  uint32
	Feedback []string
	PT       uint8  // payload type override (probator: 127)
	Codec    string // video codec name from the consumer (VP8, VP9, H264)

	Track             *webrtc.TrackRemote
	LastBytesReceived uint64
	LastPackets       uint64
	LastLost          int64
	LastStatsTime     time.Time
	// contains filtered or unexported fields
}

ConsumerTrack holds state and stats of an active consumer stream.

type ControlSender

type ControlSender func(ctx context.Context, method string, data map[string]any) error

ControlSender delivers an app-level control message (request or notification, see ControlMode).

type DataMessageCallback

type DataMessageCallback func(label string, data []byte)

DataMessageCallback receives incoming SCTP DataChannel messages.

type DataOptions

type DataOptions struct {
	Label             string  `json:"label"`
	Protocol          string  `json:"protocol"`
	Ordered           *bool   `json:"ordered"`
	MaxPacketLifeTime *uint16 `json:"maxPacketLifeTime"`
	MaxRetransmits    *uint16 `json:"maxRetransmits"`
}

ProduceData registers the SCTP DataChannel producer on Mediasoup SFU. DataOptions are mediasoup-client produceData options (zero value = reliable, ordered "chat").

type Metrics

type Metrics struct {
	JoinDuration               *metrics.Metric
	Jitter                     *metrics.Metric
	PacketLossRate             *metrics.Metric
	PacketsLost                *metrics.Metric
	PacketsReceived            *metrics.Metric
	Bitrate                    *metrics.Metric
	MOS                        *metrics.Metric
	ActiveSessions             *metrics.Metric
	ConnectionFailed           *metrics.Metric
	Errors                     *metrics.Metric
	DataMessagesSent           *metrics.Metric
	DataMessagesReceived       *metrics.Metric
	DataSendLatency            *metrics.Metric
	VideoJitter                *metrics.Metric
	VideoPacketLossRate        *metrics.Metric
	VideoBitrate               *metrics.Metric
	FallbackUsed               *metrics.Metric
	ProducerControl            *metrics.Metric
	ConsumerStateChanges       *metrics.Metric
	ProducerScore              *metrics.Metric
	ConsumerScore              *metrics.Metric
	ConsumerProdScore          *metrics.Metric
	ConsumerLayers             *metrics.Metric
	ConsumerSpatialLayer       *metrics.Metric
	IceRestarts                *metrics.Metric
	QualitySamples             *metrics.Metric
	ServerLossRate             *metrics.Metric
	ServerJitter               *metrics.Metric
	ServerRTT                  *metrics.Metric
	ServerBitrate              *metrics.Metric
	ServerNacks                *metrics.Metric
	ServerRetransmitted        *metrics.Metric
	ServerPlis                 *metrics.Metric
	ServerTransportRecvBitrate *metrics.Metric
	ServerTransportSendBitrate *metrics.Metric
	ServerProbationBitrate     *metrics.Metric
	ServerAvailableOutgoing    *metrics.Metric
	ResidualLossRate           *metrics.Metric
	VideoResidualLossRate      *metrics.Metric
	RecoveryTime               *metrics.Metric
	Rejoins                    *metrics.Metric
	RejoinDuration             *metrics.Metric
	FloorRequest               *metrics.Metric
}

Metrics holds k6 metric descriptors.

func RegisterMetrics

func RegisterMetrics(registry *metrics.Registry) *Metrics

RegisterMetrics registers all PTT metrics into k6 registry.

type Module

type Module struct {
	// contains filtered or unexported fields
}

Module is the VU-specific module instance.

func (*Module) Exports

func (m *Module) Exports() modules.Exports

Exports exports the JS API functions and constructors.

type RecvTransport

type RecvTransport struct {
	// contains filtered or unexported fields
}

RecvTransport manages the downstream WebRTC connection for audio consumption (Listener).

func NewRecvTransport

func NewRecvTransport(protooCli *protoo.Client, params *mediasoup.TransportParams, api *webrtc.API, statsGetter stats.Getter, profile mediasoup.SDPProfile, onStateChange StateChangeCallback, onDataMessage DataMessageCallback, dumpAudioPath string, strictPriority bool) (*RecvTransport, error)

NewRecvTransport creates a RecvTransport.

func (*RecvTransport) Close

func (rt *RecvTransport) Close() error

Close terminates the recv transport.

func (*RecvTransport) ConsumerIDs

func (rt *RecvTransport) ConsumerIDs() []string

ConsumerIDs returns the ids of the open consumers.

func (*RecvTransport) ConsumerInfo

func (rt *RecvTransport) ConsumerInfo(id string) (kind, priority string, ok bool)

ConsumerInfo returns kind and priority of an open consumer (ok is false when unknown).

func (*RecvTransport) ConsumerKind

func (rt *RecvTransport) ConsumerKind(id string) string

ConsumerKind returns the media kind of an open consumer ("" when unknown).

func (*RecvTransport) GetStats

func (rt *RecvTransport) GetStats() []ConsumerStats

GetStats collects stats across all active consumers and calculates real bitrate (Fix Issue 10).

func (*RecvTransport) HandleNewConsumer

func (rt *RecvTransport) HandleNewConsumer(ctx context.Context, req *mediasoup.NewConsumerRequest) error

HandleNewConsumer processes a server request for a new incoming audio consumer.

func (*RecvTransport) HandleNewDataConsumer

func (rt *RecvTransport) HandleNewDataConsumer(ctx context.Context, data json.RawMessage) error

HandleNewDataConsumer follows mediasoup-client's receiveDataChannel: create a negotiated DataChannel on the recv PC (id = streamId) and, the first time, add the m=application section.

func (*RecvTransport) ID

func (rt *RecvTransport) ID() string

ID returns the SFU transport id.

func (*RecvTransport) PeerConnection

func (rt *RecvTransport) PeerConnection() *webrtc.PeerConnection

PeerConnection exposes the PC for getStats and updateIceServers.

func (*RecvTransport) RemoveConsumer

func (rt *RecvTransport) RemoveConsumer(consumerID string)

RemoveConsumer closes a consumer and renegotiates its m-section as closed (mediasoup-client's stopReceiving), so the section can be recycled by a later consumer of the same kind.

func (*RecvTransport) RemoveConsumersByProducerID

func (rt *RecvTransport) RemoveConsumersByProducerID(producerID string)

RemoveConsumersByProducerID closes every consumer of a producer.

func (*RecvTransport) RemoveDataConsumer

func (rt *RecvTransport) RemoveDataConsumer(dataConsumerID string) bool

RemoveDataConsumer closes the channel of a dataConsumerClosed notification. It reports whether the data consumer was known.

func (*RecvTransport) RestartIce

func (rt *RecvTransport) RestartIce(ctx context.Context, ice mediasoup.IceParameters) error

RestartIce applies new SFU iceParameters, like mediasoup-client's recv handler: a new remote offer with the new credentials (Pion restarts ICE when the remote ufrag changes), then the answer.

func (*RecvTransport) SetConsumersPaused

func (rt *RecvTransport) SetConsumersPaused(ids []string, paused bool) []string

SetConsumersPaused records the paused state of consumers (Consumer.pause/resume). Unknown ids are ignored. Returns the ids changed.

type RootModule

type RootModule struct {
	// contains filtered or unexported fields
}

RootModule represents the root extension module.

func New

func New() *RootModule

New creates a new RootModule.

func (*RootModule) NewModuleInstance

func (r *RootModule) NewModuleInstance(vu modules.VU) modules.Instance

NewModuleInstance creates a new module instance for each VU.

type SendTransport

type SendTransport struct {
	// contains filtered or unexported fields
}

SendTransport manages the upstream WebRTC connection for audio/video publishing (Speaker).

func NewSendTransport

func NewSendTransport(ctx context.Context, protooCli *protoo.Client, params *mediasoup.TransportParams, api *webrtc.API, profile mediasoup.SDPProfile, onStateChange StateChangeCallback) (*SendTransport, error)

NewSendTransport creates and negotiates a SendTransport with Mediasoup SFU.

func (*SendTransport) Close

func (st *SendTransport) Close() error

Close terminates the send transport and peer connection.

func (*SendTransport) CloseProducers

func (st *SendTransport) CloseProducers(ctx context.Context, send ControlSender) error

CloseProducers stops media, closes the producers on the SFU and forgets their ids, so the next StartSpeaking produces again (mediasoup-client Producer.close plus closeProducer).

func (*SendTransport) DataBufferedAmount

func (st *SendTransport) DataBufferedAmount() uint64

DataBufferedAmount is the bytes queued on the data channel (DataProducer.bufferedAmount).

func (*SendTransport) DefaultDataLabel added in v0.2.0

func (st *SendTransport) DefaultDataLabel() string

DefaultDataLabel is the label of the first produced data channel ("" before any).

func (*SendTransport) ID

func (st *SendTransport) ID() string

ID returns the SFU transport id.

func (*SendTransport) PauseProducers

func (st *SendTransport) PauseProducers(ctx context.Context, send ControlSender) error

PauseProducers stops sending media and tells the SFU (mediasoup-client Producer.pause with zeroRtpOnPause, plus the app's pauseProducer message).

func (*SendTransport) PeerConnection

func (st *SendTransport) PeerConnection() *webrtc.PeerConnection

PeerConnection exposes the PC for getStats and updateIceServers.

func (*SendTransport) Produce

func (st *SendTransport) Produce(ctx context.Context, priority string) (string, error)

Produce registers the audio producer on Mediasoup SFU.

func (*SendTransport) ProduceData

func (st *SendTransport) ProduceData(ctx context.Context, opts DataOptions, appData map[string]any) (*webrtc.DataChannel, string, error)

ProduceData opens a DataChannel and registers it with produceData. The default reliable "chat" channel is created with the transport (so the first SDP has m=application), other options get a channel of their own on the already running SCTP association. The first produced channel is the default one (SendData without a label, periodic sender), each further label gets its own DataProducer, like calling mediasoup-client's produceData again. A known label is returned as is.

func (*SendTransport) ProduceVideo

func (st *SendTransport) ProduceVideo(ctx context.Context, priority string) (string, error)

ProduceVideo registers the video producer on Mediasoup SFU for PTV.

func (*SendTransport) ProducerIDs

func (st *SendTransport) ProducerIDs() []string

ProducerIDs returns the open audio/video producer ids.

func (*SendTransport) ProducerKind

func (st *SendTransport) ProducerKind(id string) string

ProducerKind returns "audio"/"video" for one of this transport's producers ("" when unknown).

func (*SendTransport) RestartIce

func (st *SendTransport) RestartIce(ice mediasoup.IceParameters) error

RestartIce applies new SFU iceParameters (from the restartIce request), like mediasoup-client's send handler: ICE-restart offer, then the remote answer rebuilt with the new credentials.

func (*SendTransport) ResumeProducers

func (st *SendTransport) ResumeProducers(ctx context.Context, send ControlSender) error

ResumeProducers tells the SFU to resume, and the caller restarts the media writers.

func (*SendTransport) SendDataMessage

func (st *SendTransport) SendDataMessage(label string, data []byte, text bool) error

SendDataMessage sends bytes through the SCTP DataChannel. SendDataMessage sends on the channel of label ("" = the default one). text sends a WebRTC string (PPID 51) like a browser's send(string), since mediasoup apps may ignore binary (e.g. the demo's bot).

func (*SendTransport) SetLayersActive

func (st *SendTransport) SetLayersActive(active []bool) error

SetLayersActive enables/disables simulcast layers (lowest first), like setting encodings[i].active in mediasoup-client. Layers beyond the list keep their state.

func (*SendTransport) StopSpeaking

func (st *SendTransport) StopSpeaking()

StopSpeaking cancels ongoing audio, video, and data transmissions.

func (*SendTransport) StreamAudio

func (st *SendTransport) StreamAudio(frames [][]byte, duration time.Duration)

StreamAudio sends audio frames with 20ms pacing until duration expires or cancel is called.

func (*SendTransport) StreamVideo

func (st *SendTransport) StreamVideo(frames [][]byte, fps int, duration time.Duration)

StreamVideo sends video frames paced by the configured FPS until duration expires or cancel is called.

type StateChangeCallback

type StateChangeCallback func(transportType string, state webrtc.PeerConnectionState)

StateChangeCallback receives connection state changes.

type StatsCollector

type StatsCollector struct {
	// contains filtered or unexported fields
}

StatsCollector proxies stats.Getter across all PeerConnections on an API instance.

func (*StatsCollector) Add

func (s *StatsCollector) Add(g stats.Getter)

func (*StatsCollector) Get

func (s *StatsCollector) Get(ssrc uint32) *stats.Stats

type VideoSample

type VideoSample struct {
	ID        uint64   `json:"id" js:"id"`
	Path      string   `json:"path" js:"path"`
	FourCC    string   `json:"fourcc" js:"fourcc"`
	Width     uint16   `json:"width" js:"width"`
	Height    uint16   `json:"height" js:"height"`
	FPS       int      `json:"fps" js:"fps"`
	NumFrames int      `json:"numFrames" js:"numFrames"`
	Frames    [][]byte `json:"-" js:"-"` // not exposed: large, only Go reads it
}

VideoSample represents pre-parsed IVF video frames loaded in RAM.

func LoadVideo

func LoadVideo(filePath string) (*VideoSample, error)

LoadVideo loads an IVF video file (VP8/VP9/AV1) into memory. Ponytail note: Read once into shared memory, reuse across thousands of VUs.

func ResolveVideoSample

func ResolveVideoSample(val any) (*VideoSample, error)

ResolveVideoSample safely extracts or loads a VideoSample from various JS representations.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL