コード例 #1
0
    /**
     *  Checks if sound card supports the chosen parameters.
     *
     *  @returns  true if hardware supports it
     *  @throws AudioOutputException - if device cannot be accessed
     */
    bool AudioOutputDeviceAlsa::HardwareParametersSupported(String card, uint channels, int samplerate, uint numfragments, uint fragmentsize) throw (AudioOutputException) {
        pcm_name = "hw:" + card;
        int err;
        if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, SND_PCM_NONBLOCK)) < 0) {
            throw AudioOutputException(String("Error opening PCM device ") + pcm_name + ": " + snd_strerror(err));
        }
        snd_pcm_hw_params_alloca(&hwparams);
        if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
            snd_pcm_close(pcm_handle);
            return false;
        }
        if (snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
            snd_pcm_close(pcm_handle);
            return false;
        }
        #if WORDS_BIGENDIAN
        if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE) < 0)
        #else // little endian
        if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0)
        #endif
        {
            snd_pcm_close(pcm_handle);
            return false;
        }
        int dir = 0;
        if (snd_pcm_hw_params_test_rate(pcm_handle, hwparams, samplerate, dir) < 0) {
            snd_pcm_close(pcm_handle);
            return false;
        }
        if (snd_pcm_hw_params_test_channels(pcm_handle, hwparams, channels) < 0) {
            snd_pcm_close(pcm_handle);
            return false;
        }
        if (snd_pcm_hw_params_test_periods(pcm_handle, hwparams, numfragments, dir) < 0) {
            snd_pcm_close(pcm_handle);
            return false;
        }
        if (snd_pcm_hw_params_test_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments)) < 0) {
            snd_pcm_close(pcm_handle);
            return false;
        }

        snd_pcm_close(pcm_handle);
        return true;
    }
コード例 #2
0
ファイル: ALSACapRec.c プロジェクト: jamieguinan/cti
static void get_channels_range(Instance *pi, Range *range)
{
  int i;
  int rc;
  ALSAio_private *priv = (ALSAio_private *)pi;

  if (!priv->c.handle) {
    fprintf(stderr, "*** device is not open!\n");
    return;
  }

  Range_clear(range);
  range->type = RANGE_INT_ENUM;

  for (i=0; i < table_size(channels); i++) {
    rc = snd_pcm_hw_params_test_channels(priv->c.handle, priv->c.hwparams, channels[i]);
    if (rc == 0) {
      printf("  %d-channel sampling available\n", channels[i]);
      Array_append(range->int_enums, rates[i]);
    }
  }
}
コード例 #3
0
ファイル: AESinkALSA.cpp プロジェクト: CharlieMarshall/xbmc
void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &device, const std::string &description, snd_config_t *config)
{
  snd_pcm_t *pcmhandle = NULL;
  if (!OpenPCMDevice(device, "", ALSA_MAX_CHANNELS, &pcmhandle, config))
    return;

  snd_pcm_info_t *pcminfo;
  snd_pcm_info_alloca(&pcminfo);
  memset(pcminfo, 0, snd_pcm_info_sizeof());

  int err = snd_pcm_info(pcmhandle, pcminfo);
  if (err < 0)
  {
    CLog::Log(LOGINFO, "CAESinkALSA - Unable to get pcm_info for \"%s\"", device.c_str());
    snd_pcm_close(pcmhandle);
  }

  int cardNr = snd_pcm_info_get_card(pcminfo);

  CAEDeviceInfo info;
  info.m_deviceName = device;
  info.m_deviceType = AEDeviceTypeFromName(device);

  if (cardNr >= 0)
  {
    /* "HDA NVidia", "HDA Intel", "HDA ATI HDMI", "SB Live! 24-bit External", ... */
    char *cardName;
    if (snd_card_get_name(cardNr, &cardName) == 0)
      info.m_displayName = cardName;

    if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 &&
        info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI")
    {
      /* We already know this is HDMI, strip it */
      info.m_displayName.erase(info.m_displayName.size()-5);
    }

    /* "CONEXANT Analog", "USB Audio", "HDMI 0", "ALC889 Digital" ... */
    std::string pcminfoName = snd_pcm_info_get_name(pcminfo);

    /*
     * Filter "USB Audio", in those cases snd_card_get_name() is more
     * meaningful already
     */
    if (pcminfoName != "USB Audio")
      info.m_displayNameExtra = pcminfoName;

    if (info.m_deviceType == AE_DEVTYPE_HDMI)
    {
      /* replace, this was likely "HDMI 0" */
      info.m_displayNameExtra = "HDMI";

      int dev = snd_pcm_info_get_device(pcminfo);

      if (dev >= 0)
      {
        /* lets see if we can get ELD info */

        snd_ctl_t *ctlhandle;
        std::stringstream sstr;
        sstr << "hw:" << cardNr;
        std::string strHwName = sstr.str();

        if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) == 0)
        {
          snd_hctl_t *hctl;
          if (snd_hctl_open_ctl(&hctl, ctlhandle) == 0)
          {
            snd_hctl_load(hctl);
            bool badHDMI = false;
            if (!GetELD(hctl, dev, info, badHDMI))
              CLog::Log(LOGDEBUG, "CAESinkALSA - Unable to obtain ELD information for device \"%s\" (not supported by device, or kernel older than 3.2)",
                        device.c_str());

            /* snd_hctl_close also closes ctlhandle */
            snd_hctl_close(hctl);

            if (badHDMI)
            {
              /* 
               * Warn about disconnected devices, but keep them enabled 
               * Detection can go wrong on Intel, Nvidia and on all 
               * AMD (fglrx) hardware, so it is not safe to close those
               * handles
               */
              CLog::Log(LOGDEBUG, "CAESinkALSA - HDMI device \"%s\" may be unconnected (no ELD data)", device.c_str());
            }
          }
          else
          {
            snd_ctl_close(ctlhandle);
          }
        }
      }
    }
    else if (info.m_deviceType == AE_DEVTYPE_IEC958)
    {
      /* append instead of replace, pcminfoName is useful for S/PDIF */
      if (!info.m_displayNameExtra.empty())
        info.m_displayNameExtra += ' ';
      info.m_displayNameExtra += "S/PDIF";
    }
    else if (info.m_displayNameExtra.empty())
    {
      /* for USB audio, it gets a bit confusing as there is
       * - "SB Live! 24-bit External"
       * - "SB Live! 24-bit External, S/PDIF"
       * so add "Analog" qualifier to the first one */
      info.m_displayNameExtra = "Analog";
    }

    /* "default" is a device that will be used for all inputs, while
     * "@" will be mangled to front/default/surroundXX as necessary */
    if (device == "@" || device == "default")
    {
      /* Make it "Default (whatever)" */
      info.m_displayName = "Default (" + info.m_displayName + (info.m_displayNameExtra.empty() ? "" : " " + info.m_displayNameExtra + ")");
      info.m_displayNameExtra = "";
    }

  }
  else
  {
    /* virtual devices: "default", "pulse", ... */
    /* description can be e.g. "PulseAudio Sound Server" - for hw devices it is
     * normally uninteresting, like "HDMI Audio Output" or "Default Audio Device",
     * so we only use it for virtual devices that have no better display name */
    info.m_displayName = description;
  }

  snd_pcm_hw_params_t *hwparams;
  snd_pcm_hw_params_alloca(&hwparams);
  memset(hwparams, 0, snd_pcm_hw_params_sizeof());

  /* ensure we can get a playback configuration for the device */
  if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0)
  {
    CLog::Log(LOGINFO, "CAESinkALSA - No playback configurations available for device \"%s\"", device.c_str());
    snd_pcm_close(pcmhandle);
    return;
  }

  /* detect the available sample rates */
  for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate)
    if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0)
      info.m_sampleRates.push_back(*rate);

  /* detect the channels available */
  int channels = 0;
  for (int i = ALSA_MAX_CHANNELS; i >= 1; --i)
  {
    /* Reopen the device if needed on the special "surroundXX" cases */
    if (info.m_deviceType == AE_DEVTYPE_PCM && (i == 8 || i == 6 || i == 4))
      OpenPCMDevice(device, "", i, &pcmhandle, config);

    if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0)
    {
      channels = i;
      break;
    }
  }

  if (device == "default" && channels == 2)
  {
    /* This looks like the ALSA standard default stereo dmix device, we
     * probably want to use "@" instead to get surroundXX. */
    snd_pcm_close(pcmhandle);
    EnumerateDevice(list, "@", description, config);
    return;
  }

  CAEChannelInfo alsaChannels;
  for (int i = 0; i < channels; ++i)
  {
    if (!info.m_channels.HasChannel(ALSAChannelMap[i]))
      info.m_channels += ALSAChannelMap[i];
    alsaChannels += ALSAChannelMap[i];
  }

  /* remove the channels from m_channels that we cant use */
  info.m_channels.ResolveChannels(alsaChannels);

  /* detect the PCM sample formats that are available */
  for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
  {
    if (AE_IS_RAW(i) || i == AE_FMT_MAX)
      continue;
    snd_pcm_format_t fmt = AEFormatToALSAFormat(i);
    if (fmt == SND_PCM_FORMAT_UNKNOWN)
      continue;

    if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0)
      info.m_dataFormats.push_back(i);
  }

  snd_pcm_close(pcmhandle);
  list.push_back(info);
}
コード例 #4
0
bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
{
    // Set nearest to closest settings that do work.
    // See if what is in settings will work (return value).
    int err = 0;
    snd_pcm_t* handle;
    snd_pcm_hw_params_t *params;
    QString dev = device;

    QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput);

    if(dev.compare(QLatin1String("default")) == 0) {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        dev = QLatin1String(devices.first().constData());
#else
        dev = QLatin1String("hw:0,0");
#endif
    } else {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        dev = device;
#else
        int idx = 0;
        char *name;

        QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1);

        while(snd_card_get_name(idx,&name) == 0) {
            if(shortName.compare(QLatin1String(name)) == 0)
                break;
            idx++;
        }
        dev = QString(QLatin1String("hw:%1,0")).arg(idx);
