分类 Linux 下的文章

1. 录音的 pcm 文件直接播放,使用:

#!/bin/bash
play -t raw -r 44.1k -e signed-integer -b 16 -c 2 loved.pcm
play -t raw -r 48k -e floating-point -b 32 -c 2 ./data_decode/out.pcm

参考: https://blog.csdn.net/lc999102/article/details/80579866

2. json.h 没有相应的头文件。json.h, curl.h

sudo apt-get install libjsoncpp-dev 
sudo ln -s /usr/include/jsoncpp/json/ /usr/include/json

sudo apt install libcurl4-openssl-dev
sudo ln -s /usr/include/x86_64-linux-gnu/curl /usr/include/curl

sudo apt-get install libopencv-dev

参考: https://blog.csdn.net/zhangpeterx/article/details/92175479

3. QCoreApplication 找不到定义的地方。

QCoreApplication 在 5.14.2/Src/qtbase/src/corelib/kernel/qcoreapplication.h 里面,定义为 class Q_CORE_EXPORT QCoreApplication。 参考: https://www.cnblogs.com/lyggqm/p/6281581.html

4. ffmpeg 的 cmake 配置

cmake_minimum_required(VERSION 3.10)

project(ffmpeg_test)

set(SRC_LIST main.cpp)
include_directories("/usr/include/x86_64-linux-gnu")
link_directories("/usr/lib/x86_64-linux-gnu")

add_executable(ffmpeg_test ${SRC_LIST})

#target_link_libraries(${PROJECT_NAME} libavutil.so libavcodec.so libavformat.so libavdevice.so.57 libavfilter.so libswscale.so libpostproc.so)

#target_link_libraries(${PROJECT_NAME} libavutil.so libavcodec.so libavformat.so libswscale.so)

target_link_libraries(${PROJECT_NAME} avutil avcodec avformat swscale)

参考: https://blog.csdn.net/wangchao1412/article/details/103454371 https://www.jianshu.com/p/72cdcb8d06a7 https://blog.csdn.net/BigDream123/article/details/89741253

5. 使用百度的 tts,需要安装百度 aip sdk

pip3 install baidu-aip --user

参考: https://blog.csdn.net/m0_37886429/article/details/85222593

6. pcm 和 wav 互转

参考: https://blog.csdn.net/sinat_37816910/article/details/105054372 https://blog.csdn.net/huplion/article/details/81260874

7. alsaaudio 中的 openPCM 这个参数的顺序有问题,不要按照 api 上面的顺序写。全部用关键词的方式去写,就没有问题。

        try:
            self.__alsaDev = alsaaudio.PCM(type = alsaaudio.PCM_PLAYBACK, mode = alsaaudio.PCM_NORMAL, rate = 16000, channels = 8, format = alsaaudio.PCM_FORMAT_S16_LE, periodsize = 160, device = "plughw:" + self.__devName)
        except Exception as e:
            print("alsaaudio open pcm exception: ", e)

8. 其他格式转换为 wav 格式,使用 pydub 中的 AudioSegment

    @staticmethod
    def extractToWave(srcPath, destDir = None, destPrefix = None):
        (srcDir, fileName) = os.path.split(srcPath)
        (fileNoExt, ext) = os.path.splitext(fileName)
        if ext == ".wav":
            return srcPath

        if destDir is None:
            destDir = srcDir
        if destPrefix is None:
            destPrefix = ""
        if not os.path.exists(destDir):
            os.makedirs(destDir)
        destName = destPrefix + fileNoExt + ".wav"
        destPath = destDir + "/" + destName
        #print(destPath)
        if ext == ".mp3":
            data = AudioSegment.from_mp3(srcPath)
        else:
            return None
        data.export(destPath, format = "wav")
        return destPath

参考: https://www.cnblogs.com/xingshansi/p/6799994.html https://ithelp.ithome.com.tw/articles/10252078 https://blog.csdn.net/baidu_29198395/article/details/86694365

9. alsaaudio 播放 wav 格式

    def playThreadWav(self, path, index):
        if self.__alsaDev:
            self.__alsaDev.close()
        print("alsa playback wav thread run: %d" % index)

        with wave.open(path, 'rb') as f:
            self.__rate = f.getframerate()
            self.__channels = f.getnchannels()
            self.__depthBits = f.getsampwidth() * 8
            self.__format = self.bitsToFormat(self.__depthBits)
            self.__periodSize = int(self.__rate / 100)
            try:
                self.__alsaDev = alsaaudio.PCM(type = alsaaudio.PCM_PLAYBACK,
                                               mode = alsaaudio.PCM_NORMAL,
                                               rate = self.__rate,
                                               channels = self.__channels,
                                               format = self.__format,
                                               periodsize = self.__periodSize,
                                               device = "plughw:" + self.__devName)
            except Exception as e:
                print("alsaaudio open exception: ", e)

            if self.__alsaDev is None:
                print("open alsa audio device failed")
                self.clearThreadParam(index)
                return "finished"

            data = f.readframes(self.__periodSize)
            while data and self.__eStop == False:
                try:
                    self.__alsaDev.write(data)
                except ALSAAudioError as e:
                    print("alsa audio play except: ", e)
                    break
                data = f.readframes(self.__periodSize)

        self.afterThreadComplete(index)
        return "finished"

    def clearThreadParam(self, index):
        del self.__poolDict[index]
        self.__rate = 0
        self.__channels = 0
        self.__depthBits = 0
        self.__format = 0
        self.__periodSize = 0

    def afterThreadComplete(self, index):
        self.__alsaDev.close()
        self.__alsaDev = None
        if index in self.__hookDict:
            if self.__eStop != True:
                self.__hookDict[index]()
            del self.__hookDict[index]
        self.clearThreadParam(index)

参考: https://www.programcreek.com/python/example/91453/alsaaudio.PCM

10. 使用 websocket 的时候, pip3 install --user websocket-client 而不是 websocket

11. pcm 转 wav

        (file, ext) = os.path.splitext(path)
        wavPath = file + ".wav"
        EspAudioUtil.pcmToWave(path, wavPath, rate, channels, bits)
        os.remove(path)

参考: https://stackoverflow.com/questions/16111038/how-to-convert-pcm-files-to-wav-files-scripting

12. 多通道音频抽取单通道数据

    @staticmethod
    def pcmExtractOneChannal(multiChannArray, channels, index):
        array = multiChannArray
        array.shape = -1, channels
        array = array.T
        return array[index]

    @staticmethod
    def pcmExtractOneChannalFile(multiPath, channels, index, dataBits, onePath):
        audioData = None
        if dataBits == 16:
            dataType = np.uint16
        with open(multiPath, 'rb') as f:
            audioData = np.fromfile(f, dtype = dataType)
        oneData = __class__.pcmExtractOneChannal(audioData, channels, index)
        oneData.tofile(onePath)

    @staticmethod
    def pcmExtractOneChannalBinary(multiBinary, channels, index, dataBits):
        audioData = None
        if dataBits == 16:
            dataType = np.uint16
        audioData = np.fromstring(multiBinary, dtype = dataType)
        oneData = __class__.pcmExtractOneChannal(audioData, channels, index)
        return oneData.tobytes()

参考: https://www.pythonf.cn/read/128012

13 pcm 和 wave 互转

    @staticmethod
    def pcmToWave(pcmPath, wavPath, rate, channels, depthBits):
        with open(pcmPath, "rb") as pcmFile:
            print("pcm open")
            pcmData = pcmFile.read()
        with wave.open(wavPath, "wb") as wavFile:
            print(channels, int(depthBits / 8), rate)
            print(len(pcmData))
            wavFile.setparams((channels, int(depthBits / 8), rate, 0, 'NONE', 'NONE'))
            wavFile.writeframes(pcmData)

    @staticmethod
    def waveToPCM(wavPath, pcmPath, dataBits = 16):
        if dataBits == 16:
            dataType = np.uint16
        with open(wavPath, 'rb') as f:
            f.seek(0)
            f.read(44)
            data = np.fromfile(f, dtype = dataType)
            data.tofile(pcmPath)
        with wave.open(wavPath, 'rb') as f:
            return f.getparams()

参考: https://blog.csdn.net/sinat_37816910/article/details/105054372 https://docs.python.org/3/library/wave.html

14. 停止 baidu 的 websocket,需要发送 cancel,至于是否 self.ws.keep_running = False 不太确定

