-
Notifications
You must be signed in to change notification settings - Fork 61
Expand file tree
/
Copy pathdemo.js
More file actions
129 lines (108 loc) · 5.42 KB
/
demo.js
File metadata and controls
129 lines (108 loc) · 5.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Yellowstone Example.
//
// Connects to the specified RTSP server url,
// Once connected, opens a file and streams H264 and AAC to the files
//
// Yellowstone is written in TypeScript. This example uses Javascript and
// the typescript compiled files in the ./dist folder
//
//
// Note on RTSPS (TLS) connection
// Test Bosch IP Camera with "RTSPS" will stream "rtp over rtsp" in a Secure RTSPS connection
// Text Axis IP Camera with "RTSPS" wants to encrypt the RTP packets (SRTP) which this library does not currently support and uses RTP/SAVP instead of RTP/AVP
// Used to connect to Wowza Demo URL but they have taken it away, and the replacement URL on their web site does not work.
const { RTSPClient, H264Transport, H265Transport, H266Transport, AV1Transport, AACTransport } = require("../dist");
const fs = require("fs");
const { exit } = require("process");
const { program } = require("commander");
program.name("demo");
program.description("Yellowstone RTSP Client Test Software");
program.option('-u, --username <value>', 'Optional RTSP Username');
program.option('-p, --password <value>', 'Optional RTSP Password');
program.option('-o, --outfile <value>', 'Optional Output File with no File Extension for captured H264/H265/AV1/AAC');
program.option('-t, --transport <value>', 'Optional RTP Transport - UDP or TCP');
program.argument('<rtsp url eg rtsp://1.2.3.4/stream1>');
program.parse(process.argv);
const options = program.opts();
// Will automatically exit if the Argument (the RTSL URL) is missing
const url = program.args[0];
let username = "";
let password = "";
if ('username' in options) username = options.username;
if ('password' in options) password = options.password;
let transport = "tcp";
if ('transport' in options) transport = options.transport.toString().toLowerCase();
const filename = "outfile"
console.log("Connecting to " + url);
// Step 1: Create an RTSPClient instance
const client = new RTSPClient(username, password);
// Step 2: Connect to a specified URL using the client instance.
//
// "keepAlive" option is set to true by default
// "connection" option is set to "udp" by default and defines the method the RTP media packets are set to Yellowstone. Options are "udp" or "tcp" (where RTP media packets are sent down the RTSP connection)
// "secure" option is set to true when connecting with TLS to the RTSP Server (eg for RTSPS)
client.connect(url, { connection: transport, secure: false })
.then(async (detailsArray) => {
console.log("Connected");
if (detailsArray.length == 0) {
console.log("ERROR: There are no compatible RTP payloads to save to disk");
exit();
}
for (let x = 0; x < detailsArray.length; x++) {
let details = detailsArray[x];
console.log(`Stream ${x}. Codec is`, details.codec);
// Step 3: Open the output file
if (details.codec == "H264") {
const videoFile = fs.createWriteStream(filename + '.264');
// Step 4: Create H264Transport passing in the client, file, and details
// This class subscribes to the client 'data' event, looking for the video payload
const h264 = new H264Transport(client, videoFile, details);
}
if (details.codec == "H265") {
const videoFile = fs.createWriteStream(filename + '.265');
// Step 4: Create H265Transport passing in the client, file, and details
// This class subscribes to the client 'data' event, looking for the video payload
const h265 = new H265Transport(client, videoFile, details);
}
if (details.codec == "H266") {
const videoFile = fs.createWriteStream(filename + '.266');
// Step 4: Create H266Transport passing in the client, file, and details
// This class subscribes to the client 'data' event, looking for the video payload
const h266 = new H266Transport(client, videoFile, details);
}
if (details.codec == "AV1") {
const videoFile = fs.createWriteStream(filename + '.obu');
// Step 4: Create AV1Transport passing in the client, file, and details
// This class subscribes to the client 'data' event, looking for the video payload
const av1 = new AV1Transport(client, videoFile, details);
}
if (details.codec == "AAC") {
const audioFile = fs.createWriteStream(filename + '.aac');
// Add AAC Transport
// This class subscribes to the client 'data' event, looking for the audio payload
const aac = new AACTransport(client, audioFile, details);
}
}
// Step 5: Start streaming!
await client.play();
console.log("Play sent");
})
.catch(e => {
console.log(e);
client.removeAllListeners();
client.close(true); // true = don't send a TEARDOWN
}
);
// The "data" event is fired for every RTP packet.
client.on("data", (channel, data, packet) => {
console.log("RTP:", "Channel=" + channel, "TYPE=" + packet.payloadType, "ID=" + packet.id, "TS=" + packet.timestamp, "M=" + packet.marker, (packet.wallclockTime == undefined ? "Time=Unknown" : "Time="+packet.wallclockTime.toISOString()));
});
// The "controlData" event is fired for every RTCP packet.
client.on("controlData", (channel, rtcpPacket) => {
console.log("RTCP:", "Channel=" + channel, "PT=" + rtcpPacket.packetType);
});
// The "log" event allows you to optionally log any output from the library.
// You can hook this into your own logging system super easily.
client.on("log", (data, prefix) => {
console.log(prefix + ": " + data);
});