#endif
    }
    if(mode == QAudio::AudioOutput) {
        err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
    } else {
        err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
    }
    if(err < 0) {
        handle = 0;
        return false;
    }

    bool testChannel = false;
    bool testCodec = false;
    bool testFreq = false;
    bool testType = false;
    bool testSize = false;

    int  dir = 0;

    snd_pcm_nonblock( handle, 0 );
    snd_pcm_hw_params_alloca( &params );
    snd_pcm_hw_params_any( handle, params );

    // set the values!
    snd_pcm_hw_params_set_channels(handle,params,format.channels());
    snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);

    err = -1;

    switch(format.sampleSize()) {
        case 8:
            if(format.sampleType() == QAudioFormat::SignedInt)
                err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
            else if(format.sampleType() == QAudioFormat::UnSignedInt)
                err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
            break;
        case 16:
            if(format.sampleType() == QAudioFormat::SignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
            } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
            }
            break;
        case 32:
            if(format.sampleType() == QAudioFormat::SignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
            } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
            }
    }

    // For now, just accept only audio/pcm codec
    if(!format.codec().startsWith(QLatin1String("audio/pcm"))) {
        err=-1;
    } else
        testCodec = true;

    if(err>=0 && format.channels() != -1) {
        err = snd_pcm_hw_params_test_channels(handle,params,format.channels());
        if(err>=0)
            err = snd_pcm_hw_params_set_channels(handle,params,format.channels());
        if(err>=0)
            testChannel = true;
    }

    if(err>=0 && format.frequency() != -1) {
        err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0);
        if(err>=0)
            err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
        if(err>=0)
            testFreq = true;
    }

    if((err>=0 && format.sampleSize() != -1) &&
            (format.sampleType() != QAudioFormat::Unknown)) {
        switch(format.sampleSize()) {
            case 8:
                if(format.sampleType() == QAudioFormat::SignedInt)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
                else if(format.sampleType() == QAudioFormat::UnSignedInt)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
                break;
            case 16:
                if(format.sampleType() == QAudioFormat::SignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
                } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
                }
                break;
            case 32:
                if(format.sampleType() == QAudioFormat::SignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
                } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
                }
        }
        if(err>=0) {
            testSize = true;
            testType = true;
        }
    }
    if(err>=0)
        err = snd_pcm_hw_params(handle, params);

    if(err == 0) {
        // settings work
        // close()
        if(handle)
            snd_pcm_close(handle);
        return true;
    }
    if(handle)
        snd_pcm_close(handle);

    return false;
}
コード例 #5
0
bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
{
    // Set nearest to closest settings that do work.
    // See if what is in settings will work (return value).
    int err = 0;
    snd_pcm_t* handle;
    snd_pcm_hw_params_t *params;
    QString dev = device;

    // open()
    if(!dev.contains(QLatin1String("default"))) {
        int idx = snd_card_get_index(dev.toLocal8Bit().constData());
        dev = QString(QLatin1String("hw:%1,0")).arg(idx);
    }
    if(mode == QAudio::AudioOutput) {
        err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
    } else {
        err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
    }
    if(err < 0) {
        handle = 0;
        return false;
    }

    bool testChannel = false;
    bool testCodec = false;
    bool testFreq = false;
    bool testType = false;
    bool testSize = false;

    int  dir = 0;

    snd_pcm_nonblock( handle, 0 );
    snd_pcm_hw_params_alloca( &params );
    snd_pcm_hw_params_any( handle, params );

    // set the values!
    snd_pcm_hw_params_set_channels(handle,params,format.channels());
    snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
    switch(format.sampleSize()) {
        case 8:
            if(format.sampleType() == QAudioFormat::SignedInt)
                snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
            else if(format.sampleType() == QAudioFormat::UnSignedInt)
                snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
            break;
        case 16:
            if(format.sampleType() == QAudioFormat::SignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
            } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
            }
            break;
        case 32:
            if(format.sampleType() == QAudioFormat::SignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
            } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
            }
    }

    // For now, just accept only audio/pcm codec
    if(!format.codec().startsWith(QLatin1String("audio/pcm"))) {
        err=-1;
    } else
        testCodec = true;

    if(err>=0 && format.channels() != -1) {
        err = snd_pcm_hw_params_test_channels(handle,params,format.channels());
        if(err>=0)
            err = snd_pcm_hw_params_set_channels(handle,params,format.channels());
        if(err>=0)
            testChannel = true;
    }

    if(err>=0 && format.frequency() != -1) {
        err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0);
        if(err>=0)
            err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
        if(err>=0)
            testFreq = true;
    }

    if((err>=0 && format.sampleSize() != -1) &&
            (format.sampleType() != QAudioFormat::Unknown)) {
        switch(format.sampleSize()) {
            case 8:
                if(format.sampleType() == QAudioFormat::SignedInt)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
                else if(format.sampleType() == QAudioFormat::UnSignedInt)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
                break;
            case 16:
                if(format.sampleType() == QAudioFormat::SignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
                } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
                }
                break;
            case 32:
                if(format.sampleType() == QAudioFormat::SignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
                } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
                }
        }
        if(err>=0) {
            testSize = true;
            testType = true;
        }
    }
    if(err>=0)
        err = snd_pcm_hw_params(handle, params);

    if(err == 0) {
        // settings work
        // close()
        if(handle)
            snd_pcm_close(handle);
        return true;
    }
    if(handle)
        snd_pcm_close(handle);

    return false;
}
コード例 #6
0
ファイル: alsa.c プロジェクト: LighFusion/surreal
static ALCboolean alsa_reset_playback(ALCdevice *device)
{
    alsa_data *data = (alsa_data*)device->ExtraData;
    snd_pcm_uframes_t periodSizeInFrames;
    unsigned int periodLen, bufferLen;
    snd_pcm_sw_params_t *sp = NULL;
    snd_pcm_hw_params_t *hp = NULL;
    snd_pcm_access_t access;
    snd_pcm_format_t format;
    unsigned int periods;
    unsigned int rate;
    const char *funcerr;
    int allowmmap;
    int err;

    format = -1;
    switch(device->FmtType)
    {
        case DevFmtByte:
            format = SND_PCM_FORMAT_S8;
            break;
        case DevFmtUByte:
            format = SND_PCM_FORMAT_U8;
            break;
        case DevFmtShort:
            format = SND_PCM_FORMAT_S16;
            break;
        case DevFmtUShort:
            format = SND_PCM_FORMAT_U16;
            break;
        case DevFmtInt:
            format = SND_PCM_FORMAT_S32;
            break;
        case DevFmtUInt:
            format = SND_PCM_FORMAT_U32;
            break;
        case DevFmtFloat:
            format = SND_PCM_FORMAT_FLOAT;
            break;
    }

    allowmmap = GetConfigValueBool("alsa", "mmap", 1);
    periods = device->NumUpdates;
    periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
    bufferLen = periodLen * periods;
    rate = device->Frequency;

    snd_pcm_hw_params_malloc(&hp);
#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
    CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
    /* set interleaved access */
    if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
    {
        if(periods > 2)
        {
            periods--;
            bufferLen = periodLen * periods;
        }
        CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
    }
    /* test and set format (implicitly sets sample bits) */
    if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0)
    {
        static const struct {
            snd_pcm_format_t format;
            enum DevFmtType fmttype;
        } formatlist[] = {
            { SND_PCM_FORMAT_FLOAT, DevFmtFloat  },
            { SND_PCM_FORMAT_S32,   DevFmtInt    },
            { SND_PCM_FORMAT_U32,   DevFmtUInt   },
            { SND_PCM_FORMAT_S16,   DevFmtShort  },
            { SND_PCM_FORMAT_U16,   DevFmtUShort },
            { SND_PCM_FORMAT_S8,    DevFmtByte   },
            { SND_PCM_FORMAT_U8,    DevFmtUByte  },
        };
        size_t k;

        for(k = 0;k < COUNTOF(formatlist);k++)
        {
            format = formatlist[k].format;
            if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0)
            {
                device->FmtType = formatlist[k].fmttype;
                break;
            }
        }
    }
    CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
    /* test and set channels (implicitly sets frame bits) */
    if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
    {
        static const enum DevFmtChannels channellist[] = {
            DevFmtStereo,
            DevFmtQuad,
            DevFmtX51,
            DevFmtX71,
            DevFmtMono,
        };
        size_t k;

        for(k = 0;k < COUNTOF(channellist);k++)
        {
            if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
            {
                device->FmtChans = channellist[k];
                break;
            }
        }
    }
    CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
    /* set rate (implicitly constrains period/buffer parameters) */
    if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0)
        ERR("Failed to disable ALSA resampler\n");
    CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL));
    /* set buffer time (implicitly constrains period/buffer parameters) */
    CHECK(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL));
    /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
    CHECK(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL));
    /* install and prepare hardware configuration */
    CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
    /* retrieve configuration info */
    CHECK(snd_pcm_hw_params_get_access(hp, &access));
    CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
    CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL));

    snd_pcm_hw_params_free(hp);
    hp = NULL;
    snd_pcm_sw_params_malloc(&sp);

    CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp));
    CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames));
    CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods));
    CHECK(snd_pcm_sw_params(data->pcmHandle, sp));
