Разъем Flask не отсоединяется от аудиозаписей> 30 с - PullRequest
0 голосов
/ 13 июня 2019

Функция Flask socketio не отключается, когда аудиозаписи длиннее, чем около 30 секунд, но только в том случае, если их обслуживает gunicorn в службах приложений Azure.Кажется, что локальный dev имеет почти неограниченную емкость, и более короткие аудиозаписи работают нормально в среде Azure.

Кажется, что код действительно работает правильно, за исключением запуска voice_disconnect_request().Хотя код после disconnect() выполняется (т.е. @socketio.on('disconnect', namespace='/voice_enroll') -> voice_test_disconnect()), поэтому я не уверен, почему emit('my_response',{'data': 'Voice Enroll Complete!', 'count': session['receive_count']}) не работает.По какой-то причине, если это не сработает, $('form#connect').submit(function(event) будет запущен снова, что автоматически создаст новое соединение и запустит рекордер.

Кнопки на сайте действительно отключатся / включатся правильно и сразу,поэтому кажется, что кнопка записи не должна быть активной, функция отключения должна быть полностью корректной, и она не должна снова вызывать $('form#connect').submit(function(event).В случаях, когда запрос на отключение отправляется надлежащим образом, все работает как положено.

Я пытался запустить voice_enroll() в потоке (код показан ниже), так как это занимает несколько секунд, и я был обеспокоен, что некоторыетам некоторая задержка.

Я попытался использовать разные размеры буфера для audio_context.

Я изменил множество асинхронных режимов и настроек Gunicorn, но на самом деле я в растерянности из-за чего ещепытаться.Там нет сообщений об ошибках нигде.Кажется, что он просто сдался и начал все сначала.

Я пробовал это для настроек gunicorn

gunicorn --worker-class eventlet -w 1 --bind '0.0.0.0:8000' app:server --timeout 300
gunicorn --worker-class gevent -w 1 --bind '0.0.0.0:8000' app:server --timeout 300
gunicorn -w 1 --threads 12 --bind '0.0.0.0:8000' app:server --timeout 300

python

@socketio.on('my_event', namespace='/voice_enroll')
def voice_message(message):
    session['receive_count'] = session.get('receive_count', 0) + 1
    emit('my_response',
         {'data': message['data'], 'count': session['receive_count']})

@socketio.on('disconnect_request', namespace='/voice_enroll')
def voice_disconnect_request():
    session['receive_count'] = session.get('receive_count', 0) + 1
    emit('my_response',
         {'data': 'Voice Enroll Complete!', 'count': session['receive_count']})
    disconnect()

@socketio.on('connect', namespace='/voice_enroll')
def voice_test_connect():
    session['audio'] = []
    emit('my_response', {'data': 'Connected', 'count': 0})

@socketio.on('sample_rate', namespace='/voice_enroll')
def voice_handle_my_sample_rate(sampleRate):
    session['sample_rate'] = sampleRate
    session['receive_count'] = session.get('receive_count', 0) + 1
    emit('my_response', {'data': "sampleRate : %s" % sampleRate, 'count': session['receive_count'] })

@socketio.on('audio', namespace='/voice_enroll')
def voice_handle_my_custom_event(audio):
    """
    """
    values = OrderedDict(sorted(audio.items(), key=lambda t: int(t[0]))).values()
    session['audio'] += values

@socketio.on('disconnect', namespace='/voice_enroll')
def voice_test_disconnect():
    # https://stackoverflow.com/a/18644461/466693
    sample_rate = session['sample_rate']
    my_audio = np.array(session['audio'], np.float32)
    scaled = np.round(32767*np.sin(my_audio))
    scipy.io.wavfile.write('out.wav', sample_rate, scaled.astype(np.int16))
    audio = AudioSegment.from_file('out.wav', format='wav').set_frame_rate(MS_VOICE_FRAMERATE)
    audio.export('temp.wav', format='wav')
    thread = Thread(target=enroll_voice, args=('temp.wav', current_user.username))
    thread.start()
    session['audio'] = []

и

JS

      var namespace = '/voice_enroll';
      var socket = null;
      var mediaStream = null;

      // prepare button state
      $('#disconnect input')[0].disabled = true;

      // audio functions
      function initializeRecorder(stream){
         // https://stackoverflow.com/a/42360902/466693
         mediaStream = stream;

         // get sample rate
         audio_context = new AudioContext;
         sampleRate = audio_context.sampleRate;
         console.log('<sample_rate>', sampleRate);
         socket.emit('sample_rate', sampleRate);

         var audioInput = audio_context.createMediaStreamSource(stream);

         console.log("Created media stream.");

         var bufferSize = 8192;
         // record only 1 channel
         var recorder = audio_context.createScriptProcessor(bufferSize, 1, 1);
         // specify the processing function
         recorder.onaudioprocess = recorderProcess;
         // connect stream to our recorder
         audioInput.connect(recorder);
         // connect our recorder to the previous destination
         recorder.connect(audio_context.destination);
      }
      function recorderProcess(e) {
        var left = e.inputBuffer.getChannelData(0);
        socket.emit('audio', left);
      }

      $('form#connect').submit(function(event) {
          if(socket == null){
            socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);
            socket.on('connect', function() {
                socket.emit('my_event', {data: 'I\'m connected!'});
                navigator.getUserMedia({audio: true}, initializeRecorder, function(a, b, c){
                  console.log(a, b, c);
                });
            });
            socket.on('my_response', function(msg) {
                  $('#log').append('<br>' + $('<div/>').text('Received #' + msg.count + ': ' + msg.data).html());
            });
          }
          else {
            socket.disconnect();
            socket.connect();
          }
          $('#connect input')[0].disabled = true;
          $('#disconnect input')[0].disabled = false;
          return false;
      });
      $('form#disconnect').submit(function(event) {
          mediaStream.getAudioTracks()[0].stop();
          audio_context.close();
          socket.emit('disconnect_request');
          $('#connect input')[0].disabled = false;
          $('#disconnect input')[0].disabled = true;
          return false;
      });

Опция Flask socketio должна корректно завершиться, выдав сообщение о разъединении, чтобы предупредить конечных пользователей об успешном завершении процесса, как это происходит для локального разработчика и для коротких аудиосообщений.

...