0

我目前正在尝试使以下代码工作,但是当尝试使用 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

有什么办法可以解决这个问题?

4

0 回答 0