#undef CHECK
    snd_pcm_sw_params_free(sp);
    sp = NULL;

    /* Increase periods by one, since the temp buffer counts as an extra
     * period */
    if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
        device->NumUpdates = periods+1;
    else
        device->NumUpdates = periods;
    device->UpdateSize = periodSizeInFrames;
    device->Frequency = rate;

    SetDefaultChannelOrder(device);

    return ALC_TRUE;

error:
    ERR("%s failed: %s\n", funcerr, snd_strerror(err));
    if(hp) snd_pcm_hw_params_free(hp);
    if(sp) snd_pcm_sw_params_free(sp);
    return ALC_FALSE;
}
コード例 #7
0
bool QAlsaAudioDeviceInfo::testSettings(const QAudioFormat& format) const
{
    // Set nearest to closest settings that do work.
    // See if what is in settings will work (return value).
    int err = -1;
    snd_pcm_t* pcmHandle;
    snd_pcm_hw_params_t *params;
    QString dev;

#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
    dev = device;
    if (dev.compare(QLatin1String("default")) == 0) {
        QList<QByteArray> devices = availableDevices(QAudio::AudioOutput);
        if (!devices.isEmpty())
            dev = QLatin1String(devices.first().constData());
    }
#else
    if (dev.compare(QLatin1String("default")) == 0) {
        dev = QLatin1String("hw:0,0");
    } else {
        int idx = 0;
        char *name;

        QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1);

        while(snd_card_get_name(idx,&name) == 0) {
            if(shortName.compare(QLatin1String(name)) == 0)
                break;
            idx++;
        }
        dev = QString(QLatin1String("hw:%1,0")).arg(idx);
    }
