@homebridge/camera-utils
Version:
Utilities to simplify homebridge camera plugin development
96 lines • 3.93 kB
JavaScript
import { FfmpegProcess } from './ffmpeg-process.js';
import { reservePorts } from './ports.js';
import { getSsrc } from './rtp.js';
import { RtpSplitter } from './rtp-splitter.js';
import { createCryptoLine } from './srtp.js';
const defaultStartStreamReqeuest = {
audio: {
codec: 'AAC_eld',
channel: 1,
sample_rate: 16,
pt: 110,
},
};
export class ReturnAudioTranscoder {
options;
returnRtpSplitter;
startStreamRequest;
ffmpegProcess;
constructor(options) {
this.options = options;
this.startStreamRequest = this.options.startStreamRequest || defaultStartStreamReqeuest;
this.ffmpegProcess = new FfmpegProcess({
ffmpegArgs: [
'-hide_banner',
'-protocol_whitelist',
'pipe,udp,rtp,file,crypto',
'-f',
'sdp',
'-acodec',
this.startStreamRequest.audio.codec === 'OPUS' ? 'libopus' : 'libfdk_aac',
'-i',
'pipe:',
'-map',
'0:0',
...this.options.outputArgs,
],
...this.options,
});
// allow return audio splitter to be passed in if you want to create one in the prepare stream phase, and create the transcoder in the stream request phase
this.returnRtpSplitter = options.returnAudioSplitter || new RtpSplitter();
}
reservedPortsPromise = reservePorts({ count: 2 });
// Removed duplicate constructor
async start() {
const [rtpPort, rtcpPort] = await this.reservedPortsPromise;
const { targetAddress, addressVersion, audio: { srtp_key: srtpKey, srtp_salt: srtpSalt }, } = this.options.prepareStreamRequest;
const { ssrc: incomingAudioSsrc, rtcpPort: incomingAudioRtcpPort } = this.options.incomingAudioOptions;
const { codec, sample_rate, channel, pt: packetType, } = this.startStreamRequest.audio;
this.ffmpegProcess.writeStdin(
// This SDP was generated using ffmpeg, and describes the type of packets we expect to receive from HomeKit.
[
'v=0',
'o=- 0 0 IN IP4 127.0.0.1',
's=Talk',
`c=IN ${addressVersion
.replace('v', '')
.toUpperCase()} ${targetAddress}`,
't=0 0',
'a=tool:libavformat 58.38.100',
`m=audio ${rtpPort} RTP/AVP ${packetType}`,
'b=AS:24',
...(codec === 'OPUS'
? [
`a=rtpmap:${packetType} opus/${sample_rate}000/${channel}`,
`a=fmtp:${packetType} minptime=10;useinbandfec=1`,
]
: [
`a=rtpmap:${packetType} MPEG4-GENERIC/${sample_rate}000/${channel}`,
`a=fmtp:${packetType} profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=F8F0212C00BC00`,
]),
createCryptoLine({
srtpKey,
srtpSalt,
}),
].join('\n'));
this.returnRtpSplitter.addMessageHandler(({ isRtpMessage, message }) => {
// This splitter will receive all audio-related packets from HomeKit.
// This includes RTP + RTCP for return audio, as well as RTCP for incoming audio
if (!isRtpMessage && getSsrc(message) === incomingAudioSsrc) {
return {
port: incomingAudioRtcpPort,
};
}
return {
port: isRtpMessage ? rtpPort : rtcpPort,
};
});
// this is the port that needs to be passed to homebridge as audio.port
return this.returnRtpSplitter.portPromise;
}
stop() {
this.ffmpegProcess.stop();
this.returnRtpSplitter.close();
}
}
//# sourceMappingURL=return-audio-transcoder.js.map