// Initialize the BlockSound class BlockSound::BlockSound() { sample_size = 0; #ifdef __APPLE__ remaining = 0; UInt32 size = sizeof(device); if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, (void *)&device) != noErr) return; size = sizeof(format); if (AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat, &size, &format) != noErr) return; // Set up a format we like... format.mSampleRate = 44100.0; // 44.1kHz format.mChannelsPerFrame = 2; // stereo if (AudioDeviceSetProperty(device, NULL, 0, false, kAudioDevicePropertyStreamFormat, sizeof(format), &format) != noErr) return; // Check we got linear pcm - what to do if we did not ??? if (format.mFormatID != kAudioFormatLinearPCM) return; // Attach the callback and start the device # if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 if (AudioDeviceCreateIOProcID(device, audio_cb, (void *)this, &audio_proc_id) != noErr) return; AudioDeviceStart(device, audio_proc_id); # else if (AudioDeviceAddIOProc(device, audio_cb, (void *)this) != noErr) return; AudioDeviceStart(device, audio_cb); # endif sample_size = (int)format.mSampleRate; #elif defined(WIN32) WAVEFORMATEX format; memset(&format, 0, sizeof(format)); format.cbSize = sizeof(format); format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = 2; format.nSamplesPerSec = 44100; format.nAvgBytesPerSec = 44100 * 4; format.nBlockAlign = 4; format.wBitsPerSample = 16; data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, format.nSamplesPerSec * 4); if (!data_handle) return; data_ptr = (LPSTR)GlobalLock(data_handle); header_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR)); if (!header_handle) return; header_ptr = (WAVEHDR *)GlobalLock(header_handle); header_ptr->lpData = data_ptr; header_ptr->dwFlags = 0; header_ptr->dwLoops = 0; if (waveOutOpen(&device, WAVE_MAPPER, &format, 0, 0, WAVE_ALLOWSYNC) != MMSYSERR_NOERROR) return; sample_size = format.nSamplesPerSec; #else # ifdef HAVE_ALSA_ASOUNDLIB_H handle = NULL; if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) >= 0) { // Initialize PCM sound stuff... snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); snd_pcm_hw_params_any(handle, params); snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16); snd_pcm_hw_params_set_channels(handle, params, 2); unsigned rate = 44100; int dir; snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir); snd_pcm_uframes_t period = (int)rate; snd_pcm_hw_params_set_period_size_near(handle, params, &period, &dir); sample_size = rate; if (snd_pcm_hw_params(handle, params) < 0) { sample_size = 0; snd_pcm_close(handle); handle = NULL; } } # endif // HAVE_ALSA_ASOUNDLIB_H #endif // __APPLE__ if (sample_size) { // Make an explosion sound by passing white noise through a low pass // filter with a decreasing frequency... sample_data = new short[2 * sample_size]; short *sample_ptr = sample_data; int max_sample = 2 * sample_size - 2; *sample_ptr++ = 0; *sample_ptr++ = 0; for (int j = max_sample; j > 0; j --, sample_ptr ++) { float freq = (float)j / (float)max_sample; float volume = 32767.0 * (0.5 * sqrt(freq) + 0.5); float sample = 0.0001 * ((rand() % 20001) - 10000); *sample_ptr = (int)(volume * freq * sample + (1.0 - freq) * sample_ptr[-2]); } } }
int Aisound::Open_Pcm() { BEGINFUNC_USING_BY_VOICE int err; int dir; int size; char *buffer; unsigned int val; snd_pcm_uframes_t frames; snd_pcm_hw_params_t* params; int channels = 0; if ( (err = snd_pcm_open(&handle, "plug:cmd", SND_PCM_STREAM_PLAYBACK, 0)) < 0) { dbug_out("cannot open audio device (%s)\n", snd_strerror (err)); goto OpenPcmFail; } dbug_out("After snd_pcm_open for SND_PCM_STREAM_PLAYBACK"); snd_pcm_hw_params_alloca(¶ms);//为å�‚æ•°å�˜é‡�分é…�空间 if( (err = snd_pcm_hw_params_any(handle, params)) < 0)//å�‚æ•°åˆ�始化 { dbug_out("snd_pcm_hw_params_any failed! err = %d\n", err); goto OpenPcmFail; } if( (err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)//设置为交错模å¼� { dbug_out("snd_pcm_hw_params_set_access failed! err = %d\n", err); goto OpenPcmFail; } if( (err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE)) < 0)//使用16ä½�æ ·æœ¬ { dbug_out("snd_pcm_hw_params_set_format failed! err = %d\n", err); goto OpenPcmFail; } channels = val = 1; if( (err = snd_pcm_hw_params_set_channels(handle, params, val)) < 0)//设置为立体声 { dbug_out("snd_pcm_hw_params_set_channels failed! err = %d\n", err); goto OpenPcmFail; } val = 16000; if( (err = snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir)) < 0)//è®¾ç½®é‡‡æ ·çŽ‡ä¸º44.1KHz { dbug_out("snd_pcm_hw_params_set_rate_near failed! err = %d\n", err); goto OpenPcmFail; } #if 1 frames = 32; if( (err = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir)) < 0) { dbug_out("snd_pcm_hw_params_set_period_size_near failed! err = %d\n", err); goto OpenPcmFail; } if ( (err = snd_pcm_hw_params(handle, params)) < 0) { dbug_out("snd_pcm_hw_params-failed! err = %d err: %s\n", err, snd_strerror(err)); goto OpenPcmFail; } if( (err = snd_pcm_hw_params_get_period_size(params, &frames, &dir)) < 0) { dbug_out("snd_pcm_hw_params_get_period_size failed! err = %d\n", err); goto OpenPcmFail; } size = frames * channels * 2; buffer = (char *)malloc(sizeof(char) * size); if( (err = snd_pcm_hw_params_get_period_time(params, &val, &dir)) < 0) { dbug_out("snd_pcm_hw_params_get_period_time failed! err = %d\n", err); goto OpenPcmFail; } return 0; OpenPcmFail: return -1; #endif ENDFUNC_USING_BY_VOICE }
bool CAESinkALSA::InitializeHW(AEAudioFormat &format) { snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_alloca(&hw_params); memset(hw_params, 0, snd_pcm_hw_params_sizeof()); snd_pcm_hw_params_any(m_pcm, hw_params); snd_pcm_hw_params_set_access(m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); unsigned int sampleRate = format.m_sampleRate; #if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC) // alsa/kernel lies, so map everything to 44100 or 48000 switch(sampleRate) { case 11025: case 22050: case 88200: case 176400: sampleRate = 44100; break; case 8000: case 16000: case 24000: case 32000: case 96000: case 192000: case 384000: sampleRate = 48000; break; } #endif unsigned int channelCount = format.m_channelLayout.Count(); snd_pcm_hw_params_set_rate_near (m_pcm, hw_params, &sampleRate, NULL); snd_pcm_hw_params_set_channels_near(m_pcm, hw_params, &channelCount); /* ensure we opened X channels or more */ if (format.m_channelLayout.Count() > channelCount) { CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Unable to open the required number of channels"); } /* update the channelLayout to what we managed to open */ format.m_channelLayout.Reset(); for (unsigned int i = 0; i < channelCount; ++i) format.m_channelLayout += ALSAChannelMap[i]; snd_pcm_format_t fmt = AEFormatToALSAFormat(format.m_dataFormat); if (fmt == SND_PCM_FORMAT_UNKNOWN) { /* if we dont support the requested format, fallback to float */ format.m_dataFormat = AE_FMT_FLOAT; fmt = SND_PCM_FORMAT_FLOAT; } /* try the data format */ if (snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0) { /* if the chosen format is not supported, try each one in decending order */ CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(format.m_dataFormat)); 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; if (m_passthrough && i != AE_FMT_S16BE && i != AE_FMT_S16LE) continue; fmt = AEFormatToALSAFormat(i); if (fmt == SND_PCM_FORMAT_UNKNOWN || snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0) { fmt = SND_PCM_FORMAT_UNKNOWN; continue; } int fmtBits = CAEUtil::DataFormatToBits(i); int bits = snd_pcm_hw_params_get_sbits(hw_params); if (bits != fmtBits) { /* if we opened in 32bit and only have 24bits, pack into 24 */ if (fmtBits == 32 && bits == 24) i = AE_FMT_S24NE4; else continue; } /* record that the format fell back to X */ format.m_dataFormat = i; CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Using data format %s", CAEUtil::DataFormatToStr(format.m_dataFormat)); break; } /* if we failed to find a valid output format */ if (fmt == SND_PCM_FORMAT_UNKNOWN) { CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Unable to find a suitable output format"); return false; } } snd_pcm_uframes_t periodSize, bufferSize; snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize); snd_pcm_hw_params_get_period_size_max(hw_params, &periodSize, NULL); /* We want to make sure, that we have max 200 ms Buffer with a periodSize of approx 50 ms. Choosing a higher bufferSize will cause problems with menu sounds. Buffer will be increased after those are fixed. */ periodSize = std::min(periodSize, (snd_pcm_uframes_t) sampleRate / 20); bufferSize = std::min(bufferSize, (snd_pcm_uframes_t) sampleRate / 5); #if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC) // must be pot for pivos. bufferSize = CheckNP2(bufferSize); #endif /* According to upstream we should set buffer size first - so make sure it is always at least 4x period size to not get underruns (some systems seem to have issues with only 2 periods) */ periodSize = std::min(periodSize, bufferSize / 4); #if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC) // must be pot for pivos. periodSize = CheckNP2(periodSize); #endif CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, bufferSize %lu", periodSize, bufferSize); snd_pcm_hw_params_t *hw_params_copy; snd_pcm_hw_params_alloca(&hw_params_copy); snd_pcm_hw_params_copy(hw_params_copy, hw_params); // copy what we have and is already working // first trying bufferSize, PeriodSize // for more info see here: // http://mailman.alsa-project.org/pipermail/alsa-devel/2009-September/021069.html // the last three tries are done as within pulseaudio // backup periodSize and bufferSize first. Restore them after every failed try snd_pcm_uframes_t periodSizeTemp, bufferSizeTemp; periodSizeTemp = periodSize; bufferSizeTemp = bufferSize; if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0 || snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { bufferSize = bufferSizeTemp; periodSize = periodSizeTemp; // retry with PeriodSize, bufferSize snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy if (snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0 || snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { // try only periodSize periodSize = periodSizeTemp; snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy if(snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { // try only BufferSize bufferSize = bufferSizeTemp; snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restory working copy if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { // set default that Alsa would choose CLog::Log(LOGWARNING, "CAESinkAlsa::IntializeHW - Using default alsa values - set failed"); if (snd_pcm_hw_params(m_pcm, hw_params) != 0) { CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Could not init a valid sink"); return false; } } } // reread values when alsa default was kept snd_pcm_get_params(m_pcm, &bufferSize, &periodSize); } } CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, bufferSize %lu", periodSize, bufferSize); /* set the format parameters */ format.m_sampleRate = sampleRate; format.m_frames = periodSize; format.m_frameSamples = periodSize * format.m_channelLayout.Count(); format.m_frameSize = snd_pcm_frames_to_bytes(m_pcm, 1); m_bufferSize = (unsigned int)bufferSize; m_timeout = std::ceil((double)(bufferSize * 1000) / (double)sampleRate); CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Setting timeout to %d ms", m_timeout); return true; }
int main() { int rc; snd_pcm_t* handle; snd_pcm_hw_params_t* params; unsigned int val; unsigned int val2; int dir; snd_pcm_uframes_t frames; if ( (rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) { std::cerr << "unable to open pcm devices: " << snd_strerror(rc) << std::endl; exit(1); } snd_pcm_hw_params_alloca(¶ms); snd_pcm_hw_params_any(handle, params); snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(handle, params, 2); val = 44100; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); if ( (rc = snd_pcm_hw_params(handle, params)) < 0) { std::cerr << "unable to set hw parameters: " << snd_strerror(rc) << std::endl; exit(1); } std::cout << "PCM handle name = " << snd_pcm_name(handle) << std::endl; std::cout << "PCM state = " << snd_pcm_state_name(snd_pcm_state(handle)) << std::endl; snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *)&val); std::cout << "access type = " << snd_pcm_access_name((snd_pcm_access_t)val) << std::endl; snd_pcm_hw_params_get_format(params, (snd_pcm_format_t*)(&val)); std::cout << "format = '" << snd_pcm_format_name((snd_pcm_format_t)val) << "' (" << snd_pcm_format_description((snd_pcm_format_t)val) << ")" << std::endl; snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *)&val); std::cout << "subformat = '" << snd_pcm_subformat_name((snd_pcm_subformat_t)val) << "' (" << snd_pcm_subformat_description((snd_pcm_subformat_t)val) << ")" << std::endl; snd_pcm_hw_params_get_channels(params, &val); std::cout << "channels = " << val << std::endl; snd_pcm_hw_params_get_rate(params, &val, &dir); std::cout << "rate = " << val << " bps" << std::endl; snd_pcm_hw_params_get_period_time(params, &val, &dir); std::cout << "period time = " << val << " us" << std::endl; snd_pcm_hw_params_get_period_size(params, &frames, &dir); std::cout << "period size = " << static_cast<int>(frames) << " frames" << std::endl; snd_pcm_hw_params_get_buffer_time(params, &val, &dir); std::cout << "buffer time = " << val << " us" << std::endl; snd_pcm_hw_params_get_buffer_size(params, (snd_pcm_uframes_t *) &val); std::cout << "buffer size = " << val << " frames" << std::endl; snd_pcm_hw_params_get_periods(params, &val, &dir); std::cout << "periods per buffer = " << val << " frames" << std::endl; snd_pcm_hw_params_get_rate_numden(params, &val, &val2); std::cout << "exact rate = " << val/val2 << " bps" << std::endl; val = snd_pcm_hw_params_get_sbits(params); std::cout << "significant bits = " << val << std::endl; snd_pcm_hw_params_get_tick_time(params, &val, &dir); std::cout << "tick time = " << val << " us" << std::endl; val = snd_pcm_hw_params_is_batch(params); std::cout << "is batch = " << val << std::endl; val = snd_pcm_hw_params_is_block_transfer(params); std::cout << "is block transfer = " << val << std::endl; val = snd_pcm_hw_params_is_double(params); std::cout << "is double = " << val << std::endl; val = snd_pcm_hw_params_is_half_duplex(params); std::cout << "is half duplex = " << val << std::endl; val = snd_pcm_hw_params_is_joint_duplex(params); std::cout << "is joint duplex = " << val << std::endl; val = snd_pcm_hw_params_can_overrange(params); std::cout << "can overrange = " << val << std::endl; val = snd_pcm_hw_params_can_mmap_sample_resolution(params); std::cout << "can mmap = " << val << std::endl; val = snd_pcm_hw_params_can_pause(params); std::cout << "can pause = " << val << std::endl; val = snd_pcm_hw_params_can_resume(params); std::cout << "can resume = " << val << std::endl; val = snd_pcm_hw_params_can_sync_start(params); std::cout << "can sync start = " << val << std::endl; snd_pcm_close(handle); return 0; }
bool ALSAWriter::processParams(bool *paramsCorrected) { const unsigned chn = getParam("chn").toUInt(); const unsigned rate = getParam("rate").toUInt(); const bool resetAudio = channels != chn || sample_rate != rate; channels = chn; sample_rate = rate; if (resetAudio || err) { snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); close(); QString chosenDevName = devName; if (autoFindMultichannelDevice && channels > 2) { bool mustAutoFind = true, forceStereo = false; if (!snd_pcm_open(&snd, chosenDevName.toLocal8Bit(), SND_PCM_STREAM_PLAYBACK, 0)) { if (snd_pcm_type(snd) == SND_PCM_TYPE_HW) { unsigned max_chn = 0; snd_pcm_hw_params_any(snd, params); mustAutoFind = snd_pcm_hw_params_get_channels_max(params, &max_chn) || max_chn < channels; } #ifdef HAVE_CHMAP else if (paramsCorrected) { snd_pcm_chmap_query_t **chmaps = snd_pcm_query_chmaps(snd); if (chmaps) snd_pcm_free_chmaps(chmaps); else forceStereo = true; } #endif snd_pcm_close(snd); snd = nullptr; } if (mustAutoFind) { QString newDevName; if (channels <= 4) newDevName = "surround40"; else if (channels <= 6) newDevName = "surround51"; else newDevName = "surround71"; if (!newDevName.isEmpty() && newDevName != chosenDevName) { if (ALSACommon::getDevices().first.contains(newDevName)) chosenDevName = newDevName; else if (forceStereo) { channels = 2; *paramsCorrected = true; } } } } if (!chosenDevName.isEmpty()) { bool sndOpen = !snd_pcm_open(&snd, chosenDevName.toLocal8Bit(), SND_PCM_STREAM_PLAYBACK, 0); if (devName != chosenDevName) { if (sndOpen) QMPlay2Core.logInfo("ALSA :: " + devName + "\" -> \"" + chosenDevName + "\""); else { sndOpen = !snd_pcm_open(&snd, devName.toLocal8Bit(), SND_PCM_STREAM_PLAYBACK, 0); QMPlay2Core.logInfo("ALSA :: " + tr("Cannot open") + " \"" + chosenDevName + "\", " + tr("back to") + " \"" + devName + "\""); } } if (sndOpen) { snd_pcm_hw_params_any(snd, params); snd_pcm_format_t fmt = SND_PCM_FORMAT_UNKNOWN; if (!snd_pcm_hw_params_test_format(snd, params, SND_PCM_FORMAT_S32)) { fmt = SND_PCM_FORMAT_S32; sample_size = 4; } else if (!snd_pcm_hw_params_test_format(snd, params, SND_PCM_FORMAT_S16)) { fmt = SND_PCM_FORMAT_S16; sample_size = 2; } else if (!snd_pcm_hw_params_test_format(snd, params, SND_PCM_FORMAT_S8)) { fmt = SND_PCM_FORMAT_S8; sample_size = 1; } unsigned delay_us = round(delay * 1000000.0); if (fmt != SND_PCM_FORMAT_UNKNOWN && set_snd_pcm_hw_params(snd, params, fmt, channels, sample_rate, delay_us)) { bool err2 = false; if (channels != chn || sample_rate != rate) { if (paramsCorrected) *paramsCorrected = true; else err2 = true; } if (!err2) { err2 = snd_pcm_hw_params(snd, params); if (err2 && paramsCorrected) //jakiś błąd, próba zmiany sample_rate { snd_pcm_hw_params_any(snd, params); err2 = snd_pcm_hw_params_set_rate_resample(snd, params, false) || !set_snd_pcm_hw_params(snd, params, fmt, channels, sample_rate, delay_us) || snd_pcm_hw_params(snd, params); if (!err2) *paramsCorrected = true; } if (!err2) { modParam("delay", delay_us / 1000000.0); if (paramsCorrected && *paramsCorrected) { modParam("chn", channels); modParam("rate", sample_rate); } canPause = snd_pcm_hw_params_can_pause(params) && snd_pcm_hw_params_can_resume(params); mustSwapChn = channels == 6 || channels == 8; #ifdef HAVE_CHMAP if (mustSwapChn) { snd_pcm_chmap_query_t **chmaps = snd_pcm_query_chmaps(snd); if (chmaps) { for (int i = 0; chmaps[i]; ++i) { if (chmaps[i]->map.channels >= channels) { for (uint j = 0; j < channels; ++j) { mustSwapChn &= chmaps[i]->map.pos[j] == j + SND_CHMAP_FL; if (!mustSwapChn) break; } break; } } snd_pcm_free_chmaps(chmaps); } } #endif return true; } } } } } err = true; QMPlay2Core.logError("ALSA :: " + tr("Cannot open audio output stream")); } return readyWrite(); }
void play(int sec, int freq, char *file) { long loops; int rc; int size; snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val; int dir; snd_pcm_uframes_t frames; char *buffer; int fd; /* Check ranges */ if (sec < 1 || sec > 4000) { printf("WARNING: Incorrect time to play range [1,4000] s\n"); printf("\tSetting time to play to 5s...\n"); sec = 5; } if (freq < 1000 || freq > 100000) { printf("ERROR: Incorrect frequency range [1000,100000] Hz\n"); printf("\tSetting frequency to 44.1 kHz...\n"); freq = 44100; } /* Open file */ fd = open(file, O_RDONLY); if (fd < 0) { /* There was an error opening the file */ printf("ERROR: Couldn't open file to play\n"); printf("\tPlease make sure file exists\n"); } else { /* Print that the file is playing with its parameters */ printf("Playing file %s for %d seconds", file, sec); printf(" and frequency %d...\n", freq); /* Open PCM device for playback */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values */ snd_pcm_hw_params_any(handle, params); /* Set hardware parameters */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 2); /* freq bits/second sampling rate (CD quality) */ val = freq; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Set period size to 32 frames */ frames = 32; snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } /* Use a buffer large enough to hold one period */ snd_pcm_hw_params_get_period_size(params, &frames, &dir); size = frames * 4; /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(size); /* We want to loop for sec seconds */ snd_pcm_hw_params_get_period_time(params, &val, &dir); /* sec seconds in microseconds divided by period time */ loops = sec*1000000 / val; while (loops > 0) { loops--; rc = read(fd, buffer, size); if (rc == 0) { fprintf(stderr, "end of file on input\n"); break; } else if (rc != size) { fprintf(stderr, "short read: read %d bytes\n", rc); } rc = snd_pcm_writei(handle, buffer, frames); if (rc == -EPIPE) { /* EPIPE means underrun */ fprintf(stderr, "underrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from writei: %s\n", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short write, write %d frames\n", rc); } } /*Close handle and free buffer*/ snd_pcm_drain(handle); snd_pcm_close(handle); free(buffer); } }
Error AudioDriverALSA::init() { active=false; thread_exited=false; exit_thread=false; pcm_open = false; samples_in = NULL; samples_out = NULL; mix_rate = GLOBAL_DEF("audio/mix_rate",44100); output_format = OUTPUT_STEREO; channels = 2; int status; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; #define CHECK_FAIL(m_cond)\ if (m_cond) {\ fprintf(stderr,"ALSA ERR: %s\n",snd_strerror(status));\ snd_pcm_close(pcm_handle);\ ERR_FAIL_COND_V(m_cond,ERR_CANT_OPEN);\ } //todo, add //6 chans - "plug:surround51" //4 chans - "plug:surround40"; status = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); ERR_FAIL_COND_V( status<0, ERR_CANT_OPEN ); snd_pcm_hw_params_alloca(&hwparams); status = snd_pcm_hw_params_any(pcm_handle, hwparams); CHECK_FAIL( status<0 ); status = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); CHECK_FAIL( status<0 ); //not interested in anything else status = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE); CHECK_FAIL( status<0 ); //todo: support 4 and 6 status = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2); CHECK_FAIL( status<0 ); status = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &mix_rate, NULL); CHECK_FAIL( status<0 ); int latency = GLOBAL_DEF("audio/output_latency",25); buffer_size = nearest_power_of_2( latency * mix_rate / 1000 ); // set buffer size from project settings status = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size); CHECK_FAIL( status<0 ); // make period size 1/8 period_size = buffer_size >> 3; status = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size, NULL); CHECK_FAIL( status<0 ); unsigned int periods=2; status = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, NULL); CHECK_FAIL( status<0 ); status = snd_pcm_hw_params(pcm_handle,hwparams); CHECK_FAIL( status<0 ); //snd_pcm_hw_params_free(&hwparams); snd_pcm_sw_params_alloca(&swparams); status = snd_pcm_sw_params_current(pcm_handle, swparams); CHECK_FAIL( status<0 ); status = snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, period_size); CHECK_FAIL( status<0 ); status = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1); CHECK_FAIL( status<0 ); status = snd_pcm_sw_params(pcm_handle, swparams); CHECK_FAIL( status<0 ); samples_in = memnew_arr(int32_t, period_size*channels); samples_out = memnew_arr(int16_t, period_size*channels); snd_pcm_nonblock(pcm_handle, 0); mutex=Mutex::create(); thread = Thread::create(AudioDriverALSA::thread_func, this); return OK; };
static int init_audio_device(common_data_t *p_common_data) { int ret; int dir = 0; unsigned int val; snd_pcm_hw_params_t *p_params; snd_pcm_uframes_t buffer_size; unsigned int buffer_time; unsigned int period_time; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; size_t bits_per_sample; size_t bits_per_frame; ret = snd_pcm_open(&p_common_data->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, 0); if (ret < 0) { dbg_alsa("unable to open pcm device: %s\n", snd_strerror(ret)); return -1; } snd_pcm_hw_params_alloca(&p_params); snd_pcm_hw_params_any(p_common_data->handle, p_params); snd_pcm_hw_params_set_access(p_common_data->handle, p_params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(p_common_data->handle, p_params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(p_common_data->handle, p_params, 2); val = 44100; snd_pcm_hw_params_set_rate_near(p_common_data->handle, p_params, &val, &dir); snd_pcm_hw_params_get_buffer_time_max(p_params, &buffer_time, 0); // if (buffer_time > 500000) // buffer_time = 500000; // // period_time = buffer_time / 4; // // snd_pcm_hw_params_set_period_time_near(p_common_data->handle, p_params, &period_time, 0); // snd_pcm_hw_params_set_buffer_time_near(p_common_data->handle, p_params, &buffer_time, 0); p_common_data->period_size = 2048; snd_pcm_hw_params_set_period_size_near(p_common_data->handle, p_params, &p_common_data->period_size, &dir); ret = snd_pcm_hw_params(p_common_data->handle, p_params); if (ret < 0){ dbg_alsa("unable to set hw parameters: %s\n", snd_strerror(ret)); exit(1); } ret = snd_pcm_state(p_common_data->handle); dbg("state is %d\n", ret); snd_pcm_hw_params_get_period_size(p_params, &p_common_data->period_size, &dir); snd_pcm_hw_params_get_buffer_size(p_params, &buffer_size); if (p_common_data->period_size == buffer_size) { dbg_alsa("Can't use period size equal to buffer size (%lu == %lu)\n", p_common_data->period_size, buffer_size); } dbg("period size is : %lu frames\n", p_common_data->period_size); dbg("buffer size is : %lu frames\n", buffer_size); bits_per_sample = snd_pcm_format_physical_width(format); bits_per_frame = bits_per_sample * 2; p_common_data->chunk_bytes = p_common_data->period_size * bits_per_frame / 8; //g_buf = (msg_t *)malloc(sizeof(msg_t)+(char)p_common_data->chunk_bytes); dbg("sample rate is %d\n", val); dbg("bits_per_sample %d\n", bits_per_sample); dbg("bits_per_frame %d\n", bits_per_frame); dbg("chunk_bytes %d\n", p_common_data->chunk_bytes); dbg("PCM handle name = '%s'\n",snd_pcm_name(p_common_data->handle)); return 0; }
bool QAudioInputPrivate::open() { #ifdef DEBUG_AUDIO QTime now(QTime::currentTime()); qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; #endif clockStamp.restart(); timeStamp.restart(); elapsedTimeOffset = 0; int dir; int err = 0; int count=0; unsigned int freakuency=settings.frequency(); if (!settings.isValid()) { qWarning("QAudioOutput: open error, invalid format."); } else if (settings.frequency() <= 0) { qWarning("QAudioOutput: open error, invalid sample rate (%d).", settings.frequency()); } else { err = -1; } if (err == 0) { errorState = QAudio::OpenError; deviceState = QAudio::StoppedState; return false; } QString dev = QString(QLatin1String(m_device.constData())); QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioInput); if(dev.compare(QLatin1String("default")) == 0) { #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) dev = QLatin1String(devices.first()); #else dev = QLatin1String("hw:0,0"); #endif } else { #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) dev = QLatin1String(m_device); #else int idx = 0; char *name; QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData()); while(snd_card_get_name(idx,&name) == 0) { if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0) break; idx++; } dev = QString(QLatin1String("hw:%1,0")).arg(idx); #endif } // Step 1: try and open the device while((count < 5) && (err < 0)) { err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); if(err < 0) count++; } if (( err < 0)||(handle == 0)) { errorState = QAudio::OpenError; deviceState = QAudio::StoppedState; emit stateChanged(deviceState); return false; } snd_pcm_nonblock( handle, 0 ); // Step 2: Set the desired HW parameters. snd_pcm_hw_params_alloca( &hwparams ); bool fatal = false; QString errMessage; unsigned int chunks = 8; err = snd_pcm_hw_params_any( handle, hwparams ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_any: err = %1").arg(err); } if ( !fatal ) { err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_access( handle, hwparams, access ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_access: err = %1").arg(err); } } if ( !fatal ) { err = setFormat(); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_format: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_channels: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params(handle, hwparams); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params: err = %1").arg(err); } } if( err < 0) { qWarning()<<errMessage; errorState = QAudio::OpenError; deviceState = QAudio::StoppedState; emit stateChanged(deviceState); return false; } snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames); buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames); snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir); period_size = snd_pcm_frames_to_bytes(handle,period_frames); snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir); snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir); // Step 3: Set the desired SW parameters. snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_alloca(&swparams); snd_pcm_sw_params_current(handle, swparams); snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames); snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames); snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames); snd_pcm_sw_params(handle, swparams); // Step 4: Prepare audio if(audioBuffer == 0) audioBuffer = new char[buffer_size]; snd_pcm_prepare( handle ); snd_pcm_start(handle); // Step 5: Setup timer bytesAvailable = checkBytesReady(); if(pullMode) connect(audioSource,SIGNAL(readyRead()),this,SLOT(userFeed())); // Step 6: Start audio processing chunks = buffer_size/period_size; timer->start(period_time*chunks/2000); errorState = QAudio::NoError; totalTimeValue = 0; return true; }
bool CAESinkALSA::InitializeHW(AEAudioFormat &format) { snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_alloca(&hw_params); memset(hw_params, 0, snd_pcm_hw_params_sizeof()); snd_pcm_hw_params_any(m_pcm, hw_params); snd_pcm_hw_params_set_access(m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); unsigned int sampleRate = format.m_sampleRate; unsigned int channelCount = format.m_channelLayout.Count(); snd_pcm_hw_params_set_rate_near (m_pcm, hw_params, &sampleRate, NULL); snd_pcm_hw_params_set_channels_near(m_pcm, hw_params, &channelCount); /* ensure we opened X channels or more */ if (format.m_channelLayout.Count() > channelCount) { CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Unable to open the required number of channels"); } /* update the channelLayout to what we managed to open */ format.m_channelLayout.Reset(); for (unsigned int i = 0; i < channelCount; ++i) format.m_channelLayout += ALSAChannelMap[i]; snd_pcm_format_t fmt = AEFormatToALSAFormat(format.m_dataFormat); if (fmt == SND_PCM_FORMAT_UNKNOWN) { /* if we dont support the requested format, fallback to float */ format.m_dataFormat = AE_FMT_FLOAT; fmt = SND_PCM_FORMAT_FLOAT; } /* try the data format */ if (snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0) { /* if the chosen format is not supported, try each one in decending order */ CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(format.m_dataFormat)); 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; if (m_passthrough && i != AE_FMT_S16BE && i != AE_FMT_S16LE) continue; fmt = AEFormatToALSAFormat(i); if (fmt == SND_PCM_FORMAT_UNKNOWN || snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0) { fmt = SND_PCM_FORMAT_UNKNOWN; continue; } int fmtBits = CAEUtil::DataFormatToBits(i); int bits = snd_pcm_hw_params_get_sbits(hw_params); if (bits != fmtBits) { /* if we opened in 32bit and only have 24bits, pack into 24 */ if (fmtBits == 32 && bits == 24) i = AE_FMT_S24NE4; else continue; } /* record that the format fell back to X */ format.m_dataFormat = i; CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Using data format %s", CAEUtil::DataFormatToStr(format.m_dataFormat)); break; } /* if we failed to find a valid output format */ if (fmt == SND_PCM_FORMAT_UNKNOWN) { CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Unable to find a suitable output format"); return false; } } unsigned int periods; snd_pcm_uframes_t periodSize, bufferSize; snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize); bufferSize = std::min(bufferSize, (snd_pcm_uframes_t)8192); periodSize = bufferSize / ALSA_PERIODS; periods = ALSA_PERIODS; CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize); /* work on a copy of the hw params */ snd_pcm_hw_params_t *hw_params_copy; snd_pcm_hw_params_alloca(&hw_params_copy); /* try to set the buffer size then the period size */ snd_pcm_hw_params_copy(hw_params_copy, hw_params); snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize); snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL); snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL); if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { /* try to set the period size then the buffer size */ snd_pcm_hw_params_copy(hw_params_copy, hw_params); snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL); snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize); snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL); if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { /* try to just set the buffer size */ snd_pcm_hw_params_copy(hw_params_copy, hw_params); snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize); snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL); if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { /* try to just set the period size */ snd_pcm_hw_params_copy(hw_params_copy, hw_params); snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL); snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL); if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Failed to set the parameters"); return false; } } } } snd_pcm_hw_params_get_period_size(hw_params_copy, &periodSize, NULL); snd_pcm_hw_params_get_buffer_size(hw_params_copy, &bufferSize); CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize); /* set the format parameters */ format.m_sampleRate = sampleRate; format.m_frames = periodSize; format.m_frameSamples = periodSize * format.m_channelLayout.Count(); format.m_frameSize = snd_pcm_frames_to_bytes(m_pcm, 1); m_bufferSize = (unsigned int)bufferSize; m_timeout = std::ceil((double)(bufferSize * 1000) / (double)sampleRate); CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Setting timeout to %d ms", m_timeout); return true; }
/* Initialise audio devices. */ int digi_init() { int err, tmp; char *device = "plughw:0,0"; snd_pcm_hw_params_t *params; pthread_attr_t attr; pthread_mutexattr_t mutexattr; //added on 980905 by adb to init sound kill system memset(SampleHandles, 255, sizeof(SampleHandles)); //end edit by adb /* Open the ALSA sound device */ if ((err = snd_pcm_open(&snd_devhandle,device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { con_printf(CON_CRITICAL, "open failed: %s\n", snd_strerror( err )); return -1; } snd_pcm_hw_params_alloca(¶ms); err = snd_pcm_hw_params_any(snd_devhandle, params); if (err < 0) { con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_access(snd_devhandle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_format(snd_devhandle, params, SND_PCM_FORMAT_U8); if (err < 0) { con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_channels(snd_devhandle, params, 2); if (err < 0) { con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err)); return -1; } tmp = 11025; err = snd_pcm_hw_params_set_rate_near(snd_devhandle, params, &tmp, NULL); if (err < 0) { con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err)); return -1; } snd_pcm_hw_params_set_periods(snd_devhandle, params, 3, 0); snd_pcm_hw_params_set_buffer_size(snd_devhandle,params, (SOUND_BUFFER_SIZE*3)/2); err = snd_pcm_hw_params(snd_devhandle, params); if (err < 0) { con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err)); return -1; } /* Start the mixer thread */ /* We really should check the results of these */ pthread_mutexattr_init(&mutexattr); pthread_mutex_init(&mutex,&mutexattr); pthread_mutexattr_destroy(&mutexattr); if (pthread_attr_init(&attr) != 0) { con_printf(CON_CRITICAL, "failed to init attr\n"); snd_pcm_close( snd_devhandle ); return -1; } pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&thread_id,&attr,mixer_thread,NULL); pthread_attr_destroy(&attr); digi_initialised = 1; return 0; }
void ags_devout_alsa_init(AgsDevout *devout, GError **error) { static unsigned int period_time = 100000; static snd_pcm_format_t format = SND_PCM_FORMAT_S16; int rc; snd_pcm_t *handle; snd_pcm_hw_params_t *hwparams; unsigned int val; snd_pcm_uframes_t frames; unsigned int rate; unsigned int rrate; unsigned int channels; snd_pcm_uframes_t size; snd_pcm_sframes_t buffer_size; snd_pcm_sframes_t period_size; snd_pcm_sw_params_t *swparams; int period_event = 0; int err, dir; /* Open PCM device for playback. */ if ((err = snd_pcm_open(&handle, devout->out.alsa.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); return; } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); /* choose all parameters */ err = snd_pcm_hw_params_any(handle, hwparams); if (err < 0) { printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); return; } /* set hardware resampling */ err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, 1); if (err < 0) { printf("Resampling setup failed for playback: %s\n", snd_strerror(err)); return; } /* set the interleaved read/write format */ err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { printf("Access type not available for playback: %s\n", snd_strerror(err)); return; } /* set the sample format */ err = snd_pcm_hw_params_set_format(handle, hwparams, format); if (err < 0) { printf("Sample format not available for playback: %s\n", snd_strerror(err)); return; } /* set the count of channels */ channels = devout->dsp_channels; err = snd_pcm_hw_params_set_channels(handle, hwparams, channels); if (err < 0) { printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); return; } /* set the stream rate */ rate = devout->frequency; rrate = rate; err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rrate, 0); if (err < 0) { printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); return; } if (rrate != rate) { printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); exit(-EINVAL); } /* set the buffer size */ size = devout->buffer_size; err = snd_pcm_hw_params_set_buffer_size(handle, hwparams, size); if (err < 0) { printf("Unable to set buffer size %i for playback: %s\n", size, snd_strerror(err)); return; } buffer_size = size; /* set the period time */ err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); if (err < 0) { printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)); return; } err = snd_pcm_hw_params_get_period_size(hwparams, &size, &dir); if (err < 0) { printf("Unable to get period size for playback: %s\n", snd_strerror(err)); return; } period_size = size; /* write the parameters to device */ err = snd_pcm_hw_params(handle, hwparams); if (err < 0) { printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); return; } /* get the current swparams */ err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err)); return; } /* start the transfer when the buffer is almost full: */ /* (buffer_size / avail_min) * avail_min */ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size); if (err < 0) { printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); return; } /* allow the transfer when at least period_size samples can be processed */ /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */ err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size); if (err < 0) { printf("Unable to set avail min for playback: %s\n", snd_strerror(err)); return; } /* write the parameters to the playback device */ err = snd_pcm_sw_params(handle, swparams); if (err < 0) { printf("Unable to set sw params for playback: %s\n", snd_strerror(err)); return; } /* */ devout->out.alsa.handle = handle; devout->delay_counter = 0; }
void ags_devout_pcm_info(char *card_id, guint *channels_min, guint *channels_max, guint *rate_min, guint *rate_max, guint *buffer_size_min, guint *buffer_size_max, GError **error) { int rc; snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val; int dir; snd_pcm_uframes_t frames; int err; /* Open PCM device for playback. */ handle = NULL; rc = snd_pcm_open(&handle, card_id, SND_PCM_STREAM_PLAYBACK, 0); if(rc < 0) { g_message("unable to open pcm device: %s\n\0", snd_strerror(rc)); g_set_error(error, AGS_DEVOUT_ERROR, AGS_DEVOUT_ERROR_LOCKED_SOUNDCARD, "unable to open pcm device: %s\n\0", snd_strerror(rc)); return; } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* channels */ snd_pcm_hw_params_get_channels_min(params, &val); *channels_min = val; snd_pcm_hw_params_get_channels_max(params, &val); *channels_max = val; /* samplerate */ dir = 0; snd_pcm_hw_params_get_rate_min(params, &val, &dir); *rate_min = val; dir = 0; snd_pcm_hw_params_get_rate_max(params, &val, &dir); *rate_max = val; /* buffer size */ dir = 0; snd_pcm_hw_params_get_buffer_size_min(params, &frames); *buffer_size_min = frames; dir = 0; snd_pcm_hw_params_get_buffer_size_max(params, &frames); *buffer_size_max = frames; snd_pcm_close(handle); }
/** * Create and initialize Alsa audio output device with given parameters. * * @param Parameters - optional parameters * @throws AudioOutputException if output device cannot be opened */ AudioOutputDeviceAlsa::AudioOutputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters), Thread(true, true, 1, 0) { pcm_handle = NULL; stream = SND_PCM_STREAM_PLAYBACK; this->uiAlsaChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt(); this->uiSamplerate = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt(); this->FragmentSize = ((DeviceCreationParameterInt*)Parameters["FRAGMENTSIZE"])->ValueAsInt(); uint Fragments = ((DeviceCreationParameterInt*)Parameters["FRAGMENTS"])->ValueAsInt(); String Card = ((DeviceCreationParameterString*)Parameters["CARD"])->ValueAsString(); dmsg(2,("Checking if hw parameters supported...\n")); if (HardwareParametersSupported(Card, uiAlsaChannels, uiSamplerate, Fragments, FragmentSize)) { pcm_name = "hw:" + Card; } else { fprintf(stderr, "Warning: your soundcard doesn't support chosen hardware parameters; "); fprintf(stderr, "trying to compensate support lack with plughw..."); fflush(stdout); pcm_name = "plughw:" + Card; } dmsg(2,("HW check completed.\n")); 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) { throw AudioOutputException(String("Error opening PCM device ") + pcm_name + ": " + snd_strerror(err)); } if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) { throw AudioOutputException(String("Error, cannot initialize hardware parameter structure: ") + snd_strerror(err)); } /* 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) { throw AudioOutputException(String("Error snd_pcm_hw_params_set_access: ") + snd_strerror(err)); } /* 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 { throw AudioOutputException(String("Error setting sample format: ") + snd_strerror(err)); } 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, &uiSamplerate, &dir)) < 0) #else if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, uiSamplerate, &dir)) < 0) #endif { throw AudioOutputException(String("Error setting sample rate: ") + snd_strerror(err)); } if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, uiAlsaChannels)) < 0) { throw AudioOutputException(String("Error setting number of channels: ") + snd_strerror(err)); } /* Set number of periods. Periods used to be called fragments. */ if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, Fragments, dir)) < 0) { throw AudioOutputException(String("Error setting number of periods: ") + snd_strerror(err)); } /* 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) { throw AudioOutputException(String("Error setting buffersize: ") + snd_strerror(err)); } /* Apply HW parameter settings to */ /* PCM device and prepare device */ if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { throw AudioOutputException(String("Error setting HW params: ") + snd_strerror(err)); } if (snd_pcm_sw_params_malloc(&swparams) != 0) { throw AudioOutputException(String("Error in snd_pcm_sw_params_malloc: ") + snd_strerror(err)); } if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) { throw AudioOutputException(String("Error in snd_pcm_sw_params_current: ") + snd_strerror(err)); } if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) { throw AudioOutputException(String("Error in snd_pcm_sw_params_set_stop_threshold: ") + snd_strerror(err)); } if (snd_pcm_sw_params(pcm_handle, swparams) != 0) { throw AudioOutputException(String("Error in snd_pcm_sw_params: ") + snd_strerror(err)); } if ((err = snd_pcm_prepare(pcm_handle)) < 0) { throw AudioOutputException(String("Error snd_pcm_prepare: ") + snd_strerror(err)); } // allocate Alsa output buffer pAlsaOutputBuffer = new int16_t[uiAlsaChannels * FragmentSize]; // create audio channels for this audio device to which the sampler engines can write to for (int i = 0; i < uiAlsaChannels; i++) this->Channels.push_back(new AudioChannel(i, FragmentSize)); if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) { Play(); } }
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(¶ms); 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); }
int alsa_init(alsa_dev_t *dev, void *ptr, void (*callback)(snd_async_handler_t *)) { snd_pcm_t *phandle; snd_pcm_t *chandle; int err; snd_pcm_hw_params_t *hwparams_capture, *hwparams_playback; snd_pcm_sw_params_t *swparams_capture, *swparams_playback; struct sched_param param; err = sched_getparam(0, ¶m); if (err < 0) { perror("sched_getparam():"); exit(-1); } param.sched_priority = sched_get_priority_max(SCHED_FIFO); err = sched_setscheduler(0, SCHED_FIFO, ¶m); if (err < 0) { perror("sched_setscheduler():"); exit(-1); } snd_pcm_hw_params_alloca(&hwparams_capture); snd_pcm_sw_params_alloca(&swparams_capture); snd_pcm_hw_params_alloca(&hwparams_playback); snd_pcm_sw_params_alloca(&swparams_playback); err = snd_output_stdio_attach(&dev->output, stdout, 0); if (err < 0) { printf("Output failed: %s\n", snd_strerror(err)); exit(-1); } printf("Playback device is %s\n", dev->pdevice); printf("Stream parameters are %dHz, %s, %d channels\n", dev->rate, snd_pcm_format_name(dev->format), dev->channels); if ((err = snd_pcm_open(&phandle, dev->pdevice, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); exit(-1); } if ((err = alsa_set_hwparams(dev, phandle, hwparams_playback, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { printf("Setting of hwparams_playback failed: %s\n", snd_strerror(err)); exit(-1); } if ((err = alsa_set_swparams(dev, phandle, swparams_playback)) < 0) { printf("Setting of swparams_playback failed: %s\n", snd_strerror(err)); exit(-1); } snd_pcm_dump(phandle, dev->output); printf("Capture device is %s\n", dev->cdevice); if ((err = snd_pcm_open(&chandle, dev->cdevice, SND_PCM_STREAM_CAPTURE, 0)) < 0) { printf("Capture open error: %s\n", snd_strerror(err)); exit(-1); } if ((err = alsa_set_hwparams(dev, chandle, hwparams_capture, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { printf("Setting of hwparams_capture failed: %s\n", snd_strerror(err)); exit(-1); } if ((err = alsa_set_swparams(dev, chandle, swparams_capture)) < 0) { printf("Setting of swparams_capture failed: %s\n", snd_strerror(err)); exit(-1); } snd_pcm_dump(chandle, dev->output); if ((err = snd_pcm_link(phandle, chandle)) < 0) { printf("snd_pcm_link() failed: %s\n", snd_strerror(err)); exit(-1); } dev->chandle = chandle; dev->phandle = phandle; err = alsa_async_direct_loop(dev, ptr, callback); if (err < 0) printf("Transfer failed: %s\n", snd_strerror(err)); return 0; }
s32 Init() { //fprintf(stderr,"* SPU2-X: Initing Alsa\n"); snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_status_t *status; int pchannels = 2; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; handle = NULL; pcm_callback = NULL; pspeed = SAMPLE_RATE; // buffer time and period time are in microseconds... // (don't simplify the equation below -- it'll just cause integer rounding errors. period_time = (SndOutPacketSize * 1000) / (SampleRate / 1000); buffer_time = period_time * NumBuffers; int err; err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC /*| SND_PCM_NONBLOCK*/); if (err < 0) { fprintf(stderr, "Audio open error: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_nonblock(handle, 0); if (err < 0) { fprintf(stderr, "Can't set blocking mode: %s\n", snd_strerror(err)); return -1; } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, hwparams); if (err < 0) { fprintf(stderr, "Broken configuration for this PCM: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { fprintf(stderr, "Access type not available: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_format(handle, hwparams, format); if (err < 0) { fprintf(stderr, "Sample format not available: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_channels(handle, hwparams, pchannels); if (err < 0) { fprintf(stderr, "Channels count not available: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0); if (err < 0) { fprintf(stderr, "Rate not available: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); if (err < 0) { fprintf(stderr, "Buffer time error: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); if (err < 0) { fprintf(stderr, "Period time error: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params(handle, hwparams); if (err < 0) { fprintf(stderr, "Unable to install hw params: %s\n", snd_strerror(err)); return -1; } snd_pcm_status_alloca(&status); err = snd_pcm_status(handle, status); if (err < 0) { fprintf(stderr, "Unable to get status: %s\n", snd_strerror(err)); return -1; } // Bind our asynchronous callback magic: if (handle == NULL) fprintf(stderr, "No handle."); //fprintf(stderr,"* SPU2-X:Iz setting your internal callback.\n"); // The external handler never seems to get called after this. snd_async_add_pcm_handler(&pcm_callback, handle, ExternalCallback, this); err = snd_pcm_start(handle); if (err < 0) { fprintf(stderr, "Pcm start failed: %s\n", snd_strerror(err)); return -1; } // Diagnostic code: //buffer_size = snd_pcm_status_get_avail(status); //fprintf(stderr,"All set up.\n"); return 0; }
void SetupSound(void) { snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_status_t *status; int pspeed; int pchannels; int format; int buffer_time; int period_time; int err; if(iDisStereo) pchannels=1; else pchannels=2; pspeed=48000; format=SND_PCM_FORMAT_S16_LE; buffer_time=500000; period_time=buffer_time/4; if((err=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))<0) { printf("Audio open error: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_nonblock(handle, 0))<0) { printf("Can't set blocking moded: %s\n", snd_strerror(err)); return; } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if((err=snd_pcm_hw_params_any(handle, hwparams))<0) { printf("Broken configuration for this PCM: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED))<0) { printf("Access type not available: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_format(handle, hwparams, format))<0) { printf("Sample format not available: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_channels(handle, hwparams, pchannels))<0) { printf("Channels count not available: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0))<0) { printf("Rate not available: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0))<0) { printf("Buffer time error: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0))<0) { printf("Period time error: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params(handle, hwparams))<0) { printf("Unable to install hw params: %s\n", snd_strerror(err)); return; } snd_pcm_status_alloca(&status); if((err=snd_pcm_status(handle, status))<0) { printf("Unable to get status: %s\n", snd_strerror(err)); return; } buffer_size=snd_pcm_status_get_avail(status); }
/* open & setup audio device return: 1=success 0=fail */ static int init(int rate_hz, int channels, int format, int flags) { unsigned int alsa_buffer_time = 500000; /* 0.5 s */ unsigned int alsa_fragcount = 16; int err; int block; strarg_t device; snd_pcm_uframes_t chunk_size; snd_pcm_uframes_t bufsize; snd_pcm_uframes_t boundary; const opt_t subopts[] = { {"block", OPT_ARG_BOOL, &block, NULL}, {"device", OPT_ARG_STR, &device, str_maxlen}, {NULL} }; char alsa_device[ALSA_DEVICE_SIZE + 1]; // make sure alsa_device is null-terminated even when using strncpy etc. memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1); mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz, channels, format); alsa_handler = NULL; #if SND_LIB_VERSION >= 0x010005 mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version()); #else mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR); #endif snd_lib_error_set_handler(alsa_error_handler); ao_data.samplerate = rate_hz; ao_data.format = format; ao_data.channels = channels; switch (format) { case AF_FORMAT_S8: alsa_format = SND_PCM_FORMAT_S8; break; case AF_FORMAT_U8: alsa_format = SND_PCM_FORMAT_U8; break; case AF_FORMAT_U16_LE: alsa_format = SND_PCM_FORMAT_U16_LE; break; case AF_FORMAT_U16_BE: alsa_format = SND_PCM_FORMAT_U16_BE; break; case AF_FORMAT_AC3_LE: case AF_FORMAT_S16_LE: case AF_FORMAT_IEC61937_LE: alsa_format = SND_PCM_FORMAT_S16_LE; break; case AF_FORMAT_AC3_BE: case AF_FORMAT_S16_BE: case AF_FORMAT_IEC61937_BE: alsa_format = SND_PCM_FORMAT_S16_BE; break; case AF_FORMAT_U32_LE: alsa_format = SND_PCM_FORMAT_U32_LE; break; case AF_FORMAT_U32_BE: alsa_format = SND_PCM_FORMAT_U32_BE; break; case AF_FORMAT_S32_LE: alsa_format = SND_PCM_FORMAT_S32_LE; break; case AF_FORMAT_S32_BE: alsa_format = SND_PCM_FORMAT_S32_BE; break; case AF_FORMAT_U24_LE: alsa_format = SND_PCM_FORMAT_U24_3LE; break; case AF_FORMAT_U24_BE: alsa_format = SND_PCM_FORMAT_U24_3BE; break; case AF_FORMAT_S24_LE: alsa_format = SND_PCM_FORMAT_S24_3LE; break; case AF_FORMAT_S24_BE: alsa_format = SND_PCM_FORMAT_S24_3BE; break; case AF_FORMAT_FLOAT_LE: alsa_format = SND_PCM_FORMAT_FLOAT_LE; break; case AF_FORMAT_FLOAT_BE: alsa_format = SND_PCM_FORMAT_FLOAT_BE; break; case AF_FORMAT_MU_LAW: alsa_format = SND_PCM_FORMAT_MU_LAW; break; case AF_FORMAT_A_LAW: alsa_format = SND_PCM_FORMAT_A_LAW; break; default: alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1 break; } //subdevice parsing // set defaults block = 1; /* switch for spdif * sets opening sequence for SPDIF * sets also the playback and other switches 'on the fly' * while opening the abstract alias for the spdif subdevice * 'iec958' */ if (AF_FORMAT_IS_IEC61937(format)) { device.str = "iec958"; mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n", channels); } else /* in any case for multichannel playback we should select * appropriate device */ switch (channels) { case 1: case 2: device.str = "default"; mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n"); break; case 4: if (alsa_format == SND_PCM_FORMAT_FLOAT_LE) // hack - use the converter plugin device.str = "plug:surround40"; else device.str = "surround40"; mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n"); break; case 6: if (alsa_format == SND_PCM_FORMAT_FLOAT_LE) device.str = "plug:surround51"; else device.str = "surround51"; mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n"); break; case 8: if (alsa_format == SND_PCM_FORMAT_FLOAT_LE) device.str = "plug:surround71"; else device.str = "surround71"; mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround71\n"); break; default: device.str = "default"; mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ChannelsNotSupported,channels); } device.len = strlen(device.str); if (subopt_parse(ao_subdevice, subopts) != 0) { print_help(); return 0; } parse_device(alsa_device, device.str, device.len); mp_msg(MSGT_AO,MSGL_V,"alsa-init: using device %s\n", alsa_device); if (!alsa_handler) { int open_mode = block ? 0 : SND_PCM_NONBLOCK; int isac3 = AF_FORMAT_IS_IEC61937(format); //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC mp_msg(MSGT_AO,MSGL_V,"alsa-init: opening device in %sblocking mode\n", block ? "" : "non-"); if ((err = try_open_device(alsa_device, open_mode, isac3)) < 0) { if (err != -EBUSY && !block) { mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_OpenInNonblockModeFailed); if ((err = try_open_device(alsa_device, 0, isac3)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err)); return 0; } } else { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err)); return 0; } } if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSetBlockMode, snd_strerror(err)); } else { mp_msg(MSGT_AO,MSGL_V,"alsa-init: device reopened in blocking mode\n"); } snd_pcm_hw_params_alloca(&alsa_hwparams); snd_pcm_sw_params_alloca(&alsa_swparams); // setting hw-parameters if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetInitialParameters, snd_strerror(err)); return 0; } err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetAccessType, snd_strerror(err)); return 0; } /* workaround for nonsupported formats sets default format to S16_LE if the given formats aren't supported */ if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams, alsa_format)) < 0) { mp_msg(MSGT_AO,MSGL_INFO, MSGTR_AO_ALSA_FormatNotSupportedByHardware, af_fmt2str_short(format)); alsa_format = SND_PCM_FORMAT_S16_LE; if (AF_FORMAT_IS_AC3(ao_data.format)) ao_data.format = AF_FORMAT_AC3_LE; else if (AF_FORMAT_IS_IEC61937(ao_data.format)) ao_data.format = AF_FORMAT_IEC61937_LE; else ao_data.format = AF_FORMAT_S16_LE; } if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams, alsa_format)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetFormat, snd_strerror(err)); return 0; } if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams, &ao_data.channels)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetChannels, snd_strerror(err)); return 0; } /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11) prefer our own resampler, since that allows users to choose the resampler, even per file if desired */ #if SND_LIB_VERSION >= 0x010009 if ((err = snd_pcm_hw_params_set_rate_resample(alsa_handler, alsa_hwparams, 0)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToDisableResampling, snd_strerror(err)); return 0; } #endif if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, &ao_data.samplerate, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSamplerate2, snd_strerror(err)); return 0; } bytes_per_sample = af_fmt2bits(ao_data.format) / 8; bytes_per_sample *= ao_data.channels; ao_data.bps = ao_data.samplerate * bytes_per_sample; if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, &alsa_buffer_time, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetBufferTimeNear, snd_strerror(err)); return 0; } if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams, &alsa_fragcount, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriods, snd_strerror(err)); return 0; } /* finally install hardware parameters */ if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetHwParameters, snd_strerror(err)); return 0; } // end setting hw-params // gets buffersize for control if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBufferSize, snd_strerror(err)); return 0; } else { ao_data.buffersize = bufsize * bytes_per_sample; mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize); } if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetPeriodSize, snd_strerror(err)); return 0; } else { mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n", chunk_size); } ao_data.outburst = chunk_size * bytes_per_sample; /* setting software parameters */ if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters, snd_strerror(err)); return 0; } #if SND_LIB_VERSION >= 0x000901 if ((err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBoundary, snd_strerror(err)); return 0; } #else boundary = 0x7fffffff; #endif /* start playing when one period has been written */ if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, chunk_size)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStartThreshold, snd_strerror(err)); return 0; } /* disable underrun reporting */ if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, boundary)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStopThreshold, snd_strerror(err)); return 0; } #if SND_LIB_VERSION >= 0x000901 /* play silence when there is an underrun */ if ((err = snd_pcm_sw_params_set_silence_size(alsa_handler, alsa_swparams, boundary)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSilenceSize, snd_strerror(err)); return 0; } #endif if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters, snd_strerror(err)); return 0; } /* end setting sw-params */ mp_msg(MSGT_AO,MSGL_V,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", ao_data.samplerate, ao_data.channels, (int)bytes_per_sample, ao_data.buffersize, snd_pcm_format_description(alsa_format)); } // end switch alsa_handler (spdif) alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams); return 1; } // end init
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( ¶ms ); 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; }
int main() { int rc; snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val, val2; int dir; snd_pcm_uframes_t frames; /* Open PCM device for playback. */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 2); /* 44100 bits/second sampling rate (CD quality) */ val = 44100; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } /* Display information about the PCM interface */ printf("PCM handle name = '%s'\n", snd_pcm_name(handle)); printf("PCM state = %s\n", snd_pcm_state_name(snd_pcm_state(handle))); snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *) &val); printf("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val)); snd_pcm_hw_params_get_format(params, &val); printf("format = '%s' (%s)\n", snd_pcm_format_name((snd_pcm_format_t)val), snd_pcm_format_description( (snd_pcm_format_t)val)); snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *)&val); printf("subformat = '%s' (%s)\n", snd_pcm_subformat_name((snd_pcm_subformat_t)val), snd_pcm_subformat_description( (snd_pcm_subformat_t)val)); snd_pcm_hw_params_get_channels(params, &val); printf("channels = %d\n", val); snd_pcm_hw_params_get_rate(params, &val, &dir); printf("rate = %d bps\n", val); snd_pcm_hw_params_get_period_time(params, &val, &dir); printf("period time = %d us\n", val); snd_pcm_hw_params_get_period_size(params, &frames, &dir); printf("period size = %d frames\n", (int)frames); snd_pcm_hw_params_get_buffer_time(params, &val, &dir); printf("buffer time = %d us\n", val); snd_pcm_hw_params_get_buffer_size(params, (snd_pcm_uframes_t *) &val); printf("buffer size = %d frames\n", val); snd_pcm_hw_params_get_periods(params, &val, &dir); printf("periods per buffer = %d frames\n", val); snd_pcm_hw_params_get_rate_numden(params, &val, &val2); printf("exact rate = %d/%d bps\n", val, val2); val = snd_pcm_hw_params_get_sbits(params); printf("significant bits = %d\n", val); snd_pcm_hw_params_get_tick_time(params, &val, &dir); printf("tick time = %d us\n", val); val = snd_pcm_hw_params_is_batch(params); printf("is batch = %d\n", val); val = snd_pcm_hw_params_is_block_transfer(params); printf("is block transfer = %d\n", val); val = snd_pcm_hw_params_is_double(params); printf("is double = %d\n", val); val = snd_pcm_hw_params_is_half_duplex(params); printf("is half duplex = %d\n", val); val = snd_pcm_hw_params_is_joint_duplex(params); printf("is joint duplex = %d\n", val); val = snd_pcm_hw_params_can_overrange(params); printf("can overrange = %d\n", val); val = snd_pcm_hw_params_can_mmap_sample_resolution(params); printf("can mmap = %d\n", val); val = snd_pcm_hw_params_can_pause(params); printf("can pause = %d\n", val); val = snd_pcm_hw_params_can_resume(params); printf("can resume = %d\n", val); val = snd_pcm_hw_params_can_sync_start(params); printf("can sync start = %d\n", val); snd_pcm_close(handle); return 0; }
/* setup alsa data format and buffer geometry */ static inline int alsa_set_hwparams(ao_device *device, ao_sample_format *format) { ao_alsa_internal *internal = (ao_alsa_internal *) device->internal; snd_pcm_hw_params_t *params; int err; unsigned int rate = internal->sample_rate = format->rate; /* allocate the hardware parameter structure */ snd_pcm_hw_params_alloca(¶ms); /* fetch all possible hardware parameters */ err = snd_pcm_hw_params_any(internal->pcm_handle, params); if (err < 0){ adebug("snd_pcm_hw_params_any() failed.\n" " Device exists but no matching hardware?\n"); return err; } /* set the access type */ err = snd_pcm_hw_params_set_access(internal->pcm_handle, params, internal->access_mask); if (err < 0){ adebug("snd_pcm_hw_params_set_access() failed.\n"); return err; } /* set the sample bitformat */ err = snd_pcm_hw_params_set_format(internal->pcm_handle, params, internal->bitformat); if (err < 0){ /* the device may support a greater bit-depth than the one requested. */ switch(internal->bitformat){ case SND_PCM_FORMAT_U8: if (!snd_pcm_hw_params_set_format(internal->pcm_handle, params, SND_PCM_FORMAT_S16)){ adebug("snd_pcm_hw_params_set_format() unable to open %d bit playback.\n",format->bits); adebug("snd_pcm_hw_params_set_format() using 16 bit playback instead.\n"); format->bits = 16; break; } case SND_PCM_FORMAT_S16: if (!snd_pcm_hw_params_set_format(internal->pcm_handle, params, SND_PCM_FORMAT_S24)){ adebug("snd_pcm_hw_params_set_format() unable to open %d bit playback.\n",format->bits); adebug("snd_pcm_hw_params_set_format() using 24 bit playback instead.\n"); format->bits = 24; break; } case SND_PCM_FORMAT_S24: if (!snd_pcm_hw_params_set_format(internal->pcm_handle, params, SND_PCM_FORMAT_S32)){ adebug("snd_pcm_hw_params_set_format() unable to open %d bit playback.\n",format->bits); adebug("snd_pcm_hw_params_set_format() using 32 bit playback instead.\n"); format->bits = 32; break; } case SND_PCM_FORMAT_S32: adebug("snd_pcm_hw_params_set_format() failed.\n"); return err; } } /* set the number of channels */ err = snd_pcm_hw_params_set_channels(internal->pcm_handle, params, (unsigned int)device->output_channels); if (err < 0){ adebug("snd_pcm_hw_params_set_channels() failed.\n"); return err; } /* set the sample rate */ err = snd_pcm_hw_params_set_rate_near(internal->pcm_handle, params, &rate, 0); if (err < 0){ adebug("snd_pcm_hw_params_set_rate_near() failed.\n"); return err; } if (rate > 1.05 * format->rate || rate < 0.95 * format->rate) { awarn("sample rate %i not supported " "by the hardware, using %u\n", format->rate, rate); } /* set the time per hardware sample transfer */ if(internal->period_time==0) internal->period_time=internal->buffer_time/4; err = snd_pcm_hw_params_set_period_time_near(internal->pcm_handle, params, &(internal->period_time), 0); if (err < 0){ adebug("snd_pcm_hw_params_set_period_time_near() failed.\n"); return err; } /* set the length of the hardware sample buffer in microseconds */ /* some plug devices have very high minimum periods; don't allow a buffer size small enough that it's ~ guaranteed to skip */ if(internal->buffer_time<internal->period_time*3) internal->buffer_time=internal->period_time*3; err = snd_pcm_hw_params_set_buffer_time_near(internal->pcm_handle, params, &(internal->buffer_time), 0); if (err < 0){ adebug("snd_pcm_hw_params_set_buffer_time_near() failed.\n"); return err; } /* commit the params structure to the hardware via ALSA */ err = snd_pcm_hw_params(internal->pcm_handle, params); if (err < 0){ adebug("snd_pcm_hw_params() failed.\n"); return err; } /* save the period size in frames for posterity */ err = snd_pcm_hw_params_get_period_size(params, &(internal->period_size), 0); if (err < 0){ adebug("snd_pcm_hw_params_get_period_size() failed.\n"); return err; } return 1; }
bool QAudioOutputPrivate::open() { if(opened) return true; #ifdef DEBUG_AUDIO QTime now(QTime::currentTime()); qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; #endif timeStamp.restart(); elapsedTimeOffset = 0; int dir; int err = 0; int count=0; unsigned int freakuency=settings.frequency(); if (!settings.isValid()) { qWarning("QAudioOutput: open error, invalid format."); } else if (settings.frequency() <= 0) { qWarning("QAudioOutput: open error, invalid sample rate (%d).", settings.frequency()); } else { err = -1; } if (err == 0) { errorState = QAudio::OpenError; deviceState = QAudio::StoppedState; return false; } QString dev = QString(QLatin1String(m_device.constData())); 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()); #else dev = QLatin1String("hw:0,0"); #endif } else { #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) dev = QLatin1String(m_device); #else int idx = 0; char *name; QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData()); while(snd_card_get_name(idx,&name) == 0) { if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0) break; idx++; } dev = QString(QLatin1String("hw:%1,0")).arg(idx); #endif } // Step 1: try and open the device while((count < 5) && (err < 0)) { err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); if(err < 0) count++; } if (( err < 0)||(handle == 0)) { errorState = QAudio::OpenError; deviceState = QAudio::StoppedState; return false; } snd_pcm_nonblock( handle, 0 ); // Step 2: Set the desired HW parameters. snd_pcm_hw_params_alloca( &hwparams ); bool fatal = false; QString errMessage; unsigned int chunks = 8; err = snd_pcm_hw_params_any( handle, hwparams ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_any: err = %1").arg(err); } if ( !fatal ) { err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_access( handle, hwparams, access ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_access: err = %1").arg(err); } } if ( !fatal ) { err = setFormat(); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_format: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_channels: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 ); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); } } if ( !fatal ) { unsigned int maxBufferTime = 0; unsigned int minBufferTime = 0; unsigned int maxPeriodTime = 0; unsigned int minPeriodTime = 0; err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &dir); if ( err >= 0) err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &dir); if ( err >= 0) err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &dir); if ( err >= 0) err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &dir); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: buffer/period min and max: err = %1").arg(err); } else { if (maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time) { #ifdef DEBUG_AUDIO qDebug()<<"defaults out of range"; qDebug()<<"pmin="<<minPeriodTime<<", pmax="<<maxPeriodTime<<", bmin="<<minBufferTime<<", bmax="<<maxBufferTime; #endif period_time = minPeriodTime; if (period_time*4 <= maxBufferTime) { // Use 4 periods if possible buffer_time = period_time*4; chunks = 4; } else if (period_time*2 <= maxBufferTime) { // Use 2 periods if possible buffer_time = period_time*2; chunks = 2; } else { qWarning()<<"QAudioOutput: alsa only supports single period!"; fatal = true; } #ifdef DEBUG_AUDIO qDebug()<<"used: buffer_time="<<buffer_time<<", period_time="<<period_time; #endif } } } if ( !fatal ) { err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err); } } if ( !fatal ) { err = snd_pcm_hw_params(handle, hwparams); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params: err = %1").arg(err); } } if( err < 0) { qWarning()<<errMessage; errorState = QAudio::OpenError; deviceState = QAudio::StoppedState; return false; } snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames); buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames); snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir); period_size = snd_pcm_frames_to_bytes(handle,period_frames); snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir); snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir); // Step 3: Set the desired SW parameters. snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_alloca(&swparams); snd_pcm_sw_params_current(handle, swparams); snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames); snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames); snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames); snd_pcm_sw_params(handle, swparams); // Step 4: Prepare audio if(audioBuffer == 0) audioBuffer = new char[snd_pcm_frames_to_bytes(handle,buffer_frames)]; snd_pcm_prepare( handle ); snd_pcm_start(handle); // Step 5: Setup callback and timer fallback snd_async_add_pcm_handler(&ahandler, handle, async_callback, this); bytesAvailable = bytesFree(); // Step 6: Start audio processing timer->start(period_time/1000); clockStamp.restart(); timeStamp.restart(); elapsedTimeOffset = 0; errorState = QAudio::NoError; totalTimeValue = 0; opened = true; return true; }
int main(int argc, char **argv){ int i; int aver,val,val2; int16_t buf[BUFSIZE]; double d_buffer[BUFSIZE]; double pitch = 0.0; struct timespec before,after; struct pitch_tracker_params *settings; snd_pcm_uframes_t period_size = PERIOD_SIZE; //ALSA PCM configuration snd_pcm_t *handle; snd_pcm_hw_params_t *params; int dir,rc; snd_pcm_uframes_t frames; /* Open PCM device for capture */ rc = snd_pcm_open( &handle, "default" , SND_PCM_STREAM_CAPTURE , 0); if(rc < 0 ){ fprintf(stderr,"unable to open pcm device: %s\n",snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED); /* unsigned 16-bit format */ snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16); snd_pcm_hw_params_set_channels(handle, params, 1); /* 44100 bits/second sampling rate */ val = 44100; snd_pcm_hw_params_set_rate_near(handle,params, &val, &dir); /* set size time*/ snd_pcm_hw_params_set_period_size_near(handle, params, &period_size , &dir); /* write configuration */ rc = snd_pcm_hw_params(handle,params); /*Display info*/ printf("PCM handle name = '%s'\n", snd_pcm_name(handle)); printf("PCM state = %s\n", snd_pcm_state_name(snd_pcm_state(handle))); snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *) &val); printf("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val)); snd_pcm_hw_params_get_format(params, &val); printf("format = '%s' (%s)\n", snd_pcm_format_name((snd_pcm_format_t)val), snd_pcm_format_description( (snd_pcm_format_t)val)); snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *)&val); printf("subformat = '%s' (%s)\n", snd_pcm_subformat_name((snd_pcm_subformat_t)val), snd_pcm_subformat_description( (snd_pcm_subformat_t)val)); snd_pcm_hw_params_get_channels(params, &val); printf("channels = %d\n", val); snd_pcm_hw_params_get_rate(params, &val, &dir); printf("rate = %d bps\n", val); snd_pcm_hw_params_get_period_time(params, &val, &dir); printf("period time = %d us\n", val); snd_pcm_hw_params_get_period_size(params, &frames, &dir); printf("period size = %d frames\n", (int)frames); snd_pcm_hw_params_get_buffer_time(params, &val, &dir); printf("buffer time = %d us\n", val); snd_pcm_hw_params_get_buffer_size(params, (snd_pcm_uframes_t *) &val); printf("buffer size = %d frames\n", val); snd_pcm_hw_params_get_periods(params, &val, &dir); printf("periods per buffer = %d frames\n", val); snd_pcm_hw_params_get_rate_numden(params, &val, &val2); printf("exact rate = %d/%d bps\n", val, val2); val = snd_pcm_hw_params_get_sbits(params); printf("significant bits = %d\n", val); val = snd_pcm_hw_params_is_batch(params); printf("is batch = %d\n", val); val = snd_pcm_hw_params_is_block_transfer(params); printf("is block transfer = %d\n", val); val = snd_pcm_hw_params_is_double(params); printf("is double = %d\n", val); val = snd_pcm_hw_params_is_half_duplex(params); printf("is half duplex = %d\n", val); val = snd_pcm_hw_params_is_joint_duplex(params); printf("is joint duplex = %d\n", val); val = snd_pcm_hw_params_can_overrange(params); printf("can overrange = %d\n", val); val = snd_pcm_hw_params_can_mmap_sample_resolution(params); printf("can mmap = %d\n", val); val = snd_pcm_hw_params_can_pause(params); printf("can pause = %d\n", val); val = snd_pcm_hw_params_can_resume(params); printf("can resume = %d\n", val); val = snd_pcm_hw_params_can_sync_start(params); printf("can sync start = %d\n", val); settings = open_pitch_tracker(); while(1){ rc = snd_pcm_readi(handle, buf, frames); if (rc == -EPIPE) { /* EPIPE means overrun */ fprintf(stderr, "overrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from read: %s\n", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short read, read %d frames\n", rc); } for( i = 0 ; i< BUFSIZE ; i++){ d_buffer[i] = (double) buf[i]; } pitch = compute_pitch(d_buffer, BUFSIZE, S16, settings ,ACCURACY); if( pitch != 0.0 ) printf("frequency -> %f\n",pitch); memset(buf,0,BUFSIZE); } close_pitch_tracker(&settings); snd_pcm_drain(handle); snd_pcm_close(handle); return 0; }
int main(int argc , char *argv[]) { int socket_desc , client_sock , c , *new_sock; struct sockaddr_in server , client; pthread_t sniffer_thread1; snd_pcm_hw_params_t *params; unsigned int val; int dir; int rcm; //Prepare the sockaddr_in structure server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons( 2008 ); //Create socket socket_desc = socket(AF_INET , SOCK_STREAM , 0); if (socket_desc == -1) { printf("Could not create socket"); } //Bind if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) { //print the error message perror("bind failed. Error"); return 1; } puts("bind done"); //Listen listen(socket_desc , 3); //Accept and incoming connection puts("Waiting for incoming connections..."); c = sizeof(struct sockaddr_in); snd_pcm_open(&handle, "plughw:1,0", SND_PCM_STREAM_CAPTURE, 0); /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 1); /* 44100 bits/second sampling rate (CD quality) */ val = 32768; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Set period size to 32 frames. */ frames = SIZE; snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); /* Write the parameters to the driver */ rcm = snd_pcm_hw_params(handle, params); if (rcm < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rcm)); exit(1); } /* Use a buffer large enough to hold one period */ snd_pcm_hw_params_get_period_size(params, &frames, &dir); /* 2 bytes/sample, 2 channels */ /* We want to loop for 5 seconds */ snd_pcm_hw_params_get_period_time(params, &val, &dir); while(1){ pthread_t sniffer_thread; if(client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) { puts("Connection accepted"); new_sock = malloc(4); *new_sock = client_sock; } if( pthread_create(&sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0) { perror("could not create thread"); return 1; } //Now join the thread , so that we dont terminate before the thread //pthread_join( sniffer_thread , NULL); puts("Handler assigned"); if (client_sock < 0) { perror("accept failed"); { perror("accept failed"); return 1; } } } snd_pcm_drain(handle); snd_pcm_close(handle); return 0; }
static pj_status_t open_capture (struct alsa_stream* stream, const pjmedia_aud_param *param) { snd_pcm_hw_params_t* params; snd_pcm_format_t format; int result; unsigned int rate; snd_pcm_uframes_t tmp_buf_size; snd_pcm_uframes_t tmp_period_size; if (param->rec_id < 0 || param->rec_id >= stream->af->dev_cnt) return PJMEDIA_EAUD_INVDEV; /* Open PCM for capture */ PJ_LOG (5,(THIS_FILE, "open_capture: Open capture device '%s'", stream->af->devs[param->rec_id].name)); result = snd_pcm_open (&stream->ca_pcm, stream->af->devs[param->rec_id].name, SND_PCM_STREAM_CAPTURE, 0); if (result < 0) return PJMEDIA_EAUD_SYSERR; /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca (¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any (stream->ca_pcm, params); /* Set interleaved mode */ snd_pcm_hw_params_set_access (stream->ca_pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Set format */ switch (param->bits_per_sample) { case 8: TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S8")); format = SND_PCM_FORMAT_S8; break; case 16: TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S16_LE")); format = SND_PCM_FORMAT_S16_LE; break; case 24: TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S24_LE")); format = SND_PCM_FORMAT_S24_LE; break; case 32: TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S32_LE")); format = SND_PCM_FORMAT_S32_LE; break; default: TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S16_LE")); format = SND_PCM_FORMAT_S16_LE; break; } snd_pcm_hw_params_set_format (stream->ca_pcm, params, format); /* Set number of channels */ TRACE_((THIS_FILE, "open_capture: set channels: %d", param->channel_count)); snd_pcm_hw_params_set_channels (stream->ca_pcm, params, param->channel_count); /* Set clock rate */ rate = param->clock_rate; TRACE_((THIS_FILE, "open_capture: set clock rate: %d", rate)); snd_pcm_hw_params_set_rate_near (stream->ca_pcm, params, &rate, NULL); TRACE_((THIS_FILE, "open_capture: clock rate set to: %d", rate)); /* Set period size to samples_per_frame frames. */ stream->ca_frames = (snd_pcm_uframes_t) param->samples_per_frame / param->channel_count; TRACE_((THIS_FILE, "open_capture: set period size: %d", stream->ca_frames)); tmp_period_size = stream->ca_frames; snd_pcm_hw_params_set_period_size_near (stream->ca_pcm, params, &tmp_period_size, NULL); TRACE_((THIS_FILE, "open_capture: period size set to: %d", tmp_period_size)); /* Set the sound device buffer size and latency */ if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) tmp_buf_size = (rate / 1000) * param->input_latency_ms; else tmp_buf_size = (rate / 1000) * PJMEDIA_SND_DEFAULT_REC_LATENCY; snd_pcm_hw_params_set_buffer_size_near (stream->ca_pcm, params, &tmp_buf_size); stream->param.input_latency_ms = tmp_buf_size / (rate / 1000); /* Set our buffer */ stream->ca_buf_size = stream->ca_frames * param->channel_count * (param->bits_per_sample/8); stream->ca_buf = (char*) pj_pool_alloc (stream->pool, stream->ca_buf_size); TRACE_((THIS_FILE, "open_capture: buffer size set to: %d", (int)tmp_buf_size)); TRACE_((THIS_FILE, "open_capture: capture_latency set to: %d ms", (int)stream->param.input_latency_ms)); /* Activate the parameters */ result = snd_pcm_hw_params (stream->ca_pcm, params); if (result < 0) { snd_pcm_close (stream->ca_pcm); return PJMEDIA_EAUD_SYSERR; } PJ_LOG (5,(THIS_FILE, "Opened device alsa(%s) for capture, sample rate=%d" ", ch=%d, bits=%d, period size=%d frames, latency=%d ms", stream->af->devs[param->rec_id].name, rate, param->channel_count, param->bits_per_sample, stream->ca_frames, (int)stream->param.input_latency_ms)); return PJ_SUCCESS; }
static bool audio_capture_configure(uint32_t samplerate) { assert(acapt_hdl != NULL); snd_pcm_hw_params_t *hw_params = NULL; snd_pcm_hw_params_alloca(&hw_params); int err = 0; /* set hardware params */ if ((err = snd_pcm_hw_params_any(acapt_hdl, hw_params)) < 0) { fprintf(stderr, "ERROR: snd_pcm_hw_params_any() has failed - %s\n", snd_strerror(err)); return false; } /* interleaved samples */ if ((err = snd_pcm_hw_params_set_access(acapt_hdl, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf(stderr, "ERROR: snd_pcm_hw_params_set_access() has " "failed - %s\n", snd_strerror(err)); return false; } /* 1 channel (mono) capture */ if ((err = snd_pcm_hw_params_set_channels(acapt_hdl, hw_params, 1)) < 0) { fprintf(stderr, "ERROR: snd_pcm_hw_params_set_channels() has " "failed - %s\n", snd_strerror(err)); return false; } /* 16 bit PCM samples */ if ((err = snd_pcm_hw_params_set_format(acapt_hdl, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { fprintf(stderr, "ERROR: snd_pcm_hw_params_set_format() has " "failed - %s\n", snd_strerror(err)); return false; } /* set samplerate */ if ((err = snd_pcm_hw_params_set_rate(acapt_hdl, hw_params, samplerate, 0)) < 0) { fprintf(stderr, "ERROR: snd_pcm_hw_params_set_rate() has " "failed - %s\n", snd_strerror(err)); return false; } /* apply hardware parameters */ if ((err = snd_pcm_hw_params(acapt_hdl, hw_params)) < 0) { fprintf(stderr, "ERROR: snd_pcm_hw_params() has failed - %s\n\n", snd_strerror(err)); return false; } /* set software parameters */ snd_pcm_sw_params_t *sw_params = NULL; snd_pcm_sw_params_alloca(&sw_params); if ((err = snd_pcm_sw_params_current(acapt_hdl, sw_params)) < 0) { fprintf(stderr, "ERROR: snd_pcm_sw_params_current() has failed - %s\n", snd_strerror(err)); return false; } if ((err = snd_pcm_sw_params_set_start_threshold(acapt_hdl, sw_params, 0U)) < 0) { fprintf(stderr, "ERROR: snd_pcm_sw_params_set_start_threshold() has " "failed - %s\n", snd_strerror(err)); return false; } /* apply software parameters */ if ((err = snd_pcm_sw_params(acapt_hdl, sw_params)) < 0) { fprintf(stderr, "ERROR: snd_pcm_sw_params() has failed - %s\n", snd_strerror(err)); return false; } return true; }
void *audiothread(void *v) { int policy; sched_param sched; int err; alsaaudio *dev; pthread_getschedparam(pthread_self(),&policy,&sched); sched.sched_priority++;//policy=SCHED_RR; pthread_setschedparam(pthread_self(),policy,&sched); dev=(alsaaudio*)v; unsigned int val; snd_pcm_t *fd; snd_pcm_uframes_t periodsize; snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca(&hwparams); int output_rate; int channels; int fragment_size; int fragment_count; err=snd_pcm_open(&fd, strdup("default"), SND_PCM_STREAM_PLAYBACK, 0); if (err<0) return -1; fragment_size=LINUXFRAG; //overall buffer size fragment_count=2; //2 - 16 fragment count - 2 minimum, the lower it is potentially the lower the latency //configure device if (snd_pcm_hw_params_any(fd, hwparams) < 0) { //printf("linuxaudio failed at params any\n"); return -1; } if (snd_pcm_hw_params_set_access(fd, hwparams,SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { //printf("linuxaudio failed at set access\n"); return -1; } if (snd_pcm_hw_params_set_format(fd, hwparams,SND_PCM_FORMAT_S16_LE) < 0) { //printf("linuxaudio failed at set format\n"); return -1; } val = 44100; if (snd_pcm_hw_params_set_rate_near(fd, hwparams,&val, 0) < 0) { // Try 48KHZ too //printf("linuxaudio - %d HZ not available, trying 48000HZ\n", output_rate); val = 48000; if (snd_pcm_hw_params_set_rate_near(fd, hwparams,&val, 0) < 0) { //printf("linuxaudio failed at setting output rate (%d)\n", output_rate); return -1; } dev->mix->freq=val; } channels=2; if (snd_pcm_hw_params_set_channels(fd, hwparams, channels) < 0) { //printf("linuxaudio failed at set channels (%d)\n", channels); return -1; } periodsize = (fragment_size) / 4; // bytes -> frames for 16-bit,stereo - should be a minimum of 512 if (snd_pcm_hw_params_set_period_size_near(fd, hwparams,&periodsize, 0) < 0) { //printf("linuxaudio failed at set period size (%d)\n", (int)periodsize); return -1; } val = fragment_count; if (snd_pcm_hw_params_set_periods_near(fd, hwparams,&val, 0) < 0) { //printf("linuxaudio failed at set periods (%d)\n", val); //should attempt a one by one period increase up to 16? return -1; } if (snd_pcm_hw_params(fd, hwparams) < 0) { //printf("linuxaudio failed at installing hw params\n"); return -1; } //loop while playing sound dev->playing=1; while (dev->playing) { dev->mix->mix16(dev->buffer); if ((snd_pcm_writei (fd, dev->buffer,LINUXFRAG/2)) < 0) { //Half buffer for two channels? //printf ("linuxaudio warning: buffer underrun occurred\n"); if (snd_pcm_prepare(fd) < 0) { //printf ("linuxaudio failed at preparing pcm\n"); dev->playing=0; //die gracefully } } } snd_pcm_drop(fd); snd_pcm_close (fd); return 0; }
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); }
input_module_t *alsa_open_module(module_param_t *params) { input_module_t *mod = calloc(1, sizeof(input_module_t)); im_alsa_state *s; module_param_t *current; char *device = "plughw:0,0"; /* default device */ int format = AFMT_S16_LE; int channels, rate; int use_metadata = 1; /* Default to on */ unsigned int buffered_time; snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE; snd_pcm_hw_params_t *hwparams; int err; mod->type = ICES_INPUT_PCM; mod->subtype = INPUT_PCM_LE_16; mod->getdata = alsa_read; mod->handle_event = event_handler; mod->metadata_update = metadata_update; mod->internal = calloc(1, sizeof(im_alsa_state)); s = mod->internal; s->fd = NULL; /* Set it to something invalid, for now */ s->rate = 44100; /* Defaults */ s->channels = 2; thread_mutex_create(&s->metadatalock); current = params; while(current) { if(!strcmp(current->name, "rate")) s->rate = atoi(current->value); else if(!strcmp(current->name, "channels")) s->channels = atoi(current->value); else if(!strcmp(current->name, "device")) device = current->value; else if(!strcmp(current->name, "metadata")) use_metadata = atoi(current->value); else if(!strcmp(current->name, "metadatafilename")) ices_config->metadata_filename = current->value; else LOG_WARN1("Unknown parameter %s for alsa module", current->name); current = current->next; } snd_pcm_hw_params_alloca(&hwparams); if ((err = snd_pcm_open(&s->fd, device, stream, 0)) < 0) { LOG_ERROR2("Failed to open audio device %s: %s", device, snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_any(s->fd, hwparams)) < 0) { LOG_ERROR1("Failed to initialize hwparams: %s", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_access(s->fd, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { LOG_ERROR1("Error setting access: %s", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_format(s->fd, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) { LOG_ERROR1("Couldn't set sample format to SND_PCM_FORMAT_S16_LE: %s", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_rate_near(s->fd, hwparams, &s->rate, 0)) < 0) { LOG_ERROR1("Error setting rate: %s", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_channels(s->fd, hwparams, s->channels)) < 0) { LOG_ERROR1("Error setting channels: %s", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_periods(s->fd, hwparams, 2, 0)) < 0) { LOG_ERROR1("Error setting periods: %s", snd_strerror(err)); goto fail; } buffered_time = 500000; if ((err = snd_pcm_hw_params_set_buffer_time_near(s->fd, hwparams, &buffered_time, 0)) < 0) { LOG_ERROR1("Error setting buffersize: %s", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params(s->fd, hwparams)) < 0) { LOG_ERROR1("Error setting HW params: %s", snd_strerror(err)); goto fail; } /* We're done, and we didn't fail! */ LOG_INFO3("Opened audio device %s at %d channel(s), %d Hz", device, s->channels, s->rate); if(use_metadata) { if(ices_config->metadata_filename) thread_create("im_alsa-metadata", metadata_thread_signal, mod, 1); else thread_create("im_alsa-metadata", metadata_thread_stdin, mod, 1); LOG_INFO0("Started metadata update thread"); } return mod; fail: close_module(mod); /* safe, this checks for valid contents */ return NULL; }