WIP: gst-snowmix plugins set

master
informatic 2019-02-22 17:09:37 +01:00
parent 8993042ac0
commit 7407e7bd45
6 changed files with 301 additions and 0 deletions

View File

@ -44,6 +44,9 @@ class SnowmixClient(object):
self.fd = self.sock.makefile('rw')
self.version = self.fd.readline().split(' ')[2]
def close(self):
self.sock.close()
def flush_input(self):
self.sock.setblocking(0)
@ -186,6 +189,18 @@ class SnowmixClient(object):
print(scene_id, frame_id, active)
print(next(self.call('tcl eval SceneSetFrameActive %d %d %d 0' % (scene_id, frame_id, active))))
def audio_rate(self, audio_type='feed'):
return {
int(line.split(' ')[2]): int(line.split(' ')[4])
for line in self.call('audio %s rate' % (audio_type), 'STAT:')
}
def audio_channels(self, audio_type='feed'):
return {
int(line.split(' ')[2]): int(line.split(' ')[4])
for line in self.call('audio %s channels' % (audio_type), 'STAT:')
}
if __name__ == "__main__":
c = SnowmixClient('snowmix')

4
gst-snowmix/README.md Normal file
View File

@ -0,0 +1,4 @@
gst-snowmix
===========
Just a bunch of Gstreamer elements to interact with snowmix

View File

@ -0,0 +1,135 @@
#!/usr/bin/env python
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4
# sinkelement.py
# (c) 2005 Edward Hervey <edward@fluendo.com>
# (c) 2007 Jan Schmidt <jan@fluendo.com>
# Licensed under LGPL
#
# Small test application to show how to write a sink element
# in 20 lines in python and place into the gstreamer registry
# so it can be autoplugged or used from parse_launch.
#
# You can run the example from the source doing from gst-python/:
#
# $ export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD/plugin:$PWD/examples/plugins
# $ GST_DEBUG=python:4 gst-launch-1.0 fakesrc num-buffers=10 ! mysink
# inf notes 20190221
# https://gist.github.com/jackersson/9d3b0c578c1e625b6b79ea04e2cebd15
# https://mathieuduponchelle.github.io/2018-02-01-Python-Elements.html?gi-language=undefined
import os
import logging
from snowmix import SnowmixClient
import gi
gi.require_version('GstBase', '1.0')
from gi.repository import Gst, GObject, GstBase, Gio
Gst.init(None)
#
# Simple Sink element created entirely in python
#
class SnowmixAudioSink(Gst.Bin):
__gstmetadata__ = ('CustomSink','Sink', \
'Custom test sink element', 'Edward Hervey')
__gsttemplates__ = Gst.PadTemplate.new("sink",
Gst.PadDirection.SINK,
Gst.PadPresence.ALWAYS,
Gst.Caps.new_any())
__gproperties__ = {
"feed": (int,
"Feed",
"Target feed number",
1,
255,
1,
GObject.ParamFlags.READWRITE
),
#"host": (str,
# "Snowmix Host",
# "Target snowmix host",
# '',
# GObject.ParamFlags.READWRITE
# ),
"port": (int,
"Snowmix Port",
"Target snowmix port",
0,
65535,
9999,
GObject.ParamFlags.READWRITE
),
# [...]
}
def __init__(self, *args, **kwargs):
Gst.info('init(%r, %r)' % (args, kwargs))
super(SnowmixAudioSink, self).__init__(*args, **kwargs)
self.caps = caps = Gst.ElementFactory.make("capsfilter", None)
self.sink = sink = Gst.ElementFactory.make("multisocketsink", None)
self.add(sink)
self.add(caps)
# Link from left to right
caps.link(sink)
# Expose first/last
self.add_pad(Gst.GhostPad.new("sink", caps.get_static_pad("sink")))
#print(dir(self))
#print(self.list_properties())
self._propstorage = {e.name: e.default_value for e in self.list_properties()}
#self.props = {k: e[5] for k, e in } #SnowmixAudioSink.__gproperties__.entries()}
def do_change_state(self, state):
Gst.info('do_change_state(%r)' % (state))
if state == Gst.StateChange.READY_TO_PAUSED:
ip = '' or os.getenv('SNOWMIX_IP') or '127.0.0.1'
port = self.props.port or os.getenv('SNOWMIX_PORT') or 9999
client = SnowmixClient(ip, port)
rate = client.audio_rate()[self.props.feed]
channels = client.audio_channels()[self.props.feed]
self.caps.set_property("caps", Gst.Caps.from_string(
"audio/x-raw,rate=%d,channels=%d,format=S16LE,layout=interleaved" % (rate, channels)))
client.close()
self.socket = Gio.Socket.new(
Gio.SocketFamily.IPV4, Gio.SocketType.STREAM,
Gio.SocketProtocol.DEFAULT)
self.socket.connect(Gio.InetSocketAddress.new_from_string(
ip, port))
self.socket.send(b'audio feed ctr isaudio %d\n' % (self.props.feed))
self.sink.emit('add', self.socket)
return Gst.Bin.do_change_state(self, state)
def do_set_property(self, prop, value):
Gst.info('do_set_property(%r, %r)' % (prop, value))
if prop.name not in self._propstorage:
raise AttributeError('unknown property %s' % prop.name)
self._propstorage[prop.name] = value
raise AttributeError('unknown property %s' % prop.name)
#return Gst.Bin.do_set_property(self, prop, value)
def do_get_property(self, prop):
if prop.name in self._propstorage:
return self._propstorage[prop.name]
def do_render(self, buffer):
Gst.info("timestamp(buffer):%s" % (Gst.TIME_ARGS(buffer.pts)))
return Gst.FlowReturn.OK
GObject.type_register(SnowmixAudioSink)
__gstelementfactory__ = ("snowmixaudiosink", Gst.Rank.NONE, SnowmixAudioSink)

View File

@ -0,0 +1 @@
../../api/snowmix.py

View File

@ -0,0 +1,135 @@
#!/usr/bin/env python
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4
# sinkelement.py
# (c) 2005 Edward Hervey <edward@fluendo.com>
# (c) 2007 Jan Schmidt <jan@fluendo.com>
# Licensed under LGPL
#
# Small test application to show how to write a sink element
# in 20 lines in python and place into the gstreamer registry
# so it can be autoplugged or used from parse_launch.
#
# You can run the example from the source doing from gst-python/:
#
# $ export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD/plugin:$PWD/examples/plugins
# $ GST_DEBUG=python:4 gst-launch-1.0 fakesrc num-buffers=10 ! mysink
# inf notes 20190221
# https://gist.github.com/jackersson/9d3b0c578c1e625b6b79ea04e2cebd15
# https://mathieuduponchelle.github.io/2018-02-01-Python-Elements.html?gi-language=undefined
import os
from snowmix import SnowmixClient
from gi.repository import Gst, GObject, GstBase, Gio
Gst.init(None)
#
# Simple Sink element created entirely in python
#
class SnowmixAudioSource(Gst.Bin):
__gstmetadata__ = ('CustomSource','Source', \
'Custom test source element', 'Edward Hervey')
__gsttemplates__ = Gst.PadTemplate.new("src",
Gst.PadDirection.SRC,
Gst.PadPresence.ALWAYS,
Gst.Caps.new_any())
__gproperties__ = {
"mixer": (int,
"Mixer",
"Source mixer number",
1,
255,
1,
GObject.ParamFlags.READWRITE
),
#"host": (str,
# "Snowmix Host",
# "Target snowmix host",
# '',
# GObject.ParamFlags.READWRITE
# ),
"port": (int,
"Snowmix Port",
"Target snowmix port",
0,
65535,
9999,
GObject.ParamFlags.READWRITE
),
# [...]
}
def __init__(self, *args, **kwargs):
Gst.info('init(%r, %r)' % (args, kwargs))
super(SnowmixAudioSource, self).__init__(*args, **kwargs)
self.caps = caps = Gst.ElementFactory.make("capsfilter", None)
self.source = source = Gst.ElementFactory.make("socketsrc", None)
self.add(source, caps)
# Link from left to right
#source.link(caps)
#caps.link(sink)
# Expose first/last
self.add_pad(Gst.GhostPad.new("src", source.get_static_pad("src")))
#print(dir(self))
#print(self.list_properties())
self._propstorage = {e.name: e.default_value for e in self.list_properties()}
#self.props = {k: e[5] for k, e in } #SnowmixAudioSource.__gproperties__.entries()}
def do_change_state(self, state):
Gst.info('do_change_state(%r)' % (state))
if state == Gst.StateChange.NULL_TO_READY:
ip = '' or os.getenv('SNOWMIX_IP') or '127.0.0.1'
port = self.props.port or os.getenv('SNOWMIX_PORT') or 9999
client = SnowmixClient(ip, port)
rate = client.audio_rate('sink')[self.props.mixer]
channels = client.audio_channels('sink')[self.props.mixer]
c = Gst.Caps.from_string(
"audio/x-raw,rate=%d,channels=%d,format=S16LE,layout=interleaved" % (rate, channels))
self.source.set_property('do-timestamp', True)
self.source.set_property("caps", c)
# self.caps.set_property("caps", c)
client.close()
self.socket = Gio.Socket.new(
Gio.SocketFamily.IPV4, Gio.SocketType.STREAM,
Gio.SocketProtocol.DEFAULT)
self.socket.connect(Gio.InetSocketAddress.new_from_string(
ip, port))
self.socket.send(b'audio sink ctr isaudio %d\n' % (self.props.mixer))
self.source.set_property('socket', self.socket)
return Gst.Bin.do_change_state(self, state)
def do_set_property(self, prop, value):
Gst.info('do_set_property(%r, %r)' % (prop, value))
if prop.name not in self._propstorage:
raise AttributeError('unknown property %s' % prop.name)
self._propstorage[prop.name] = value
raise AttributeError('unknown property %s' % prop.name)
#return Gst.Bin.do_set_property(self, prop, value)
def do_get_property(self, prop):
if prop.name in self._propstorage:
return self._propstorage[prop.name]
def do_render(self, buffer):
Gst.info("timestamp(buffer):%s" % (Gst.TIME_ARGS(buffer.pts)))
return Gst.FlowReturn.OK
GObject.type_register(SnowmixAudioSource)
__gstelementfactory__ = ("snowmixaudiosrc", Gst.Rank.NONE, SnowmixAudioSource)

11
gst-snowmix/runtest Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:~/Projects/gst-python/plugin/:$PWD
export GST_DEBUG=python:4
gst-inspect-1.0 | grep -i py
echo ====
gst-launch-1.0 -v pulsesrc server=sound.waw.hackerspace.pl buffer-time=2000000 do-timestamp=true ! audioconvert ! audioresample ! snowmixaudiosink feed=2
#gst-launch-1.0 -v pulsesrc server=sound.waw.hackerspace.pl ! snowmixaudiosink feed=2
# feed=4
#GST_DEBUG=python:4 gst-launch-1.0 fakesrc num-buffers=10 ! identity_py ! fakesink
#gst-launch-1.0 -v audiotestsrc_py is-live=true ! fakesink silent=false