我目前正在尝试使以下代码工作,但是当尝试使用 portaudio 访问设备时,我使用 linux 计算机的功能,并且卡使用 ALSA。并且两个代码都使用相同版本的 portaudio
portaudio 提供了以下代码 pa_dev.c。此代码可以访问设备,并打印设备:
/** @file pa_devs.c
@ingroup examples_src
@brief List available devices, including device information.
@author Phil Burk http://www.softsynth.com
@note Define PA_USE_ASIO=0 to compile this code on Windows without
ASIO support.
*/
/*
* $Id: pa_devs.c 1752 2011-09-08 03:21:55Z philburk $
*
* This program uses the PortAudio Portable Audio Library.
* For more information see: http://www.portaudio.com
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
#include <stdio.h>
#include <math.h>
#include "portaudio.h"
#ifdef WIN32
#if PA_USE_ASIO
#include "pa_asio.h"
#endif
#endif
/*******************************************************************/
static void PrintSupportedStandardSampleRates(
const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters )
{
static double standardSampleRates[] = {
8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */
};
int i, printCount;
PaError err;
printCount = 0;
for( i=0; standardSampleRates[i] > 0; i++ )
{
err = Pa_IsFormatSupported( inputParameters, outputParameters, standardSampleRates[i] );
if( err == paFormatIsSupported )
{
if( printCount == 0 )
{
printf( "\t%8.2f", standardSampleRates[i] );
printCount = 1;
}
else if( printCount == 4 )
{
printf( ",\n\t%8.2f", standardSampleRates[i] );
printCount = 1;
}
else
{
printf( ", %8.2f", standardSampleRates[i] );
++printCount;
}
}
}
if( !printCount )
printf( "None\n" );
else
printf( "\n" );
}
/*******************************************************************/
int main(void);
int main(void)
{
int i, numDevices, defaultDisplayed;
const PaDeviceInfo *deviceInfo;
PaStreamParameters inputParameters, outputParameters;
PaError err;
Pa_Initialize();
printf( "PortAudio version number = %d\nPortAudio version text = '%s'\n",
Pa_GetVersion(), Pa_GetVersionText() );
numDevices = Pa_GetDeviceCount();
if( numDevices < 0 )
{
printf( "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices );
err = numDevices;
goto error;
}
printf( "Number of devices = %d\n", numDevices );
for( i=0; i<numDevices; i++ )
{
deviceInfo = Pa_GetDeviceInfo( i );
printf( "--------------------------------------- device #%d\n", i );
/* Mark global and API specific default devices */
defaultDisplayed = 0;
if( i == Pa_GetDefaultInputDevice() )
{
printf( "[ Default Input" );
defaultDisplayed = 1;
}
else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultInputDevice )
{
const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
printf( "[ Default %s Input", hostInfo->name );
defaultDisplayed = 1;
}
if( i == Pa_GetDefaultOutputDevice() )
{
printf( (defaultDisplayed ? "," : "[") );
printf( " Default Output" );
defaultDisplayed = 1;
}
else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultOutputDevice )
{
const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
printf( (defaultDisplayed ? "," : "[") );
printf( " Default %s Output", hostInfo->name );
defaultDisplayed = 1;
}
if( defaultDisplayed )
printf( " ]\n" );
/* print device info fields */
printf( "Name = %s\n", deviceInfo->name );
printf( "Host API = %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name );
printf( "Max inputs = %d", deviceInfo->maxInputChannels );
printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels );
printf( "Default low input latency = %8.4f\n", deviceInfo->defaultLowInputLatency );
printf( "Default low output latency = %8.4f\n", deviceInfo->defaultLowOutputLatency );
printf( "Default high input latency = %8.4f\n", deviceInfo->defaultHighInputLatency );
printf( "Default high output latency = %8.4f\n", deviceInfo->defaultHighOutputLatency );
#ifdef WIN32
#if PA_USE_ASIO
/* ASIO specific latency information */
if( Pa_GetHostApiInfo( deviceInfo->hostApi )->type == paASIO ){
long minLatency, maxLatency, preferredLatency, granularity;
err = PaAsio_GetAvailableLatencyValues( i,
&minLatency, &maxLatency, &preferredLatency, &granularity );
printf( "ASIO minimum buffer size = %ld\n", minLatency );
printf( "ASIO maximum buffer size = %ld\n", maxLatency );
printf( "ASIO preferred buffer size = %ld\n", preferredLatency );
if( granularity == -1 )
printf( "ASIO buffer granularity = power of 2\n" );
else
printf( "ASIO buffer granularity = %ld\n", granularity );
}
#endif /* PA_USE_ASIO */
#endif /* WIN32 */
printf( "Default sample rate = %8.2f\n", deviceInfo->defaultSampleRate );
/* poll for standard sample rates */
inputParameters.device = i;
inputParameters.channelCount = deviceInfo->maxInputChannels;
inputParameters.sampleFormat = paInt16;
inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
inputParameters.hostApiSpecificStreamInfo = NULL;
outputParameters.device = i;
outputParameters.channelCount = deviceInfo->maxOutputChannels;
outputParameters.sampleFormat = paInt16;
outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
outputParameters.hostApiSpecificStreamInfo = NULL;
if( inputParameters.channelCount > 0 )
{
printf("Supported standard sample rates\n for half-duplex 16 bit %d channel input = \n",
inputParameters.channelCount );
PrintSupportedStandardSampleRates( &inputParameters, NULL );
}
if( outputParameters.channelCount > 0 )
{
printf("Supported standard sample rates\n for half-duplex 16 bit %d channel output = \n",
outputParameters.channelCount );
PrintSupportedStandardSampleRates( NULL, &outputParameters );
}
if( inputParameters.channelCount > 0 && outputParameters.channelCount > 0 )
{
printf("Supported standard sample rates\n for full-duplex 16 bit %d channel input, %d channel output = \n",
inputParameters.channelCount, outputParameters.channelCount );
PrintSupportedStandardSampleRates( &inputParameters, &outputParameters );
}
}
Pa_Terminate();
printf("----------------------------------------------\n");
return 0;
error:
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;
}
但是,当我从以下代码中调用函数 Pa_GetDeviceCount() 和 Pa_GetDeviceInfo() 时,portaudio 检测到 0 设备并给我消息“设备不可用”
// online/online-audio-source.cc
// Copyright 2012 Cisco Systems (author: Matthias Paulik)
// Modifications to the original contribution by Cisco Systems made by:
// Vassil Panayotov
// See ../../COPYING for clarification regarding multiple authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <cmath>
#include <vector>
#ifndef KALDI_NO_PORTAUDIO
#include "base/timer.h"
#endif // KALDI_NO_PORTAUDIO
#include "online-audio-source.h"
namespace kaldi {
#ifndef KALDI_NO_PORTAUDIO
// The actual PortAudio callback - delegates to OnlinePaSource->Callback()
int PaCallback(const void *input, void *output,
long unsigned frame_count,
const PaStreamCallbackTimeInfo *time_info,
PaStreamCallbackFlags status_flags,
void *user_data) {
OnlinePaSource *pa_src = reinterpret_cast<OnlinePaSource*>(user_data);
return pa_src->Callback(input, output, frame_count, time_info, status_flags);
}
OnlinePaSource::OnlinePaSource(const uint32 timeout,
const uint32 sample_rate,
const uint32 rb_size,
const uint32 report_interval)
: timeout_(timeout), timed_out_(false),
sample_rate_(sample_rate), pa_started_(false),
report_interval_(report_interval), nread_calls_(0),
noverflows_(0), samples_lost_(0) {
using namespace std;
// Note this will work for 32bit integers but not for 64bit.
// For 64bit integers even double wouldn't work
// You would have to use something like
// int64 rb_bits = 0; while (rb_size != 0) {++rb_bits; rb_size >>= 1;}
// it would be much faster than two logs of FP numbers (even floats), too,
// but I don't have the time to test it.
float f = Log(static_cast<float>(rb_size)) / Log(static_cast<float>(2));
int32 rb_bits = static_cast<int32>(ceil(f));
if (rb_bits > 30) // ok, this limit is somewhat arbitrary
throw invalid_argument("PortAudio ring buffer too large!");
rb_size_ = 1 << rb_bits;
ring_buffer_ = new char[rb_size_];
ring_buffer_size_t rbs = PaUtil_InitializeRingBuffer(
&pa_ringbuf_, sizeof(SampleType),
rb_size_ / sizeof(SampleType), ring_buffer_);
if (rbs != 0)
KALDI_ERR << "PortAudio ring buffer init error";
PaError paerr = Pa_Initialize();
if (paerr != paNoError)
{
KALDI_ERR << "PortAudio initialization error";
// Monophone, 16-bit input hardcoded
KALDI_ASSERT(sizeof(SampleType) == 2 &&
"The current OnlinePaSource code assumes 16-bit input");
}
cout<<"la on va voir si on a des devices"<<endl;
int numDevices;
numDevices=Pa_GetDeviceCount();
cout<< " on a " << numDevices <<endl;
printf( "PortAudio version number = %d\nPortAudio version text = '%s'\n",Pa_GetVersion(), Pa_GetVersionText() );
paerr = Pa_OpenDefaultStream(&pa_stream_, 1, 0, paInt16, sample_rate_, 0,PaCallback, this);
//paerr=Pa_OpenStream
cout<<"Avant la boucle "<<endl;
if (paerr != paNoError)
{
cout<<"On est dans la boucle"<<endl;
const PaDeviceInfo *deviceInfo;
int i=0;
int numDevices;
numDevices=Pa_GetDeviceCount();
cout<<numDevices<<endl;
for (i=0;i<numDevices;i++)
{
deviceInfo=Pa_GetDeviceInfo(i);
cout<<"information sur le device"<<endl;
cout<<"name: "<<deviceInfo->name<<endl;
cout<<"maxInputChannels: "<<deviceInfo->maxInputChannels<<endl;
cout<<"maxOutputChannels: "<<deviceInfo->maxOutputChannels<<endl;
cout<<"defaultSampleRate: "<<deviceInfo->defaultSampleRate<<endl;
}
cout<<Pa_GetErrorText(paerr)<<endl;
KALDI_ERR << "PortAudio failed to open the default stream";
}
}
OnlinePaSource::~OnlinePaSource() {
if (pa_started_)
Pa_StopStream(pa_stream_);
if (pa_stream_ != 0) {
Pa_CloseStream(pa_stream_);
Pa_Terminate();
}
if (ring_buffer_ != 0)
delete [] ring_buffer_;
}
bool OnlinePaSource::Read(Vector<BaseFloat> *data) {
if (!pa_started_) { // start stream the first time Read() is called
PaError paerr = Pa_StartStream(pa_stream_);
if (paerr != paNoError)
KALDI_ERR << "Error while trying to open PortAudio stream";
pa_started_ = true;
}
Timer timer;
if (report_interval_ != 0
&& (++nread_calls_ % report_interval_) == 0
&& noverflows_ > 0) {
KALDI_VLOG(1) << noverflows_
<< " PortAudio ring buffer overflows detected "
<< "and " << samples_lost_ << " sample(s) were lost";
samples_lost_ = noverflows_ = 0;
}
uint32 nsamples_req = data->Dim(); // samples to request
timed_out_ = false;
while (true) {
ring_buffer_size_t nsamples;
nsamples = PaUtil_GetRingBufferReadAvailable(&pa_ringbuf_);
if (nsamples >= nsamples_req)
break;
if (timeout_ > 0) {
int32 elapsed = static_cast<int32>(timer.Elapsed() * 1000);
if (elapsed > timeout_) {
nsamples_req = nsamples;
timed_out_ = true;
KALDI_VLOG(2) << "OnlinePaSource::Read() timeout";
break;
}
}
Pa_Sleep(2);
}
std::vector<int16> buf(nsamples_req);
rbs_t nsamples_rcv;
nsamples_rcv = PaUtil_ReadRingBuffer(&pa_ringbuf_, buf.data(), nsamples_req);
if (nsamples_rcv != nsamples_req) {
KALDI_WARN << "Requested: " << nsamples_req
<< "; Received: " << nsamples_rcv << " samples";
// This would be a PortAudio error.
}
data->Resize(nsamples_rcv);
for (int i = 0; i < nsamples_rcv; ++i)
(*data)(i) = static_cast<BaseFloat>(buf[i]);
return (nsamples_rcv != 0);
// NOTE (Dan): I'm pretty sure this return value is not right, it could be
// this way because we're waiting. Vassil or someone will have to figure this
// out.
}
// Accepts the data and writes it to the ring buffer
int OnlinePaSource::Callback(const void *input, void *output,
ring_buffer_size_t frame_count,
const PaStreamCallbackTimeInfo *time_info,
PaStreamCallbackFlags status_flags) {
if (report_interval_ != 0) {
if (frame_count > PaUtil_GetRingBufferWriteAvailable(&pa_ringbuf_))
++noverflows_;
}
rbs_t written = PaUtil_WriteRingBuffer(&pa_ringbuf_, input, frame_count);
samples_lost_ += frame_count - written;
return paContinue;
}
#endif // KALDI_NO_PORTAUDIO
bool OnlineVectorSource::Read(Vector<BaseFloat> *data) {
KALDI_ASSERT(data->Dim() > 0);
int32 n_elem = std::min(src_.Dim() - pos_,
static_cast<uint32>(data->Dim()));
if (n_elem > 0) {
SubVector<BaseFloat> subsrc(src_, pos_, n_elem);
if (data->Dim() == subsrc.Dim()) {
data->CopyFromVec(subsrc);
} else {
data->Resize(n_elem);
for (int32 i = 0; i < subsrc.Dim(); ++i)
(*data)(i) = subsrc(i);
}
pos_ += n_elem;
return true;
}
return false;
}
} // namespace kaldi
有什么办法可以解决这个问题?