#endif

    snd_pcm_stream_t stream = mode == QAudio::AudioOutput
                            ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE;

    if (snd_pcm_open(&pcmHandle, dev.toLocal8Bit().constData(), stream, 0) < 0)
        return false;

    snd_pcm_nonblock(pcmHandle, 0);
    snd_pcm_hw_params_alloca(&params);
    snd_pcm_hw_params_any(pcmHandle, params);

    // set the values!
    snd_pcm_hw_params_set_channels(pcmHandle, params, format.channelCount());
    snd_pcm_hw_params_set_rate(pcmHandle, params, format.sampleRate(), 0);

    snd_pcm_format_t pcmFormat = SND_PCM_FORMAT_UNKNOWN;
    switch (format.sampleSize()) {
    case 8:
        if (format.sampleType() == QAudioFormat::SignedInt)
            pcmFormat = SND_PCM_FORMAT_S8;
        else if (format.sampleType() == QAudioFormat::UnSignedInt)
            pcmFormat = SND_PCM_FORMAT_U8;
        break;
    case 16:
        if (format.sampleType() == QAudioFormat::SignedInt) {
            pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian
                      ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_S16_BE;
        } else if (format.sampleType() == QAudioFormat::UnSignedInt) {
            pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian
                      ? SND_PCM_FORMAT_U16_LE : SND_PCM_FORMAT_U16_BE;
        }
        break;
    case 32:
        if (format.sampleType() == QAudioFormat::SignedInt) {
            pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian
                      ? SND_PCM_FORMAT_S32_LE : SND_PCM_FORMAT_S32_BE;
        } else if (format.sampleType() == QAudioFormat::UnSignedInt) {
            pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian
                      ? SND_PCM_FORMAT_U32_LE : SND_PCM_FORMAT_U32_BE;
        } else if (format.sampleType() == QAudioFormat::Float) {
            pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian
                      ? SND_PCM_FORMAT_FLOAT_LE : SND_PCM_FORMAT_FLOAT_BE;
        }
    }

    if (pcmFormat != SND_PCM_FORMAT_UNKNOWN)
        err = snd_pcm_hw_params_set_format(pcmHandle, params, pcmFormat);

    // For now, just accept only audio/pcm codec
    if (!format.codec().startsWith(QLatin1String("audio/pcm")))
        err = -1;

    if (err >= 0 && format.channelCount() != -1) {
        err = snd_pcm_hw_params_test_channels(pcmHandle, params, format.channelCount());
        if (err >= 0)
            err = snd_pcm_hw_params_set_channels(pcmHandle, params, format.channelCount());
    }

    if (err >= 0 && format.sampleRate() != -1) {
        err = snd_pcm_hw_params_test_rate(pcmHandle, params, format.sampleRate(), 0);
        if (err >= 0)
            err = snd_pcm_hw_params_set_rate(pcmHandle, params, format.sampleRate(), 0);
    }

    if (err >= 0 && pcmFormat != SND_PCM_FORMAT_UNKNOWN)
        err = snd_pcm_hw_params_set_format(pcmHandle, params, pcmFormat);

    if (err >= 0)
        err = snd_pcm_hw_params(pcmHandle, params);

    snd_pcm_close(pcmHandle);

    return (err == 0);
}
コード例 #8
0
ファイル: AudioTest.c プロジェクト: tician/nan-darwin-op
int main(int argc, char *argv[])
{
  const char *device_name = "hw";
  snd_pcm_t *pcm;
  snd_pcm_hw_params_t *hw_params;
  unsigned int i;
  unsigned int min, max;
  int any_rate;
  int err;

  if (argc > 1)
    device_name = argv[1];

  err = snd_pcm_open(&pcm, device_name, SND_PCM_STREAM_CAPTURE, 
		     SND_PCM_NONBLOCK);
  if (err < 0) {
    fprintf(stderr, "cannot open device '%s': %s\n", device_name, 
	    snd_strerror(err));
    return 1;
  }

  snd_pcm_hw_params_alloca(&hw_params);
  err = snd_pcm_hw_params_any(pcm, hw_params);
  if (err < 0) {
    fprintf(stderr, "cannot get hardware parameters: %s\n", 
	    snd_strerror(err));
    snd_pcm_close(pcm);
    return 1;
  }

  printf("Device: %s (type: %s)\n", device_name, 
	 snd_pcm_type_name(snd_pcm_type(pcm)));

  printf("Access types:");
  for (i = 0; i < ARRAY_SIZE(accesses); ++i) {
    if (!snd_pcm_hw_params_test_access(pcm, hw_params, accesses[i]))
      printf(" %s", snd_pcm_access_name(accesses[i]));
  }
  putchar('\n');

  printf("Formats:");
  for (i = 0; i < ARRAY_SIZE(formats); ++i) {
    if (!snd_pcm_hw_params_test_format(pcm, hw_params, formats[i]))
      printf(" %s", snd_pcm_format_name(formats[i]));
  }
  putchar('\n');

  err = snd_pcm_hw_params_get_channels_min(hw_params, &min);
  if (err < 0) {
    fprintf(stderr, "cannot get minimum channels count: %s\n", 
	    snd_strerror(err));
    snd_pcm_close(pcm);
    return 1;
  }
  err = snd_pcm_hw_params_get_channels_max(hw_params, &max);
  if (err < 0) {
    fprintf(stderr, "cannot get maximum channels count: %s\n", 
	    snd_strerror(err));
    snd_pcm_close(pcm);
    return 1;
  }
  printf("Channels:");
  for (i = min; i <= max; ++i) {
    if (!snd_pcm_hw_params_test_channels(pcm, hw_params, i))
      printf(" %u", i);
  }
  putchar('\n');

  err = snd_pcm_hw_params_get_rate_min(hw_params, &min, NULL);
  if (err < 0) {
    fprintf(stderr, "cannot get minimum rate: %s\n", 
	    snd_strerror(err));
    snd_pcm_close(pcm);
    return 1;
  }
  err = snd_pcm_hw_params_get_rate_max(hw_params, &max, NULL);
  if (err < 0) {
    fprintf(stderr, "cannot get maximum rate: %s\n", 
	    snd_strerror(err));
    snd_pcm_close(pcm);
    return 1;
  }
  printf("Sample rates:");
  if (min == max)
    printf(" %u", min);
  else if (!snd_pcm_hw_params_test_rate(pcm, hw_params, min + 1, 0))
    printf(" %u-%u", min, max);
  else {
    any_rate = 0;
    for (i = 0; i < ARRAY_SIZE(rates); ++i) {
      if (!snd_pcm_hw_params_test_rate(pcm, hw_params, 
				       rates[i], 0)) {
	any_rate = 1;
	printf(" %u", rates[i]);
      }
    }
    if (!any_rate)
      printf(" %u-%u", min, max);
  }
  putchar('\n');

  err = snd_pcm_hw_params_get_period_time_min(hw_params, &min, NULL);
  if (err < 0) {
    fprintf(stderr, "cannot get minimum period time: %s\n", 
	    snd_strerror(err));
    snd_pcm_close(pcm);
    return 1;
  }
  err = snd_pcm_hw_params_get_period_time_max(hw_params, &max, NULL);
  if (err < 0) {
    fprintf(stderr, "cannot get maximum period time: %s\n", 
	    snd_strerror(err));
    snd_pcm_close(pcm);
    return 1;
  }
  printf("Interrupt interval: %u-%u us\n", min, max);

  err = snd_pcm_hw_params_get_buffer_time_min(hw_params, &min, NULL);
  if (err < 0) {
    fprintf(stderr, "cannot get minimum buffer time: %s\n", 
	    snd_strerror(err));
    snd_pcm_close(pcm);
    return 1;
  }
  err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &max, NULL);
  if (err < 0) {
    fprintf(stderr, "cannot get maximum buffer time: %s\n", 
	    snd_strerror(err));
    snd_pcm_close(pcm);
    return 1;
  }
  printf("Buffer size: %u-%u us\n", min, max);

  snd_pcm_close(pcm);
  return 0;
}
コード例 #9
0
ファイル: alsaio.cpp プロジェクト: svn2github/linuxsampler
int AlsaIO::Initialize(uint Channels, uint Samplerate, uint Fragments, uint FragmentSize, String Card) {
    this->uiChannels           = Channels;
    this->uiSamplerate         = Samplerate;
    this->uiMaxSamplesPerCycle = FragmentSize;
    this->bInterleaved         = true;

    if (HardwareParametersSupported(Channels, Samplerate, Fragments, FragmentSize)) {
        pcm_name = "hw:" + Card;
    }
    else {
        printf("Warning: your soundcard doesn't support chosen hardware parameters; ");
        printf("trying to compensate support lack with plughw...");
        fflush(stdout);
        pcm_name = "plughw:" + Card;
    }

    int err;

    snd_pcm_hw_params_alloca(&hwparams);  // Allocate the snd_pcm_hw_params_t structure on the stack.

    /* Open PCM. The last parameter of this function is the mode. */
    /* If this is set to 0, the standard mode is used. Possible   */
    /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.       */
    /* If SND_PCM_NONBLOCK is used, read / write access to the    */
    /* PCM device will return immediately. If SND_PCM_ASYNC is    */
    /* specified, SIGIO will be emitted whenever a period has     */
    /* been completely processed by the soundcard.                */
    if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0)) < 0) {
        fprintf(stderr, "Error opening PCM device %s: %s\n", pcm_name.c_str(), snd_strerror(err));
        return -1;
    }

    if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
        fprintf(stderr, "Error, cannot initialize hardware parameter structure: %s.\n", snd_strerror(err));
        return -1;
    }

    /* Set access type. This can be either    */
    /* SND_PCM_ACCESS_RW_INTERLEAVED or       */
    /* SND_PCM_ACCESS_RW_NONINTERLEAVED.      */
    if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_set_access: %s.\n", snd_strerror(err));
        return -1;
    }

    /* Set sample format */
    #if WORDS_BIGENDIAN
    if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE)) < 0) {
    #else // little endian
    if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) {
    #endif
        fprintf(stderr, "Error setting sample format. : %s\n", snd_strerror(err));
        return -1;
    }

    int dir = 0;

    /* Set sample rate. If the exact rate is not supported */
    /* by the hardware, use nearest possible rate.         */
    #if ALSA_MAJOR > 0
    if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &Samplerate, &dir)) < 0) {
    #else
    if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, Samplerate, &dir)) < 0) {
    #endif
        fprintf(stderr, "Error setting sample rate. : %s\n", snd_strerror(err));
        return -1;
    }

    if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, Channels)) < 0) {
        fprintf(stderr, "Error setting number of channels. : %s\n", snd_strerror(err));
        return -1;
    }

    /* Set number of periods. Periods used to be called fragments. */
    if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, Fragments, dir)) < 0) {
        fprintf(stderr, "Error setting number of periods. : %s\n", snd_strerror(err));
        return -1;
    }

    /* Set buffer size (in frames). The resulting latency is given by */
    /* latency = periodsize * periods / (rate * bytes_per_frame)     */
    if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (FragmentSize * Fragments))) < 0) {
        fprintf(stderr, "Error setting buffersize. : %s\n", snd_strerror(err));
        return -1;
    }

    /* Apply HW parameter settings to */
    /* PCM device and prepare device  */
    if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
        fprintf(stderr, "Error setting HW params. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params_malloc(&swparams) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params_malloc. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params_current. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params_set_stop_threshold. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params(pcm_handle, swparams) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params. : %s\n", snd_strerror(err));
        return -1;
    }

    if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
        fprintf(stderr, "Error snd_pcm_prepare : %s\n", snd_strerror(err));
        return -1;
    }

    // allocate the audio output buffer
    pOutputBuffer = new int16_t[Channels * FragmentSize];
    
    this->bInitialized = true;

    return 0;
}

