Skip to content
GitLab
Explorer
Connexion
Navigation principale
Rechercher ou aller à…
Projet
S
Server Rtmp
Gestion
Activité
Membres
Labels
Programmation
Tickets
0
Tableaux des tickets
Jalons
Wiki
Jira
Code
Requêtes de fusion
0
Dépôt
Branches
Validations
Étiquettes
Graphe du dépôt
Comparer les révisions
Extraits de code
Compilation
Pipelines
Jobs
Planifications de pipeline
Artéfacts
Déploiement
Releases
Registre de paquets
Opération
Environnements
Modules Terraform
Surveillance
Incidents
Service d'assistance
Analyse
Données d'analyse des chaînes de valeur
Contributor analytics
Données d'analyse CI/CD
Données d'analyse du dépôt
Expériences du modèle
Aide
Aide
Support
Documentation de GitLab
Comparer les forfaits GitLab
Forum de la communauté
Contribuer à GitLab
Donner votre avis
Raccourcis clavier
?
Extraits de code
Groupes
Projets
marketing confort
Server Rtmp
Validations
7d8f9ffb
Valider
7d8f9ffb
rédigé
il y a 5 mois
par
oussama aftys
Parcourir les fichiers
Options
Téléchargements
Correctifs
Plain Diff
Update recorder.js
parent
8cce8ef3
Branches
ant-media
Aucune requête de fusion associée trouvée
Modifications
1
Masquer les modifications d'espaces
En ligne
Côte à côte
Affichage de
1 fichier modifié
register-live-api/recorder.js
+88
-73
88 ajouts, 73 suppressions
register-live-api/recorder.js
avec
88 ajouts
et
73 suppressions
register-live-api/recorder.js
+
88
−
73
Voir le fichier @
7d8f9ffb
...
...
@@ -5,11 +5,11 @@ require('dotenv').config();
const
s3
=
new
AWS
.
S3
({
credentials
:
{
accessKeyId
:
"
AKIA
3FLDZT775ARNAJHT
"
,
secretAccessKey
:
"
KE7/v+viEDQgevGH5CVoF5QXhDZ54vgp651RwW6s
"
accessKeyId
:
"
AKIA
TAVAAX3PWTIIE46W
"
,
secretAccessKey
:
"
nBPzcg40m43E0iDi7oV56JSEUcn5/2MXEUYLUbgj
"
},
region
:
process
.
env
.
AWS_REGION
||
"
eu-
north-1
"
,
endpoint
:
process
.
env
.
AWS_ENDPOINT
||
"
https://s3.eu-
north-1
.amazonaws.com
"
region
:
process
.
env
.
AWS_REGION
||
"
eu-
west-3
"
,
endpoint
:
process
.
env
.
AWS_ENDPOINT
||
"
https://s3.eu-
west-3
.amazonaws.com
"
});
...
...
@@ -23,47 +23,51 @@ const activeRecordings = new Map();
*/
function
startRecording
(
streamKey
)
{
const
outputFile
=
`/tmp/
${
streamKey
}
.mp4`
;
const
ffmpegArgs
=
[
'
-timeout
'
,
'
5000000
'
,
'
-reconnect
'
,
'
1
'
,
'
-reconnect_at_eof
'
,
'
1
'
,
'
-reconnect_streamed
'
,
'
1
'
,
'
-reconnect_delay_max
'
,
'
2
'
,
'
-i
'
,
`http://
127.0.0.1/hl
s/
${
streamKey
}
.m3u8`
,
'
-i
'
,
`http
s
://
ant-media-ovh.mydressin-server.com:5443/live/stream
s/
${
streamKey
}
_adaptive
.m3u8`
,
'
-c
'
,
'
copy
'
,
outputFile
,
];
// Introduce a 20-second delay before starting the FFmpeg process
setTimeout
(()
=>
{
// Spawn FFmpeg process after the delay
const
ffmpegProcess
=
spawn
(
'
ffmpeg
'
,
ffmpegArgs
);
// Spawn FFmpeg process
const
ffmpegProcess
=
spawn
(
'
ffmpeg
'
,
ffmpegArgs
);
// Handle stderr output (FFmpeg logs to stderr)
ffmpegProcess
.
stderr
.
on
(
'
data
'
,
(
data
)
=>
{
console
.
error
(
`[
${
streamKey
}
] FFmpeg Error:
${
data
}
`
);
});
// Handle stderr output (FFmpeg logs to stderr)
ffmpegProcess
.
stderr
.
on
(
'
data
'
,
(
data
)
=>
{
console
.
error
(
`[
${
streamKey
}
] FFmpeg Error:
${
data
}
`
);
});
// Handle process errors
ffmpegProcess
.
on
(
'
error
'
,
(
err
)
=>
{
console
.
error
(
`[
${
streamKey
}
] Process Error:
${
err
}
`
);
activeRecordings
.
delete
(
streamKey
);
});
// Handle process e
rrors
ffmpegProcess
.
on
(
'
e
rror
'
,
(
err
)
=>
{
console
.
error
(
`[
${
streamKey
}
]
Process Error:
${
err
}
`
);
activeRecordings
.
delete
(
streamKey
);
});
// Handle process e
xit
ffmpegProcess
.
on
(
'
e
xit
'
,
(
code
,
signal
)
=>
{
console
.
log
(
`[
${
streamKey
}
]
FFmpeg exited with code
${
code
}
(
${
signal
}
)
`
);
activeRecordings
.
delete
(
streamKey
);
});
// Handle process exit
ffmpegProcess
.
on
(
'
exit
'
,
(
code
,
signal
)
=>
{
console
.
log
(
`[
${
streamKey
}
] FFmpeg exited with code
${
code
}
(
${
signal
}
)`
);
activeRecordings
.
delete
(
streamKey
);
});
// Store recording information in Map
activeRecordings
.
set
(
streamKey
,
{
process
:
ffmpegProcess
,
outputFile
,
startTime
:
Date
.
now
()
});
// Store recording information in Map
activeRecordings
.
set
(
streamKey
,
{
process
:
ffmpegProcess
,
outputFile
,
startTime
:
Date
.
now
()
});
console
.
log
(
`[
${
streamKey
}
] FFmpeg process started after 20 seconds delay`
);
},
20000
);
// 20 seconds delay before starting FFmpeg
return
ffmpegProcess
.
pid
;
return
0
;
}
/**
...
...
@@ -73,56 +77,66 @@ function startRecording(streamKey) {
*/
async
function
stopRecording
(
streamKey
)
{
const
recording
=
activeRecordings
.
get
(
streamKey
);
if
(
!
recording
)
{
throw
new
Error
(
`No active recording for
${
streamKey
}
`
);
}
const
newFileName
=
`
${
streamKey
}
.mp4`
;
const
outputFile
=
`/tmp/
${
streamKey
}
.mp4`
;
const
{
process
:
ffmpegProcess
,
outputFile
}
=
recording
;
const
newFileName
=
`
${
streamKey
}
.mp4`
;
// Unique filename with timestamp
if
(
!
recording
)
{
console
.
error
(
`[
${
streamKey
}
] No active recording found`
);
// Use setImmediate to defer the upload and cleanup
setImmediate
(()
=>
uploadAndCleanup
(
outputFile
,
newFileName
));
return
{
status
:
'
error
'
,
message
:
`No active recording for
${
streamKey
}
`
};
}
else
{
try
{
// Graceful shutdown with SIGINT
ffmpegProcess
.
kill
(
'
SIGINT
'
);
// Wait for graceful exit with timeout
await
new
Promise
((
resolve
,
reject
)
=>
{
const
timeout
=
setTimeout
(()
=>
{
reject
(
new
Error
(
`[
${
streamKey
}
] FFmpeg shutdown timeout`
));
},
30000
);
// 30-second timeout
ffmpegProcess
.
once
(
'
exit
'
,
(
code
,
signal
)
=>
{
clearTimeout
(
timeout
);
if
(
code
===
0
)
{
console
.
log
(
`[
${
streamKey
}
] FFmpeg exited gracefully`
);
resolve
();
}
else
{
reject
(
new
Error
(
`[
${
streamKey
}
] FFmpeg exited with code
${
code
}
(
${
signal
}
)`
));
}
});
});
}
catch
(
err
)
{
console
.
error
(
`[
${
streamKey
}
] Error stopping recording:`
,
err
.
message
);
try
{
// Force kill if graceful shutdown failed
ffmpegProcess
.
kill
(
'
SIGKILL
'
);
}
catch
(
killErr
)
{
console
.
error
(
`[
${
streamKey
}
] Force kill failed:`
,
killErr
.
message
);
const
{
process
:
ffmpegProcess
}
=
recording
;
ffmpegProcess
.
kill
(
'
SIGINT
'
);
// Wait for graceful exit with timeout
await
new
Promise
((
resolve
,
reject
)
=>
{
const
timeout
=
setTimeout
(()
=>
{
reject
(
new
Error
(
`[
${
streamKey
}
] FFmpeg shutdown timeout`
));
},
30000
);
// 30-second timeout
ffmpegProcess
.
once
(
'
exit
'
,
(
code
,
signal
)
=>
{
clearTimeout
(
timeout
);
if
(
code
===
0
)
{
console
.
log
(
`[
${
streamKey
}
] FFmpeg exited gracefully`
);
resolve
();
}
else
{
reject
(
new
Error
(
`[
${
streamKey
}
] FFmpeg exited with code
${
code
}
(
${
signal
}
)`
));
}
});
});
}
catch
(
err
)
{
console
.
error
(
`[
${
streamKey
}
] Error stopping recording:`
,
err
.
message
);
try
{
// Force kill if graceful shutdown failed
ffmpegProcess
.
kill
(
'
SIGKILL
'
);
}
catch
(
killErr
)
{
console
.
error
(
`[
${
streamKey
}
] Force kill failed:`
,
killErr
.
message
);
}
}
finally
{
// Always clean up from active recordings
activeRecordings
.
delete
(
streamKey
);
}
}
finally
{
// Always clean up from active recordings
activeRecordings
.
delete
(
streamKey
);
}
try
{
await
uploadAndCleanup
(
outputFile
,
newFileName
);
return
{
// Use setImmediate to defer the upload and cleanup
setImmediate
(
async
()
=>
{
try
{
await
uploadAndCleanup
(
outputFile
,
newFileName
);
console
.
log
(
`[
${
streamKey
}
] Recording uploaded as
${
newFileName
}
`
);
}
catch
(
err
)
{
console
.
error
(
`[
${
streamKey
}
] Upload failed:`
,
err
.
message
);
}
});
return
{
status
:
'
success
'
,
message
:
`Recording
uploaded as
${
newFileName
}
`
,
message
:
`Recording
process initiated for
${
newFileName
}
`
,
file
:
newFileName
};
}
catch
(
err
)
{
console
.
error
(
`[
${
streamKey
}
] Upload failed:`
,
err
.
message
);
throw
err
;
}
}
...
...
@@ -138,6 +152,7 @@ async function uploadAndCleanup(outputFile, newFileName) {
console
.
log
(
`[
${
newFileName
}
] Local file cleaned up`
);
}
catch
(
err
)
{
console
.
error
(
`[
${
newFileName
}
] Cleanup error:`
,
err
.
message
);
fs
.
unlinkSync
(
outputFile
);
throw
err
;
}
}
...
...
@@ -152,9 +167,9 @@ async function uploadToS3(filePath, newFileName) {
return
new
Promise
((
resolve
,
reject
)
=>
{
// Use file stream for memory efficiency
const
fileStream
=
fs
.
createReadStream
(
filePath
);
const
params
=
{
Bucket
:
'
bucket-rtmp
'
,
Bucket
:
'
mydressin-live-records
'
,
Key
:
newFileName
,
Body
:
fileStream
,
ContentType
:
'
video/mp4
'
,
...
...
This diff is collapsed.
Click to expand it.
Aperçu
0%
Veuillez réessayer
ou
joindre un nouveau fichier
.
Annuler
You are about to add
0
people
to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Enregistrer le commentaire
Annuler
Veuillez vous
inscrire
ou vous
se connecter
pour commenter