Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/395.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何以编程方式启用侧音/麦克风通过 我目前的项目是在C++中实现一个本地的库,我将通过JNA访问,这个项目是一个低延时的通信模拟器。为了模拟模拟器所基于的硬件,需要在传输时启用侧音。 当然,事实证明JAVA声音很难达到接近零的延迟(我们能得到的最好结果是~120ms),为了保持可理解性,我们需要侧音上的延迟接近零。幸运的是,在Windows中似乎有一种方法可以收听usb耳机的麦克风,从而产生完美的旁白_Java_C++_Windows_Audio_Com - Fatal编程技术网

如何以编程方式启用侧音/麦克风通过 我目前的项目是在C++中实现一个本地的库,我将通过JNA访问,这个项目是一个低延时的通信模拟器。为了模拟模拟器所基于的硬件,需要在传输时启用侧音。 当然,事实证明JAVA声音很难达到接近零的延迟(我们能得到的最好结果是~120ms),为了保持可理解性,我们需要侧音上的延迟接近零。幸运的是,在Windows中似乎有一种方法可以收听usb耳机的麦克风,从而产生完美的旁白

如何以编程方式启用侧音/麦克风通过 我目前的项目是在C++中实现一个本地的库,我将通过JNA访问,这个项目是一个低延时的通信模拟器。为了模拟模拟器所基于的硬件,需要在传输时启用侧音。 当然,事实证明JAVA声音很难达到接近零的延迟(我们能得到的最好结果是~120ms),为了保持可理解性,我们需要侧音上的延迟接近零。幸运的是,在Windows中似乎有一种方法可以收听usb耳机的麦克风,从而产生完美的旁白,java,c++,windows,audio,com,Java,C++,Windows,Audio,Com,音频属性->播放->耳机->属性->音量 (请注意,这与“收听此设备”功能不同,后者会产生非常糟糕的延迟) 我一直在使用核心音频API的MSDN示例,我能够查询设备并获取它们的频道、音量级别、静音设置等。但是麦克风级别的静音/取消静音似乎连核心音频API都无法访问 我的问题是:有没有一种方法可以通过编程方式与usb耳机的麦克风音量/静音设置交互 我们的模拟器是标准化的,因此我们不必担心支持各种各样的耳机(目前有2个)。解决这个问题的关键是向后遍历设备拓扑树,直到找到负责设置sidetone m

音频属性->播放->耳机->属性->音量

(请注意,这与“收听此设备”功能不同,后者会产生非常糟糕的延迟)

我一直在使用核心音频API的MSDN示例,我能够查询设备并获取它们的频道、音量级别、静音设置等。但是麦克风级别的静音/取消静音似乎连核心音频API都无法访问

我的问题是:有没有一种方法可以通过编程方式与usb耳机的麦克风音量/静音设置交互


我们的模拟器是标准化的,因此我们不必担心支持各种各样的耳机(目前有2个)。

解决这个问题的关键是向后遍历设备拓扑树,直到找到负责设置sidetone mute属性的部分。因此,在我的CPP项目中,我有几种方法一起工作,以确定我在拓扑树中查找
SuperMix
零件的位置

SuperMix
似乎是sidetone的通用名称,至少我们支持的两款耳机都使用它。这两款耳机的驾驶树是相同的,您的里程可能会有所不同。这就是前面提到的WalkTreeBackwardsFromPart示例的输出(请参阅)

这是我对WalkTreeBackwardsFromPart的修改版本,出于所有目的,它只是检查我们当前正在查看的部分是否是SuperMix,以及该部分的直接子部分是否是卷节点,这是为了防止错误的分配,因为我发现对于我们的耳机,通常会有两个称为SuperMix的节点,唯一的区别是我们想要的那个节点有一个卷节点子节点

HRESULT Sidetone::WalkTreeBackwardsFromPart(IPart *part) {

    HRESULT hr;

    if (wcscmp(this->getPartName(part), L"SuperMix") == 0 && this->treePeek(part, L"Volume")){

        this->superMix = part;

        IPart** superMixChildren = this->getChildParts(part);
        int nSuperMixChildren = sizeof(superMixChildren) / sizeof(superMixChildren[0]);
        if (nSuperMixChildren > 0){

            for (int i = 0; i < nSuperMixChildren; i++){

                if (wcscmp(this->getPartName(superMixChildren[i]), L"Volume") == 0){

                    this->volumeNode = this->getIPartAsIAudioVolumeLevel(superMixChildren[i]);
                    if (this->volumeNode != NULL){

                        IPart** volumeNodeChildren = this->getChildParts(superMixChildren[i]);
                        int nVolumeNodeChildren = sizeof(volumeNodeChildren) / sizeof(volumeNodeChildren[0]);
                        if (nVolumeNodeChildren > 0){

                            for (int j = 0; j < nVolumeNodeChildren; j++){

                                if (wcscmp(this->getPartName(volumeNodeChildren[j]), L"Mute") == 0){

                                    this->muteNode = this->getIPartAsIAudioMute(volumeNodeChildren[j]);
                                    break;
                                }
                            }
                        }
                    }
                    break;
                }
            }
        }
        delete[] superMixChildren;


        this->muteNode; // = someotherfunc();
        this->superMixFound = true;
        return S_OK;

    } else if(superMixFound == false){

        IPartsList *pIncomingParts = NULL;
        hr = part->EnumPartsIncoming(&pIncomingParts);
        if (E_NOTFOUND == hr) {
            // not an error... we've just reached the end of the path
            //printf("%S - No incoming parts at this part: 0x%08x\n", this->MSGIDENTIFIER, hr);
            return S_OK;
        }
        if (FAILED(hr)) {
            printf("%S - Couldn't enum incoming parts: hr = 0x%08x\n", this->MSGIDENTIFIER, hr);
            return hr;
        }
        UINT nParts = 0;
        hr = pIncomingParts->GetCount(&nParts);
        if (FAILED(hr)) {
            printf("%S - Couldn't get count of incoming parts: hr = 0x%08x\n", this->MSGIDENTIFIER, hr);
            pIncomingParts->Release();
            return hr;
        }

        // walk the tree on each incoming part recursively
        for (UINT n = 0; n < nParts; n++) {
            IPart *pIncomingPart = NULL;
            hr = pIncomingParts->GetPart(n, &pIncomingPart);
            if (FAILED(hr)) {
                printf("%S - Couldn't get part #%u (0-based) of %u (1-basedSmile hr = 0x%08x\n", this->MSGIDENTIFIER, n, nParts, hr);
                pIncomingParts->Release();
                return hr;
            }

            hr = WalkTreeBackwardsFromPart(pIncomingPart);
            if (FAILED(hr)) {
                printf("%S - Couldn't walk tree on part #%u (0-based) of %u (1-basedSmile hr = 0x%08x\n", this->MSGIDENTIFIER, n, nParts, hr);
                pIncomingPart->Release();
                pIncomingParts->Release();
                return hr;
            }
            pIncomingPart->Release();
        }

        pIncomingParts->Release();
    }

    return S_OK;
}
HRESULT侧音::WalkTreeBackwardsFromPart(IPart*部件){
HRESULT-hr;
如果(wcscmp(this->getPartName(part),L“SuperMix”)==0&&this->treePeek(part,L“Volume”)){
这->超级混合=零件;
IPart**superMixChildren=此->获取子零件(零件);
int nsupermischchildren=sizeof(superMixChildren)/sizeof(superMixChildren[0]);
如果(NSUPPERMIXCHILDREN>0){
对于(int i=0;igetPartName(superMixChildren[i]),L“Volume”)==0){
this->volumeNode=this->getIPartAsIAudioVolumeLevel(superMixChildren[i]);
如果(此->卷节点!=NULL){
IPart**volumeNodeChildren=this->getChildParts(超级混合儿童[i]);
int nVolumeNodeChildren=sizeof(volumeNodeChildren)/sizeof(volumeNodeChildren[0]);
如果(nVolumeNodeChildren>0){
for(int j=0;jgetPartName(volumeNodeChildren[j]),L“Mute”)==0{
this->muteNode=this->getIPartAsIAudioMute(volumeNodeChildren[j]);
打破
}
}
}
}
打破
}
}
}
删除[]子项;
this->muteNode;//=someotherfunc();
这->superMixFound=true;
返回S_OK;
}else if(superMixFound==false){
IPartsList*pIncomingParts=NULL;
hr=零件->枚举零件进料(&P)零件;
如果(E_NOTFOUND==hr){
//不是一个错误…我们刚刚走到路的尽头
//printf(“%S-此部件没有传入部件:0x%08x\n”,此->MSGIDENTIFIER,hr);
返回S_OK;
}
如果(失败(小时)){
printf(“%S-无法枚举传入部分:hr=0x%08x\n”,此->MSGIDENTIFIER,hr);
返回人力资源;
}
UINT npart=0;
hr=pIncomingParts->GetCount(&nParts);
如果(失败(小时)){
printf(“%S-无法获取传入部件的计数:hr=0x%08x\n”,此->MSGIDENTIFIER,hr);
pIncomingParts->Release();
返回人力资源;
}
//递归地遍历每个传入部件上的树
对于(UINT n=0;nGetPart(n,&pIncomingPart);
如果(失败(小时)){
printf(“%S-无法获取%u(1-basedFile hr=0x%08x\n)的部分#%u(基于0),此->MSGIDENTIFIER,n,npart,hr);
pIncomingParts->Release();
返回人力资源;
}
hr=从部件(pIncomingPart)返回的步行树;
如果(失败(小时)){
printf(“%S-无法在%u(1-basedFile hr=0x%08x\n)的部分#%u(基于0)上遍历树,此->MSGIDENTIFIER,n,npart,hr);
pIncomingPart->Release();
pIncomingParts->Release();
返回人力资源;
}
pIncomingPart->Release();
}
pIncomingParts->Release();
}
返回S_OK;
}
Sidetone::superMixFound
是一个布尔成员,用于快速中断递归循环,防止我们进一步遍历设备拓扑树(浪费时间)

Sidetone::getPartName()
是一种简单的可重用方法,用于返回
HRESULT Sidetone::WalkTreeBackwardsFromPart(IPart *part) {

    HRESULT hr;

    if (wcscmp(this->getPartName(part), L"SuperMix") == 0 && this->treePeek(part, L"Volume")){

        this->superMix = part;

        IPart** superMixChildren = this->getChildParts(part);
        int nSuperMixChildren = sizeof(superMixChildren) / sizeof(superMixChildren[0]);
        if (nSuperMixChildren > 0){

            for (int i = 0; i < nSuperMixChildren; i++){

                if (wcscmp(this->getPartName(superMixChildren[i]), L"Volume") == 0){

                    this->volumeNode = this->getIPartAsIAudioVolumeLevel(superMixChildren[i]);
                    if (this->volumeNode != NULL){

                        IPart** volumeNodeChildren = this->getChildParts(superMixChildren[i]);
                        int nVolumeNodeChildren = sizeof(volumeNodeChildren) / sizeof(volumeNodeChildren[0]);
                        if (nVolumeNodeChildren > 0){

                            for (int j = 0; j < nVolumeNodeChildren; j++){

                                if (wcscmp(this->getPartName(volumeNodeChildren[j]), L"Mute") == 0){

                                    this->muteNode = this->getIPartAsIAudioMute(volumeNodeChildren[j]);
                                    break;
                                }
                            }
                        }
                    }
                    break;
                }
            }
        }
        delete[] superMixChildren;


        this->muteNode; // = someotherfunc();
        this->superMixFound = true;
        return S_OK;

    } else if(superMixFound == false){

        IPartsList *pIncomingParts = NULL;
        hr = part->EnumPartsIncoming(&pIncomingParts);
        if (E_NOTFOUND == hr) {
            // not an error... we've just reached the end of the path
            //printf("%S - No incoming parts at this part: 0x%08x\n", this->MSGIDENTIFIER, hr);
            return S_OK;
        }
        if (FAILED(hr)) {
            printf("%S - Couldn't enum incoming parts: hr = 0x%08x\n", this->MSGIDENTIFIER, hr);
            return hr;
        }
        UINT nParts = 0;
        hr = pIncomingParts->GetCount(&nParts);
        if (FAILED(hr)) {
            printf("%S - Couldn't get count of incoming parts: hr = 0x%08x\n", this->MSGIDENTIFIER, hr);
            pIncomingParts->Release();
            return hr;
        }

        // walk the tree on each incoming part recursively
        for (UINT n = 0; n < nParts; n++) {
            IPart *pIncomingPart = NULL;
            hr = pIncomingParts->GetPart(n, &pIncomingPart);
            if (FAILED(hr)) {
                printf("%S - Couldn't get part #%u (0-based) of %u (1-basedSmile hr = 0x%08x\n", this->MSGIDENTIFIER, n, nParts, hr);
                pIncomingParts->Release();
                return hr;
            }

            hr = WalkTreeBackwardsFromPart(pIncomingPart);
            if (FAILED(hr)) {
                printf("%S - Couldn't walk tree on part #%u (0-based) of %u (1-basedSmile hr = 0x%08x\n", this->MSGIDENTIFIER, n, nParts, hr);
                pIncomingPart->Release();
                pIncomingParts->Release();
                return hr;
            }
            pIncomingPart->Release();
        }

        pIncomingParts->Release();
    }

    return S_OK;
}