参考: https://www.coder.work/article/1269314

15. 播放音乐并立即停止

cmd = "AUDIODEV=hw:realtekrt5651co play ~/esp_run/speech/test.wav"
sub = subprocess.Popen(cmd, shell = True)
print(sub.poll())
time.sleep(5)
print("kill")
print(time.time())
sub.kill()  #sub.send_signal(signal.SIGKILL)
# sub.wait()
print(time.time())
print(sub.poll())
sub = subprocess.Popen("stty echo", shell = True)

16. 如果需要使用 alsaaudio 在录音的时候播放其他音频,那么可能录音回发生 overrun,主要是播放音频的 set 函数回导致 overrun,其他一些耗时的处理也会导致 overrun,比如 mp3 解码。

17. subprocess kill 之后,使用 wait() 函数的时候,提示 EOFError 的时候,可以使用

stty sane

来恢复。

18. 寻找目录,寻找文件

def searchDir(path, dirName):
    for root, dirs, files in os.walk(path):
        if dirName in dirs:
            return os.path.join(root, dirName)
    return None

def searchFile(path, fileName):
    for root, dirs, files in os.walk(path):
        if fileName in files:
            return os.path.join(root, fileName)

19. 需要依赖的文件收集

def assembleDepends(path):
    cmd = 'grep -R "import" ' + path
    f = os.popen(cmd)
    data = f.readlines()
    f.close()
    #print(data)
    dependDict = {}
    if data != None:
        for line in data:
            lineData = line[line.find(":") + 1 : ]
            if lineData.startswith("#"):
                continue
            print(lineData)
            dependList = []
            if lineData.find("from") == -1:
                lineData = lineData.replace(" ", "").replace("\n", "")
                dependList = lineData[lineData.find("import") + len("import") : ].split(",")
                #print(dependList)
                for depend in dependList:
                    if depend.startswith("esp_"):
                        dependDict[depend] = 1
            else:
                start = lineData.find("from") + len("from") + 1
                end = lineData.find("import")
                lineData = lineData[start : end].strip()
                #print(lineData)
                if lineData.startswith("esp_"):
                    dependDict[lineData] = 1
        #print(dependDict)
        return dependDict
    return None

20. 降噪算法效果好,耗时低的是 WebRTC, python 可以使用 https://github.com/xiongyihui/python-webrtc-audio-processing 这边的代码。

今天先参照 https://www.jianshu.com/p/ddf7c0153644 这个里面的说明写了相应的配置文件,结果一启动容器就报错了。

Creating docker-test_mysql_1 ... 
Creating docker-test_mysql_1 ... error

ERROR: for docker-test_mysql_1  Cannot start service mysql: driver failed programming external connectivity on endpoint docker-test_mysql_1 (22e74af6dece7dd4cae19aa8809099c6fde961e19f6b43178bb34a595e1c5a02): Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use

ERROR: for mysql  Cannot start service mysql: driver failed programming external connectivity on endpoint docker-test_mysql_1 (22e74af6dece7dd4cae19aa8809099c6fde961e19f6b43178bb34a595e1c5a02): Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use
ERROR: Encountered errors while bringing up the project.

参考 https://www.cnblogs.com/loovelj/p/7823093.html 这个里面的做法,首先查看是否本机的 mysql 占用了端口。

netstat -tunlp | grep 3306

确定是本机的 mysql,就停止服务。

service mysql stop

然后通过 ps -ef|grep mysqld 可以发现 mysql 已经停止了。然后重新使用 docker-compose up -d 启动容器,这下就不报错了。

使用 docker ps 来查看容易的状态属性,id 和 names 这两个值都可以用来指定容器。

docker exec -it docker-test_mysql_1 bash
docker exec -it f24473a1626a bash

上面这两条命令分别用 name 和 id 来指定容器执行 bash 命令,效果是一样的。这样就进入了容器的命令行。

停止 docker

docker-compose stop

删除 docker

docker rm docker-test_mysql_1

docker 中使用 mysql 的时候,init 文件夹下面的 sql, sh, sql.gz 这些文件会被遍历,然后执行,但是执行顺序没有办法保证,所以想要按照一定顺序执行,只能通过 sh 脚本来编写处理过程, 具体参考:https://blog.csdn.net/boling_cavalry/article/details/71055159