/**
 *  Checks if sound card supports the chosen parameters.
 *
 *  @returns  true if hardware supports it
 */
bool AlsaIO::HardwareParametersSupported(uint channels, int samplerate, uint numfragments, uint fragmentsize) {
    pcm_name = "hw:0,0";
    if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0) < 0) return false;
    snd_pcm_hw_params_alloca(&hwparams);
    if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    #if WORDS_BIGENDIAN
    if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE) < 0) {
    #else // little endian
    if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
    #endif
        snd_pcm_close(pcm_handle);
        return false;
    }
    int dir = 0;
    if (snd_pcm_hw_params_test_rate(pcm_handle, hwparams, samplerate, dir) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_channels(pcm_handle, hwparams, channels) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_periods(pcm_handle, hwparams, numfragments, dir) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments)) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }

    snd_pcm_close(pcm_handle);
    return true;
}

void AlsaIO::Activate() {
    this->StartThread();
}

int AlsaIO::Main() {
    if (!pEngine) {
        fprintf(stderr, "AlsaIO: No Sampler Engine assigned, exiting.\n");
        exit(EXIT_FAILURE);
    }
    if (!bInitialized) {
        fprintf(stderr, "AlsaIO: Not yet intitialized, exiting.\n");
        exit(EXIT_FAILURE);
    }

    while (true) {

        // let the engine render audio for the current audio fragment
        pEngine->RenderAudio(uiMaxSamplesPerCycle);


        // check clipping in the audio sum, convert to sample_type
        // (from 32bit to 16bit sample) and copy to output buffer
        float sample_point; uint o = 0;
        for (uint s = 0; s < uiMaxSamplesPerCycle; s++) {
            for (uint c = 0; c < uiChannels; c++) {
                sample_point = pEngine->GetAudioSumBuffer(c)[s] * pEngine->Volume;
                if (sample_point < -32768.0) sample_point = -32768.0;
                if (sample_point >  32767.0) sample_point =  32767.0;
                this->pOutputBuffer[o++] = (int32_t) sample_point;
            }
        }


        // output sound
        int res = Output();
        if (res < 0) {
            fprintf(stderr, "AlsaIO: Audio output error, exiting.\n");
            exit(EXIT_FAILURE);
        }
    }
}

/**
 *  Will be called after every audio fragment cycle, to output the audio data
 *  of the current fragment to the soundcard.
 *
 *  @returns  0 on success
 */
int AlsaIO::Output() {
    int err = snd_pcm_writei(pcm_handle, pOutputBuffer, uiMaxSamplesPerCycle);
    if (err < 0) {
        fprintf(stderr, "Error snd_pcm_writei failed. : %s\n", snd_strerror(err));
        return -1;
    }
    return 0;
}

void AlsaIO::Close() {
    if (bInitialized) {
        //dmsg(0,("Stopping Alsa Thread..."));
        //StopThread();  //FIXME: commented out due to a bug in thread.cpp (StopThread() doesn't return at all)
        //dmsg(0,("OK\n"));
        if (pcm_handle) {
            //FIXME: currently commented out due to segfault
            //snd_pcm_close(pcm_handle);
            pcm_handle = NULL;
        }
        if (pOutputBuffer) {
            //FIXME: currently commented out due to segfault
            //delete[] pOutputBuffer;
            pOutputBuffer = NULL;
        }
        bInitialized = false;
    }
}

void* AlsaIO::GetInterleavedOutputBuffer() {
    return pOutputBuffer;
}

void* AlsaIO::GetChannelOutputBufer(uint Channel) {
    fprintf(stderr, "AlsaIO::GetChannelOutputBufer(): Only interleaved access allowed so far, exiting.\n");
    exit(EXIT_FAILURE);
    // just to avoid compiler warnings
    return NULL;
}
コード例 #10
0
void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list)
{
  /* ensure that ALSA has been initialized */
  if(!snd_config)
    snd_config_update();

  snd_ctl_t *ctlhandle;
  snd_pcm_t *pcmhandle;

  snd_ctl_card_info_t *ctlinfo;
  snd_ctl_card_info_alloca(&ctlinfo);
  memset(ctlinfo, 0, snd_ctl_card_info_sizeof());

  snd_pcm_hw_params_t *hwparams;
  snd_pcm_hw_params_alloca(&hwparams);
  memset(hwparams, 0, snd_pcm_hw_params_sizeof());

  snd_pcm_info_t *pcminfo;
  snd_pcm_info_alloca(&pcminfo);
  memset(pcminfo, 0, snd_pcm_info_sizeof());

  /* get the sound config */
  snd_config_t *config;
  snd_config_copy(&config, snd_config);

  std::string strHwName;
  int n_cards = -1;
  while (snd_card_next(&n_cards) == 0 && n_cards != -1)
  {
    std::stringstream sstr;
    sstr << "hw:" << n_cards;
    std::string strHwName = sstr.str();

    if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) != 0)
    {
      CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to open control for device %s", strHwName.c_str());
      continue;
    }

    if (snd_ctl_card_info(ctlhandle, ctlinfo) != 0)
    {
      CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to get card control info for device %s", strHwName.c_str());
      snd_ctl_close(ctlhandle);
      continue;
    }

    snd_hctl_t *hctl;
    if (snd_hctl_open_ctl(&hctl, ctlhandle) != 0)
      hctl = NULL;
    snd_hctl_load(hctl);

    int pcm_index    = 0;
    int iec958_index = 0;
    int hdmi_index   = 0;

    int dev = -1;
    while (snd_ctl_pcm_next_device(ctlhandle, &dev) == 0 && dev != -1)
    {
      snd_pcm_info_set_device   (pcminfo, dev);
      snd_pcm_info_set_subdevice(pcminfo, 0  );
      snd_pcm_info_set_stream   (pcminfo, SND_PCM_STREAM_PLAYBACK);

      if (snd_ctl_pcm_info(ctlhandle, pcminfo) < 0)
      {
        CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Skipping device %s,%d as it does not have PCM playback ability", strHwName.c_str(), dev);
        continue;
      }

      int dev_index;
      sstr.str(std::string());
      CAEDeviceInfo info;
      std::string devname = snd_pcm_info_get_name(pcminfo);

      bool maybeHDMI = false;

      /* detect HDMI */
      if (devname.find("HDMI") != std::string::npos)
      { 
        info.m_deviceType = AE_DEVTYPE_HDMI;
        dev_index = hdmi_index++;
        sstr << "hdmi";
      }
      else
      {
        /* detect IEC958 */

        /* some HDMI devices (intel) report Digital for HDMI also */
        if (devname.find("Digital") != std::string::npos)
          maybeHDMI = true;

        if (maybeHDMI || devname.find("IEC958" ) != std::string::npos)
        {
          info.m_deviceType = AE_DEVTYPE_IEC958;
          dev_index = iec958_index; /* dont increment, it might be HDMI */
          sstr << "iec958";
        }
        else
        {
          info.m_deviceType = AE_DEVTYPE_PCM;
          dev_index = pcm_index++;
          sstr << "hw";
        }
      }

      /* build the driver string to pass to ALSA */
      sstr << ":CARD=" << snd_ctl_card_info_get_id(ctlinfo) << ",DEV=" << dev_index;
      info.m_deviceName = sstr.str();

      /* get the friendly display name*/
      info.m_displayName      = snd_ctl_card_info_get_name(ctlinfo);
      info.m_displayNameExtra = devname;

      /* open the device for testing */
      int err = snd_pcm_open_lconf(&pcmhandle, info.m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0, config);

      /* if open of possible IEC958 failed and it could be HDMI, try as HDMI */
      if (err < 0 && maybeHDMI)
      {
        /* check for HDMI if it failed */
        sstr.str(std::string());
        dev_index = hdmi_index;

        sstr << "hdmi";
        sstr << ":CARD=" << snd_ctl_card_info_get_id(ctlinfo) << ",DEV=" << dev_index;
        info.m_deviceName = sstr.str();
        err = snd_pcm_open_lconf(&pcmhandle, info.m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0, config);

        /* if it was valid, increment the index and set the type */
        if (err >= 0)
        {
          ++hdmi_index;
          info.m_deviceType = AE_DEVTYPE_HDMI;
        }
      }

      /* if it's still IEC958, increment the index */
      if (info.m_deviceType == AE_DEVTYPE_IEC958)
        ++iec958_index;

      /* final error check */
      if (err < 0)
      {
        CLog::Log(LOGINFO, "CAESinkALSA::EnumerateDevicesEx - Unable to open %s for capability detection", strHwName.c_str());
        continue;
      }

      /* see if we can get ELD for this device */
      if (info.m_deviceType == AE_DEVTYPE_HDMI)
      {
        bool badHDMI = false;
        if (hctl && !GetELD(hctl, dev, info, badHDMI))
          CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to obtain ELD information for device %s, make sure you have ALSA >= 1.0.25", info.m_deviceName.c_str());

        if (badHDMI)
        {
          CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Skipping HDMI device %s as it has no ELD data", info.m_deviceName.c_str());
          continue;
        }
      }

      /* ensure we can get a playback configuration for the device */
      if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0)
      {
        CLog::Log(LOGINFO, "CAESinkALSA::EnumerateDevicesEx - No playback configurations available for device %s", info.m_deviceName.c_str());
        snd_pcm_close(pcmhandle);
        continue;
      }

      /* detect the available sample rates */
      for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate)
        if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0)
          info.m_sampleRates.push_back(*rate);

      /* detect the channels available */
      int channels = 0;
      for (int i = 1; i <= ALSA_MAX_CHANNELS; ++i)
        if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0)
          channels = i;

      CAEChannelInfo alsaChannels;
      for (int i = 0; i < channels; ++i)
      {
        if (!info.m_channels.HasChannel(ALSAChannelMap[i]))
          info.m_channels += ALSAChannelMap[i];
        alsaChannels += ALSAChannelMap[i];
      }

      /* remove the channels from m_channels that we cant use */
      info.m_channels.ResolveChannels(alsaChannels);

      /* detect the PCM sample formats that are available */
      for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
      {
        if (AE_IS_RAW(i) || i == AE_FMT_MAX)
          continue;
        snd_pcm_format_t fmt = AEFormatToALSAFormat(i);
        if (fmt == SND_PCM_FORMAT_UNKNOWN)
          continue;

        if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0)
          info.m_dataFormats.push_back(i);
      }

      snd_pcm_close(pcmhandle);
      list.push_back(info);
    }

    /* snd_hctl_close also closes ctlhandle */
    if (hctl)
      snd_hctl_close(hctl);
    else
      snd_ctl_close(ctlhandle);
  }
}
コード例 #11
0
ファイル: alsa.c プロジェクト: FLYKingdom/vlc
/*****************************************************************************
 * Probe: probe the audio device for available formats and channels
 *****************************************************************************/
