--- sidebar_position: 9 --- # P2P and Media API P2P APIs send plugin data to connected peers. Media APIs play audio and contribute custom streams. ## Required Capabilities | Method | Capability | | --- | --- | | `p2p.connectedPeers()` | `p2p.data` | | `p2p.broadcastData(eventName, payload)` | `p2p.data` | | `p2p.sendData(peerId, eventName, payload)` | `p2p.data` | | `media.playAudioClip(request)` | `media.playAudio` | | `media.addCustomAudioStream(request)` | `media.addAudioStream` | | `media.addCustomVideoStream(request)` | `media.addVideoStream` | | `media.setInputVolume(volume)` | `audio.volume` | | `media.setOutputVolume(volume)` | `audio.volume` | ## Connected Peers ```js export function activate(context) { const peerIds = context.api.p2p.connectedPeers(); context.api.logger.info('Connected peers', { peerIds }); } ``` ## Broadcast Data ```js export function activate(context) { context.api.p2p.broadcastData('soundboard:played', { soundId: 'airhorn-short', label: 'Airhorn', playedBy: 'Alice', playedAt: 1777473600000 }); } ``` ## Send Data to One Peer ```js export function activate(context) { context.api.p2p.sendData('peer-muse-laptop', 'private-tool:ping', { requestId: 'ping-20260429-001', message: 'Are you receiving plugin data?' }); } ``` ## Play an Audio Clip ```js export async function activate(context) { await context.api.media.playAudioClip({ url: 'https://cdn.example.com/metoyou/sounds/chime.wav', volume: 0.65 }); } ``` ## Add a Custom Audio Stream ```js export async function activate(context) { const audioContext = new AudioContext(); const oscillator = audioContext.createOscillator(); const gain = audioContext.createGain(); const destination = audioContext.createMediaStreamDestination(); oscillator.type = 'sine'; oscillator.frequency.value = 440; gain.gain.value = 0.03; oscillator.connect(gain); gain.connect(destination); oscillator.start(); await context.api.media.addCustomAudioStream({ label: 'Tuning tone', stream: destination.stream }); setTimeout(async () => { oscillator.stop(); await audioContext.close(); }, 1000); } ``` ## Add a Custom Video Stream ```js export async function activate(context) { const canvas = document.createElement('canvas'); canvas.width = 1280; canvas.height = 720; const ctx = canvas.getContext('2d'); ctx.fillStyle = '#111827'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#ffffff'; ctx.font = '48px sans-serif'; ctx.fillText('Plugin camera scene', 80, 120); const stream = canvas.captureStream(15); await context.api.media.addCustomVideoStream({ label: 'Plugin camera scene', stream }); } ``` ## Set Volumes ```js export function activate(context) { context.api.media.setInputVolume(0.85); context.api.media.setOutputVolume(0.75); } ``` Use media APIs with visible controls and clear user consent. Unexpected audio or video is a poor user experience.