簡體   English   中英

我可以使用 Javascript 到 stream 使用 ALAudioDevice(setClientPreferences 然后訂閱)來自 Pepper 的麥克風的音頻嗎?

[英]Can I use Javascript to stream audio sound from Pepper's microphone using ALAudioDevice (setClientPreferences and then subscribe)?

我使用 python 成功地將 Pepper 麥克風的音頻聲音傳輸到我的筆記本電腦:

 class SoundReceiverModule(naoqi.ALModule):
    .......
    def start( self ):
        audio = naoqi.ALProxy( "ALAudioDevice", self.strNaoIp, 9559 );
        nNbrChannelFlag = 3; 
        nDeinterleave = 0;
        nSampleRate = 48000;
        audio.setClientPreferences( self.getName(),  nSampleRate, nNbrChannelFlag, nDeinterleave ); 
        audio.subscribe( self.getName() );  

    def processRemote( self, nbOfChannels, nbrOfSamplesByChannel, aTimeStamp, buffer ):
        aSoundDataInterlaced = np.fromstring( str(buffer), dtype=np.int16 );
        aSoundData = np.reshape( aSoundDataInterlaced, (nbOfChannels, nbrOfSamplesByChannel), 'F' );
    .......

但是,當我使用 Javascript 執行此操作時,訂閱 ALAudioDevice 后未生成任何信號。 誰能幫我解決這個問題? 謝謝!

抱歉,我目前無法對此進行測試,但我希望這是一個起點。 請讓我知道這是否有效,或者如果沒有,您會收到任何錯誤。

class SoundReceiverModule {
    constructor(){
    }
    processRemote(nbOfChannels, nbrOfSamplesByChannel, buffer, timeStamp){
        console.log(buffer)
    }
}

const channels = 3;
const deinterleaved = 0;
const sampleRate = 48000;
const moduleName = SoundReceiverModule.name;

// with /libs/qimessaging/2/qimessaging.js included
QiSession.connect(function (session) {
    session.service("ALAudioDevice").then(function (ALAudioDevice) {
        ALAudioDevice.setClientPreferences(moduleName, sampleRate, channels, deinterleaved);
        ALAudioDevice.subscribe(moduleName);
    });
});

這是我將添加的另一種方法作為替代答案,因為它更像是一種解決方法。 這個想法是像您一樣使用 Python 中的 SoundReceiverModule,然后在 javascript API 可以接收的事件中發布聲音數據。 我們將通過新的 ALMemory 事件sound-data-processed傳遞這些數據。

您需要制作一個看起來像這樣的 Choregraphe 應用程序。 請注意,web 頁面必須存儲為html/index.html

在此處輸入圖像描述

在 index.html 中放入以下內容。 當然,您可以將此代碼移動到單獨的.js 文件中,並將其包含在 html 中。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
    <title>SoundReceiverModuleTest</title>
</head>

<body style="background: black;">
    <script src="/libs/qimessaging/2/qimessaging.js"></script>
    <script type="text/javascript">
        QiSession.connect(function (session) {
            session.service("ALMemory").then(function (ALMemory) {
                ALMemory.subscriber("sound-data-processed").then(function (subscriber){
                    subscriber.signal.connect(function (data){
                        // here is the sound data from the Python event
                        // alert will show it on Pepper's tablet screen
                        alert(data);
                    });
                });
            });
        });
    </script>
</body>

</html>

我稍微修改了此處文檔中的示例 Python 音頻模塊。 您可以從外部計算機運行它(如果您安裝了 python qi sdk),如下所示:

python audio_module.py --ip <nao-ip>

audio_module.py是我保存以下文件的方式,而<nao-ip>是 Pepper 在與計算機相同的網絡上的 IP 地址。

#! /usr/bin/env python
# -*- encoding: UTF-8 -*-

"""Example: Get Signal from Front Microphone & Calculate its rms Power"""


import qi
import argparse
import sys
import time
import numpy as np


class SoundProcessingModule(object):
    """
    A simple get signal from the front microphone of Nao & calculate its rms power.
    It requires numpy.
    """

    def __init__( self, app):
        """
        Initialise services and variables.
        """
        super(SoundProcessingModule, self).__init__()
        app.start()
        session = app.session

        # Get the service ALAudioDevice.
        self.audio_service = session.service("ALAudioDevice")
        self.memory_service = session.service('ALMemory')
        self.isProcessingDone = False
        self.nbOfFramesToProcess = 20
        self.framesCount=0
        self.micFront = []
        self.module_name = "SoundProcessingModule"

    def startProcessing(self):
        """
        Start processing
        """
        # ask for the front microphone signal sampled at 16kHz
        # if you want the 4 channels call setClientPreferences(self.module_name, 48000, 0, 0)
        self.audio_service.setClientPreferences(self.module_name, 16000, 3, 0)
        self.audio_service.subscribe(self.module_name)

        while self.isProcessingDone == False:
            time.sleep(1)

        self.audio_service.unsubscribe(self.module_name)

    def processRemote(self, nbOfChannels, nbOfSamplesByChannel, timeStamp, inputBuffer):
        """
        Publish sound data to ALMemory event.
        """
        self.framesCount = self.framesCount + 1

        if (self.framesCount <= self.nbOfFramesToProcess):
            # convert inputBuffer to signed integer as it is interpreted as a string by python
            soundData = self.convertStr2SignedInt(inputBuffer)
            # send the data to an ALMemory event that can be read in Javascript
            self.memory_service.raise_event('sound-data-processed', soundData)
        else :
            self.isProcessingDone=True

    def convertStr2SignedInt(self, data) :
        """
        This function takes a string containing 16 bits little endian sound
        samples as input and returns a vector containing the 16 bits sound
        samples values converted between -1 and 1.
        """
        signedData=[]
        ind=0;
        for i in range (0,len(data)/2) :
            signedData.append(data[ind]+data[ind+1]*256)
            ind=ind+2

        for i in range (0,len(signedData)) :
            if signedData[i]>=32768 :
                signedData[i]=signedData[i]-65536

        for i in range (0,len(signedData)) :
            signedData[i]=signedData[i]/32768.0

        return signedData


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", type=str, default="127.0.0.1",
                        help="Robot IP address. On robot or Local Naoqi: use '127.0.0.1'.")
    parser.add_argument("--port", type=int, default=9559,
                        help="Naoqi port number")

    args = parser.parse_args()
    try:
        # Initialize qi framework.
        connection_url = "tcp://" + args.ip + ":" + str(args.port)
        app = qi.Application(["SoundProcessingModule", "--qi-url=" + connection_url])
    except RuntimeError:
        print ("Can't connect to Naoqi at ip \"" + args.ip + "\" on port " + str(args.port) +".\n"
               "Please check your script arguments. Run with -h option for help.")
        sys.exit(1)
    MySoundProcessingModule = SoundProcessingModule(app)
    app.session.registerService("SoundProcessingModule", MySoundProcessingModule)
    MySoundProcessingModule.startProcessing()

運行 choregraphe 時產生的錯誤:

[ERROR] behavior.box:_safeCallOfUserMethod:125 _Behavior__lastUploadedChoregrapheBehaviorbehavior_11662506592:/ALSoundDevice_1: Traceback (most recent call last): File "/opt/aldebaran/lib/python2.7/site-packages/albehavior.py", line 115, in _safeCallOfUserMethod func() File "<string>", line 31, in onUnload File "/opt/aldebaran/lib/python2.7/site-packages/ialbehavior.py", line 108, in <lambda> __getattr__ = lambda self, name: _swig_getattr(self, behavior, name) File "/opt/aldebaran/lib/python2.7/site-packages/ialbehavior.py", line 57, in _swig_getattr raise AttributeError(name) AttributeError: soundReceiver [ERROR] behavior.box:_safeCallOfUserMethod:125 _Behavior__lastUploadedChoregrapheBehaviorbehavior_11662506592:/ALSoundDevice_1: Traceback (most recent call last): File "/opt/aldebaran/lib/python2.7/site-packages/albehavior.py", line 115, in _safeCallOfUserMethod func() File "<string>", line 34, in onInput_onStart TypeError: __init__() takes exactly 2 arguments (1 given) 運行編排時出錯

但是,當我在 self.soundReceiver = SoundReceiverModule( 'SoundReceiver' ) 中添加一個輸入名稱時,運行 choregraphe 后,pepper 的肩部 LED 變為黃色(然后是紅色),並且在瀏覽網頁 http://pepper-ip 時未收到任何信號/應用/....

問題部分解決了: 在此處輸入圖像描述

import numpy as np
class SoundReceiverModule(ALModule):
    def __init__( self, strModuleName, strNaoIp ):
        try:
            ALModule.__init__(self, strModuleName )
            self.BIND_PYTHON( self.getName(), "callback" )
            self.strNaoIp = strNaoIp
        except BaseException, err:
            print( "loading error: %s" % str(err) )
    
        def __del__( self ):
            print( "SoundReceiverModule.__del__: cleaning everything" );
            self.stop();        

    def start(self):
        audio = ALProxy("ALAudioDevice", self.strNaoIp, 9559)
        nNbrChannelFlag = 3
        nDeinterleave = 0
        nSampleRate = 48000
        audio.setClientPreferences(self.getName(),  nSampleRate, nNbrChannelFlag, nDeinterleave)
        audio.subscribe(self.getName())

    def stop(self):
        audio = ALProxy("ALAudioDevice", self.strNaoIp, 9559)
        audio.unsubscribe(self.getName())

    def processRemote(self, nbOfChannels, nbrOfSamplesByChannel, aTimeStamp, buffer):
        self.memory = ALProxy("ALMemory") 
        aSoundDataInterlaced = np.fromstring(str(buffer), dtype=np.int16)
        aSoundData = np.reshape(aSoundDataInterlaced, (nbOfChannels, nbrOfSamplesByChannel), 'F')
        self.memory.raiseEvent('sound-data-processed', aSoundData)

class MyClass(GeneratedClass):
    def __init__(self):
        GeneratedClass.__init__(self)
        self.myBroker = ALBroker("myBroker", "0.0.0.0", 0, "192.168.24.201", 9559)

    def onLoad(self):   
        #put initialization code here
        pass

    def onUnload(self):
        #put clean-up code here
        SoundReceiver.stop()

    def onInput_onStart(self):
        global SoundReceiver
        SoundReceiver = SoundReceiverModule("SoundReceiver", "192.168.24.201")
        SoundReceiver.start()

    def onInput_onStop(self):
        self.myBroker.shutdown()
        self.onUnload() 
        
    def onStopped():    
        self.onStopped()

但是,未解決的問題是“訂閱 SoundReceiver 時沒有聲音數據流”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM