update restream concierge configuration format, hand out actual node url
This commit is contained in:
parent
124e366268
commit
e2130621ad
|
@ -47,44 +47,6 @@ class Stream(models.Model):
|
||||||
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Stream)
|
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Stream)
|
||||||
|
|
||||||
|
|
||||||
class Restream(models.Model):
|
|
||||||
FORMATS = (
|
|
||||||
('flv', 'flv (RTMP)'),
|
|
||||||
('mpegts', 'mpegts (SRT)'),
|
|
||||||
)
|
|
||||||
stream = models.ForeignKey(Stream, on_delete=models.CASCADE, help_text=_('restream_stream_help'))
|
|
||||||
target = models.CharField(max_length=500, help_text=_('restream_target_help'))
|
|
||||||
name = models.CharField(max_length=100, help_text=_('restream_name_help'))
|
|
||||||
active = models.BooleanField(help_text=_('restream_activate_help'))
|
|
||||||
format = models.CharField(max_length=6, choices=FORMATS, default='flv', help_text=_('restream_format_help'))
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = _('restream_verbose_name')
|
|
||||||
verbose_name_plural = _('restream_verbose_name_plural')
|
|
||||||
|
|
||||||
def class_name(self):
|
|
||||||
return _('restream_class_name')
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse('config:restream_detail', kwargs={'pk': self.pk})
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '{} to {}'.format(self.stream, self.name)
|
|
||||||
|
|
||||||
def get_json_config(self):
|
|
||||||
config = {
|
|
||||||
'name': self.name,
|
|
||||||
'app': settings.GLOBAL_STREAM_NAMESPACE,
|
|
||||||
'stream': str(self.stream.stream),
|
|
||||||
'target': self.target,
|
|
||||||
'format': self.format
|
|
||||||
}
|
|
||||||
return json.dumps(config)
|
|
||||||
|
|
||||||
|
|
||||||
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Restream)
|
|
||||||
|
|
||||||
|
|
||||||
class SRSNode(models.Model):
|
class SRSNode(models.Model):
|
||||||
name = models.CharField(max_length=100, help_text=_('srsnode_name_help'))
|
name = models.CharField(max_length=100, help_text=_('srsnode_name_help'))
|
||||||
api_base = models.CharField(max_length=256, help_text=_('srsnode_api_base_help'))
|
api_base = models.CharField(max_length=256, help_text=_('srsnode_api_base_help'))
|
||||||
|
@ -111,3 +73,59 @@ class SRSStreamInstance(models.Model):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.stream} on {self.node}"
|
return f"{self.stream} on {self.node}"
|
||||||
|
|
||||||
|
|
||||||
|
class Restream(models.Model):
|
||||||
|
FORMATS = (
|
||||||
|
('flv', 'flv (RTMP)'),
|
||||||
|
('mpegts', 'mpegts (SRT)'),
|
||||||
|
)
|
||||||
|
stream = models.ForeignKey(Stream, on_delete=models.CASCADE, help_text=_('restream_stream_help'))
|
||||||
|
target = models.CharField(max_length=500, help_text=_('restream_target_help'))
|
||||||
|
name = models.CharField(max_length=100, help_text=_('restream_name_help'))
|
||||||
|
active = models.BooleanField(help_text=_('restream_activate_help'))
|
||||||
|
format = models.CharField(max_length=6, choices=FORMATS, default='flv', help_text=_('restream_format_help'))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('restream_verbose_name')
|
||||||
|
verbose_name_plural = _('restream_verbose_name_plural')
|
||||||
|
|
||||||
|
def class_name(self):
|
||||||
|
return _('restream_class_name')
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('config:restream_detail', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '{} to {}'.format(self.stream, self.name)
|
||||||
|
|
||||||
|
def get_concierge_configuration(self):
|
||||||
|
stream_instances = SRSStreamInstance.objects.filter(stream=self.stream).all()
|
||||||
|
|
||||||
|
if not stream_instances:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# We use the actual SRS node of the first stream instance to make sure
|
||||||
|
# that we use the same node for the restreaming. This avoids unnecessary
|
||||||
|
# traffic between the SRS nodes. In theory a clustered SRS setup could
|
||||||
|
# provide the same stream on all edges, but that would mean east-west
|
||||||
|
# traffic between the nodes.
|
||||||
|
|
||||||
|
# This assumption breaks when a second stream instance appears on another
|
||||||
|
# SRS node, and only afterwards the first stream instance is removed.
|
||||||
|
# In that case, the restreaming would not be retriggered, and the edge
|
||||||
|
# would automatically start pulling the stream from the other SRS node.
|
||||||
|
|
||||||
|
# It's a tradeoff between stability and efficiency. We choose stability.
|
||||||
|
rtmp_base = stream_instances[0].node.rtmp_base
|
||||||
|
|
||||||
|
return {
|
||||||
|
'config_version': 1,
|
||||||
|
'stream_source_url': f"{rtmp_base}/{settings.GLOBAL_STREAM_NAMESPACE}/{self.stream.stream}",
|
||||||
|
'stream_target_url': self.target,
|
||||||
|
'stream_target_transport': self.format,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Restream)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
import json
|
||||||
|
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.db.models.signals import post_save, post_delete
|
from django.db.models.signals import post_save, post_delete
|
||||||
|
|
||||||
from config.models import Restream, Stream
|
from config.models import Restream, Stream
|
||||||
from config.signals_shared import stream_active, stream_inactive
|
from config.signals_shared import stream_active, stream_inactive
|
||||||
from concierge.models import Task
|
from concierge.models import Task
|
||||||
|
@ -10,7 +13,7 @@ def create_restream_tasks(sender, **kwargs):
|
||||||
restreams = Restream.objects.filter(active=True, stream=stream)
|
restreams = Restream.objects.filter(active=True, stream=stream)
|
||||||
for restream in restreams:
|
for restream in restreams:
|
||||||
Task.objects.get_or_create(stream=restream.stream, type='restream', config_id=restream.id,
|
Task.objects.get_or_create(stream=restream.stream, type='restream', config_id=restream.id,
|
||||||
configuration=restream.get_json_config())
|
configuration=json.dumps(restream.get_concierge_configuration()))
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Restream)
|
@receiver(post_save, sender=Restream)
|
||||||
|
@ -28,7 +31,7 @@ def update_restream_tasks(sender, **kwargs):
|
||||||
# If the configuration is set to be active, and the stream is published, (re)create new task
|
# If the configuration is set to be active, and the stream is published, (re)create new task
|
||||||
if instance.active and instance.stream.publish_counter > 0:
|
if instance.active and instance.stream.publish_counter > 0:
|
||||||
task = Task(stream=instance.stream, type='restream', config_id=instance.id,
|
task = Task(stream=instance.stream, type='restream', config_id=instance.id,
|
||||||
configuration=instance.get_json_config())
|
configuration=json.dumps(instance.get_concierge_configuration()))
|
||||||
task.save()
|
task.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue