Salve a tutti, ho fatto un programma che registra in continuazione da una sorgente audio, comprime l'audio e ne fa pezzetti da un'ora per 90 giorni (poi cancello i file piu' vecchi).
Normalmente funziona per diverse settimane con un errore di "troppi file aperti".
Cercando su internet con gstreamer AND "too many files open" e' venuto fuori questo thread:
http://gstreamer-devel.966125.n4.nabble.com/Too-many-files-open-issue-td4687242.html
che mi sembra attinente.
Sembrerebbe che la semplice interruzione della pipeline, la sua distruzione e la sua riapertura NON siano sufficienti a FERMARE la registrazione.
Si deve inviare un EOS alla pipeline ed il codice C proposto e' questo:
void worker(GstElement *pipeline) {
gst_element_send_event(pipeline, gst_event_new_eos());
}
void stopListening() {
boost::thread *th = new boost::thread(worker,pipeline);
}
nel mio programma, che trovate qui':
https://sourceforge.net/projects/prsose/files/tools/PRS_recorder-0.0.10.tar.gz/
il codice che si occupa di chiudere la pipeline e generare un nuovo file e' questo:
Public Sub PipeLine(command As String)
Dim Destinazione As New String[]
Dim Risultato As String
Dim clienti As String[]
Dim I As Integer
Select Case command
Case "start"
InitCaptureSystem
InitSink
muxer.LinkTo(sink)
Try pl.Play
If Error Then
Message.Warning("Error starting gstreamer graph. Is Jack Audio server runnig?", "ok")
ToggleButton_RecStop.Value = False
Endif
'riconnette al volo le sorgenti (se la cosa va gestita dall'applicazione e non dal sistema
If AutoReconnectSource = True Then
'non so perche' ma i client mi cambiano nome in modo progressivo .. quindi devo trovare quelli al momento validi per il mio programma
'quindi scansiono i clienti di jack attivi (ho dato il play alla pipeline quindi c'e' anche il recorder) e mi trovo quelli con il nome
'simile a quello che ho settato io in init_capture_system .... ovver "client_name" qualcosa
Shell "jack_lsp" To Risultato
clienti = Split(Risultato, gb.CrLf)
For i = 0 To clienti.Count - 1
If clienti[i] Like ("*" & clientname & "*") Then
Destinazione.Add(clienti[i], Destinazione.Count)
Endif
Next
'a questo punto dovrei avere uno o piu' sink del mio programma che ricevono l'audio dalla sorgente che ho indicato
Shell "jack_connect " & Replace(FirstJackSource, " ", "\\ ") & " " & Destinazione[0]
If StereoSource = True Then
Shell "jack_connect " & GetNextOf(FirstJackSource) & " " & Destinazione[1]
Endif
Endif
Timer_RecordClock.Start
Case "stop"
Try pl.stop
Try Copy User.home & "/" & ClientName & ".ogg" To RealName
Try pl.Close
CheckForFilesToDelete
Timer_RecordClock.Stop
End Select
End
mentre l'inizializzazione della pipeline si fa cosi' (nel mio programma):
Public Sub InitCaptureSystem()
Try pl.Stop
Try pl.close
Try Recorder_Client.close
Try audioformat.close
Try audio_converter.close
Try lev.close
Try muxer.close
Try que1.close
Try que2.close
Try que3.close
'in teoria dovrebbe funzionare:
'gst-launch-1.0 jackaudiosrc connect=0 client-name="test" ! audioconvert ! avenc_aac ! mp4mux ! filesink location=aac_audio.mp4
pl = New MediaPipeline As "PipeLine"
'dico a gstreamer che la sorgente audio e' una sorgente di jack-server
Recorder_Client = New MediaControl(pl, "jackaudiosrc")
Recorder_Client["client-name"] = ClientName
Recorder_Client["connect"] = 0
audioformat = New MediaFilter(pl, "audio/x-raw,channels=2")
audio_converter = New MediaControl(pl, "audioconvert")
'qui decidiamo il tipo di encoder
Select Case encType
Case "vorbis"
encoder = New MediaControl(pl, "vorbisenc")
encoder["name"] = "enc"
encoder["quality"] = -0.1
Case "opus"
encoder = New MediaControl(pl, "opusenc") 'opusenc name=enc bitrate=24000 bitrate-type="vbr"
encoder["name"] = "enc"
encoder["bitrate"] = 24000
encoder["bitrate-type"] = 2 '0=cbr 1=vbr 2=CONSTRAINED_VBR .. che penso sia vbr entro un certo bitrate
Case "mp3"
encoder = New MediaControl(pl, "lamemp3enc") 'opusenc name=enc bitrate=24000 bitrate-type="vbr"
encoder["name"] = "enc"
encoder["bitrate"] = 32
encoder["cbr"] = False 'esempi lamemp3enc target=bitrate cbr=true bitrate=192 | lamemp3enc target=quality quality=0
End Select
lev = New MediaControl(pl, "level")
lev["message"] = True
muxer = New MediaControl(pl, "oggmux")
que1 = New MediaControl(pl, "queue")
que2 = New MediaControl(pl, "queue")
que3 = New MediaControl(pl, "queue")
' Parte audio SENZA LIVELLI AUDIO:
Recorder_Client.LinkTo(audioformat)
audioformat.LinkTo(audio_converter)
'audio_converter.LinkTo(encoder)
'per cercare di estrarre i livelli dell'audio in ingresso invece:
audio_converter.LinkTo(lev)
lev.LinkTo(encoder)
'
encoder.LinkTo(muxer)
End
Public Sub InitSink()
'Dim sink As MediaControl
Try sink.close
'se si vuole registrare su file;
sink = New MediaControl(pl, "filesink")
'sarebbe da rendere parametrica la path
sink["location"] = User.Home & "/" & ClientName & ".ogg"
RealName = RecordingRoot & "/" & ClientName & "_" & Format(Now, "yyyy-mm-dd_hh-nn-ss") & ".ogg"
End
Da super scarsone di C, come faccio a mandare questo fatidico messaggio di EOS alla pipeline?
PS: in allegato l'ultima versione con qualche piccola modifica.
si pl e' una variabile globale ....
nella procedura (che si ripete ogni ora ma che nella prima invocazione NON trovera' nessuna vecchia pipeline) l'idea e' di "distruggere" la vecchia PL e ricrearne un'altra (che viene riferita in piu' parti del codice).
Tu dici che la "new" nella procedura istanzia un oggetto che e' distaccato dal resto a causa dello scope locale? Non penso, di solito in tutti gli esempi con GStreamer si fa cosi'.
Comunque la dichiarazione in testa al codice e' questa:
' Gambas class file
Public pl As MediaPipeline
Public Recorder_Client As MediaControl
Public audio_converter As MediaControl
Public audioformat As MediaControl
Public encoder As MediaControl
Public que1 As MediaControl
Public que2 As MediaControl
Public que3 As MediaControl
Public muxer As MediaControl
Public lev As MediaControl
Public sink As MediaControl
Public ClientName As String
Public RecordingRoot As String
Public Spezzetta As Boolean
'per gestire la riconnessione delle sorgenti dall'interno dell'applicazione.
Public StereoSource As Boolean
Public FirstJackSource As String
Public AutoReconnectSource As Boolean
Public Giorni As Integer
Public RealName As String
Public encType As String = "vorbis"
.... etc etc ..
in ogni caso, dando un'occhiata qui':
https://fossies.org/linux/gambas/gb.media/src/c_media.c
sembrerebbe che GIA' ORA, fermando una pipeline con il metodo pipeline.stop
si dovrebbe mandare il segnale EOS ....
1807 void MEDIA_stop_pipeline(CMEDIACONTROL *_object)
1808 {
1809 int try;
1810
1811 // "It is not allowed to post GST_MESSAGE_EOS when not in the PLAYING state." says the documentation
1812 if ((THIS->state == GST_STATE_PLAYING) && !THIS->eos)
1813 {
1814 try = 0;
1815 gst_element_send_event(ELEMENT, gst_event_new_eos());
1816 while (!THIS->eos)
1817 {
1818 try++;
1819 if (try > 25)
1820 {
1821 fprintf(stderr, "gb.media: warning: could not catch end of stream\n");
1822 break;
1823 }
1824 cb_message(THIS_PIPELINE);
1825 usleep(10000);
1826 }
1827 }
1828
1829 MEDIA_set_state(THIS, GST_STATE_READY, TRUE);
1830 cb_message(THIS_PIPELINE);
1831 }