static void Probe( aout_instance_t * p_aout,
                   const char * psz_device, const char * psz_iec_device,
                   int *pi_snd_pcm_format )
{
    struct aout_sys_t * p_sys = p_aout->output.p_sys;
    vlc_value_t val, text;
    int i_ret;

    var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
    text.psz_string = _("Audio Device");
    var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );

    /* We'll open the audio device in non blocking mode so we can just exit
     * when it is already in use, but for the real stuff we'll still use
     * the blocking mode */

    /* Now test linear PCM capabilities */
    if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
                                 SND_PCM_STREAM_PLAYBACK,
                                 SND_PCM_NONBLOCK ) ) )
    {
        int i_channels;
        snd_pcm_hw_params_t * p_hw;
        snd_pcm_hw_params_alloca (&p_hw);

        if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
        {
            msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
                              ", disabling linear PCM audio" );
            snd_pcm_close( p_sys->p_snd_pcm );
            var_Destroy( p_aout, "audio-device" );
            return;
        }

        if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
                                           *pi_snd_pcm_format ) < 0 )
        {
            int i_snd_rc = -1;

            if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
            {
                *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
                i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
                                                    p_hw, *pi_snd_pcm_format );
            }
            if ( i_snd_rc < 0 )
            {
                msg_Warn( p_aout, "unable to set stream sample size and "
                          "word order, disabling linear PCM audio" );
                snd_pcm_close( p_sys->p_snd_pcm );
                var_Destroy( p_aout, "audio-device" );
                return;
            }
        }

        i_channels = aout_FormatNbChannels( &p_aout->output.output );

        while ( i_channels > 0 )
        {
            if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
                                                   i_channels ) )
            {
                switch ( i_channels )
                {
                case 1:
                    val.i_int = AOUT_VAR_MONO;
                    text.psz_string = _("Mono");
                    var_Change( p_aout, "audio-device",
                                VLC_VAR_ADDCHOICE, &val, &text );
                    break;
                case 2:
                    val.i_int = AOUT_VAR_STEREO;
                    text.psz_string = _("Stereo");
                    var_Change( p_aout, "audio-device",
                                VLC_VAR_ADDCHOICE, &val, &text );
                    var_Set( p_aout, "audio-device", val );
                    break;
                case 4:
                    val.i_int = AOUT_VAR_2F2R;
                    text.psz_string = _("2 Front 2 Rear");
                    var_Change( p_aout, "audio-device",
                                VLC_VAR_ADDCHOICE, &val, &text );
                    break;
                case 6:
                    val.i_int = AOUT_VAR_5_1;
                    text.psz_string = "5.1";
                    var_Change( p_aout, "audio-device",
                                VLC_VAR_ADDCHOICE, &val, &text );
                    break;
                }
            }

            --i_channels;
        }

        /* Special case for mono on stereo only boards */
        i_channels = aout_FormatNbChannels( &p_aout->output.output );
        var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
        if( val.i_int <= 0 && i_channels == 1 )
        {
            if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
            {
                val.i_int = AOUT_VAR_STEREO;
                text.psz_string = (char*)N_("Stereo");
                var_Change( p_aout, "audio-device",
                            VLC_VAR_ADDCHOICE, &val, &text );
                var_Set( p_aout, "audio-device", val );
            }
        }

        /* Close the previously opened device */
        snd_pcm_close( p_sys->p_snd_pcm );
    }
    else if ( i_ret == -EBUSY )
    {
        msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
    }

    /* Test for S/PDIF device if needed */
    if ( psz_iec_device )
    {
        /* Opening the device should be enough */
        if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
                                     SND_PCM_STREAM_PLAYBACK,
                                     SND_PCM_NONBLOCK ) ) )
        {
            val.i_int = AOUT_VAR_SPDIF;
            text.psz_string = (char*)N_("A/52 over S/PDIF");
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
            if( config_GetInt( p_aout, "spdif" ) )
                var_Set( p_aout, "audio-device", val );

            snd_pcm_close( p_sys->p_snd_pcm );
        }
        else if ( i_ret == -EBUSY )
        {
            msg_Warn( p_aout, "audio device: %s is already in use",
                      psz_iec_device );
        }
    }

    var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
    if( val.i_int <= 0 )
    {
        /* Probe() has failed. */
        msg_Dbg( p_aout, "failed to find a usable alsa configuration" );
        var_Destroy( p_aout, "audio-device" );
        return;
    }

    /* Add final settings to the variable */
    var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
    var_SetBool( p_aout, "intf-change", true );
}