在 init 脚本中 mysql -uroot -p$MYSQL_ROOT_PASSWORD <<EOF 注意 -p 后面不要有空格,否则可能不能以 root 登录 mysql; 不要忘了给 init 脚本所有人可执行权限,因为只有 db 对应的文件夹是 mysql的,其他的文件夹都是 1000:1000,可能导致执行权限问题。

在 init 脚本中,mysql 命令里面创建用户的时候,密码必须有单引号,因为用了单引号,变量外面就必须有大括号,才能保证正确。

create user '${MYSQL_USER}'@'localhost' IDENTIFIED BY '${MYSQL_PASS}';

在mysql 中使用 root 登录的时候,通过命令 select * from mysql.user 来查看有哪些用户。

GRANT ALL PRIVILEGES ON  数据库名.表名 TO '$user1'@'%' IDENTIFIED BY '$password1' REQUIRE X509;
GRANT  SELECT,INSERT,ALTER,UPDATE,DELETE ON iot_ny.* TO  'Iothui'@'localhost';

可以用这些命令给用户赋权。

搜索可以用哪些镜像,可以去 https://hub.docker.com/ 上搜索。

参考: https://blog.csdn.net/weixin_33670713/article/details/93029183 https://stackoverflow.com/questions/33470753/create-mysql-database-and-user-in-bash-script https://blog.csdn.net/wangmx1993328/article/details/81805371 https://blog.csdn.net/boling_cavalry/article/details/71120725 https://stackoverflow.com/questions/20033648/how-to-run-mysql-command-on-bash https://superuser.com/questions/288621/create-mysql-database-with-one-line-in-bash https://www.cnblogs.com/fuhai0815/p/9548213.html https://blog.csdn.net/m0_38143867/article/details/94046889 https://github.com/zq2599/docker_disconf/blob/master/docker-compose.yml https://www.cnblogs.com/whych/p/9446032.html https://blog.csdn.net/u011913691/article/details/90665639 https://github.com/SingletonPattern/compose-demo/blob/master/compose-demo/docker-compose.yml https://www.cnblogs.com/ray-mmss/p/12249204.html https://blog.csdn.net/weixin_41043145/article/details/92834784 https://www.cnblogs.com/badaoliumangqizhi/archive/2019/09/16/11530695.html https://www.jianshu.com/p/658911a8cff3 https://www.jianshu.com/p/ddf7c0153644

没有安装过 docker 的 ubuntu 安装 docker的步骤:

$ sudo apt-get update

$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

如果选择官方的源:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
apt-key fingerprint 0EBFCD88

如果选择阿里的源:

sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add -
sudo apt-key fingerprint 0EBFCD88

添加官方仓库:

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

添加阿里仓库:

sudo add-apt-repository \
   "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
apt-cache madison docker-ce

从上面输出的版本中找到你需要的版本:

sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io

如果这里报错,可以尝试这个命令,我用这个命令进行安装就没有问题:

sudo apt-get -y install docker-ce=[VERSION]
sudo docker run hello-world
sudo gpasswd -a 用户名 docker
sudo service docker restart
newgrp - docker

安装 docker-compose,先去 https://github.com/docker/compose/releases 找到你需要的版本,然后替换下面的 1.24.1 这个版本号,我用的是 1.27.3 :

sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose --version

参考: https://docs.docker.com/engine/install/ubuntu/ https://www.cnblogs.com/walker-lin/p/11214127.html https://www.runoob.com/docker/docker-compose.html https://blog.csdn.net/liqi_q/article/details/83030737 https://www.cnblogs.com/grow1016/p/11533645.html

使用 韦东山 的 imx6ul 的开发板,按照手册上面的 nfs rootfs 的说明进行操作,结果开发板加载的时候,打印 VFS: Unable to mount root fs via NFS, trying floppy.然后直接卡住不动了。

经过仔细分析,原来是因为我 虚拟机使用的是 桥接网络,所以端口不需要特别的设定。

setenv netargs 'setenv bootargs console=${console},${baudrate} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp,port=2049,mountport=9999'

上面这个端口设定是不需要的,改成下面这种就可以,或者直接取消这条命令。

setenv netargs 'setenv bootargs console=${console},${baudrate} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp'