Modifing filename building + pathname definition.
[libre-streamer.git] / stream_2016 / gstconf.py
index 9e69df60ad8232292f5b0f20dbd983c965012866..115c2d0ed53afcf1a5a878ead391a14a69b681d1 100755 (executable)
@@ -1,58 +1,89 @@
 #!/usr/bin/env python3.4
+# -*- coding: utf-8 -*-
 
-# This file is part of Libre-Streamer.
+# This file is part of ABYSS.
+# ABYSS Broadcast Your Streaming Successfully 
 #
-# Libre-Streamer is free software: you can redistribute it and/or modify
+# ABYSS is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
-# Libre-Streamer is distributed in the hope that it will be useful,
+# ABYSS is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with Libre-Streamer.  If not, see <http://www.gnu.org/licenses/>.
+# along with ABYSS.  If not, see <http://www.gnu.org/licenses/>.
 #
 # Copyright (c) 2016 David Testé
 
 from os import rename
 from os import listdir
+from os import path
+from os import mkdir
 from time import localtime, strftime
+import configparser
 
 import gi
 from gi.repository import Gst
 from gi.repository import GstVideo
 
-# Pathname has to be defined
-PATHNAME = ''
-AUDIO_DEFAULT = PATHNAME + 'AUDIO_DEFAULT'
-RAWVIDEO_DEFAULT = PATHNAME + 'RAWVIDEO_DEFAULT'
-STREAM_DEFAULT = PATHNAME + 'STREAM_DEFAULT'
+DIR_NAME = 'FILES_RECORDED'
+AUDIO_DEFAULT = './' + DIR_NAME + '/' + 'AUDIO_DEFAULT'
+RAWVIDEO_DEFAULT = './' + DIR_NAME + '/' + 'RAWVIDEO_DEFAULT'
+STREAM_DEFAULT = './' + DIR_NAME + '/' + 'STREAM_DEFAULT'
 BACKUP_SUFFIX = '_BACKUP'
+FAILED_SUFFIX = '_FAILED_'
+fail_counter = 1
 AUDIO_BACKUP = AUDIO_DEFAULT + BACKUP_SUFFIX
 RAWVIDEO_BACKUP = RAWVIDEO_DEFAULT + BACKUP_SUFFIX
 STREAM_BACKUP = STREAM_DEFAULT + BACKUP_SUFFIX
 ERROR = '[ERROR] '
 INFO = '[INFO] '
 WARN = '[WARN] '
+CONFIG = '.abyss'
 
+sources = {'RTSP_IP' : None,
+           'AUDIO_INPUT' : None,}
+sinks = {'AUDIO_OUTPUT' : None,
+         'DIR': None,
+         'STREAM_SERVER_IP' : None,
+         'SERVER_PORT' : None,
+         'PASSWORD' : None,
+         'AUDIO_MOUNT' : None,
+         'VIDEO_MOUNT' : None,}
+
+##AUDIO_INPUT = 'alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00-CODEC.analog-stereo'
+##AUDIO_OUTPUT = 'alsa_output.pci-0000_00_1b.0.analog-stereo'
+
+config = configparser.RawConfigParser()
+if path.exists(CONFIG):
+    config.read(CONFIG)
+    try:
+        sources = {key : config.get('sources', key) for key in sources}
+        sinks = {key : config.get('sinks', key) for key in sinks}
+    except:
+        print(ERROR, gettime(), 'Failed to parse config file.')
+else:
+    print(ERROR, gettime(), '".abyss" config file doesn\'t exist.')
+
+if not path.isdir(DIR_NAME):
+    mkdir(DIR_NAME)
 
 class New_user_pipeline():
 
     
     def __init__(self, feed='main'):
+        self.rtsp_address = 'rtsp://' + sources['RTSP_IP']
         self.feed = feed
-##        if self.feed == 'main':
         self.user_pipeline = self.create_gstreamer_pipeline()
-##        elif self.feed == 'backup':
-##            self.user_pipeline = self.create_gstreamer_pipeline(feed='backup')
             
     def create_video_sources(self):
         """Create video inputs from various sources."""
         self.videosrc = Gst.ElementFactory.make('rtspsrc', 'videosrc')
-        self.videosrc.set_property('location', 'rtsp://192.168.48.2:554')
+        self.videosrc.set_property('location', self.rtsp_address)
         self.videosrc.set_property('latency', 0)
 ##        self.videosrc.set_property('debug', True)
         if self.feed == 'backup':
@@ -72,7 +103,15 @@ class New_user_pipeline():
             elif len(devices) == 1:
                 return '/dev/video0'
         print(ERROR, gettime(), 'No webcam device found.')
-        
+
+    def find_mixingdesk_device(self):
+        """Look out for the USB mixing desk device.
+        Product used here: Behringer XENYX Q1002USB.
+        """
+        # shell cmd : 'pactl list | grep alsa_input'
+        # AUDIO_INPUT --> const used currently
+        pass
+
     def create_pipeline_callbacks(self):
         """Callbacks to connect dynamically created pads."""
         self.videosrc.connect('pad-added', self.on_pad_added_to_rtspsrc)
@@ -85,7 +124,7 @@ class New_user_pipeline():
     def create_audio_sources(self):
         """Create audio inputs from various sources."""
         self.audiosrc = Gst.ElementFactory.make('pulsesrc', 'audiosrc')
-##        self.videosrc.set_property('latency', 0)
+        self.audiosrc.set_property('device', sources['AUDIO_INPUT'])
 
     def create_audiolevel_plugin(self):
         """Create audio level plugin to feed a vu-meter."""
@@ -95,32 +134,38 @@ class New_user_pipeline():
     def create_filesink(self):
         """Create storable output elements."""
         self.disksink_rawvideo = Gst.ElementFactory.make('filesink')
-        #[TO DO]: File location has to be defined 
         self.disksink_rawvideo.set_property('location', RAWVIDEO_DEFAULT)
         self.disksink_audio = Gst.ElementFactory.make('filesink')
         self.disksink_audio.set_property('location', AUDIO_DEFAULT)
         self.disksink_stream = Gst.ElementFactory.make('filesink')
         self.disksink_stream.set_property('location', STREAM_DEFAULT)
-        
+        if self.feed == 'backup':
+            self.disksink_rawvideo.set_property('location', RAWVIDEO_BACKUP)
+            self.disksink_audio.set_property('location', AUDIO_BACKUP)
+            self.disksink_stream.set_property('location', STREAM_BACKUP)
+            
     def create_streamsink(self):
         """Create streamable output elements."""
         # To local screen:
         self.screensink = Gst.ElementFactory.make('xvimagesink', 'screensink')
         self.screensink.set_property('sync', False)
+        # To local audio output (headphones):
+        self.audiosink = Gst.ElementFactory.make('pulsesink', 'audiosink')
+        self.audiosink.set_property('device', sinks['AUDIO_OUTPUT'])
+        self.audiosink.set_property('sync', False)
         # To icecast server:
         self.icecastsink_audio = Gst.ElementFactory.make('shout2send', 'icecastsink_audio')
         self.icecastsink_audio.set_property('sync', False)
-## Configuration should be written on a file locally to keep safe private addresses
-        self.icecastsink_audio.set_property('ip', 'live2.fsf.org')
-        self.icecastsink_audio.set_property('port', 80)
-        self.icecastsink_audio.set_property('mount', 'testaudio.ogg')
-        self.icecastsink_audio.set_property('password', 'thahw3Wiez')
+        self.icecastsink_audio.set_property('ip', sinks['STREAM_SERVER_IP'])
+        self.icecastsink_audio.set_property('port', int(sinks['SERVER_PORT']))
+        self.icecastsink_audio.set_property('mount', sinks['AUDIO_MOUNT'])
+        self.icecastsink_audio.set_property('password', sinks['PASSWORD'])
         self.icecastsink_stream = Gst.ElementFactory.make('shout2send', 'icecastsink_stream')
         self.icecastsink_stream.set_property('sync', False)
-        self.icecastsink_stream.set_property('ip', 'live2.fsf.org')
-        self.icecastsink_stream.set_property('port', 80)
-        self.icecastsink_stream.set_property('mount', 'teststream.webm')
-        self.icecastsink_stream.set_property('password', 'thahw3Wiez')
+        self.icecastsink_stream.set_property('ip', sinks['STREAM_SERVER_IP'])
+        self.icecastsink_stream.set_property('port', int(sinks['SERVER_PORT']))
+        self.icecastsink_stream.set_property('mount', sinks['VIDEO_MOUNT'])
+        self.icecastsink_stream.set_property('password', sinks['PASSWORD'])
 
     def create_payloader_elements(self):
         pass
@@ -201,7 +246,6 @@ class New_user_pipeline():
         self.queuev_3 = Gst.ElementFactory.make('queue', 'queuev_3')
         self.queuev_4 = Gst.ElementFactory.make('queue', 'queuev_4')
         self.queuev_5 = Gst.ElementFactory.make('queue', 'queuev_5')
-        self.queuev_6 = Gst.ElementFactory.make('queue', 'queuev_6')
         # For audio feed:
         self.queuea_1 = Gst.ElementFactory.make('queue', 'queuea_1')
         self.queuea_2 = Gst.ElementFactory.make('queue', 'queuea_2')
@@ -232,6 +276,8 @@ class New_user_pipeline():
         # Output elements:
         self.create_filesink()
         self.create_streamsink()
+        if self.feed == 'test':
+            print('TEST OK...', end='')
         print('created')
         if self.feed == 'backup':
             print (INFO,
@@ -242,38 +288,45 @@ class New_user_pipeline():
 
     def add_elements_to_pipeline(self):
         print(INFO, gettime(), 'Pipeline creation state: adding elements... ', end='')        
+        cond = self.feed != 'test'
+
         # Inputs elements:
         self.streampipe.add(self.audiosrc)
         # Middle elements:
         self.streampipe.add(self.audiolevel)
-        self.streampipe.add(self.vorbisenc)
-        self.streampipe.add(self.vp8enc)
-        self.streampipe.add(self.mkvmux)
-        self.streampipe.add(self.oggmux)
-        self.streampipe.add(self.webmmux)
-        self.streampipe.add(self.tee_rawaudio)
-        self.streampipe.add(self.tee_rawvideo)
-        self.streampipe.add(self.tee_streamaudio)
-        self.streampipe.add(self.tee_streamfull)
-        self.streampipe.add(self.queuev_2)
-        self.streampipe.add(self.queuev_3)
-        self.streampipe.add(self.queuev_4)
-        self.streampipe.add(self.queuev_5)
         self.streampipe.add(self.queuea_1)
-        self.streampipe.add(self.queuea_2)
-        self.streampipe.add(self.queuea_3)
-        self.streampipe.add(self.queuea_4)
-        self.streampipe.add(self.queuea_5)
-        self.streampipe.add(self.queuem_1)
-        self.streampipe.add(self.queuem_2)
+        self.streampipe.add(self.queuev_3)
+        if cond: 
+            self.streampipe.add(self.vorbisenc)
+            self.streampipe.add(self.oggmux)
+            self.streampipe.add(self.queuea_2)
+            self.streampipe.add(self.queuea_3)
+            self.streampipe.add(self.vp8enc)
+            self.streampipe.add(self.mkvmux)
+            self.streampipe.add(self.webmmux)
+            self.streampipe.add(self.tee_rawaudio)
+            self.streampipe.add(self.tee_rawvideo)
+            self.streampipe.add(self.tee_streamaudio)
+            self.streampipe.add(self.tee_streamfull)
+            self.streampipe.add(self.queuev_2)
+            self.streampipe.add(self.queuev_4)
+            self.streampipe.add(self.queuev_5)
+            self.streampipe.add(self.queuea_4)
+            self.streampipe.add(self.queuea_5)
+            self.streampipe.add(self.queuem_1)
+            self.streampipe.add(self.queuem_2)
         # Outputs elements:
         self.streampipe.add(self.screensink)
-        self.streampipe.add(self.disksink_rawvideo)
-        self.streampipe.add(self.disksink_audio)
-        self.streampipe.add(self.disksink_stream)
-        self.streampipe.add(self.icecastsink_audio)
-        self.streampipe.add(self.icecastsink_stream)
-        if self.feed == 'main':
+        if cond:
+            self.streampipe.add(self.disksink_rawvideo)
+            self.streampipe.add(self.disksink_audio)
+            self.streampipe.add(self.disksink_stream)
+            self.streampipe.add(self.icecastsink_audio)
+            self.streampipe.add(self.icecastsink_stream)
+        else:
+            self.streampipe.add(self.audiosink)
+
+        if self.feed == 'main' or self.feed == 'test':
             # Inputs elements:
             self.streampipe.add(self.videosrc)
             # Middle elements:
@@ -283,6 +336,8 @@ class New_user_pipeline():
             self.streampipe.add(self.capsfilter)
             self.streampipe.add(self.tee_videodecoded)
             self.streampipe.add(self.queuev_1)
+            if self.feed == 'test':
+                print ('TEST OK...', end='')
         elif self.feed == 'backup':
             # Inputs elements:
             self.streampipe.add(self.videosrc_backup)
@@ -294,62 +349,75 @@ class New_user_pipeline():
     def link_pipeline_elements(self):
         """Link all elements with static pads."""
         print(INFO, gettime(), 'Pipeline creation state: linking elements... ', end='')
+        cond = self.feed != 'test'
+        
         # Audio feed:
         self.audiosrc.link(self.audiolevel)
         self.audiolevel.link(self.queuea_1)
-        self.queuea_1.link(self.vorbisenc)
-        self.connect_tee(self.tee_rawaudio,
-                         self.vorbisenc,
-                         self.queuea_2,
-                         self.queuea_5,)
-        self.queuea_2.link(self.oggmux)
-        self.connect_tee(self.tee_streamaudio,
-                         self.oggmux,
-                         self.queuea_3,
-                         self.queuea_4,)
-        self.queuea_3.link(self.disksink_audio)
-        self.queuea_4.link(self.icecastsink_audio)
-        self.queuea_5.link(self.webmmux)
+        if cond:
+            self.queuea_1.link(self.vorbisenc)
+            self.connect_tee(self.tee_rawaudio,
+                             self.vorbisenc,
+                             self.queuea_2,
+                             self.queuea_5,)
+            self.queuea_2.link(self.oggmux)
+            self.connect_tee(self.tee_streamaudio,
+                             self.oggmux,
+                             self.queuea_3,
+                             self.queuea_4,)
+            self.queuea_3.link(self.disksink_audio)
+            self.queuea_4.link(self.icecastsink_audio)
+            self.queuea_5.link(self.webmmux)
+        else:
+            self.queuea_1.link(self.audiosink)
+            
         # Video feed:
-        self.queuev_2.link(self.mkvmux)
-        self.mkvmux.link(self.queuev_4)
-        self.queuev_4.link(self.disksink_rawvideo)
+        if cond:
+            self.queuev_2.link(self.mkvmux)
+            self.mkvmux.link(self.queuev_4)
+            self.queuev_4.link(self.disksink_rawvideo)
+        else:
+            self.queuev_1.link(self.rtpjpegdepay)
+            self.rtpjpegdepay.link(self.jpegdec)
+            self.jpegdec.link(self.queuev_3)
         self.queuev_3.link(self.screensink)
+
         # Stream (audio+video) feed:
-        self.vp8enc.link(self.queuev_5)
-        self.queuev_5.link(self.webmmux)
-        self.connect_tee(self.tee_streamfull,
-                         self.webmmux,
-                         self.queuem_1,
-                         self.queuem_2,)
-        self.queuem_1.link(self.disksink_stream)
-        self.queuem_2.link(self.icecastsink_stream)
-        if self.feed == 'main':
-            # linking here RTSP feed
-            self.queuev_1.link(self.rtpjpegdepay)
-            self.connect_tee(self.tee_rawvideo,
-                             self.rtpjpegdepay,
-                             self.queuev_2,
-                             self.jpegdec,)
-            self.connect_tee(self.tee_videodecoded,
-                             self.jpegdec,
-                             self.queuev_3,
-                             self.scaling,)
-            # Stream (video) feed:
-            self.scaling.link(self.capsfilter)
-            self.capsfilter.link(self.vp8enc)
-            
-        elif self.feed == 'backup':
-            # linking here backup feed (WEBCAM)
-            self.videosrc_backup.link(self.capsfilter_backup)
-            self.connect_tee(self.tee_rawvideo,
-                             self.capsfilter_backup,
-                             self.queuev_2,
-                             self.queuev_3,
-                             output_element_3=self.vp8enc)
+        if cond:
+            self.vp8enc.link(self.queuev_5)
+            self.queuev_5.link(self.webmmux)
+            self.connect_tee(self.tee_streamfull,
+                             self.webmmux,
+                             self.queuem_1,
+                             self.queuem_2,)
+            self.queuem_1.link(self.disksink_stream)
+            self.queuem_2.link(self.icecastsink_stream)
+            if self.feed == 'main':
+                # linking here RTSP feed
+                self.queuev_1.link(self.rtpjpegdepay)
+                self.connect_tee(self.tee_rawvideo,
+                                 self.rtpjpegdepay,
+                                 self.queuev_2,
+                                 self.jpegdec,)
+                self.connect_tee(self.tee_videodecoded,
+                                 self.jpegdec,
+                                 self.queuev_3,
+                                 self.scaling,)
+                # Stream (video) feed:
+                self.scaling.link(self.capsfilter)
+                self.capsfilter.link(self.vp8enc)            
+            elif self.feed == 'backup':
+                # linking here backup feed (WEBCAM)
+                self.videosrc_backup.link(self.capsfilter_backup)
+                self.connect_tee(self.tee_rawvideo,
+                                 self.capsfilter_backup,
+                                 self.queuev_2,
+                                 self.queuev_3,
+                                 output_element_3=self.vp8enc)
 ##            self.capsfilter_backup.link(self.queuev_3)
-            # Stream (video) feed:
-            print('BACKUP OK...', end='')
+                print('BACKUP OK...', end='')
+        if not cond:
+            print('TEST OK...', end='')
         print('linked')
 
     def create_gstreamer_pipeline(self):
@@ -359,7 +427,7 @@ class New_user_pipeline():
         # Setting-up:
         self.add_elements_to_pipeline()
         self.link_pipeline_elements()
-        if self.feed == 'main':
+        if self.feed == 'main' or self.feed == 'test':
             self.create_pipeline_callbacks()
 
         global bus
@@ -373,46 +441,60 @@ class New_user_pipeline():
         return self.streampipe
 
     def on_message(self, bus, message):
-        #
-##        print("[MESSAGE]", message.get_structure().get_name()) # [DEBUG]
-        #
         t = message.type
         if t == Gst.MessageType.EOS:
             self.streampipe.set_state(Gst.State.NULL)
         elif t == Gst.MessageType.ERROR:
             err, debug = message.parse_error()
             print (ERROR, '%s' % err, debug)
-#            self.streampipe.set_state(Gst.State.NULL)
             
     def stream_play(self):
         self.streampipe.set_state(Gst.State.PLAYING)
         if self.feed == 'backup':
             print(WARN, gettime(), 'Backup pipeline started.')
-        print(INFO, gettime(), 'PLAYING State resquested')
+        print(INFO, gettime(), 'PLAYING State resquested.')
         
     def stream_stop(self):
         self.streampipe.set_state(Gst.State.NULL)
-        print(INFO, gettime(), 'STOPPED State resquested')
+        print(INFO, gettime(), 'STOPPED State resquested.')
         
-    def get_stream_state(self):
-        print(self.streampipe.get_state(self))
-##[FIXME]        return self.streampipe.get_state()
-        
-    def set_filenames(self, string):
+    def set_filenames(self, string, streamfailed=False):
         """Sets filename and location for each sink."""
+        global fail_counter
         filename = string
-        audio = PATHNAME + filename + '_AUDIO'
-        rawvideo = PATHNAME + filename + '_RAWVIDEO'
-        stream = PATHNAME + filename + '_STREAM'
+        audio = './' + DIR_NAME + '/' + filename + '_AUDIO'
+        rawvideo = './' + DIR_NAME + '/' + filename + '_RAWVIDEO'
+        stream = './' + DIR_NAME + '/' + filename + '_STREAM'
         if self.feed == 'main':
-            rename(AUDIO_DEFAULT, audio)
-            rename(RAWVIDEO_DEFAULT, rawvideo)
-            rename(STREAM_DEFAULT, stream)
+            if streamfailed and filename:
+                audio = audio + FAILED_SUFFIX + str(fail_counter)
+                rawvideo = rawvideo + FAILED_SUFFIX + str(fail_counter)
+                stream = stream + FAILED_SUFFIX + str(fail_counter)
+                self.rename_files(audio, rawvideo, stream)
+                fail_counter += 1
+            elif streamfailed:
+                audio = AUDIO_DEFAULT + FAILED_SUFFIX + str(fail_counter)
+                rawvideo = RAWVIDEO_DEFAULT + FAILED_SUFFIX + str(fail_counter)
+                stream = STREAM_DEFAULT + FAILED_SUFFIX + str(fail_counter)
+                self.rename_files(audio, rawvideo, stream)
+                fail_counter += 1
+            else:
+                self.rename_files(audio, rawvideo, stream)
         elif self.feed == 'backup':
+##            print('INSIDE BACKUP RENAMING')
             rename(AUDIO_BACKUP, audio)
             rename(RAWVIDEO_BACKUP, rawvideo)
             rename(STREAM_BACKUP, stream)
 
+        print(INFO, gettime(), 'Audio file written on disk.')
+        print(INFO, gettime(), 'Raw video file written on disk.')
+        print(INFO, gettime(), 'Streamed file written on disk.')
+        
+    def rename_files(self, audio_name, rawvideo_name, stream_name):
+        rename(AUDIO_DEFAULT, audio_name)
+        rename(RAWVIDEO_DEFAULT, rawvideo_name)
+        rename(STREAM_DEFAULT, stream_name)
+
 def get_gstreamer_bus():
     return bus