python QMediaPlayer release resource

489 Views Asked by At

I have some code which:

  1. Records from microphone using pyqt5 AudioInput

  2. Write to file record.mp3 with pydub AudioSegment.

  3. Preview the record.mp3 with the following code:

    def preview_record(self,ui): filename = self.record_path #filename = filename.replace(" ","+") url = QtCore.QUrl.fromLocalFile(r""+filename) content = QtMultimedia.QMediaContent(url) self.player = QtMultimedia.QMediaPlayer() self.player.setMedia(content) self.player.play()

The problem is that if i preview the recorded file, and then record a new file, then in step 2):

PermissionError: [Errno 13] Permission denied: '../disket box/weather news/record.mp3'

That's because the resource is opened for preview. How can i release the resource to fix the problem?

Edit: Example to reproduce the problem:

from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia
from PyQt5.QtCore import QDate, QTime,QTimer, QDateTime, Qt
from pydub import AudioSegment
from datetime import datetime
import vlc
import ctypes
import os
from pathlib import Path
import shutil
from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia
import time
import moviepy.editor
import moviepy.video.fx.all as vfx
from pydub import AudioSegment

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.record = QtWidgets.QPushButton(Form)
        self.record.setGeometry(QtCore.QRect(110, 30, 161, 61))
        self.record.setObjectName("record")
        self.stop = QtWidgets.QPushButton(Form)
        self.stop.setGeometry(QtCore.QRect(110, 140, 161, 61))
        self.stop.setObjectName("stop")
        self.preview = QtWidgets.QPushButton(Form)
        self.preview.setGeometry(QtCore.QRect(120, 250, 151, 81))
        self.preview.setObjectName("preview")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)
        
        self.destinationFile = QtCore.QFile()
        
        self.record.clicked.connect(lambda state:self.start_recording())
        self.stop.clicked.connect(lambda state:self.stop_recording())
        self.preview.clicked.connect(lambda state:self.preview_record())

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "StackOverflow example"))
        self.record.setText(_translate("Form", "Record"))
        self.stop.setText(_translate("Form", "Stop"))
        self.preview.setText(_translate("Form", "Preview"))
        
    def start_recording(self):
        self.destinationFile.setFileName("record.raw")
        self.destinationFile.open( QtCore.QIODevice.ReadWrite | QtCore.QIODevice.Truncate )
        
        info = QtMultimedia.QAudioDeviceInfo.defaultInputDevice()

        format = QtMultimedia.QAudioFormat()
        format.setSampleRate(44100);
        format.setChannelCount(1);
        format.setSampleSize(16);
        format.setCodec("audio/pcm");
        format.setByteOrder(QtMultimedia.QAudioFormat.LittleEndian)
        format.setSampleType(QtMultimedia.QAudioFormat.SignedInt)

        
        
        input_devices = QtMultimedia.QAudioDeviceInfo.availableDevices(QtMultimedia.QAudio.AudioInput)
        
        if (info.isFormatSupported(format) is not True):
            format = info.nearestFormat(format)
            print("format changed")

        self.audio = QtMultimedia.QAudioInput(input_devices[0],format)
        self.audio.start(self.destinationFile)
    
    def stop_recording(self):
        self.audio.stop()
        self.destinationFile.close()
        raw_audio = AudioSegment.from_file("record.raw", format="raw",frame_rate=44100, channels=1, sample_width=2)
        raw_audio.export("record.mp3", format="mp3")

        
        self.record_path = os.path.abspath("record.mp3")
        
    def preview_record(self):
        filename = self.record_path
        url = QtCore.QUrl.fromLocalFile(r""+filename)
        content = QtMultimedia.QMediaContent(url)
        self.player = QtMultimedia.QMediaPlayer()
        self.player.setMedia(content)
        self.player.play()


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    app.addLibraryPath(r"C:/Users/Χρήστος/AppData/Local/Programs/Python/Python38/lib/site-packages/PyQt5/Qt/plugins")
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.showMaximized()
    sys.exit(app.exec_())

To reproduce it follow this steps:

  1. Press Record Button to start recording
  2. Press Stop Button to stop recording
  3. Press Preview Button to preview recording (and wait preview to finish)
  4. Press Record Button again for a new record
  5. Press Stop Button to stop the new recording

The error is:

Traceback (most recent call last):
  File "stack_record.py", line 36, in <lambda>
    self.stop.clicked.connect(lambda state:self.stop_recording())
  File "stack_record.py", line 75, in stop_recording
    raw_audio.export("record.mp3", format="mp3")
  File "C:\Users\╫±▐≤ΪΎ≥\AppData\Local\Programs\Python\Python38\lib\site-packages\pydub\audio_segment.py", line 809, in export
    out_f, _ = _fd_or_path_or_tempfile(out_f, 'wb+')
  File "C:\Users\╫±▐≤ΪΎ≥\AppData\Local\Programs\Python\Python38\lib\site-packages\pydub\utils.py", line 60, in _fd_or_path_or_tempfile
    fd = open(fd, mode=mode)
PermissionError: [Errno 13] Permission denied: 'record.mp3'
1

There are 1 best solutions below

1
On
  1. I use the stateChanged signal of self.player

self.player.stateChanged.connect(lambda state:self.mediastate_changed(state,ui))

  1. When preview is finished i delete the self.player instance

def mediastate_changed(self, state,ui): if self.player.state() != QtMultimedia.QMediaPlayer.PlayingState: del self.player